1 #ifndef BOOST_LEAF_PRED_HPP_INCLUDED 2 #define BOOST_LEAF_PRED_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/handle_errors.hpp> 20 21 #if __cplusplus >= 201703L 22 # define BOOST_LEAF_MATCH_ARGS(et,v1,v) auto v1, auto... v 23 #else 24 # define BOOST_LEAF_MATCH_ARGS(et,v1,v) typename leaf_detail::et::type v1, typename leaf_detail::et::type... v 25 #endif 26 #define BOOST_LEAF_ESC(...) __VA_ARGS__ 27 28 namespace boost { namespace leaf { 29 30 namespace leaf_detail 31 { 32 #if __cplusplus >= 201703L 33 template <class MatchType, class T> cmp_value_pack(MatchType const & e,bool (* P)(T)noexcept)34 BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE bool cmp_value_pack( MatchType const & e, bool (*P)(T) noexcept ) noexcept 35 { 36 BOOST_LEAF_ASSERT(P != 0); 37 return P(e); 38 } 39 40 template <class MatchType, class T> cmp_value_pack(MatchType const & e,bool (* P)(T))41 BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE bool cmp_value_pack( MatchType const & e, bool (*P)(T) ) 42 { 43 BOOST_LEAF_ASSERT(P != 0); 44 return P(e); 45 } 46 #endif 47 48 template <class MatchType, class V> cmp_value_pack(MatchType const & e,V v)49 BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE bool cmp_value_pack( MatchType const & e, V v ) 50 { 51 return e == v; 52 } 53 54 template <class MatchType, class VCar, class... VCdr> cmp_value_pack(MatchType const & e,VCar car,VCdr...cdr)55 BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE bool cmp_value_pack( MatchType const & e, VCar car, VCdr ... cdr ) 56 { 57 return cmp_value_pack(e, car) || cmp_value_pack(e, cdr...); 58 } 59 } 60 61 //////////////////////////////////////// 62 63 template <class E, class Enum = E> 64 struct condition 65 { 66 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."); 67 }; 68 69 template <class Enum> 70 struct condition<Enum, Enum> 71 { 72 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."); 73 }; 74 75 #if __cplusplus >= 201703L 76 template <class ErrorCodeEnum> category(std::error_code const & ec)77 BOOST_LEAF_CONSTEXPR inline bool category( std::error_code const & ec ) 78 { 79 static_assert(std::is_error_code_enum<ErrorCodeEnum>::value, "leaf::category requires an error code enum"); 80 return &ec.category() == &std::error_code(ErrorCodeEnum{}).category(); 81 } 82 #endif 83 84 //////////////////////////////////////// 85 86 namespace leaf_detail 87 { 88 template <class T> 89 struct match_enum_type 90 { 91 using type = T; 92 }; 93 94 template <class Enum> 95 struct match_enum_type<condition<Enum, Enum>> 96 { 97 using type = Enum; 98 }; 99 100 template <class E, class Enum> 101 struct match_enum_type<condition<E, Enum>> 102 { 103 static_assert(sizeof(Enum) == 0, "leaf::condition<E, Enum> should be used with leaf::match_value<>, not with leaf::match<>"); 104 }; 105 } 106 107 template <class E, BOOST_LEAF_MATCH_ARGS(match_enum_type<E>, V1, V)> 108 struct match 109 { 110 using error_type = E; 111 E matched; 112 113 template <class T> evaluateboost::leaf::match114 BOOST_LEAF_CONSTEXPR static bool evaluate(T && x) 115 { 116 return leaf_detail::cmp_value_pack(std::forward<T>(x), V1, V...); 117 } 118 }; 119 120 template <class Enum, BOOST_LEAF_MATCH_ARGS(BOOST_LEAF_ESC(match_enum_type<condition<Enum, Enum>>), V1, V)> 121 struct match<condition<Enum, Enum>, V1, V...> 122 { 123 using error_type = std::error_code; 124 std::error_code const & matched; 125 evaluateboost::leaf::match126 BOOST_LEAF_CONSTEXPR static bool evaluate(std::error_code const & e) noexcept 127 { 128 return leaf_detail::cmp_value_pack(e, V1, V...); 129 } 130 }; 131 132 template <class E, BOOST_LEAF_MATCH_ARGS(match_enum_type<E>, V1, V)> 133 struct is_predicate<match<E, V1, V...>>: std::true_type 134 { 135 }; 136 137 //////////////////////////////////////// 138 139 namespace leaf_detail 140 { 141 template <class E> 142 struct match_value_enum_type 143 { 144 using type = typename std::remove_reference<decltype(std::declval<E>().value)>::type; 145 }; 146 147 template <class E, class Enum> 148 struct match_value_enum_type<condition<E, Enum>> 149 { 150 using type = Enum; 151 }; 152 153 template <class Enum> 154 struct match_value_enum_type<condition<Enum, Enum>> 155 { 156 static_assert(sizeof(Enum)==0, "leaf::condition<Enum> should be used with leaf::match<>, not with leaf::match_value<>"); 157 }; 158 } 159 160 template <class E, BOOST_LEAF_MATCH_ARGS(match_value_enum_type<E>, V1, V)> 161 struct match_value 162 { 163 using error_type = E; 164 E const & matched; 165 evaluateboost::leaf::match_value166 BOOST_LEAF_CONSTEXPR static bool evaluate(E const & e) noexcept 167 { 168 return leaf_detail::cmp_value_pack(e.value, V1, V...); 169 } 170 }; 171 172 template <class E, class Enum, BOOST_LEAF_MATCH_ARGS(BOOST_LEAF_ESC(match_value_enum_type<condition<E, Enum>>), V1, V)> 173 struct match_value<condition<E, Enum>, V1, V...> 174 { 175 using error_type = E; 176 E const & matched; 177 evaluateboost::leaf::match_value178 BOOST_LEAF_CONSTEXPR static bool evaluate(E const & e) 179 { 180 return leaf_detail::cmp_value_pack(e.value, V1, V...); 181 } 182 }; 183 184 template <class E, BOOST_LEAF_MATCH_ARGS(match_value_enum_type<E>, V1, V)> 185 struct is_predicate<match_value<E, V1, V...>>: std::true_type 186 { 187 }; 188 189 //////////////////////////////////////// 190 191 #if __cplusplus >= 201703L 192 template <auto, auto, auto...> 193 struct match_member; 194 195 template <class T, class E, T E::* P, auto V1, auto... V> 196 struct match_member<P, V1, V...> 197 { 198 using error_type = E; 199 E const & matched; 200 evaluateboost::leaf::match_member201 BOOST_LEAF_CONSTEXPR static bool evaluate(E const & e) noexcept 202 { 203 return leaf_detail::cmp_value_pack(e.*P, V1, V...); 204 } 205 }; 206 207 template <auto P, auto V1, auto... V> 208 struct is_predicate<match_member<P, V1, V...>>: std::true_type 209 { 210 }; 211 #endif 212 213 //////////////////////////////////////// 214 215 template <class P> 216 struct if_not 217 { 218 using error_type = typename P::error_type;; 219 decltype(std::declval<P>().matched) matched; 220 221 template <class E> evaluateboost::leaf::if_not222 BOOST_LEAF_CONSTEXPR static bool evaluate(E && e) noexcept 223 { 224 return !P::evaluate(std::forward<E>(e)); 225 } 226 }; 227 228 template <class P> 229 struct is_predicate<if_not<P>>: std::true_type 230 { 231 }; 232 233 //////////////////////////////////////// 234 235 236 #ifndef BOOST_LEAF_NO_EXCEPTIONS 237 238 namespace leaf_detail 239 { 240 template <class Ex> check_exception_pack(std::exception const & ex,Ex const *)241 BOOST_LEAF_CONSTEXPR inline bool check_exception_pack( std::exception const & ex, Ex const * ) noexcept 242 { 243 return dynamic_cast<Ex const *>(&ex)!=0; 244 } 245 246 template <class Ex, class... ExRest> check_exception_pack(std::exception const & ex,Ex const *,ExRest const * ...ex_rest)247 BOOST_LEAF_CONSTEXPR inline bool check_exception_pack( std::exception const & ex, Ex const *, ExRest const * ... ex_rest ) noexcept 248 { 249 return dynamic_cast<Ex const *>(&ex)!=0 || check_exception_pack(ex, ex_rest...); 250 } 251 check_exception_pack(std::exception const &)252 BOOST_LEAF_CONSTEXPR inline bool check_exception_pack( std::exception const & ) noexcept 253 { 254 return true; 255 } 256 } 257 258 template <class... Ex> 259 struct catch_ 260 { 261 using error_type = void; 262 std::exception const & matched; 263 evaluateboost::leaf::catch_264 BOOST_LEAF_CONSTEXPR static bool evaluate(std::exception const & ex) noexcept 265 { 266 return leaf_detail::check_exception_pack(ex, static_cast<Ex const *>(0)...); 267 } 268 }; 269 270 template <class Ex> 271 struct catch_<Ex> 272 { 273 using error_type = void; 274 Ex const & matched; 275 evaluateboost::leaf::catch_276 BOOST_LEAF_CONSTEXPR static Ex const * evaluate(std::exception const & ex) noexcept 277 { 278 return dynamic_cast<Ex const *>(&ex); 279 } 280 catch_boost::leaf::catch_281 explicit catch_( std::exception const & ex ): 282 matched(*dynamic_cast<Ex const *>(&ex)) 283 { 284 } 285 }; 286 287 template <class... Ex> 288 struct is_predicate<catch_<Ex...>>: std::true_type 289 { 290 }; 291 292 #endif 293 294 } } 295 296 #endif 297