File indexing completed on 2025-01-18 09:39:12
0001 #ifndef BOOST_LEAF_CONTEXT_HPP_INCLUDED
0002 #define BOOST_LEAF_CONTEXT_HPP_INCLUDED
0003
0004
0005
0006
0007
0008
0009 #include <boost/leaf/config.hpp>
0010 #include <boost/leaf/error.hpp>
0011
0012 #if !defined(BOOST_LEAF_NO_THREADS) && !defined(NDEBUG)
0013 # include <thread>
0014 #endif
0015
0016 namespace boost { namespace leaf {
0017
0018 class error_info;
0019 class diagnostic_info;
0020 class verbose_diagnostic_info;
0021
0022 template <class>
0023 struct is_predicate: std::false_type
0024 {
0025 };
0026
0027 namespace leaf_detail
0028 {
0029 template <class T>
0030 struct is_exception: std::is_base_of<std::exception, typename std::decay<T>::type>
0031 {
0032 };
0033
0034 template <class E>
0035 struct handler_argument_traits;
0036
0037 template <class E, bool IsPredicate = is_predicate<E>::value>
0038 struct handler_argument_traits_defaults;
0039
0040 template <class E>
0041 struct handler_argument_traits_defaults<E, false>
0042 {
0043 using error_type = typename std::decay<E>::type;
0044 constexpr static bool always_available = false;
0045
0046 template <class Tup>
0047 BOOST_LEAF_CONSTEXPR static error_type const * check( Tup const &, error_info const & ) noexcept;
0048
0049 template <class Tup>
0050 BOOST_LEAF_CONSTEXPR static error_type * check( Tup &, error_info const & ) noexcept;
0051
0052 template <class Tup>
0053 BOOST_LEAF_CONSTEXPR static E get( Tup & tup, error_info const & ei ) noexcept
0054 {
0055 return *check(tup, ei);
0056 }
0057
0058 static_assert(!is_predicate<error_type>::value, "Handlers must take predicate arguments by value");
0059 static_assert(!std::is_same<E, error_info>::value, "Handlers must take leaf::error_info arguments by const &");
0060 static_assert(!std::is_same<E, diagnostic_info>::value, "Handlers must take leaf::diagnostic_info arguments by const &");
0061 static_assert(!std::is_same<E, verbose_diagnostic_info>::value, "Handlers must take leaf::verbose_diagnostic_info arguments by const &");
0062 };
0063
0064 template <class Pred>
0065 struct handler_argument_traits_defaults<Pred, true>: handler_argument_traits<typename Pred::error_type>
0066 {
0067 using base = handler_argument_traits<typename Pred::error_type>;
0068 static_assert(!base::always_available, "Predicates can't use types that are always_available");
0069
0070 template <class Tup>
0071 BOOST_LEAF_CONSTEXPR static bool check( Tup const & tup, error_info const & ei ) noexcept
0072 {
0073 auto e = base::check(tup, ei);
0074 return e && Pred::evaluate(*e);
0075 }
0076
0077 template <class Tup>
0078 BOOST_LEAF_CONSTEXPR static Pred get( Tup const & tup, error_info const & ei ) noexcept
0079 {
0080 return Pred{*base::check(tup, ei)};
0081 }
0082 };
0083
0084 template <class E>
0085 struct handler_argument_always_available
0086 {
0087 using error_type = E;
0088 constexpr static bool always_available = true;
0089
0090 template <class Tup>
0091 BOOST_LEAF_CONSTEXPR static bool check( Tup &, error_info const & ) noexcept
0092 {
0093 return true;
0094 }
0095 };
0096
0097 template <class E>
0098 struct handler_argument_traits: handler_argument_traits_defaults<E>
0099 {
0100 };
0101
0102 template <>
0103 struct handler_argument_traits<void>
0104 {
0105 using error_type = void;
0106 constexpr static bool always_available = false;
0107
0108 template <class Tup>
0109 BOOST_LEAF_CONSTEXPR static std::exception const * check( Tup const &, error_info const & ) noexcept;
0110 };
0111
0112 template <class E>
0113 struct handler_argument_traits<E &&>
0114 {
0115 static_assert(sizeof(E) == 0, "Error handlers may not take rvalue ref arguments");
0116 };
0117
0118 template <class E>
0119 struct handler_argument_traits<E *>: handler_argument_always_available<typename std::remove_const<E>::type>
0120 {
0121 template <class Tup>
0122 BOOST_LEAF_CONSTEXPR static E * get( Tup & tup, error_info const & ei) noexcept
0123 {
0124 return handler_argument_traits_defaults<E>::check(tup, ei);
0125 }
0126 };
0127
0128 template <>
0129 struct handler_argument_traits<error_info const &>: handler_argument_always_available<void>
0130 {
0131 template <class Tup>
0132 BOOST_LEAF_CONSTEXPR static error_info const & get( Tup const &, error_info const & ei ) noexcept
0133 {
0134 return ei;
0135 }
0136 };
0137
0138 template <class E>
0139 struct handler_argument_traits_require_by_value
0140 {
0141 static_assert(sizeof(E) == 0, "Error handlers must take this type by value");
0142 };
0143 }
0144
0145
0146
0147 namespace leaf_detail
0148 {
0149 template <int I, class Tuple>
0150 struct tuple_for_each
0151 {
0152 BOOST_LEAF_CONSTEXPR static void activate( Tuple & tup ) noexcept
0153 {
0154 static_assert(!std::is_same<error_info, typename std::decay<decltype(std::get<I-1>(tup))>::type>::value, "Bug in LEAF: context type deduction");
0155 tuple_for_each<I-1,Tuple>::activate(tup);
0156 std::get<I-1>(tup).activate();
0157 }
0158
0159 BOOST_LEAF_CONSTEXPR static void deactivate( Tuple & tup ) noexcept
0160 {
0161 static_assert(!std::is_same<error_info, typename std::decay<decltype(std::get<I-1>(tup))>::type>::value, "Bug in LEAF: context type deduction");
0162 std::get<I-1>(tup).deactivate();
0163 tuple_for_each<I-1,Tuple>::deactivate(tup);
0164 }
0165
0166 BOOST_LEAF_CONSTEXPR static void propagate( Tuple & tup, int err_id ) noexcept
0167 {
0168 static_assert(!std::is_same<error_info, typename std::decay<decltype(std::get<I-1>(tup))>::type>::value, "Bug in LEAF: context type deduction");
0169 auto & sl = std::get<I-1>(tup);
0170 sl.propagate(err_id);
0171 tuple_for_each<I-1,Tuple>::propagate(tup, err_id);
0172 }
0173
0174 BOOST_LEAF_CONSTEXPR static void propagate_captured( Tuple & tup, int err_id ) noexcept
0175 {
0176 static_assert(!std::is_same<error_info, typename std::decay<decltype(std::get<I-1>(tup))>::type>::value, "Bug in LEAF: context type deduction");
0177 BOOST_LEAF_ASSERT(err_id != 0);
0178 auto & sl = std::get<I-1>(tup);
0179 if( sl.has_value(err_id) )
0180 (void) load_slot<false>(err_id, std::move(sl).value(err_id));
0181 tuple_for_each<I-1,Tuple>::propagate_captured(tup, err_id);
0182 }
0183
0184 template <class CharT, class Traits>
0185 static void print( std::basic_ostream<CharT, Traits> & os, void const * tup, int key_to_print )
0186 {
0187 BOOST_LEAF_ASSERT(tup != nullptr);
0188 tuple_for_each<I-1,Tuple>::print(os, tup, key_to_print);
0189 std::get<I-1>(*static_cast<Tuple const *>(tup)).print(os, key_to_print);
0190 }
0191 };
0192
0193 template <class Tuple>
0194 struct tuple_for_each<0, Tuple>
0195 {
0196 BOOST_LEAF_CONSTEXPR static void activate( Tuple & ) noexcept { }
0197 BOOST_LEAF_CONSTEXPR static void deactivate( Tuple & ) noexcept { }
0198 BOOST_LEAF_CONSTEXPR static void propagate( Tuple &, int ) noexcept { }
0199 BOOST_LEAF_CONSTEXPR static void propagate_captured( Tuple &, int ) noexcept { }
0200 template <class CharT, class Traits>
0201 BOOST_LEAF_CONSTEXPR static void print( std::basic_ostream<CharT, Traits> &, void const *, int ) { }
0202 };
0203 }
0204
0205
0206
0207 #if BOOST_LEAF_CFG_DIAGNOSTICS
0208
0209 namespace leaf_detail
0210 {
0211 template <class T> struct requires_unexpected { constexpr static bool value = false; };
0212 template <class T> struct requires_unexpected<T const> { constexpr static bool value = requires_unexpected<T>::value; };
0213 template <class T> struct requires_unexpected<T const &> { constexpr static bool value = requires_unexpected<T>::value; };
0214 template <class T> struct requires_unexpected<T const *> { constexpr static bool value = requires_unexpected<T>::value; };
0215 template <> struct requires_unexpected<e_unexpected_count> { constexpr static bool value = true; };
0216 template <> struct requires_unexpected<e_unexpected_info> { constexpr static bool value = true; };
0217
0218 template <class L>
0219 struct unexpected_requested;
0220
0221 template <template <class ...> class L>
0222 struct unexpected_requested<L<>>
0223 {
0224 constexpr static bool value = false;
0225 };
0226
0227 template <template <class...> class L, template <class> class S, class Car, class... Cdr>
0228 struct unexpected_requested<L<S<Car>, S<Cdr>...>>
0229 {
0230 constexpr static bool value = requires_unexpected<Car>::value || unexpected_requested<L<S<Cdr>...>>::value;
0231 };
0232 }
0233
0234 #endif
0235
0236
0237
0238 namespace leaf_detail
0239 {
0240 template <class T> struct does_not_participate_in_context_deduction: std::is_abstract<T> { };
0241 template <> struct does_not_participate_in_context_deduction<void>: std::true_type { };
0242 template <> struct does_not_participate_in_context_deduction<error_id>: std::true_type { };
0243
0244 template <class L>
0245 struct deduce_e_type_list;
0246
0247 template <template<class...> class L, class... T>
0248 struct deduce_e_type_list<L<T...>>
0249 {
0250 using type =
0251 leaf_detail_mp11::mp_remove_if<
0252 leaf_detail_mp11::mp_unique<
0253 leaf_detail_mp11::mp_list<typename handler_argument_traits<T>::error_type...>
0254 >,
0255 does_not_participate_in_context_deduction
0256 >;
0257 };
0258
0259 template <class L>
0260 struct deduce_e_tuple_impl;
0261
0262 template <template <class...> class L, class... E>
0263 struct deduce_e_tuple_impl<L<E...>>
0264 {
0265 using type = std::tuple<slot<E>...>;
0266 };
0267
0268 template <class... E>
0269 using deduce_e_tuple = typename deduce_e_tuple_impl<typename deduce_e_type_list<leaf_detail_mp11::mp_list<E...>>::type>::type;
0270 }
0271
0272
0273
0274 template <class... E>
0275 class context
0276 {
0277 context( context const & ) = delete;
0278 context & operator=( context const & ) = delete;
0279
0280 using Tup = leaf_detail::deduce_e_tuple<E...>;
0281 Tup tup_;
0282 bool is_active_;
0283
0284 #if !defined(BOOST_LEAF_NO_THREADS) && !defined(NDEBUG)
0285 std::thread::id thread_id_;
0286 #endif
0287
0288 protected:
0289
0290 BOOST_LEAF_CONSTEXPR error_id propagate_captured_errors( error_id err_id ) noexcept
0291 {
0292 leaf_detail::tuple_for_each<std::tuple_size<Tup>::value,Tup>::propagate_captured(tup_, err_id.value());
0293 return err_id;
0294 }
0295
0296 public:
0297
0298 BOOST_LEAF_CONSTEXPR context( context && x ) noexcept:
0299 tup_(std::move(x.tup_)),
0300 is_active_(false)
0301 {
0302 BOOST_LEAF_ASSERT(!x.is_active());
0303 }
0304
0305 BOOST_LEAF_CONSTEXPR context() noexcept:
0306 is_active_(false)
0307 {
0308 }
0309
0310 ~context() noexcept
0311 {
0312 BOOST_LEAF_ASSERT(!is_active());
0313 }
0314
0315 BOOST_LEAF_CONSTEXPR Tup const & tup() const noexcept
0316 {
0317 return tup_;
0318 }
0319
0320 BOOST_LEAF_CONSTEXPR Tup & tup() noexcept
0321 {
0322 return tup_;
0323 }
0324
0325 BOOST_LEAF_CONSTEXPR void activate() noexcept
0326 {
0327 using namespace leaf_detail;
0328 BOOST_LEAF_ASSERT(!is_active());
0329 tuple_for_each<std::tuple_size<Tup>::value,Tup>::activate(tup_);
0330 #if BOOST_LEAF_CFG_DIAGNOSTICS
0331 if( unexpected_requested<Tup>::value )
0332 tls::uint_increment<tls_tag_unexpected_enabled_counter>();
0333 #endif
0334 #if !defined(BOOST_LEAF_NO_THREADS) && !defined(NDEBUG)
0335 thread_id_ = std::this_thread::get_id();
0336 #endif
0337 is_active_ = true;
0338 }
0339
0340 BOOST_LEAF_CONSTEXPR void deactivate() noexcept
0341 {
0342 using namespace leaf_detail;
0343 BOOST_LEAF_ASSERT(is_active());
0344 is_active_ = false;
0345 #if !defined(BOOST_LEAF_NO_THREADS) && !defined(NDEBUG)
0346 BOOST_LEAF_ASSERT(std::this_thread::get_id() == thread_id_);
0347 thread_id_ = std::thread::id();
0348 #endif
0349 #if BOOST_LEAF_CFG_DIAGNOSTICS
0350 if( unexpected_requested<Tup>::value )
0351 tls::uint_decrement<tls_tag_unexpected_enabled_counter>();
0352 #endif
0353 tuple_for_each<std::tuple_size<Tup>::value,Tup>::deactivate(tup_);
0354 }
0355
0356 BOOST_LEAF_CONSTEXPR void propagate(error_id id) noexcept
0357 {
0358 BOOST_LEAF_ASSERT(!is_active());
0359 leaf_detail::tuple_for_each<std::tuple_size<Tup>::value,Tup>::propagate(tup_, id.value());
0360 }
0361
0362 BOOST_LEAF_CONSTEXPR bool is_active() const noexcept
0363 {
0364 return is_active_;
0365 }
0366
0367 template <class CharT, class Traits>
0368 void print( std::basic_ostream<CharT, Traits> & os ) const
0369 {
0370 leaf_detail::tuple_for_each<std::tuple_size<Tup>::value,Tup>::print(os, &tup_, 0);
0371 }
0372
0373 template <class CharT, class Traits>
0374 friend std::ostream & operator<<( std::basic_ostream<CharT, Traits> & os, context const & ctx )
0375 {
0376 ctx.print(os);
0377 return os;
0378 }
0379
0380 template <class R, class... H>
0381 BOOST_LEAF_CONSTEXPR R handle_error( error_id, H && ... ) const;
0382
0383 template <class R, class... H>
0384 BOOST_LEAF_CONSTEXPR R handle_error( error_id, H && ... );
0385 };
0386
0387
0388
0389 namespace leaf_detail
0390 {
0391 template <class TypeList>
0392 struct deduce_context_impl;
0393
0394 template <template <class...> class L, class... E>
0395 struct deduce_context_impl<L<E...>>
0396 {
0397 using type = context<E...>;
0398 };
0399
0400 template <class TypeList>
0401 using deduce_context = typename deduce_context_impl<TypeList>::type;
0402
0403 template <class H>
0404 struct fn_mp_args_fwd
0405 {
0406 using type = fn_mp_args<H>;
0407 };
0408
0409 template <class... H>
0410 struct fn_mp_args_fwd<std::tuple<H...> &>: fn_mp_args_fwd<std::tuple<H...>> { };
0411
0412 template <class... H>
0413 struct fn_mp_args_fwd<std::tuple<H...> const &>: fn_mp_args_fwd<std::tuple<H...>> { };
0414
0415 template <class... H>
0416 struct fn_mp_args_fwd<std::tuple<H...>>
0417 {
0418 using type = leaf_detail_mp11::mp_append<typename fn_mp_args_fwd<H>::type...>;
0419 };
0420
0421 template <class... H>
0422 struct context_type_from_handlers_impl
0423 {
0424 using type = deduce_context<leaf_detail_mp11::mp_append<typename fn_mp_args_fwd<H>::type...>>;
0425 };
0426
0427 template <class Ctx>
0428 struct polymorphic_context_impl: polymorphic_context, Ctx
0429 {
0430 error_id propagate_captured_errors() noexcept final override { return Ctx::propagate_captured_errors(captured_id_); }
0431 void activate() noexcept final override { Ctx::activate(); }
0432 void deactivate() noexcept final override { Ctx::deactivate(); }
0433 void propagate(error_id id) noexcept final override { Ctx::propagate(id); }
0434 bool is_active() const noexcept final override { return Ctx::is_active(); }
0435 #if BOOST_LEAF_CFG_DIAGNOSTICS
0436 void print( std::ostream & os ) const final override { return Ctx::print(os); }
0437 #endif
0438 };
0439 }
0440
0441 template <class... H>
0442 using context_type_from_handlers = typename leaf_detail::context_type_from_handlers_impl<H...>::type;
0443
0444
0445
0446 template <class... H>
0447 BOOST_LEAF_CONSTEXPR inline context_type_from_handlers<H...> make_context() noexcept
0448 {
0449 return { };
0450 }
0451
0452 template <class... H>
0453 BOOST_LEAF_CONSTEXPR inline context_type_from_handlers<H...> make_context( H && ... ) noexcept
0454 {
0455 return { };
0456 }
0457
0458
0459
0460 #if BOOST_LEAF_CFG_CAPTURE
0461
0462 template <class... H>
0463 inline context_ptr make_shared_context() noexcept
0464 {
0465 return std::make_shared<leaf_detail::polymorphic_context_impl<context_type_from_handlers<H...>>>();
0466 }
0467
0468 template <class... H>
0469 inline context_ptr make_shared_context( H && ... ) noexcept
0470 {
0471 return std::make_shared<leaf_detail::polymorphic_context_impl<context_type_from_handlers<H...>>>();
0472 }
0473
0474 #endif
0475
0476 } }
0477
0478 #endif