File indexing completed on 2025-09-15 08:39:08
0001 #ifndef BOOST_LEAF_CONTEXT_HPP_INCLUDED
0002 #define BOOST_LEAF_CONTEXT_HPP_INCLUDED
0003
0004
0005
0006
0007
0008 #include <boost/leaf/config.hpp>
0009 #include <boost/leaf/error.hpp>
0010
0011 #if !defined(BOOST_LEAF_NO_THREADS) && !defined(NDEBUG)
0012 # include <thread>
0013 #endif
0014
0015 namespace boost { namespace leaf {
0016
0017 class error_info;
0018 class diagnostic_info;
0019 class diagnostic_details;
0020
0021 template <class>
0022 struct is_predicate: std::false_type
0023 {
0024 };
0025
0026 namespace detail
0027 {
0028 template <class T>
0029 struct is_exception: std::is_base_of<std::exception, typename std::decay<T>::type>
0030 {
0031 };
0032
0033 template <class E>
0034 struct handler_argument_traits;
0035
0036 template <class E, bool IsPredicate = is_predicate<E>::value>
0037 struct handler_argument_traits_defaults;
0038
0039 template <class E>
0040 struct handler_argument_traits_defaults<E, false>
0041 {
0042 using error_type = typename std::decay<E>::type;
0043 using context_types = leaf_detail_mp11::mp_list<error_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, diagnostic_details>::value, "Handlers must take leaf::diagnostic_details 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 context_types = leaf_detail_mp11::mp_list<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 context_types = leaf_detail_mp11::mp_list<>;
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 <class E>
0129 struct handler_argument_traits_require_by_value
0130 {
0131 static_assert(sizeof(E) == 0, "Error handlers must take this type by value");
0132 };
0133 }
0134
0135
0136
0137 namespace detail
0138 {
0139 template <class T>
0140 struct get_dispatch
0141 {
0142 static BOOST_LEAF_CONSTEXPR T const * get(T const * x) noexcept
0143 {
0144 return x;
0145 }
0146 static BOOST_LEAF_CONSTEXPR T const * get(void const *) noexcept
0147 {
0148 return nullptr;
0149 }
0150 };
0151
0152 template <class T>
0153 BOOST_LEAF_CONSTEXPR inline T * find_in_tuple(std::tuple<> const &)
0154 {
0155 return nullptr;
0156 }
0157
0158 template <class T, int I = 0, class... Tp>
0159 BOOST_LEAF_CONSTEXPR inline typename std::enable_if<I == sizeof...(Tp) - 1, T>::type const *
0160 find_in_tuple(std::tuple<Tp...> const & t) noexcept
0161 {
0162 return get_dispatch<T>::get(&std::get<I>(t));
0163 }
0164
0165 template<class T, int I = 0, class... Tp>
0166 BOOST_LEAF_CONSTEXPR inline typename std::enable_if<I < sizeof...(Tp) - 1, T>::type const *
0167 find_in_tuple(std::tuple<Tp...> const & t) noexcept
0168 {
0169 if( T const * x = get_dispatch<T>::get(&std::get<I>(t)) )
0170 return x;
0171 else
0172 return find_in_tuple<T, I+1, Tp...>(t);
0173 }
0174 }
0175
0176
0177
0178 namespace detail
0179 {
0180 template <int I, class Tup>
0181 struct tuple_for_each
0182 {
0183 BOOST_LEAF_CONSTEXPR static void activate( Tup & tup ) noexcept
0184 {
0185 static_assert(!std::is_same<error_info, typename std::decay<decltype(std::get<I-1>(tup))>::type>::value, "Bug in LEAF: context type deduction");
0186 tuple_for_each<I-1,Tup>::activate(tup);
0187 std::get<I-1>(tup).activate();
0188 }
0189
0190 BOOST_LEAF_CONSTEXPR static void deactivate( Tup & tup ) noexcept
0191 {
0192 static_assert(!std::is_same<error_info, typename std::decay<decltype(std::get<I-1>(tup))>::type>::value, "Bug in LEAF: context type deduction");
0193 std::get<I-1>(tup).deactivate();
0194 tuple_for_each<I-1,Tup>::deactivate(tup);
0195 }
0196
0197 BOOST_LEAF_CONSTEXPR static void unload( Tup & tup, int err_id ) noexcept
0198 {
0199 static_assert(!std::is_same<error_info, typename std::decay<decltype(std::get<I-1>(tup))>::type>::value, "Bug in LEAF: context type deduction");
0200 BOOST_LEAF_ASSERT(err_id != 0);
0201 auto & sl = std::get<I-1>(tup);
0202 sl.unload(err_id);
0203 tuple_for_each<I-1,Tup>::unload(tup, err_id);
0204 }
0205
0206 template <class CharT, class Traits>
0207 static void print(std::basic_ostream<CharT, Traits> & os, void const * tup, error_id to_print, char const * & prefix)
0208 {
0209 BOOST_LEAF_ASSERT(tup != nullptr);
0210 tuple_for_each<I-1,Tup>::print(os, tup, to_print, prefix);
0211 std::get<I-1>(*static_cast<Tup const *>(tup)).print(os, to_print, prefix);
0212 }
0213 };
0214
0215 template <class Tup>
0216 struct tuple_for_each<0, Tup>
0217 {
0218 BOOST_LEAF_CONSTEXPR static void activate( Tup & ) noexcept { }
0219 BOOST_LEAF_CONSTEXPR static void deactivate( Tup & ) noexcept { }
0220 BOOST_LEAF_CONSTEXPR static void unload( Tup &, int ) noexcept { }
0221 template <class CharT, class Traits>
0222 BOOST_LEAF_CONSTEXPR static void print(std::basic_ostream<CharT, Traits> &, void const *, error_id, char const * &) { }
0223 };
0224
0225 template <class Tup, class CharT, class Traits>
0226 BOOST_LEAF_CONSTEXPR void print_tuple_contents(std::basic_ostream<CharT, Traits> & os, void const * tup, error_id to_print, char const * & prefix)
0227 {
0228 tuple_for_each<std::tuple_size<Tup>::value, Tup>::print(os, tup, to_print, prefix);
0229 }
0230 }
0231
0232
0233
0234 namespace detail
0235 {
0236 template <class T> struct does_not_participate_in_context_deduction: std::is_abstract<T> { };
0237 template <> struct does_not_participate_in_context_deduction<error_id>: std::true_type { };
0238
0239 template <class L>
0240 struct deduce_e_type_list;
0241
0242 template <template<class...> class L, class... T>
0243 struct deduce_e_type_list<L<T...>>
0244 {
0245 using type =
0246 leaf_detail_mp11::mp_remove_if<
0247 leaf_detail_mp11::mp_unique<
0248 leaf_detail_mp11::mp_append<typename handler_argument_traits<T>::context_types...>
0249 >,
0250 does_not_participate_in_context_deduction
0251 >;
0252 };
0253
0254 template <class L>
0255 struct deduce_e_tuple_impl;
0256
0257 template <template <class...> class L, class... E>
0258 struct deduce_e_tuple_impl<L<E...>>
0259 {
0260 using type = std::tuple<slot<E>...>;
0261 };
0262
0263 template <class... E>
0264 using deduce_e_tuple = typename deduce_e_tuple_impl<typename deduce_e_type_list<leaf_detail_mp11::mp_list<E...>>::type>::type;
0265 }
0266
0267
0268
0269 template <class... E>
0270 class context
0271 {
0272 context( context const & ) = delete;
0273 context & operator=( context const & ) = delete;
0274
0275 using Tup = detail::deduce_e_tuple<E...>;
0276 Tup tup_;
0277 bool is_active_;
0278
0279 #if !defined(BOOST_LEAF_NO_THREADS) && !defined(NDEBUG)
0280 std::thread::id thread_id_;
0281 #endif
0282
0283 class raii_deactivator
0284 {
0285 raii_deactivator( raii_deactivator const & ) = delete;
0286 raii_deactivator & operator=( raii_deactivator const & ) = delete;
0287 context * ctx_;
0288 public:
0289 explicit BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE raii_deactivator(context & ctx) noexcept:
0290 ctx_(ctx.is_active() ? nullptr : &ctx)
0291 {
0292 if( ctx_ )
0293 ctx_->activate();
0294 }
0295 BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE raii_deactivator( raii_deactivator && x ) noexcept:
0296 ctx_(x.ctx_)
0297 {
0298 x.ctx_ = nullptr;
0299 }
0300 BOOST_LEAF_ALWAYS_INLINE ~raii_deactivator() noexcept
0301 {
0302 if( ctx_ && ctx_->is_active() )
0303 ctx_->deactivate();
0304 }
0305 };
0306
0307 public:
0308
0309 BOOST_LEAF_CONSTEXPR context( context && x ) noexcept:
0310 tup_(std::move(x.tup_)),
0311 is_active_(false)
0312 {
0313 BOOST_LEAF_ASSERT(!x.is_active());
0314 }
0315
0316 BOOST_LEAF_CONSTEXPR context() noexcept:
0317 is_active_(false)
0318 {
0319 }
0320
0321 ~context() noexcept
0322 {
0323 BOOST_LEAF_ASSERT(!is_active());
0324 }
0325
0326 BOOST_LEAF_CONSTEXPR Tup const & tup() const noexcept
0327 {
0328 return tup_;
0329 }
0330
0331 BOOST_LEAF_CONSTEXPR Tup & tup() noexcept
0332 {
0333 return tup_;
0334 }
0335
0336 BOOST_LEAF_CONSTEXPR void activate() noexcept
0337 {
0338 using namespace detail;
0339 BOOST_LEAF_ASSERT(!is_active());
0340 tuple_for_each<std::tuple_size<Tup>::value,Tup>::activate(tup_);
0341 #if !defined(BOOST_LEAF_NO_THREADS) && !defined(NDEBUG)
0342 thread_id_ = std::this_thread::get_id();
0343 #endif
0344 is_active_ = true;
0345 }
0346
0347 BOOST_LEAF_CONSTEXPR void deactivate() noexcept
0348 {
0349 using namespace detail;
0350 BOOST_LEAF_ASSERT(is_active());
0351 is_active_ = false;
0352 #if !defined(BOOST_LEAF_NO_THREADS) && !defined(NDEBUG)
0353 BOOST_LEAF_ASSERT(std::this_thread::get_id() == thread_id_);
0354 thread_id_ = std::thread::id();
0355 #endif
0356 tuple_for_each<std::tuple_size<Tup>::value,Tup>::deactivate(tup_);
0357 }
0358
0359 BOOST_LEAF_CONSTEXPR void unload(error_id id) noexcept
0360 {
0361 BOOST_LEAF_ASSERT(!is_active());
0362 detail::tuple_for_each<std::tuple_size<Tup>::value,Tup>::unload(tup_, id.value());
0363 }
0364
0365 BOOST_LEAF_CONSTEXPR bool is_active() const noexcept
0366 {
0367 return is_active_;
0368 }
0369
0370 template <class CharT, class Traits>
0371 void print( std::basic_ostream<CharT, Traits> & os ) const
0372 {
0373 char const * prefix = "Contents:";
0374 detail::print_tuple_contents<Tup>(os, &tup_, error_id(), prefix);
0375 }
0376
0377 template <class CharT, class Traits>
0378 friend std::ostream & operator<<( std::basic_ostream<CharT, Traits> & os, context const & ctx )
0379 {
0380 ctx.print(os);
0381 return os << '\n';
0382 }
0383
0384 template <class T>
0385 BOOST_LEAF_CONSTEXPR T const * get(error_id err) const noexcept
0386 {
0387 detail::slot<T> const * e = detail::find_in_tuple<detail::slot<T>>(tup_);
0388 return e ? e->has_value(err.value()) : nullptr;
0389 }
0390
0391 template <class R, class... H>
0392 BOOST_LEAF_CONSTEXPR R handle_error( error_id, H && ... ) const;
0393
0394 template <class R, class... H>
0395 BOOST_LEAF_CONSTEXPR R handle_error( error_id, H && ... );
0396
0397 friend BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE raii_deactivator activate_context(context & ctx) noexcept
0398 {
0399 return raii_deactivator(ctx);
0400 }
0401 };
0402
0403
0404
0405 namespace detail
0406 {
0407 template <class TypeList>
0408 struct deduce_context_impl;
0409
0410 template <template <class...> class L, class... E>
0411 struct deduce_context_impl<L<E...>>
0412 {
0413 using type = context<E...>;
0414 };
0415
0416 template <class TypeList>
0417 using deduce_context = typename deduce_context_impl<TypeList>::type;
0418
0419 template <class H>
0420 struct fn_mp_args_fwd
0421 {
0422 using type = fn_mp_args<H>;
0423 };
0424
0425 template <class... H>
0426 struct fn_mp_args_fwd<std::tuple<H...> &>: fn_mp_args_fwd<std::tuple<H...>> { };
0427
0428 template <class... H>
0429 struct fn_mp_args_fwd<std::tuple<H...> const &>: fn_mp_args_fwd<std::tuple<H...>> { };
0430
0431 template <class... H>
0432 struct fn_mp_args_fwd<std::tuple<H...>>
0433 {
0434 using type = leaf_detail_mp11::mp_append<typename fn_mp_args_fwd<H>::type...>;
0435 };
0436
0437 template <class... H>
0438 struct context_type_from_handlers_impl
0439 {
0440 using type = deduce_context<leaf_detail_mp11::mp_append<typename fn_mp_args_fwd<H>::type...>>;
0441 };
0442 }
0443
0444 template <class... H>
0445 using context_type_from_handlers = typename detail::context_type_from_handlers_impl<H...>::type;
0446
0447
0448
0449 template <class... H>
0450 BOOST_LEAF_CONSTEXPR inline context_type_from_handlers<H...> make_context() noexcept
0451 {
0452 return { };
0453 }
0454
0455 template <class... H>
0456 BOOST_LEAF_CONSTEXPR inline context_type_from_handlers<H...> make_context( H && ... ) noexcept
0457 {
0458 return { };
0459 }
0460
0461 } }
0462
0463 #endif