From b4e3328cbff78db9bd38da4c0dfffd63f52622f1 Mon Sep 17 00:00:00 2001 From: Emil Dotchevski Date: Thu, 2 Jul 2020 20:34:31 -0700 Subject: [PATCH] Deleted match_if, function pointers can be passed to match now. --- .vscode/tasks.json | 27 + doc/leaf.adoc | 490 ++++++++++++------ include/boost/leaf/all.hpp | 126 ++--- include/boost/leaf/capture.hpp | 2 +- .../leaf/detail/handler_argument_traits.hpp | 98 ++-- include/boost/leaf/on_error.hpp | 6 +- include/boost/leaf/pred.hpp | 20 +- meson.build | 1 - test/Jamfile.v2 | 1 - test/match_if_test.cpp | 97 ---- test/match_test.cpp | 57 ++ 11 files changed, 505 insertions(+), 420 deletions(-) delete mode 100644 test/match_if_test.cpp diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 6b1e48f..67086d0 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -374,6 +374,33 @@ "command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test handle_some_test" } }, + { + "label": "match_test", + "type": "shell", + "command": "cd ${workspaceRoot}/bld/debug && meson test match_test", + "problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] }, + "windows": { + "command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test match_test" + } + }, + { + "label": "match_member_test", + "type": "shell", + "command": "cd ${workspaceRoot}/bld/debug && meson test match_member_test", + "problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] }, + "windows": { + "command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test match_member_test" + } + }, + { + "label": "match_value_test", + "type": "shell", + "command": "cd ${workspaceRoot}/bld/debug && meson test match_value_test", + "problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] }, + "windows": { + "command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test match_value_test" + } + }, { "label": "is_error_type_test", "type": "shell", diff --git a/doc/leaf.adoc b/doc/leaf.adoc index 997c98b..021b100 100644 --- a/doc/leaf.adoc +++ b/doc/leaf.adoc @@ -41,7 +41,7 @@ LEAF is a lightweight error handling library for {CPP}11. Features: ifndef::backend-pdf[] [grid=none, frame=none] |==== -| <> \| <> \| <> \| https://github.com/zajo/leaf/blob/master/doc/whitepaper.md[Whitepaper] \| https://github.com/zajo/leaf/blob/master/benchmark/benchmark.md[Benchmark] >| Reference: <> \| <> \| <> \| <> +| <> \| <> \| <> \| https://github.com/zajo/leaf/blob/master/doc/whitepaper.md[Whitepaper] \| https://github.com/zajo/leaf/blob/master/benchmark/benchmark.md[Benchmark] >| Reference: <> \| <> \| <> \| <> \| <> |==== endif::[] @@ -661,6 +661,125 @@ The final type of arguments that can be passed to `on_error` is a function that ''' +[[tutorial-predicates]] +=== Using Predicates to Handle Errors + +LEAF error handlers are usually selected based on the type of the arguments they take and the type of the available error objects. When an error handler takes a predicate type as an argument, the <> is able to also consider the _values_ of the available error objects. + +Consider this error code enum: + +[source,c++] +---- +enum class my_error +{ + e1=1, + e2, + e3 +}; +---- + +We could handle `my_error` errors like so: + +[source,c++] +---- +return leaf::try_handle_some( + [] + { + return f(); + }, + + []( my_error e ) + { <1> + switch(e) + { + case my_error::e1: + ....; <2> + break; + case my_error::e2: + case my_error::e3: + ....; <3> + break; + default: + ....; <4> + break; + } ); +---- +<1> This handler will be selected if we've got a `my_error` object. +<2> Handle `e1` errors. +<3> Handle `e2` and `e3` errors. +<4> Handle bad `my_error` values. + +If `my_error` object is available, LEAF will call our error handler. If not, the failure will be forwarded back to the caller of `try_handle_some`. + +This can be rewritten to use the <> predicate. The following is equivalent: + +[source,c++] +---- +return leaf::try_handle_some( + [] + { + return f(); + }, + + []( leaf::match ) + { <1> + ....; + }, + + []( leaf::match ) + { <2> + ....; + }, + + []( my_error e ) + { <3> + ....; + } ); +---- +<1> We've got a `my_error` object that compares equal to `e1`. +<2> We`ve got a `my_error` object that compares equal to either `e2` or `e3`. +<3> Handle bad `my_error` values. + +The first argument to the `match` template generally specifies the type `E` of the error object `e` that must be available for the error handler to be considered at all. The rest of the arguments are values, and cause the handler to be dropped if `e` does not compare equal to any of them. + +In particular, `match` works great with `std::error_code`. The following handler is designed to handle `ENOENT` errors: + +[source,c++] +---- +[]( leaf::match ) +{ +} +---- + +This, however, requires {CPP}17 or newer, because it is impossible to infer the type of the error enum (in this case, `std::errc`) from the specified type `std::error_code`, and {CPP}11 does not allow `auto` template arguments. LEAF provides the following workaround, compatible with {CPP}11: + +[source,c++] +---- +[]( leaf::match, std::errc::no_such_file_or_directory> ) +{ +} +---- + +In addition, it is possible to select a handler based on `std::error_category`. The following handler will match any `std::error_code` of the `std::generic_category` (requires {CPP}17 or newer): + +[source,c++] +---- +[]( std::error_code, leaf::category> ) +{ +} +---- + +LEAF supports the following useful predicates: + +* <>: as described above. +* <>: where `match` compares the object `e` of type `E` with the values `V...`, `match_value` compare `e.value` with the values `V...`. +* <>: similar to `match_value`, but takes a pointer to the data member to compare; that is, `match_member<&E::value, V...>` is equvialent to `match_value`. Note, however, that `match_member` requires {CPP}17 or newer, while `match_value` does not. +* <> is a special predicate that takes any other predicate `P` and requires that an error object of type `E` is available and that `P` evaluates to `false`. For example, `if_not>` requires that an object `e` of type `E` is available, and that it does not compare equal to any of the specified `V...`. + +NOTE: See also <>. + +''' + [[tutorial-binding_handlers]] === Binding Error Handlers in a `std::tuple` @@ -1462,7 +1581,7 @@ TIP: The automatically-generated diagnostic messages are developer-friendly, but ''' -[[tutorial-working_with_std_error_code]] +[[tutorial-std_error_code]] === Working with `std::error_code`, `std::error_condition` ==== Introduction @@ -3800,155 +3919,6 @@ The `operator<<` overload prints diagnostic information about each error object ''' -[[match]] -=== `match` - -.#include -[source,c++] ----- -namespace boost { namespace leaf { - - template - class match - { - public: - - explicit match( E const & e ) noexcept; - - bool operator()() const noexcept; - - E const & matched() const noexcept; - }; - -} } ----- - -When an instance of the `match` template is used in an error handler declaration, the <> first checks if an error object `e` of type `E` is available. If it is not available, the handler is dropped. Otherwise, the `match` object `m` is initialized with `e` and the handler is dropped if the expression `m()` evaluates to `false`. - -The expression `m()` is equivalent to: - -[.text-center] -`p~1~(V~1~) || p~2~(V~2~) || ... p~n~(V~n~)` - -Each `p~i~` is a boolean predicate that compares `e` against `V~i~`. Generally, `p~i~` is equivalent to `e == V~i~`, with the following exceptions: - -* If `E` has an accessible data member `value`, `p~i~` works with `e.value` rather than with `e` itself; -* If `E` has an accessible member function `value()`, `p~i~` works with `e.value()` rather than with `e` itself; -* If `E` is `std::error_code`, any `V~i~` may be an instance of the `leaf::category` template. In this case it is required that `std::is_error_code_enum::value` is `true`, and `p~i~` is equivalent to: - -[.text-center] -`&e.category() == &std::error_code(Enum{}).category()`. - -.Example 1: -[source,c++] ----- -enum class my_enum { e1, e2, e3 }; - -leaf::try_handle_some( - [] - { - .... - }, - - []( leaf::match ) <1> - { - .... - } ); ----- -<1> The handler is selected if an object of type `my_enum`, which compares equal to `e1` or to `e2`, is associated with the detected error. - -.Example 2: -[source,c++] ----- -struct e_errno { int value; } - -leaf::try_handle_some( - [] - { - .... - }, - - []( leaf::match ) <1> - { - .... - } ); ----- -<1> The handler is selected if an object of type `e_errno`, with `.value` equal to `ENOENT`, is associated with the detected error. - -.Example 3: -[source,c++] ----- -enum class my_enum { e1=1, e2, e3 }; - -namespace std -{ - template <> struct is_error_code_enum: std::true_type { }; -} - -leaf::try_handle_some( - [] - { - .... - }, - - []( leaf::match ) <1> - { - .... - } ); ----- -<1> The handler is selected if an object of type std::error_code, which compares equal to e1 or to e2, is associated with the detected error - -.Example 4: -[source,c++] ----- -enum class enum_a { a1=1, a2, a3 }; -enum class enum_b { b1=1, b2, b3 }; - -namespace std -{ - template <> struct is_error_code_enum: std::true_type { }; - template <> struct is_error_code_enum: std::true_type { }; -} - -leaf::try_handle_some( - [] - { - .... - }, - - []( leaf::match, enum_b::b2> ) <1> - { - .... - } ); ----- -<1> The handler is selected if an object of type `std::error_code`, which either has the same `std::error_category` as that of `enum_a` or compares equal to `enum_b::b2`, is associated with the detected error. - -The use of the `leaf::category` template requires automatic deduction of the type of each `V~i~`, which in turn requires {CPP}17 or newer. The same applies to the use of `std::error_code` as `E`, but LEAF provides a compatible {CPP}11 workaround for this case, using the template `condition`. The following is equivalent to Example 3: - -.Example 5: -[source,c++] ----- -enum class my_enum { e1=1, e2, e3 }; - -namespace std -{ - template <> struct is_error_code_enum: std::true_type { }; -} - -leaf::try_handle_some( - [] - { - return f(); - }, - - []( leaf::match, my_enum::e1, my_enum::e2> ) - { - .... - } ); ----- - -''' - [[polymorphic_context]] === `polymorphic_context` @@ -4269,6 +4239,224 @@ The behavior of `verbose_diagnostic_info` (and <>) is affected WARNING: Using `verbose_diagnostic_info` will likely allocate memory dynamically. +[[predicates]] +== Reference: Predicates + +Predicates are a special types of error handler arguments which cause the <> to consider the _value_ of available error objects, not only their type. See <>. + +''' + +[[match]] +=== `match` + +.#include +[source,c++] +---- +namespace boost { namespace leaf { + + template + class match + { + public: + + E const & matched() const noexcept; + }; + +} } +---- + +When an instance of the `match` template is used as an argument to an error handler, the <> first checks if an error object `e` of type `E` is available. If it is not available, the handler is dropped. Otherwise, the handler is dropped if the following condition does not hold: + +[.text-center] +`p~1~ || p~2~ || ... p~n~`. + +Generally, `p~i~` is equivalent to `e == V~i~`, except if `V~i~` is pointer to a function + +[.text-center] +`bool (*V~i~)(T x)`. + +In this case it is required that `V~i~ != 0` and that `x` can be initialized with `E const &`, and `p~i~` is equivalent to: + +[.text-center] +`V~i~(e)`. + +In particular, it is valid to pass pointer to the function `leaf::category` for any `V~i~`, where: + +[.text-center] +`std::is_error_code_enum::value || std::is_error_condition_enum::value`. + +In this case, `p~i~` is equivalent to: + +[.text-center] +`&e.category() == &std::error_code(Enum{}).category()`. + +In the end, if the condition holds and the handler is called, it is valid to call the member function `matched` to access the matched object `e`. + +NOTE: See also <>. + +.Example 1: +[source,c++] +---- +enum class my_enum { e1, e2, e3 }; + +leaf::try_handle_some( + [] + { + .... + }, + + []( leaf::match ) <1> + { + .... + } ); +---- +<1> The handler is selected if an object of type `my_enum`, which compares equal to `e1` or to `e2`, is associated with the detected error. + +.Example 2: +[source,c++] +---- +enum class my_enum { e1=1, e2, e3 }; + +namespace std +{ + template <> struct is_error_code_enum: std::true_type { }; +} + +leaf::try_handle_some( + [] + { + .... + }, + + []( leaf::match ) <1> + { + .... + } ); +---- +<1> The handler is selected if an object of type `std::error_code`, which compares equal to `e1` or to `e2`, is associated with the detected error. + +.Example 3: +[source,c++] +---- +enum class enum_a { a1=1, a2, a3 }; +enum class enum_b { b1=1, b2, b3 }; + +namespace std +{ + template <> struct is_error_code_enum: std::true_type { }; + template <> struct is_error_code_enum: std::true_type { }; +} + +leaf::try_handle_some( + [] + { + .... + }, + + []( leaf::match, enum_b::b2> ) <1> + { + .... + } ); +---- +<1> The handler is selected if an object of type `std::error_code`, which either has the same `std::error_category` as that of `enum_a` or compares equal to `enum_b::b2`, is associated with the detected error. + +The use of the `leaf::category` template requires automatic deduction of the type of each `V~i~`, which in turn requires {CPP}17 or newer. The same applies to the use of `std::error_code` as `E`, but LEAF provides a compatible {CPP}11 workaround for this case, using the template `condition`. The following is equivalent to Example 2: + +.Example 4: +[source,c++] +---- +enum class my_enum { e1=1, e2, e3 }; + +namespace std +{ + template <> struct is_error_code_enum: std::true_type { }; +} + +leaf::try_handle_some( + [] + { + return f(); + }, + + []( leaf::match, my_enum::e1, my_enum::e2> ) + { + .... + } ); +---- + +''' + +[[match_member]] +=== `match_member` + +.#include +[source,c++] +---- +namespace boost { namespace leaf { + + template + class match_member; + + template + class match_member + { + public: + + E const & matched() const noexcept; + }; + +} } +---- + +This predicate is similar to <>, but is able to bind any accessible data member of `E`; e.g. `match_member<&E::value, V...>` is equivalent to `match_value`. + +WARNING: `match_member` requires at least {CPP}17, whereas `match_value` does not. + +NOTE: See also <>. + +''' + +[[match_value]] +=== `match_value` + +.#include +[source,c++] +---- +namespace boost { namespace leaf { + + template + class match_value + { + public: + + E const & matched() const noexcept; + }; + +} } +---- + +This predicate is similar to <>, but where `match` compares the available error object `e` of type `E` to the specified values `V...`, `match_value` compares `e.value` to the specified values `V...`. + +NOTE: See also <>. + +.Example: +[source,c++] +---- +struct e_errno { int value; } + +leaf::try_handle_some( + [] + { + .... + }, + + []( leaf::match ) <1> + { + .... + } ); +---- +<1> The handler is selected if an object of type <>, with `.value` equal to `ENOENT`, is associated with the detected error. + [[macros]] == Reference: Macros diff --git a/include/boost/leaf/all.hpp b/include/boost/leaf/all.hpp index 4ca3a29..003f5a7 100644 --- a/include/boost/leaf/all.hpp +++ b/include/boost/leaf/all.hpp @@ -1895,7 +1895,7 @@ namespace boost { namespace leaf { } } - BOOST_LEAF_CONSTEXPR int get_id() const noexcept + int get_id() const noexcept { int err_id = leaf_detail::current_id(); if( err_id != err_id_ ) @@ -1904,12 +1904,12 @@ namespace boost { namespace leaf { return leaf_detail::new_id(); } - BOOST_LEAF_CONSTEXPR error_id check() const noexcept + error_id check() const noexcept { return leaf_detail::make_error_id(check_id()); } - BOOST_LEAF_CONSTEXPR error_id assigned_error_id() const noexcept + error_id assigned_error_id() const noexcept { return leaf_detail::make_error_id(get_id()); } @@ -2184,7 +2184,7 @@ namespace boost { namespace leaf { public: - BOOST_LEAF_CONSTEXPR capturing_exception(std::exception_ptr && ex, context_ptr && ctx) noexcept: + capturing_exception(std::exception_ptr && ex, context_ptr && ctx) noexcept: ex_(std::move(ex)), ctx_(std::move(ctx)) { @@ -2540,10 +2540,10 @@ namespace boost { namespace leaf { struct e_unexpected_info; #endif - template ::type>::value> + template ::type>::value> struct handler_argument_traits_defaults { - using error_type = typename std::decay::type; + using error_type = typename std::decay::type; constexpr static bool requires_catch = RequiresCatch; constexpr static bool always_available = false; @@ -2554,20 +2554,20 @@ namespace boost { namespace leaf { BOOST_LEAF_CONSTEXPR static error_type * check( Tup &, error_info const & ) noexcept; template - BOOST_LEAF_CONSTEXPR static A get( Tup & tup, error_info const & ei ) noexcept + BOOST_LEAF_CONSTEXPR static E get( Tup & tup, error_info const & ei ) noexcept { return *check(tup, ei); } - static_assert(!std::is_same::value, "Handlers must take leaf::error_info arguments by const &"); - static_assert(!std::is_same::value, "Handlers must take leaf::diagnostic_info arguments by const &"); - static_assert(!std::is_same::value, "Handlers must take leaf::verbose_diagnostic_info arguments by const &"); + static_assert(!std::is_same::value, "Handlers must take leaf::error_info arguments by const &"); + static_assert(!std::is_same::value, "Handlers must take leaf::diagnostic_info arguments by const &"); + static_assert(!std::is_same::value, "Handlers must take leaf::verbose_diagnostic_info arguments by const &"); }; - template + template struct handler_argument_always_available { - using error_type = A; + using error_type = E; constexpr static bool requires_catch = false; constexpr static bool always_available = true; @@ -2578,24 +2578,24 @@ namespace boost { namespace leaf { }; }; - template - struct handler_argument_traits: handler_argument_traits_defaults + template + struct handler_argument_traits: handler_argument_traits_defaults { }; - template - struct handler_argument_traits + template + struct handler_argument_traits { - static_assert(sizeof(A) == 0, "Error handlers may not take rvalue ref arguments"); + static_assert(sizeof(E) == 0, "Error handlers may not take rvalue ref arguments"); }; - template - struct handler_argument_traits: handler_argument_always_available::type> + template + struct handler_argument_traits: handler_argument_always_available::type> { template - BOOST_LEAF_CONSTEXPR static A * get( Tup & tup, error_info const & ei) noexcept + BOOST_LEAF_CONSTEXPR static E * get( Tup & tup, error_info const & ei) noexcept { - return handler_argument_traits_defaults::check(tup, ei); + return handler_argument_traits_defaults::check(tup, ei); } }; @@ -2664,23 +2664,32 @@ namespace boost { namespace leaf { namespace leaf_detail { - template - BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE bool cmp_value_pack( MatchType const & x, bool (*pred)(MatchType const &) noexcept ) noexcept +#if __cplusplus >= 201703L + template + BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE bool cmp_value_pack( MatchType const & e, bool (*P)(T) noexcept ) noexcept { - BOOST_LEAF_ASSERT(pred != 0); - return pred(x); + BOOST_LEAF_ASSERT(P != 0); + return P(e); } - template - BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE bool cmp_value_pack( MatchType const & x, V v ) noexcept + template + BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE bool cmp_value_pack( MatchType const & e, bool (*P)(T) ) { - return x == v; + BOOST_LEAF_ASSERT(P != 0); + return P(e); + } +#endif + + template + BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE bool cmp_value_pack( MatchType const & e, V v ) + { + return e == v; } template - BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE bool cmp_value_pack( MatchType const & x, VCar car, VCdr ... cdr ) noexcept + BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE bool cmp_value_pack( MatchType const & e, VCar car, VCdr ... cdr ) { - return cmp_value_pack(x, car) || cmp_value_pack(x, cdr...); + return cmp_value_pack(e, car) || cmp_value_pack(e, cdr...); } } @@ -2797,43 +2806,6 @@ namespace boost { namespace leaf { #endif - //////////////////////////////////////// - - template - struct match_if; - - namespace leaf_detail - { - template - struct handler_argument_traits>: handler_argument_pred> - { - }; - - template struct handler_argument_traits const &>: bad_predicate> { }; - template struct handler_argument_traits const *>: bad_predicate> { }; - template struct handler_argument_traits &>: bad_predicate> { }; - template struct handler_argument_traits *>: bad_predicate> { }; - } - - //////////////////////////////////////// - - template - struct if_not; - - namespace leaf_detail - { - template - struct handler_argument_traits>: handler_argument_pred> - { - }; - - template struct handler_argument_traits const &>: bad_predicate> { }; - template struct handler_argument_traits const *>: bad_predicate> { }; - template struct handler_argument_traits &>: bad_predicate> { }; - template struct handler_argument_traits *>: bad_predicate> { }; - } - - } } #ifndef BOOST_LEAF_NO_EXCEPTIONS @@ -4409,12 +4381,14 @@ namespace boost { namespace leaf { static_assert(std::is_error_condition_enum::value || std::is_error_code_enum::value, "leaf::condition requires Enum to be registered either with std::is_error_condition_enum or std::is_error_code_enum."); }; +#if __cplusplus >= 201703L template BOOST_LEAF_CONSTEXPR inline bool category( std::error_code const & ec ) noexcept { static_assert(std::is_error_code_enum::value, "leaf::category requires an error code enum"); return &ec.category() == &std::error_code(ErrorCodeEnum{}).category(); } +#endif //////////////////////////////////////// @@ -4611,24 +4585,6 @@ namespace boost { namespace leaf { //////////////////////////////////////// - template - struct match_if: leaf_detail::pred - { - using error_type = E; - - BOOST_LEAF_CONSTEXPR explicit match_if(E const & e) noexcept: - leaf_detail::pred(e) - { - } - - BOOST_LEAF_CONSTEXPR static bool evaluate(E const & e) noexcept - { - return F(e); - } - }; - - //////////////////////////////////////// - template struct if_not: leaf_detail::pred { diff --git a/include/boost/leaf/capture.hpp b/include/boost/leaf/capture.hpp index 30ecd6f..da5d4d4 100644 --- a/include/boost/leaf/capture.hpp +++ b/include/boost/leaf/capture.hpp @@ -96,7 +96,7 @@ namespace boost { namespace leaf { public: - BOOST_LEAF_CONSTEXPR capturing_exception(std::exception_ptr && ex, context_ptr && ctx) noexcept: + capturing_exception(std::exception_ptr && ex, context_ptr && ctx) noexcept: ex_(std::move(ex)), ctx_(std::move(ctx)) { diff --git a/include/boost/leaf/detail/handler_argument_traits.hpp b/include/boost/leaf/detail/handler_argument_traits.hpp index a20de25..4aa45e2 100644 --- a/include/boost/leaf/detail/handler_argument_traits.hpp +++ b/include/boost/leaf/detail/handler_argument_traits.hpp @@ -36,10 +36,10 @@ namespace boost { namespace leaf { struct e_unexpected_info; #endif - template ::type>::value> + template ::type>::value> struct handler_argument_traits_defaults { - using error_type = typename std::decay::type; + using error_type = typename std::decay::type; constexpr static bool requires_catch = RequiresCatch; constexpr static bool always_available = false; @@ -50,20 +50,20 @@ namespace boost { namespace leaf { BOOST_LEAF_CONSTEXPR static error_type * check( Tup &, error_info const & ) noexcept; template - BOOST_LEAF_CONSTEXPR static A get( Tup & tup, error_info const & ei ) noexcept + BOOST_LEAF_CONSTEXPR static E get( Tup & tup, error_info const & ei ) noexcept { return *check(tup, ei); } - static_assert(!std::is_same::value, "Handlers must take leaf::error_info arguments by const &"); - static_assert(!std::is_same::value, "Handlers must take leaf::diagnostic_info arguments by const &"); - static_assert(!std::is_same::value, "Handlers must take leaf::verbose_diagnostic_info arguments by const &"); + static_assert(!std::is_same::value, "Handlers must take leaf::error_info arguments by const &"); + static_assert(!std::is_same::value, "Handlers must take leaf::diagnostic_info arguments by const &"); + static_assert(!std::is_same::value, "Handlers must take leaf::verbose_diagnostic_info arguments by const &"); }; - template + template struct handler_argument_always_available { - using error_type = A; + using error_type = E; constexpr static bool requires_catch = false; constexpr static bool always_available = true; @@ -74,24 +74,24 @@ namespace boost { namespace leaf { }; }; - template - struct handler_argument_traits: handler_argument_traits_defaults + template + struct handler_argument_traits: handler_argument_traits_defaults { }; - template - struct handler_argument_traits + template + struct handler_argument_traits { - static_assert(sizeof(A) == 0, "Error handlers may not take rvalue ref arguments"); + static_assert(sizeof(E) == 0, "Error handlers may not take rvalue ref arguments"); }; - template - struct handler_argument_traits: handler_argument_always_available::type> + template + struct handler_argument_traits: handler_argument_always_available::type> { template - BOOST_LEAF_CONSTEXPR static A * get( Tup & tup, error_info const & ei) noexcept + BOOST_LEAF_CONSTEXPR static E * get( Tup & tup, error_info const & ei) noexcept { - return handler_argument_traits_defaults::check(tup, ei); + return handler_argument_traits_defaults::check(tup, ei); } }; @@ -160,23 +160,32 @@ namespace boost { namespace leaf { namespace leaf_detail { - template - BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE bool cmp_value_pack( MatchType const & x, bool (*pred)(MatchType const &) noexcept ) noexcept +#if __cplusplus >= 201703L + template + BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE bool cmp_value_pack( MatchType const & e, bool (*P)(T) noexcept ) noexcept { - BOOST_LEAF_ASSERT(pred != 0); - return pred(x); + BOOST_LEAF_ASSERT(P != 0); + return P(e); } - template - BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE bool cmp_value_pack( MatchType const & x, V v ) noexcept + template + BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE bool cmp_value_pack( MatchType const & e, bool (*P)(T) ) { - return x == v; + BOOST_LEAF_ASSERT(P != 0); + return P(e); + } +#endif + + template + BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE bool cmp_value_pack( MatchType const & e, V v ) + { + return e == v; } template - BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE bool cmp_value_pack( MatchType const & x, VCar car, VCdr ... cdr ) noexcept + BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE bool cmp_value_pack( MatchType const & e, VCar car, VCdr ... cdr ) { - return cmp_value_pack(x, car) || cmp_value_pack(x, cdr...); + return cmp_value_pack(e, car) || cmp_value_pack(e, cdr...); } } @@ -293,43 +302,6 @@ namespace boost { namespace leaf { #endif - //////////////////////////////////////// - - template - struct match_if; - - namespace leaf_detail - { - template - struct handler_argument_traits>: handler_argument_pred> - { - }; - - template struct handler_argument_traits const &>: bad_predicate> { }; - template struct handler_argument_traits const *>: bad_predicate> { }; - template struct handler_argument_traits &>: bad_predicate> { }; - template struct handler_argument_traits *>: bad_predicate> { }; - } - - //////////////////////////////////////// - - template - struct if_not; - - namespace leaf_detail - { - template - struct handler_argument_traits>: handler_argument_pred> - { - }; - - template struct handler_argument_traits const &>: bad_predicate> { }; - template struct handler_argument_traits const *>: bad_predicate> { }; - template struct handler_argument_traits &>: bad_predicate> { }; - template struct handler_argument_traits *>: bad_predicate> { }; - } - - } } #ifndef BOOST_LEAF_NO_EXCEPTIONS diff --git a/include/boost/leaf/on_error.hpp b/include/boost/leaf/on_error.hpp index 6792270..8a29eff 100644 --- a/include/boost/leaf/on_error.hpp +++ b/include/boost/leaf/on_error.hpp @@ -54,7 +54,7 @@ namespace boost { namespace leaf { } } - BOOST_LEAF_CONSTEXPR int get_id() const noexcept + int get_id() const noexcept { int err_id = leaf_detail::current_id(); if( err_id != err_id_ ) @@ -63,12 +63,12 @@ namespace boost { namespace leaf { return leaf_detail::new_id(); } - BOOST_LEAF_CONSTEXPR error_id check() const noexcept + error_id check() const noexcept { return leaf_detail::make_error_id(check_id()); } - BOOST_LEAF_CONSTEXPR error_id assigned_error_id() const noexcept + error_id assigned_error_id() const noexcept { return leaf_detail::make_error_id(get_id()); } diff --git a/include/boost/leaf/pred.hpp b/include/boost/leaf/pred.hpp index 6b6a88c..c5d6d63 100644 --- a/include/boost/leaf/pred.hpp +++ b/include/boost/leaf/pred.hpp @@ -56,12 +56,14 @@ namespace boost { namespace leaf { static_assert(std::is_error_condition_enum::value || std::is_error_code_enum::value, "leaf::condition requires Enum to be registered either with std::is_error_condition_enum or std::is_error_code_enum."); }; +#if __cplusplus >= 201703L template BOOST_LEAF_CONSTEXPR inline bool category( std::error_code const & ec ) noexcept { static_assert(std::is_error_code_enum::value, "leaf::category requires an error code enum"); return &ec.category() == &std::error_code(ErrorCodeEnum{}).category(); } +#endif //////////////////////////////////////// @@ -258,24 +260,6 @@ namespace boost { namespace leaf { //////////////////////////////////////// - template - struct match_if: leaf_detail::pred - { - using error_type = E; - - BOOST_LEAF_CONSTEXPR explicit match_if(E const & e) noexcept: - leaf_detail::pred(e) - { - } - - BOOST_LEAF_CONSTEXPR static bool evaluate(E const & e) noexcept - { - return F(e); - } - }; - - //////////////////////////////////////// - template struct if_not: leaf_detail::pred { diff --git a/meson.build b/meson.build index 27da15a..6d35616 100644 --- a/meson.build +++ b/meson.build @@ -115,7 +115,6 @@ tests = [ 'match_test', 'match_member_test', 'match_value_test', - 'match_if_test', 'multiple_errors_test', 'optional_test', 'preload_basic_test', diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index a05bed1..94ffa0c 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -69,7 +69,6 @@ run handle_basic_test.cpp ; run handle_some_other_result_test.cpp ; run handle_some_test.cpp ; run match_test.cpp ; -run match_if_test.cpp ; run match_member_test.cpp ; run match_value_test.cpp ; run multiple_errors_test.cpp ; diff --git a/test/match_if_test.cpp b/test/match_if_test.cpp deleted file mode 100644 index ae2bbd0..0000000 --- a/test/match_if_test.cpp +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) 2018-2020 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 -#include -#include -#include -#include "_test_ec.hpp" -#include "lightweight_test.hpp" - -namespace leaf = boost::leaf; - -enum class my_error { e1=1, e2, e3 }; - -struct my_exception: std::exception -{ - int value; -}; - -template -bool cmp_my_error( my_error const & e ) -{ - return e == value; -}; - -template -bool cmp_my_exception( my_exception const & e ); - -static_assert(!leaf::leaf_detail::handler_argument_traits>>::requires_catch, "requires_catch deduction error"); -#if __cplusplus >= 201703L -static_assert(leaf::leaf_detail::handler_argument_traits>>::requires_catch, "requires_catch deduction error"); -#endif - -template -bool test(E const & e ) -{ - if( M::evaluate(e) ) - { - M m(e); - BOOST_TEST_EQ(&e, &m.matched()); - return true; - } - else - return false; -} - -int main() -{ - { - my_error e = my_error::e1; - - BOOST_TEST(( test>>(e) )); - BOOST_TEST(( !test>>(e) )); - } - - { - int r = leaf::try_handle_all( - []() -> leaf::result - { - return leaf::new_error(my_error::e1); - }, - - []( leaf::match_if> ) - { - return 1; - }, - - [] - { - return 2; - } ); - BOOST_TEST_EQ(r, 1); - } - - { - int r = leaf::try_handle_all( - []() -> leaf::result - { - return leaf::new_error(my_error::e1); - }, - - []( leaf::match_if> ) - { - return 1; - }, - - [] - { - return 2; - } ); - BOOST_TEST_EQ(r, 2); - } - - return boost::report_errors(); -} diff --git a/test/match_test.cpp b/test/match_test.cpp index cfd184f..5d15eeb 100644 --- a/test/match_test.cpp +++ b/test/match_test.cpp @@ -14,6 +14,14 @@ namespace leaf = boost::leaf; enum class my_error { e1=1, e2, e3 }; +#if __cplusplus >= 201703L +template +bool cmp_my_error( my_error const & e ) noexcept +{ + return e == value; +}; +#endif + struct my_exception: std::exception { int value; @@ -87,6 +95,15 @@ int main() #endif } +#if __cplusplus >= 201703L + { + my_error e = my_error::e1; + + BOOST_TEST(( test>>(e) )); + BOOST_TEST(( !test>>(e) )); + } +#endif + { int r = leaf::try_handle_all( []() -> leaf::result @@ -173,5 +190,45 @@ int main() BOOST_TEST_EQ(r, 3); } +#if __cplusplus >= 201703L + { + int r = leaf::try_handle_all( + []() -> leaf::result + { + return leaf::new_error(my_error::e1); + }, + + []( leaf::match> ) + { + return 1; + }, + + [] + { + return 2; + } ); + BOOST_TEST_EQ(r, 1); + } + + { + int r = leaf::try_handle_all( + []() -> leaf::result + { + return leaf::new_error(my_error::e1); + }, + + []( leaf::match> ) + { + return 1; + }, + + [] + { + return 2; + } ); + BOOST_TEST_EQ(r, 2); + } +#endif + return boost::report_errors(); }