#ifndef BOOST_LEAF_PRED_HPP_INCLUDED #define BOOST_LEAF_PRED_HPP_INCLUDED // Copyright 2018-2022 Emil Dotchevski and Reverge Studios, Inc. // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include <boost/leaf/config.hpp> #include <boost/leaf/handle_errors.hpp> #if __cplusplus >= 201703L # define BOOST_LEAF_MATCH_ARGS(et,v1,v) auto v1, auto... v #else # define BOOST_LEAF_MATCH_ARGS(et,v1,v) typename leaf_detail::et::type v1, typename leaf_detail::et::type... v #endif #define BOOST_LEAF_ESC(...) __VA_ARGS__ namespace boost { namespace leaf { namespace leaf_detail { #if __cplusplus >= 201703L template <class MatchType, class T> BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE bool cmp_value_pack( MatchType const & e, bool (*P)(T) noexcept ) noexcept { BOOST_LEAF_ASSERT(P != nullptr); return P(e); } template <class MatchType, class T> BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE bool cmp_value_pack( MatchType const & e, bool (*P)(T) ) { BOOST_LEAF_ASSERT(P != nullptr); return P(e); } #endif template <class MatchType, class V> BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE bool cmp_value_pack( MatchType const & e, V v ) { return e == v; } template <class MatchType, class VCar, class... VCdr> BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE bool cmp_value_pack( MatchType const & e, VCar car, VCdr ... cdr ) { return cmp_value_pack(e, car) || cmp_value_pack(e, cdr...); } } //////////////////////////////////////// #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR template <class E, class Enum = E> struct condition { static_assert(std::is_error_condition_enum<Enum>::value || std::is_error_code_enum<Enum>::value, "leaf::condition<E, Enum> requires Enum to be registered either with std::is_error_condition_enum or std::is_error_code_enum."); }; template <class Enum> struct condition<Enum, Enum> { static_assert(std::is_error_condition_enum<Enum>::value || std::is_error_code_enum<Enum>::value, "leaf::condition<Enum> requires Enum to be registered either with std::is_error_condition_enum or std::is_error_code_enum."); }; #if __cplusplus >= 201703L template <class ErrorCodeEnum> BOOST_LEAF_CONSTEXPR inline bool category( std::error_code const & ec ) { static_assert(std::is_error_code_enum<ErrorCodeEnum>::value, "leaf::category requires an error code enum"); return &ec.category() == &std::error_code(ErrorCodeEnum{}).category(); } #endif #endif //////////////////////////////////////// namespace leaf_detail { template <class T> struct match_enum_type { using type = T; }; #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR template <class Enum> struct match_enum_type<condition<Enum, Enum>> { using type = Enum; }; template <class E, class Enum> struct match_enum_type<condition<E, Enum>> { static_assert(sizeof(Enum) == 0, "leaf::condition<E, Enum> should be used with leaf::match_value<>, not with leaf::match<>"); }; #endif } template <class E, BOOST_LEAF_MATCH_ARGS(match_enum_type<E>, V1, V)> struct match { using error_type = E; E matched; template <class T> BOOST_LEAF_CONSTEXPR static bool evaluate(T && x) { return leaf_detail::cmp_value_pack(std::forward<T>(x), V1, V...); } }; #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR template <class Enum, BOOST_LEAF_MATCH_ARGS(BOOST_LEAF_ESC(match_enum_type<condition<Enum, Enum>>), V1, V)> struct match<condition<Enum, Enum>, V1, V...> { using error_type = std::error_code; std::error_code const & matched; BOOST_LEAF_CONSTEXPR static bool evaluate(std::error_code const & e) noexcept { return leaf_detail::cmp_value_pack(e, V1, V...); } }; #endif template <class E, BOOST_LEAF_MATCH_ARGS(match_enum_type<E>, V1, V)> struct is_predicate<match<E, V1, V...>>: std::true_type { }; //////////////////////////////////////// namespace leaf_detail { template <class E> struct match_value_enum_type { using type = typename std::remove_reference<decltype(std::declval<E>().value)>::type; }; #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR template <class E, class Enum> struct match_value_enum_type<condition<E, Enum>> { using type = Enum; }; template <class Enum> struct match_value_enum_type<condition<Enum, Enum>> { static_assert(sizeof(Enum)==0, "leaf::condition<Enum> should be used with leaf::match<>, not with leaf::match_value<>"); }; #endif } template <class E, BOOST_LEAF_MATCH_ARGS(match_value_enum_type<E>, V1, V)> struct match_value { using error_type = E; E const & matched; BOOST_LEAF_CONSTEXPR static bool evaluate(E const & e) noexcept { return leaf_detail::cmp_value_pack(e.value, V1, V...); } }; #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR template <class E, class Enum, BOOST_LEAF_MATCH_ARGS(BOOST_LEAF_ESC(match_value_enum_type<condition<E, Enum>>), V1, V)> struct match_value<condition<E, Enum>, V1, V...> { using error_type = E; E const & matched; BOOST_LEAF_CONSTEXPR static bool evaluate(E const & e) { return leaf_detail::cmp_value_pack(e.value, V1, V...); } }; #endif template <class E, BOOST_LEAF_MATCH_ARGS(match_value_enum_type<E>, V1, V)> struct is_predicate<match_value<E, V1, V...>>: std::true_type { }; //////////////////////////////////////// #if __cplusplus >= 201703L template <auto, auto, auto...> struct match_member; template <class T, class E, T E::* P, auto V1, auto... V> struct match_member<P, V1, V...> { using error_type = E; E const & matched; BOOST_LEAF_CONSTEXPR static bool evaluate(E const & e) noexcept { return leaf_detail::cmp_value_pack(e.*P, V1, V...); } }; template <auto P, auto V1, auto... V> struct is_predicate<match_member<P, V1, V...>>: std::true_type { }; #endif //////////////////////////////////////// template <class P> struct if_not { using error_type = typename P::error_type; decltype(std::declval<P>().matched) matched; template <class E> BOOST_LEAF_CONSTEXPR static bool evaluate(E && e) noexcept { return !P::evaluate(std::forward<E>(e)); } }; template <class P> struct is_predicate<if_not<P>>: std::true_type { }; //////////////////////////////////////// #ifndef BOOST_LEAF_NO_EXCEPTIONS namespace leaf_detail { template <class Ex> BOOST_LEAF_CONSTEXPR inline bool check_exception_pack( std::exception const & ex, Ex const * ) noexcept { return dynamic_cast<Ex const *>(&ex)!=nullptr; } template <class Ex, class... ExRest> BOOST_LEAF_CONSTEXPR inline bool check_exception_pack( std::exception const & ex, Ex const *, ExRest const * ... ex_rest ) noexcept { return dynamic_cast<Ex const *>(&ex)!=nullptr || check_exception_pack(ex, ex_rest...); } BOOST_LEAF_CONSTEXPR inline bool check_exception_pack( std::exception const & ) noexcept { return true; } } template <class... Ex> struct catch_ { using error_type = void; std::exception const & matched; BOOST_LEAF_CONSTEXPR static bool evaluate(std::exception const & ex) noexcept { return leaf_detail::check_exception_pack(ex, static_cast<Ex const *>(nullptr)...); } }; template <class Ex> struct catch_<Ex> { using error_type = void; Ex const & matched; BOOST_LEAF_CONSTEXPR static Ex const * evaluate(std::exception const & ex) noexcept { return dynamic_cast<Ex const *>(&ex); } explicit catch_( std::exception const & ex ): matched(*dynamic_cast<Ex const *>(&ex)) { } }; template <class... Ex> struct is_predicate<catch_<Ex...>>: std::true_type { }; #endif } } #endif