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