]>
Commit | Line | Data |
---|---|---|
20effc67 TL |
1 | #ifndef BOOST_LEAF_HANDLE_ERRORS_HPP_INCLUDED |
2 | #define BOOST_LEAF_HANDLE_ERRORS_HPP_INCLUDED | |
3 | ||
4 | // Copyright (c) 2018-2020 Emil Dotchevski and Reverge Studios, Inc. | |
5 | ||
6 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
7 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
8 | ||
9 | #ifndef BOOST_LEAF_ENABLE_WARNINGS | |
10 | # if defined(__clang__) | |
11 | # pragma clang system_header | |
12 | # elif (__GNUC__*100+__GNUC_MINOR__>301) | |
13 | # pragma GCC system_header | |
14 | # elif defined(_MSC_VER) | |
15 | # pragma warning(push,1) | |
16 | # endif | |
17 | #endif | |
18 | ||
19 | #include <boost/leaf/context.hpp> | |
20 | #include <boost/leaf/detail/demangle.hpp> | |
21 | ||
22 | #ifndef BOOST_LEAF_NO_EXCEPTIONS | |
23 | # include <boost/leaf/capture.hpp> | |
24 | #endif | |
25 | ||
26 | namespace boost { namespace leaf { | |
27 | ||
28 | class error_info | |
29 | { | |
30 | error_info & operator=( error_info const & ) = delete; | |
31 | ||
32 | #ifndef BOOST_LEAF_NO_EXCEPTIONS | |
33 | static error_id unpack_error_id( std::exception const * ex ) noexcept | |
34 | { | |
35 | if( std::system_error const * se = dynamic_cast<std::system_error const *>(ex) ) | |
36 | if( is_error_id(se->code()) ) | |
37 | return leaf_detail::make_error_id(se->code().value()); | |
38 | if( std::error_code const * ec = dynamic_cast<std::error_code const *>(ex) ) | |
39 | if( is_error_id(*ec) ) | |
40 | return leaf_detail::make_error_id(ec->value()); | |
41 | if( error_id const * err_id = dynamic_cast<error_id const *>(ex) ) | |
42 | return *err_id; | |
43 | return current_error(); | |
44 | } | |
45 | ||
46 | std::exception * const ex_; | |
47 | #endif | |
48 | ||
49 | error_id const err_id_; | |
50 | ||
51 | protected: | |
52 | ||
53 | error_info( error_info const & ) noexcept = default; | |
54 | ||
55 | template <class CharT, class Traits> | |
56 | void print( std::basic_ostream<CharT, Traits> & os ) const | |
57 | { | |
58 | os << "Error ID = " << err_id_.value(); | |
59 | #ifndef BOOST_LEAF_NO_EXCEPTIONS | |
60 | if( ex_ ) | |
61 | { | |
62 | os << | |
63 | "\nException dynamic type: " << leaf_detail::demangle(typeid(*ex_).name()) << | |
64 | "\nstd::exception::what(): " << ex_->what(); | |
65 | } | |
66 | #endif | |
67 | } | |
68 | ||
69 | public: | |
70 | ||
71 | BOOST_LEAF_CONSTEXPR explicit error_info( error_id id ) noexcept: | |
72 | #ifndef BOOST_LEAF_NO_EXCEPTIONS | |
73 | ex_(0), | |
74 | #endif | |
75 | err_id_(id) | |
76 | { | |
77 | } | |
78 | ||
79 | #ifndef BOOST_LEAF_NO_EXCEPTIONS | |
80 | explicit error_info( std::exception * ex ) noexcept: | |
81 | ex_(ex), | |
82 | err_id_(unpack_error_id(ex_)) | |
83 | { | |
84 | } | |
85 | #endif | |
86 | ||
87 | BOOST_LEAF_CONSTEXPR error_id error() const noexcept | |
88 | { | |
89 | return err_id_; | |
90 | } | |
91 | ||
92 | BOOST_LEAF_CONSTEXPR std::exception * exception() const noexcept | |
93 | { | |
94 | #ifdef BOOST_LEAF_NO_EXCEPTIONS | |
95 | return nullptr; | |
96 | #else | |
97 | return ex_; | |
98 | #endif | |
99 | } | |
100 | ||
101 | template <class CharT, class Traits> | |
102 | friend std::basic_ostream<CharT, Traits> & operator<<( std::basic_ostream<CharT, Traits> & os, error_info const & x ) | |
103 | { | |
104 | os << "leaf::error_info: "; | |
105 | x.print(os); | |
106 | return os << '\n'; | |
107 | } | |
108 | }; | |
109 | ||
110 | //////////////////////////////////////// | |
111 | ||
112 | #if BOOST_LEAF_DIAGNOSTICS | |
113 | ||
114 | class diagnostic_info: public error_info | |
115 | { | |
116 | leaf_detail::e_unexpected_count const * e_uc_; | |
117 | void const * tup_; | |
118 | void (*print_)( std::ostream &, void const * tup, int key_to_print ); | |
119 | ||
120 | protected: | |
121 | ||
122 | diagnostic_info( diagnostic_info const & ) noexcept = default; | |
123 | ||
124 | template <class Tup> | |
125 | BOOST_LEAF_CONSTEXPR diagnostic_info( error_info const & ei, leaf_detail::e_unexpected_count const * e_uc, Tup const & tup ) noexcept: | |
126 | error_info(ei), | |
127 | e_uc_(e_uc), | |
128 | tup_(&tup), | |
129 | print_(&leaf_detail::tuple_for_each<std::tuple_size<Tup>::value, Tup>::print) | |
130 | { | |
131 | } | |
132 | ||
133 | public: | |
134 | ||
135 | template <class CharT, class Traits> | |
136 | friend std::basic_ostream<CharT, Traits> & operator<<( std::basic_ostream<CharT, Traits> & os, diagnostic_info const & x ) | |
137 | { | |
138 | os << "leaf::diagnostic_info for "; | |
139 | x.print(os); | |
140 | os << ":\n"; | |
141 | x.print_(os, x.tup_, x.error().value()); | |
142 | if( x.e_uc_ ) | |
143 | x.e_uc_->print(os); | |
144 | return os; | |
145 | } | |
146 | }; | |
147 | ||
148 | namespace leaf_detail | |
149 | { | |
150 | struct diagnostic_info_: diagnostic_info | |
151 | { | |
152 | template <class Tup> | |
153 | BOOST_LEAF_CONSTEXPR diagnostic_info_( error_info const & ei, leaf_detail::e_unexpected_count const * e_uc, Tup const & tup ) noexcept: | |
154 | diagnostic_info(ei, e_uc, tup) | |
155 | { | |
156 | } | |
157 | }; | |
158 | ||
159 | template <> | |
160 | struct handler_argument_traits<diagnostic_info const &>: handler_argument_always_available<e_unexpected_count> | |
161 | { | |
162 | template <class Tup> | |
163 | BOOST_LEAF_CONSTEXPR static diagnostic_info_ get( Tup const & tup, error_info const & ei ) noexcept | |
164 | { | |
165 | return diagnostic_info_(ei, handler_argument_traits_defaults<e_unexpected_count>::check(tup, ei), tup); | |
166 | } | |
167 | }; | |
168 | } | |
169 | ||
170 | #else | |
171 | ||
172 | class diagnostic_info: public error_info | |
173 | { | |
174 | protected: | |
175 | ||
176 | diagnostic_info( diagnostic_info const & ) noexcept = default; | |
177 | ||
178 | BOOST_LEAF_CONSTEXPR diagnostic_info( error_info const & ei ) noexcept: | |
179 | error_info(ei) | |
180 | { | |
181 | } | |
182 | ||
183 | public: | |
184 | ||
185 | template <class CharT, class Traits> | |
186 | friend std::basic_ostream<CharT, Traits> & operator<<( std::basic_ostream<CharT, Traits> & os, diagnostic_info const & x ) | |
187 | { | |
188 | os << | |
189 | "leaf::diagnostic_info requires #define BOOST_LEAF_DIAGNOSTICS 1\n" | |
190 | "leaf::error_info: "; | |
191 | x.print(os); | |
192 | return os << '\n'; | |
193 | } | |
194 | }; | |
195 | ||
196 | namespace leaf_detail | |
197 | { | |
198 | struct diagnostic_info_: diagnostic_info | |
199 | { | |
200 | BOOST_LEAF_CONSTEXPR diagnostic_info_( error_info const & ei ) noexcept: | |
201 | diagnostic_info(ei) | |
202 | { | |
203 | } | |
204 | }; | |
205 | ||
206 | template <> | |
207 | struct handler_argument_traits<diagnostic_info const &>: handler_argument_always_available<void> | |
208 | { | |
209 | template <class Tup> | |
210 | BOOST_LEAF_CONSTEXPR static diagnostic_info_ get( Tup const & tup, error_info const & ei ) noexcept | |
211 | { | |
212 | return diagnostic_info_(ei); | |
213 | } | |
214 | }; | |
215 | } | |
216 | ||
217 | #endif | |
218 | ||
219 | //////////////////////////////////////// | |
220 | ||
221 | #if BOOST_LEAF_DIAGNOSTICS | |
222 | ||
223 | class verbose_diagnostic_info: public error_info | |
224 | { | |
225 | leaf_detail::e_unexpected_info const * e_ui_; | |
226 | void const * tup_; | |
227 | void (*print_)( std::ostream &, void const * tup, int key_to_print ); | |
228 | ||
229 | protected: | |
230 | ||
231 | verbose_diagnostic_info( verbose_diagnostic_info const & ) noexcept = default; | |
232 | ||
233 | template <class Tup> | |
234 | BOOST_LEAF_CONSTEXPR verbose_diagnostic_info( error_info const & ei, leaf_detail::e_unexpected_info const * e_ui, Tup const & tup ) noexcept: | |
235 | error_info(ei), | |
236 | e_ui_(e_ui), | |
237 | tup_(&tup), | |
238 | print_(&leaf_detail::tuple_for_each<std::tuple_size<Tup>::value, Tup>::print) | |
239 | { | |
240 | } | |
241 | ||
242 | public: | |
243 | ||
244 | template <class CharT, class Traits> | |
245 | friend std::basic_ostream<CharT, Traits> & operator<<( std::basic_ostream<CharT, Traits> & os, verbose_diagnostic_info const & x ) | |
246 | { | |
247 | os << "leaf::verbose_diagnostic_info for "; | |
248 | x.print(os); | |
249 | os << ":\n"; | |
250 | x.print_(os, x.tup_, x.error().value()); | |
251 | if( x.e_ui_ ) | |
252 | x.e_ui_->print(os); | |
253 | return os; | |
254 | } | |
255 | }; | |
256 | ||
257 | namespace leaf_detail | |
258 | { | |
259 | struct verbose_diagnostic_info_: verbose_diagnostic_info | |
260 | { | |
261 | template <class Tup> | |
262 | BOOST_LEAF_CONSTEXPR verbose_diagnostic_info_( error_info const & ei, leaf_detail::e_unexpected_info const * e_ui, Tup const & tup ) noexcept: | |
263 | verbose_diagnostic_info(ei, e_ui, tup) | |
264 | { | |
265 | } | |
266 | }; | |
267 | ||
268 | template <> | |
269 | struct handler_argument_traits<verbose_diagnostic_info const &>: handler_argument_always_available<e_unexpected_info> | |
270 | { | |
271 | template <class Tup> | |
272 | BOOST_LEAF_CONSTEXPR static verbose_diagnostic_info_ get( Tup const & tup, error_info const & ei ) noexcept | |
273 | { | |
274 | return verbose_diagnostic_info_(ei, handler_argument_traits_defaults<e_unexpected_info>::check(tup, ei), tup); | |
275 | } | |
276 | }; | |
277 | } | |
278 | ||
279 | #else | |
280 | ||
281 | class verbose_diagnostic_info: public error_info | |
282 | { | |
283 | protected: | |
284 | ||
285 | verbose_diagnostic_info( verbose_diagnostic_info const & ) noexcept = default; | |
286 | ||
287 | BOOST_LEAF_CONSTEXPR verbose_diagnostic_info( error_info const & ei ) noexcept: | |
288 | error_info(ei) | |
289 | { | |
290 | } | |
291 | ||
292 | public: | |
293 | ||
294 | template <class CharT, class Traits> | |
295 | friend std::basic_ostream<CharT, Traits> & operator<<( std::basic_ostream<CharT, Traits> & os, verbose_diagnostic_info const & x ) | |
296 | { | |
297 | os << | |
298 | "leaf::verbose_diagnostic_info requires #define BOOST_LEAF_DIAGNOSTICS 1\n" | |
299 | "leaf::error_info: "; | |
300 | x.print(os); | |
301 | return os << '\n'; | |
302 | } | |
303 | }; | |
304 | ||
305 | namespace leaf_detail | |
306 | { | |
307 | struct verbose_diagnostic_info_: verbose_diagnostic_info | |
308 | { | |
309 | BOOST_LEAF_CONSTEXPR verbose_diagnostic_info_( error_info const & ei ) noexcept: | |
310 | verbose_diagnostic_info(ei) | |
311 | { | |
312 | } | |
313 | }; | |
314 | ||
315 | ||
316 | template <> | |
317 | struct handler_argument_traits<verbose_diagnostic_info const &>: handler_argument_always_available<void> | |
318 | { | |
319 | template <class Tup> | |
320 | BOOST_LEAF_CONSTEXPR static verbose_diagnostic_info_ get( Tup const & tup, error_info const & ei ) noexcept | |
321 | { | |
322 | return verbose_diagnostic_info_(ei); | |
323 | } | |
324 | }; | |
325 | } | |
326 | ||
327 | #endif | |
328 | ||
329 | //////////////////////////////////////// | |
330 | ||
331 | namespace leaf_detail | |
332 | { | |
333 | template <class T, class... List> | |
334 | struct type_index; | |
335 | ||
336 | template <class T, class... Cdr> | |
337 | struct type_index<T, T, Cdr...> | |
338 | { | |
339 | constexpr static int value = 0; | |
340 | }; | |
341 | ||
342 | template <class T, class Car, class... Cdr> | |
343 | struct type_index<T, Car, Cdr...> | |
344 | { | |
345 | constexpr static int value = 1 + type_index<T,Cdr...>::value; | |
346 | }; | |
347 | ||
348 | template <class T, class Tuple> | |
349 | struct tuple_type_index; | |
350 | ||
351 | template <class T, class... TupleTypes> | |
352 | struct tuple_type_index<T,std::tuple<TupleTypes...>> | |
353 | { | |
354 | constexpr static int value = type_index<T,TupleTypes...>::value; | |
355 | }; | |
356 | ||
357 | #ifndef BOOST_LEAF_NO_EXCEPTIONS | |
358 | ||
359 | template <class E, bool = std::is_class<E>::value> | |
360 | struct peek_exception; | |
361 | ||
362 | template <> | |
363 | struct peek_exception<std::exception const, true> | |
364 | { | |
365 | BOOST_LEAF_CONSTEXPR static std::exception const * peek( error_info const & ei ) noexcept | |
366 | { | |
367 | return ei.exception(); | |
368 | } | |
369 | }; | |
370 | ||
371 | template <> | |
372 | struct peek_exception<std::exception, true> | |
373 | { | |
374 | BOOST_LEAF_CONSTEXPR static std::exception * peek( error_info const & ei ) noexcept | |
375 | { | |
376 | return ei.exception(); | |
377 | } | |
378 | }; | |
379 | ||
380 | template <> | |
381 | struct peek_exception<std::error_code const, true> | |
382 | { | |
383 | static std::error_code const * peek( error_info const & ei ) noexcept | |
384 | { | |
385 | auto const ex = ei.exception(); | |
386 | if( std::system_error * se = dynamic_cast<std::system_error *>(ex) ) | |
387 | return &se->code(); | |
388 | else if( std::error_code * ec = dynamic_cast<std::error_code *>(ex) ) | |
389 | return ec; | |
390 | else | |
391 | return 0; | |
392 | } | |
393 | }; | |
394 | ||
395 | template <> | |
396 | struct peek_exception<std::error_code, true> | |
397 | { | |
398 | static std::error_code * peek( error_info const & ei ) noexcept | |
399 | { | |
400 | auto const ex = ei.exception(); | |
401 | if( std::system_error * se = dynamic_cast<std::system_error *>(ex) ) | |
402 | return const_cast<std::error_code *>(&se->code()); | |
403 | else if( std::error_code * ec = dynamic_cast<std::error_code *>(ex) ) | |
404 | return ec; | |
405 | else | |
406 | return 0; | |
407 | } | |
408 | }; | |
409 | ||
410 | template <class E> | |
411 | struct peek_exception<E, true> | |
412 | { | |
413 | static E * peek( error_info const & ei ) noexcept | |
414 | { | |
415 | return dynamic_cast<E *>(ei.exception()); | |
416 | } | |
417 | }; | |
418 | ||
419 | template <class E> | |
420 | struct peek_exception<E, false> | |
421 | { | |
422 | BOOST_LEAF_CONSTEXPR static E * peek( error_info const & ) noexcept | |
423 | { | |
424 | return 0; | |
425 | } | |
426 | }; | |
427 | ||
428 | #endif | |
429 | ||
430 | template <class E, class SlotsTuple> | |
431 | BOOST_LEAF_CONSTEXPR inline | |
432 | E const * | |
433 | peek( SlotsTuple const & tup, error_info const & ei ) noexcept | |
434 | { | |
435 | if( error_id err = ei.error() ) | |
436 | if( E const * e = std::get<tuple_type_index<slot<E>,SlotsTuple>::value>(tup).has_value(err.value()) ) | |
437 | return e; | |
438 | #ifndef BOOST_LEAF_NO_EXCEPTIONS | |
439 | else | |
440 | return peek_exception<E const>::peek(ei); | |
441 | #endif | |
442 | return 0; | |
443 | } | |
444 | ||
445 | template <class E, class SlotsTuple> | |
446 | BOOST_LEAF_CONSTEXPR inline | |
447 | E * | |
448 | peek( SlotsTuple & tup, error_info const & ei ) noexcept | |
449 | { | |
450 | if( error_id err = ei.error() ) | |
451 | if( E * e = std::get<tuple_type_index<slot<E>,SlotsTuple>::value>(tup).has_value(err.value()) ) | |
452 | return e; | |
453 | #ifndef BOOST_LEAF_NO_EXCEPTIONS | |
454 | else | |
455 | return peek_exception<E>::peek(ei); | |
456 | #endif | |
457 | return 0; | |
458 | } | |
459 | } | |
460 | ||
461 | //////////////////////////////////////// | |
462 | ||
463 | namespace leaf_detail | |
464 | { | |
465 | template <class A> | |
466 | template <class Tup> | |
467 | BOOST_LEAF_CONSTEXPR inline | |
468 | typename handler_argument_traits_defaults<A, false>::error_type const * | |
469 | handler_argument_traits_defaults<A, false>:: | |
470 | check( Tup const & tup, error_info const & ei ) noexcept | |
471 | { | |
472 | return peek<typename std::decay<A>::type>(tup, ei); | |
473 | } | |
474 | ||
475 | template <class A> | |
476 | template <class Tup> | |
477 | BOOST_LEAF_CONSTEXPR inline | |
478 | typename handler_argument_traits_defaults<A, false>::error_type * | |
479 | handler_argument_traits_defaults<A, false>:: | |
480 | check( Tup & tup, error_info const & ei ) noexcept | |
481 | { | |
482 | return peek<typename std::decay<A>::type>(tup, ei); | |
483 | } | |
484 | ||
485 | template <class Tup> | |
486 | BOOST_LEAF_CONSTEXPR inline | |
487 | std::exception const * | |
488 | handler_argument_traits<void>:: | |
489 | check( Tup const &, error_info const & ei ) noexcept | |
490 | { | |
491 | return ei.exception(); | |
492 | } | |
493 | ||
494 | template <class Tup, class... List> | |
495 | struct check_arguments; | |
496 | ||
497 | template <class Tup> | |
498 | struct check_arguments<Tup> | |
499 | { | |
500 | BOOST_LEAF_CONSTEXPR static bool check( Tup const &, error_info const & ) | |
501 | { | |
502 | return true; | |
503 | } | |
504 | }; | |
505 | ||
506 | template <class Tup, class Car, class... Cdr> | |
507 | struct check_arguments<Tup, Car, Cdr...> | |
508 | { | |
509 | BOOST_LEAF_CONSTEXPR static bool check( Tup & tup, error_info const & ei ) noexcept | |
510 | { | |
511 | return handler_argument_traits<Car>::check(tup, ei) && check_arguments<Tup, Cdr...>::check(tup, ei); | |
512 | } | |
513 | }; | |
514 | } | |
515 | ||
516 | //////////////////////////////////////// | |
517 | ||
518 | namespace leaf_detail | |
519 | { | |
520 | template <class> | |
521 | struct handler_matches_any_error: std::false_type | |
522 | { | |
523 | }; | |
524 | ||
525 | template <template<class...> class L> | |
526 | struct handler_matches_any_error<L<>>: std::true_type | |
527 | { | |
528 | }; | |
529 | ||
530 | template <template<class...> class L, class Car, class... Cdr> | |
531 | struct handler_matches_any_error<L<Car, Cdr...>> | |
532 | { | |
533 | constexpr static bool value = handler_argument_traits<Car>::always_available && handler_matches_any_error<L<Cdr...>>::value; | |
534 | }; | |
535 | } | |
536 | ||
537 | //////////////////////////////////////// | |
538 | ||
539 | namespace leaf_detail | |
540 | { | |
541 | template <class Tup, class... A> | |
542 | BOOST_LEAF_CONSTEXPR inline bool check_handler_( Tup & tup, error_info const & ei, leaf_detail_mp11::mp_list<A...> ) noexcept | |
543 | { | |
544 | return check_arguments<Tup, A...>::check(tup, ei); | |
545 | } | |
546 | ||
547 | template <class R, class F, bool IsResult = is_result_type<R>::value, class FReturnType = fn_return_type<F>> | |
548 | struct handler_caller | |
549 | { | |
550 | template <class Tup, class... A> | |
551 | BOOST_LEAF_CONSTEXPR static R call( Tup & tup, error_info const & ei, F && f, leaf_detail_mp11::mp_list<A...> ) | |
552 | { | |
553 | return std::forward<F>(f)( handler_argument_traits<A>::get(tup, ei)... ); | |
554 | } | |
555 | }; | |
556 | ||
557 | template <template <class...> class Result, class... E, class F> | |
558 | struct handler_caller<Result<void, E...>, F, true, void> | |
559 | { | |
560 | using R = Result<void, E...>; | |
561 | ||
562 | template <class Tup, class... A> | |
563 | BOOST_LEAF_CONSTEXPR static R call( Tup & tup, error_info const & ei, F && f, leaf_detail_mp11::mp_list<A...> ) | |
564 | { | |
565 | std::forward<F>(f)( handler_argument_traits<A>::get(tup, ei)... ); | |
566 | return { }; | |
567 | } | |
568 | }; | |
569 | ||
570 | template <class T> | |
571 | struct is_tuple: std::false_type { }; | |
572 | ||
573 | template <class... T> | |
574 | struct is_tuple<std::tuple<T...>>: std::true_type { }; | |
575 | ||
576 | template <class... T> | |
577 | struct is_tuple<std::tuple<T...> &>: std::true_type { }; | |
578 | ||
579 | template <class R, class Tup, class H> | |
580 | BOOST_LEAF_CONSTEXPR | |
581 | inline | |
582 | typename std::enable_if<!is_tuple<H>::value, R>::type | |
583 | handle_error_( Tup & tup, error_info const & ei, H && h ) | |
584 | { | |
585 | static_assert( handler_matches_any_error<fn_mp_args<H>>::value, "The last handler passed to handle_all must match any error." ); | |
586 | return handler_caller<R, H>::call( tup, ei, std::forward<H>(h), fn_mp_args<H>{ } ); | |
587 | } | |
588 | ||
589 | template <class R, class Tup, class Car, class... Cdr> | |
590 | BOOST_LEAF_CONSTEXPR inline | |
591 | typename std::enable_if<!is_tuple<Car>::value, R>::type | |
592 | handle_error_( Tup & tup, error_info const & ei, Car && car, Cdr && ... cdr ) | |
593 | { | |
594 | if( handler_matches_any_error<fn_mp_args<Car>>::value || check_handler_( tup, ei, fn_mp_args<Car>{ } ) ) | |
595 | return handler_caller<R, Car>::call( tup, ei, std::forward<Car>(car), fn_mp_args<Car>{ } ); | |
596 | else | |
597 | return handle_error_<R>( tup, ei, std::forward<Cdr>(cdr)...); | |
598 | } | |
599 | ||
600 | template <class R, class Tup, class HTup, size_t ... I> | |
601 | BOOST_LEAF_CONSTEXPR inline | |
602 | R | |
603 | handle_error_tuple_( Tup & tup, error_info const & ei, leaf_detail_mp11::index_sequence<I...>, HTup && htup ) | |
604 | { | |
605 | return handle_error_<R>(tup, ei, std::get<I>(std::forward<HTup>(htup))...); | |
606 | } | |
607 | ||
608 | template <class R, class Tup, class HTup, class... Cdr, size_t ... I> | |
609 | BOOST_LEAF_CONSTEXPR inline | |
610 | R | |
611 | handle_error_tuple_( Tup & tup, error_info const & ei, leaf_detail_mp11::index_sequence<I...>, HTup && htup, Cdr && ... cdr ) | |
612 | { | |
613 | return handle_error_<R>(tup, ei, std::get<I>(std::forward<HTup>(htup))..., std::forward<Cdr>(cdr)...); | |
614 | } | |
615 | ||
616 | template <class R, class Tup, class H> | |
617 | BOOST_LEAF_CONSTEXPR inline | |
618 | typename std::enable_if<is_tuple<H>::value, R>::type | |
619 | handle_error_( Tup & tup, error_info const & ei, H && h ) | |
620 | { | |
621 | return handle_error_tuple_<R>( | |
622 | tup, | |
623 | ei, | |
624 | leaf_detail_mp11::make_index_sequence<std::tuple_size<typename std::decay<H>::type>::value>(), | |
625 | std::forward<H>(h)); | |
626 | } | |
627 | ||
628 | template <class R, class Tup, class Car, class... Cdr> | |
629 | BOOST_LEAF_CONSTEXPR inline | |
630 | typename std::enable_if<is_tuple<Car>::value, R>::type | |
631 | handle_error_( Tup & tup, error_info const & ei, Car && car, Cdr && ... cdr ) | |
632 | { | |
633 | return handle_error_tuple_<R>( | |
634 | tup, | |
635 | ei, | |
636 | leaf_detail_mp11::make_index_sequence<std::tuple_size<typename std::decay<Car>::type>::value>(), | |
637 | std::forward<Car>(car), | |
638 | std::forward<Cdr>(cdr)...); | |
639 | } | |
640 | } | |
641 | ||
642 | //////////////////////////////////////// | |
643 | ||
644 | template <class... E> | |
645 | template <class R, class... H> | |
646 | BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE | |
647 | R | |
648 | context<E...>:: | |
649 | handle_error( error_id id, H && ... h ) const | |
650 | { | |
651 | BOOST_LEAF_ASSERT(!is_active()); | |
652 | return leaf_detail::handle_error_<R>(tup(), error_info(id), std::forward<H>(h)...); | |
653 | } | |
654 | ||
655 | template <class... E> | |
656 | template <class R, class... H> | |
657 | BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE | |
658 | R | |
659 | context<E...>:: | |
660 | handle_error( error_id id, H && ... h ) | |
661 | { | |
662 | BOOST_LEAF_ASSERT(!is_active()); | |
663 | return leaf_detail::handle_error_<R>(tup(), error_info(id), std::forward<H>(h)...); | |
664 | } | |
665 | ||
666 | //////////////////////////////////////// | |
667 | ||
668 | #ifdef BOOST_LEAF_NO_EXCEPTIONS | |
669 | ||
670 | template <class TryBlock, class... H> | |
671 | BOOST_LEAF_CONSTEXPR inline | |
672 | typename std::decay<decltype(std::declval<TryBlock>()().value())>::type | |
673 | try_handle_all( TryBlock && try_block, H && ... h ) noexcept | |
674 | { | |
675 | static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a try_handle_all function must be registered with leaf::is_result_type"); | |
676 | context_type_from_handlers<H...> ctx; | |
677 | auto active_context = activate_context(ctx); | |
678 | if( auto r = std::forward<TryBlock>(try_block)() ) | |
679 | return r.value(); | |
680 | else | |
681 | { | |
682 | error_id id = r.error(); | |
683 | ctx.deactivate(); | |
684 | using R = typename std::decay<decltype(std::declval<TryBlock>()().value())>::type; | |
685 | return ctx.template handle_error<R>(std::move(id), std::forward<H>(h)...); | |
686 | } | |
687 | } | |
688 | ||
689 | template <class TryBlock, class... H> | |
690 | BOOST_LEAF_NODISCARD BOOST_LEAF_CONSTEXPR inline | |
691 | typename std::decay<decltype(std::declval<TryBlock>()())>::type | |
692 | try_handle_some( TryBlock && try_block, H && ... h ) noexcept | |
693 | { | |
694 | static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a try_handle_some function must be registered with leaf::is_result_type"); | |
695 | context_type_from_handlers<H...> ctx; | |
696 | auto active_context = activate_context(ctx); | |
697 | if( auto r = std::forward<TryBlock>(try_block)() ) | |
698 | return r; | |
699 | else | |
700 | { | |
701 | error_id id = r.error(); | |
702 | ctx.deactivate(); | |
703 | using R = typename std::decay<decltype(std::declval<TryBlock>()())>::type; | |
704 | auto rr = ctx.template handle_error<R>(std::move(id), std::forward<H>(h)..., [&r]()->R { return std::move(r); }); | |
705 | if( !rr ) | |
706 | ctx.propagate(); | |
707 | return rr; | |
708 | } | |
709 | } | |
710 | ||
711 | template <class TryBlock, class... H> | |
712 | BOOST_LEAF_CONSTEXPR inline | |
713 | decltype(std::declval<TryBlock>()()) | |
714 | try_catch( TryBlock && try_block, H && ... ) noexcept | |
715 | { | |
716 | static_assert(sizeof(context_type_from_handlers<H...>) > 0, | |
717 | "When exceptions are disabled, try_catch can't fail and has no use for the handlers, but this ensures that the supplied H... types are compatible."); | |
718 | return std::forward<TryBlock>(try_block)(); | |
719 | } | |
720 | ||
721 | #else | |
722 | ||
723 | namespace leaf_detail | |
724 | { | |
725 | template <class Ctx, class TryBlock, class... H> | |
726 | decltype(std::declval<TryBlock>()()) | |
727 | try_catch_( Ctx & ctx, TryBlock && try_block, H && ... h ) | |
728 | { | |
729 | using namespace leaf_detail; | |
730 | BOOST_LEAF_ASSERT(ctx.is_active()); | |
731 | using R = decltype(std::declval<TryBlock>()()); | |
732 | try | |
733 | { | |
734 | return std::forward<TryBlock>(try_block)(); | |
735 | } | |
736 | catch( capturing_exception const & cap ) | |
737 | { | |
738 | try | |
739 | { | |
740 | cap.unload_and_rethrow_original_exception(); | |
741 | } | |
742 | catch( std::exception & ex ) | |
743 | { | |
744 | ctx.deactivate(); | |
745 | return handle_error_<R>(ctx.tup(), error_info(&ex), std::forward<H>(h)..., | |
746 | []() -> R { throw; } ); | |
747 | } | |
748 | catch(...) | |
749 | { | |
750 | ctx.deactivate(); | |
751 | return handle_error_<R>(ctx.tup(), error_info(nullptr), std::forward<H>(h)..., | |
752 | []() -> R { throw; } ); | |
753 | } | |
754 | } | |
755 | catch( std::exception & ex ) | |
756 | { | |
757 | ctx.deactivate(); | |
758 | return handle_error_<R>(ctx.tup(), error_info(&ex), std::forward<H>(h)..., | |
759 | []() -> R { throw; } ); | |
760 | } | |
761 | catch(...) | |
762 | { | |
763 | ctx.deactivate(); | |
764 | return handle_error_<R>(ctx.tup(), error_info(nullptr), std::forward<H>(h)..., | |
765 | []() -> R { throw; } ); | |
766 | } | |
767 | } | |
768 | } | |
769 | ||
770 | template <class TryBlock, class... H> | |
771 | BOOST_LEAF_CONSTEXPR inline | |
772 | typename std::decay<decltype(std::declval<TryBlock>()().value())>::type | |
773 | try_handle_all( TryBlock && try_block, H && ... h ) | |
774 | { | |
775 | static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a try_handle_all function must be registered with leaf::is_result_type"); | |
776 | context_type_from_handlers<H...> ctx; | |
777 | auto active_context = activate_context(ctx); | |
778 | if( auto r = leaf_detail::try_catch_( | |
779 | ctx, | |
780 | [&] | |
781 | { | |
782 | return std::forward<TryBlock>(try_block)(); | |
783 | }, | |
784 | std::forward<H>(h)...) ) | |
785 | return r.value(); | |
786 | else | |
787 | { | |
788 | error_id id = r.error(); | |
789 | if( ctx.is_active() ) | |
790 | ctx.deactivate(); | |
791 | using R = typename std::decay<decltype(std::declval<TryBlock>()().value())>::type; | |
792 | return ctx.template handle_error<R>(std::move(id), std::forward<H>(h)...); | |
793 | } | |
794 | } | |
795 | ||
796 | template <class TryBlock, class... H> | |
797 | BOOST_LEAF_NODISCARD BOOST_LEAF_CONSTEXPR inline | |
798 | typename std::decay<decltype(std::declval<TryBlock>()())>::type | |
799 | try_handle_some( TryBlock && try_block, H && ... h ) | |
800 | { | |
801 | static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a try_handle_some function must be registered with leaf::is_result_type"); | |
802 | context_type_from_handlers<H...> ctx; | |
803 | auto active_context = activate_context(ctx); | |
804 | if( auto r = leaf_detail::try_catch_( | |
805 | ctx, | |
806 | [&] | |
807 | { | |
808 | return std::forward<TryBlock>(try_block)(); | |
809 | }, | |
810 | std::forward<H>(h)...) ) | |
811 | return r; | |
812 | else | |
813 | { | |
814 | error_id id = r.error(); | |
815 | if( ctx.is_active() ) | |
816 | ctx.deactivate(); | |
817 | using R = typename std::decay<decltype(std::declval<TryBlock>()())>::type; | |
818 | auto rr = ctx.template handle_error<R>(std::move(id), std::forward<H>(h)..., [&r]()->R { return std::move(r); }); | |
819 | if( !rr ) | |
820 | ctx.propagate(); | |
821 | return rr; | |
822 | } | |
823 | } | |
824 | ||
825 | template <class TryBlock, class... H> | |
826 | BOOST_LEAF_CONSTEXPR inline | |
827 | decltype(std::declval<TryBlock>()()) | |
828 | try_catch( TryBlock && try_block, H && ... h ) | |
829 | { | |
830 | context_type_from_handlers<H...> ctx; | |
831 | auto active_context = activate_context(ctx); | |
832 | return leaf_detail::try_catch_( | |
833 | ctx, | |
834 | [&] | |
835 | { | |
836 | return std::forward<TryBlock>(try_block)(); | |
837 | }, | |
838 | std::forward<H>(h)...); | |
839 | } | |
840 | ||
841 | #endif | |
842 | ||
843 | } } | |
844 | ||
845 | // Boost Exception Integration | |
846 | ||
847 | namespace boost { class exception; } | |
848 | namespace boost { template <class Tag,class T> class error_info; } | |
849 | namespace boost { namespace exception_detail { template <class ErrorInfo> struct get_info; } } | |
850 | ||
851 | namespace boost { namespace leaf { | |
852 | ||
853 | namespace leaf_detail | |
854 | { | |
855 | template <class T> | |
856 | struct match_enum_type; | |
857 | ||
858 | template <class Tag, class T> | |
859 | struct match_enum_type<boost::error_info<Tag, T>> | |
860 | { | |
861 | using type = T; | |
862 | }; | |
863 | ||
864 | template <class Ex> | |
865 | BOOST_LEAF_CONSTEXPR inline Ex * get_exception( error_info const & ei ) | |
866 | { | |
867 | return dynamic_cast<Ex *>(ei.exception()); | |
868 | } | |
869 | ||
870 | template <class, class T> | |
871 | struct dependent_type { using type = T; }; | |
872 | ||
873 | template <class Dep, class T> | |
874 | using dependent_type_t = typename dependent_type<Dep, T>::type; | |
875 | ||
876 | template <class Tag, class T> | |
877 | struct handler_argument_traits<boost::error_info<Tag, T>> | |
878 | { | |
879 | using error_type = void; | |
880 | constexpr static bool always_available = false; | |
881 | ||
882 | template <class Tup> | |
883 | BOOST_LEAF_CONSTEXPR static T * check( Tup & tup, error_info const & ei ) noexcept | |
884 | { | |
885 | using boost_exception = dependent_type_t<T, boost::exception>; | |
886 | if( auto * be = get_exception<boost_exception>(ei) ) | |
887 | return exception_detail::get_info<boost::error_info<Tag, T>>::get(*be); | |
888 | else | |
889 | return 0; | |
890 | } | |
891 | ||
892 | template <class Tup> | |
893 | BOOST_LEAF_CONSTEXPR static boost::error_info<Tag, T> get( Tup const & tup, error_info const & ei ) noexcept | |
894 | { | |
895 | return boost::error_info<Tag, T>(*check(tup, ei)); | |
896 | } | |
897 | }; | |
898 | ||
899 | template <class Tag, class T> struct handler_argument_traits<boost::error_info<Tag, T> const &>: handler_argument_traits_require_by_value<boost::error_info<Tag, T>> { }; | |
900 | template <class Tag, class T> struct handler_argument_traits<boost::error_info<Tag, T> const *>: handler_argument_traits_require_by_value<boost::error_info<Tag, T>> { }; | |
901 | template <class Tag, class T> struct handler_argument_traits<boost::error_info<Tag, T> &>: handler_argument_traits_require_by_value<boost::error_info<Tag, T>> { }; | |
902 | template <class Tag, class T> struct handler_argument_traits<boost::error_info<Tag, T> *>: handler_argument_traits_require_by_value<boost::error_info<Tag, T>> { }; | |
903 | } | |
904 | ||
905 | } } | |
906 | ||
907 | #endif |