1 | //Copyright (c) 2006-2009 Emil Dotchevski and Reverge Studios, Inc. |
2 | |
3 | //Distributed under the Boost Software License, Version 1.0. (See accompanying |
4 | //file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
5 | |
6 | #ifndef BOOST_EXCEPTION_274DA366004E11DCB1DDFE2E56D89593 |
7 | #define BOOST_EXCEPTION_274DA366004E11DCB1DDFE2E56D89593 |
8 | |
9 | #include <boost/assert/source_location.hpp> |
10 | #include <boost/config.hpp> |
11 | #include <exception> |
12 | |
13 | #ifdef BOOST_EXCEPTION_MINI_BOOST |
14 | #include <memory> |
15 | namespace boost { namespace exception_detail { using std::shared_ptr; } } |
16 | #else |
17 | namespace boost { template <class T> class shared_ptr; } |
18 | namespace boost { namespace exception_detail { using boost::shared_ptr; } } |
19 | #endif |
20 | |
21 | #if !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) |
22 | #if defined(__GNUC__) && __GNUC__*100+__GNUC_MINOR__>301 |
23 | #pragma GCC system_header |
24 | #endif |
25 | #ifdef __clang__ |
26 | #pragma clang system_header |
27 | #endif |
28 | #ifdef _MSC_VER |
29 | #pragma warning(push,1) |
30 | #pragma warning(disable: 4265) |
31 | #endif |
32 | #endif |
33 | |
34 | namespace |
35 | boost |
36 | { |
37 | namespace |
38 | exception_detail |
39 | { |
40 | template <class T> |
41 | class |
42 | refcount_ptr |
43 | { |
44 | public: |
45 | |
46 | refcount_ptr(): |
47 | px_(0) |
48 | { |
49 | } |
50 | |
51 | ~refcount_ptr() |
52 | { |
53 | release(); |
54 | } |
55 | |
56 | refcount_ptr( refcount_ptr const & x ): |
57 | px_(x.px_) |
58 | { |
59 | add_ref(); |
60 | } |
61 | |
62 | refcount_ptr & |
63 | operator=( refcount_ptr const & x ) |
64 | { |
65 | adopt(px: x.px_); |
66 | return *this; |
67 | } |
68 | |
69 | void |
70 | adopt( T * px ) |
71 | { |
72 | release(); |
73 | px_=px; |
74 | add_ref(); |
75 | } |
76 | |
77 | T * |
78 | get() const |
79 | { |
80 | return px_; |
81 | } |
82 | |
83 | private: |
84 | |
85 | T * px_; |
86 | |
87 | void |
88 | add_ref() |
89 | { |
90 | if( px_ ) |
91 | px_->add_ref(); |
92 | } |
93 | |
94 | void |
95 | release() |
96 | { |
97 | if( px_ && px_->release() ) |
98 | px_=0; |
99 | } |
100 | }; |
101 | } |
102 | |
103 | //////////////////////////////////////////////////////////////////////// |
104 | |
105 | template <class Tag,class T> |
106 | class error_info; |
107 | |
108 | typedef error_info<struct throw_function_,char const *> throw_function; |
109 | typedef error_info<struct throw_file_,char const *> throw_file; |
110 | typedef error_info<struct throw_line_,int> throw_line; |
111 | typedef error_info<struct throw_column_,int> throw_column; |
112 | |
113 | template <> |
114 | class |
115 | error_info<throw_function_,char const *> |
116 | { |
117 | public: |
118 | typedef char const * value_type; |
119 | value_type v_; |
120 | explicit |
121 | error_info( value_type v ): |
122 | v_(v) |
123 | { |
124 | } |
125 | }; |
126 | |
127 | template <> |
128 | class |
129 | error_info<throw_file_,char const *> |
130 | { |
131 | public: |
132 | typedef char const * value_type; |
133 | value_type v_; |
134 | explicit |
135 | error_info( value_type v ): |
136 | v_(v) |
137 | { |
138 | } |
139 | }; |
140 | |
141 | template <> |
142 | class |
143 | error_info<throw_line_,int> |
144 | { |
145 | public: |
146 | typedef int value_type; |
147 | value_type v_; |
148 | explicit |
149 | error_info( value_type v ): |
150 | v_(v) |
151 | { |
152 | } |
153 | }; |
154 | |
155 | template <> |
156 | class |
157 | error_info<throw_column_,int> |
158 | { |
159 | public: |
160 | typedef int value_type; |
161 | value_type v_; |
162 | explicit |
163 | error_info( value_type v ): |
164 | v_(v) |
165 | { |
166 | } |
167 | }; |
168 | |
169 | class |
170 | BOOST_SYMBOL_VISIBLE |
171 | exception; |
172 | |
173 | namespace |
174 | exception_detail |
175 | { |
176 | class error_info_base; |
177 | struct type_info_; |
178 | |
179 | struct |
180 | error_info_container |
181 | { |
182 | virtual char const * diagnostic_information( char const * ) const = 0; |
183 | virtual shared_ptr<error_info_base> get( type_info_ const & ) const = 0; |
184 | virtual void set( shared_ptr<error_info_base> const &, type_info_ const & ) = 0; |
185 | virtual void add_ref() const = 0; |
186 | virtual bool release() const = 0; |
187 | virtual refcount_ptr<exception_detail::error_info_container> clone() const = 0; |
188 | |
189 | protected: |
190 | |
191 | ~error_info_container() BOOST_NOEXCEPT_OR_NOTHROW |
192 | { |
193 | } |
194 | }; |
195 | |
196 | template <class> |
197 | struct get_info; |
198 | |
199 | template <> |
200 | struct get_info<throw_function>; |
201 | |
202 | template <> |
203 | struct get_info<throw_file>; |
204 | |
205 | template <> |
206 | struct get_info<throw_line>; |
207 | |
208 | template <> |
209 | struct get_info<throw_column>; |
210 | |
211 | template <class> |
212 | struct set_info_rv; |
213 | |
214 | template <> |
215 | struct set_info_rv<throw_function>; |
216 | |
217 | template <> |
218 | struct set_info_rv<throw_file>; |
219 | |
220 | template <> |
221 | struct set_info_rv<throw_line>; |
222 | |
223 | template <> |
224 | struct set_info_rv<throw_column>; |
225 | |
226 | char const * get_diagnostic_information( exception const &, char const * ); |
227 | |
228 | void copy_boost_exception( exception *, exception const * ); |
229 | |
230 | template <class E,class Tag,class T> |
231 | E const & set_info( E const &, error_info<Tag,T> const & ); |
232 | |
233 | template <class E> |
234 | E const & set_info( E const &, throw_function const & ); |
235 | |
236 | template <class E> |
237 | E const & set_info( E const &, throw_file const & ); |
238 | |
239 | template <class E> |
240 | E const & set_info( E const &, throw_line const & ); |
241 | |
242 | template <class E> |
243 | E const & set_info( E const &, throw_column const & ); |
244 | |
245 | boost::source_location get_exception_throw_location( exception const & ); |
246 | } |
247 | |
248 | class |
249 | BOOST_SYMBOL_VISIBLE |
250 | exception |
251 | { |
252 | //<N3757> |
253 | public: |
254 | template <class Tag> void set( typename Tag::type const & ); |
255 | template <class Tag> typename Tag::type const * get() const; |
256 | //</N3757> |
257 | |
258 | protected: |
259 | |
260 | exception(): |
261 | throw_function_(0), |
262 | throw_file_(0), |
263 | throw_line_(-1), |
264 | throw_column_(-1) |
265 | { |
266 | } |
267 | |
268 | #ifdef __HP_aCC |
269 | //On HP aCC, this protected copy constructor prevents throwing boost::exception. |
270 | //On all other platforms, the same effect is achieved by the pure virtual destructor. |
271 | exception( exception const & x ) BOOST_NOEXCEPT_OR_NOTHROW: |
272 | data_(x.data_), |
273 | throw_function_(x.throw_function_), |
274 | throw_file_(x.throw_file_), |
275 | throw_line_(x.throw_line_), |
276 | throw_column_(x.throw_column_) |
277 | { |
278 | } |
279 | #endif |
280 | |
281 | virtual ~exception() BOOST_NOEXCEPT_OR_NOTHROW |
282 | #ifndef __HP_aCC |
283 | = 0 //Workaround for HP aCC, =0 incorrectly leads to link errors. |
284 | #endif |
285 | ; |
286 | |
287 | #if (defined(__MWERKS__) && __MWERKS__<=0x3207) || (defined(_MSC_VER) && _MSC_VER<=1310) |
288 | public: |
289 | #else |
290 | private: |
291 | |
292 | template <class E> |
293 | friend E const & exception_detail::set_info( E const &, throw_function const & ); |
294 | |
295 | template <class E> |
296 | friend E const & exception_detail::set_info( E const &, throw_file const & ); |
297 | |
298 | template <class E> |
299 | friend E const & exception_detail::set_info( E const &, throw_line const & ); |
300 | |
301 | template <class E> |
302 | friend E const & exception_detail::set_info( E const &, throw_column const & ); |
303 | |
304 | template <class E,class Tag,class T> |
305 | friend E const & exception_detail::set_info( E const &, error_info<Tag,T> const & ); |
306 | |
307 | friend char const * exception_detail::get_diagnostic_information( exception const &, char const * ); |
308 | |
309 | friend boost::source_location exception_detail::get_exception_throw_location( exception const & ); |
310 | |
311 | template <class> |
312 | friend struct exception_detail::get_info; |
313 | friend struct exception_detail::get_info<throw_function>; |
314 | friend struct exception_detail::get_info<throw_file>; |
315 | friend struct exception_detail::get_info<throw_line>; |
316 | friend struct exception_detail::get_info<throw_column>; |
317 | template <class> |
318 | friend struct exception_detail::set_info_rv; |
319 | friend struct exception_detail::set_info_rv<throw_function>; |
320 | friend struct exception_detail::set_info_rv<throw_file>; |
321 | friend struct exception_detail::set_info_rv<throw_line>; |
322 | friend struct exception_detail::set_info_rv<throw_column>; |
323 | friend void exception_detail::copy_boost_exception( exception *, exception const * ); |
324 | #endif |
325 | mutable exception_detail::refcount_ptr<exception_detail::error_info_container> data_; |
326 | mutable char const * throw_function_; |
327 | mutable char const * throw_file_; |
328 | mutable int throw_line_; |
329 | mutable int throw_column_; |
330 | }; |
331 | |
332 | inline |
333 | exception:: |
334 | ~exception() BOOST_NOEXCEPT_OR_NOTHROW |
335 | { |
336 | } |
337 | |
338 | namespace |
339 | exception_detail |
340 | { |
341 | template <class E> |
342 | E const & |
343 | set_info( E const & x, throw_function const & y ) |
344 | { |
345 | x.throw_function_=y.v_; |
346 | return x; |
347 | } |
348 | |
349 | template <class E> |
350 | E const & |
351 | set_info( E const & x, throw_file const & y ) |
352 | { |
353 | x.throw_file_=y.v_; |
354 | return x; |
355 | } |
356 | |
357 | template <class E> |
358 | E const & |
359 | set_info( E const & x, throw_line const & y ) |
360 | { |
361 | x.throw_line_=y.v_; |
362 | return x; |
363 | } |
364 | |
365 | template <class E> |
366 | E const & |
367 | set_info( E const & x, throw_column const & y ) |
368 | { |
369 | x.throw_column_=y.v_; |
370 | return x; |
371 | } |
372 | |
373 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
374 | |
375 | template <> |
376 | struct |
377 | set_info_rv<throw_column> |
378 | { |
379 | template <class E> |
380 | static |
381 | E const & |
382 | set( E const & x, throw_column && y ) |
383 | { |
384 | x.throw_column_=y.v_; |
385 | return x; |
386 | } |
387 | }; |
388 | |
389 | #endif |
390 | |
391 | inline boost::source_location get_exception_throw_location( exception const & x ) |
392 | { |
393 | return boost::source_location( |
394 | x.throw_file_? x.throw_file_: "" , |
395 | x.throw_line_ >= 0? x.throw_line_: 0, |
396 | x.throw_function_? x.throw_function_: "" , |
397 | x.throw_column_ >= 0? x.throw_column_: 0 |
398 | ); |
399 | } |
400 | } |
401 | |
402 | //////////////////////////////////////////////////////////////////////// |
403 | |
404 | namespace |
405 | exception_detail |
406 | { |
407 | template <class T> |
408 | struct |
409 | BOOST_SYMBOL_VISIBLE |
410 | error_info_injector: |
411 | public T, |
412 | public exception |
413 | { |
414 | explicit |
415 | error_info_injector( T const & x ): |
416 | T(x) |
417 | { |
418 | } |
419 | |
420 | ~error_info_injector() BOOST_NOEXCEPT_OR_NOTHROW |
421 | { |
422 | } |
423 | }; |
424 | |
425 | struct large_size { char c[256]; }; |
426 | large_size dispatch_boost_exception( exception const * ); |
427 | |
428 | struct small_size { }; |
429 | small_size dispatch_boost_exception( void const * ); |
430 | |
431 | template <class,int> |
432 | struct enable_error_info_helper; |
433 | |
434 | template <class T> |
435 | struct |
436 | enable_error_info_helper<T,sizeof(large_size)> |
437 | { |
438 | typedef T type; |
439 | }; |
440 | |
441 | template <class T> |
442 | struct |
443 | enable_error_info_helper<T,sizeof(small_size)> |
444 | { |
445 | typedef error_info_injector<T> type; |
446 | }; |
447 | |
448 | template <class T> |
449 | struct |
450 | enable_error_info_return_type |
451 | { |
452 | typedef typename enable_error_info_helper<T,sizeof(exception_detail::dispatch_boost_exception(static_cast<T *>(0)))>::type type; |
453 | }; |
454 | } |
455 | |
456 | template <class T> |
457 | inline |
458 | typename |
459 | exception_detail::enable_error_info_return_type<T>::type |
460 | enable_error_info( T const & x ) |
461 | { |
462 | typedef typename exception_detail::enable_error_info_return_type<T>::type rt; |
463 | return rt(x); |
464 | } |
465 | |
466 | //////////////////////////////////////////////////////////////////////// |
467 | #if defined(BOOST_NO_EXCEPTIONS) |
468 | BOOST_NORETURN void throw_exception(std::exception const & e); // user defined |
469 | #endif |
470 | |
471 | namespace |
472 | exception_detail |
473 | { |
474 | class |
475 | BOOST_SYMBOL_VISIBLE |
476 | clone_base |
477 | { |
478 | public: |
479 | |
480 | virtual clone_base const * clone() const = 0; |
481 | virtual void rethrow() const = 0; |
482 | |
483 | virtual |
484 | ~clone_base() BOOST_NOEXCEPT_OR_NOTHROW |
485 | { |
486 | } |
487 | }; |
488 | |
489 | inline |
490 | void |
491 | copy_boost_exception( exception * a, exception const * b ) |
492 | { |
493 | refcount_ptr<error_info_container> data; |
494 | if( error_info_container * d=b->data_.get() ) |
495 | data = d->clone(); |
496 | a->throw_file_ = b->throw_file_; |
497 | a->throw_line_ = b->throw_line_; |
498 | a->throw_function_ = b->throw_function_; |
499 | a->throw_column_ = b->throw_column_; |
500 | a->data_ = data; |
501 | } |
502 | |
503 | inline |
504 | void |
505 | copy_boost_exception( void *, void const * ) |
506 | { |
507 | } |
508 | |
509 | template <class T> |
510 | class |
511 | BOOST_SYMBOL_VISIBLE |
512 | clone_impl: |
513 | public T, |
514 | public virtual clone_base |
515 | { |
516 | struct clone_tag { }; |
517 | clone_impl( clone_impl const & x, clone_tag ): |
518 | T(x) |
519 | { |
520 | copy_boost_exception(this,&x); |
521 | } |
522 | |
523 | public: |
524 | |
525 | explicit |
526 | clone_impl( T const & x ): |
527 | T(x) |
528 | { |
529 | copy_boost_exception(this,&x); |
530 | } |
531 | |
532 | ~clone_impl() BOOST_NOEXCEPT_OR_NOTHROW |
533 | { |
534 | } |
535 | |
536 | private: |
537 | |
538 | clone_base const * |
539 | clone() const |
540 | { |
541 | return new clone_impl(*this,clone_tag()); |
542 | } |
543 | |
544 | void |
545 | rethrow() const |
546 | { |
547 | #if defined(BOOST_NO_EXCEPTIONS) |
548 | boost::throw_exception(*this); |
549 | #else |
550 | throw*this; |
551 | #endif |
552 | } |
553 | }; |
554 | } |
555 | |
556 | template <class T> |
557 | inline |
558 | exception_detail::clone_impl<T> |
559 | enable_current_exception( T const & x ) |
560 | { |
561 | return exception_detail::clone_impl<T>(x); |
562 | } |
563 | } |
564 | |
565 | #if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) |
566 | #pragma warning(pop) |
567 | #endif |
568 | |
569 | #endif // #ifndef BOOST_EXCEPTION_274DA366004E11DCB1DDFE2E56D89593 |
570 | |