From 8a2b9caf6ee2e69df7e9e6d00faf3250882e3e10 Mon Sep 17 00:00:00 2001 From: Emil Dotchevski Date: Sun, 20 Jan 2019 02:44:47 -0800 Subject: [PATCH] sending error_id through std::error_code --- .vscode/tasks.json | 18 +++++ example/print_file_result.cpp | 1 + example/print_half.cpp | 1 + include/boost/leaf/error.hpp | 4 + include/boost/leaf/error_code.hpp | 80 +++++++++++++++++++ include/boost/leaf/handle.hpp | 45 ++++++++--- include/boost/leaf/result.hpp | 12 ++- meson.build | 2 + test/Jamfile.v2 | 2 + test/defer_basic_test.cpp | 1 + test/defer_nested_error_result_test.cpp | 1 + test/defer_nested_new_error_result_test.cpp | 1 + test/defer_nested_success_result_test.cpp | 1 + test/handle_all_error_code_test.cpp | 70 ++++++++++++++++ test/handle_all_test.cpp | 1 + test/handle_some_basic_test.cpp | 1 + test/handle_some_error_code_test.cpp | 56 +++++++++++++ test/handle_some_test.cpp | 1 + test/preload_basic_test.cpp | 1 + test/preload_nested_error_result_test.cpp | 1 + test/preload_nested_new_error_result_test.cpp | 1 + test/preload_nested_success_result_test.cpp | 1 + 22 files changed, 287 insertions(+), 15 deletions(-) create mode 100644 include/boost/leaf/error_code.hpp create mode 100644 test/handle_all_error_code_test.cpp create mode 100644 test/handle_some_error_code_test.cpp diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 5e23d46..cd25e46 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -158,6 +158,15 @@ "command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test function_traits_test" } }, + { + "label": "handle_all_error_code_test", + "type": "shell", + "command": "cd ${workspaceRoot}/bld/debug && meson test handle_all_error_code_test", + "problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] }, + "windows": { + "command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test handle_all_error_code_test" + } + }, { "label": "handle_all_test", "type": "shell", @@ -176,6 +185,15 @@ "command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test handle_some_basic_test" } }, + { + "label": "handle_some_error_code_test", + "type": "shell", + "command": "cd ${workspaceRoot}/bld/debug && meson test handle_some_error_code_test", + "problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] }, + "windows": { + "command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test handle_some_error_code_test" + } + }, { "label": "handle_some_test", "type": "shell", diff --git a/example/print_file_result.cpp b/example/print_file_result.cpp index 0d56634..220cf61 100644 --- a/example/print_file_result.cpp +++ b/example/print_file_result.cpp @@ -8,6 +8,7 @@ // using LEAF to handle errors. It does not use exception handling. #include +#include #include #include #include diff --git a/example/print_half.cpp b/example/print_half.cpp index 7d122d4..32af03e 100644 --- a/example/print_half.cpp +++ b/example/print_half.cpp @@ -8,6 +8,7 @@ // https://github.com/ned14/outcome/blob/master/doc/src/snippets/using_result.cpp #include +#include #include #include #include diff --git a/include/boost/leaf/error.hpp b/include/boost/leaf/error.hpp index 202e511..d9f7be2 100644 --- a/include/boost/leaf/error.hpp +++ b/include/boost/leaf/error.hpp @@ -26,6 +26,7 @@ namespace boost { namespace leaf { error_id next_error() noexcept; error_id last_error() noexcept; + error_id get_error_id( std::error_code const & ) noexcept; class error_id { @@ -33,6 +34,7 @@ namespace boost { namespace leaf { friend error_id new_error( E && ... ) noexcept; friend error_id leaf::next_error() noexcept; friend error_id leaf::last_error() noexcept; + friend error_id get_error_id( std::error_code const & ) noexcept; unsigned id_; @@ -112,6 +114,8 @@ namespace boost { namespace leaf { template error_id propagate( E && ... ) const noexcept; + + std::error_code to_error_code() const noexcept; }; template diff --git a/include/boost/leaf/error_code.hpp b/include/boost/leaf/error_code.hpp new file mode 100644 index 0000000..0826211 --- /dev/null +++ b/include/boost/leaf/error_code.hpp @@ -0,0 +1,80 @@ +#ifndef BOOST_LEAF_B146ADCE1C7A11E9A455E6F387D1CC0E +#define BOOST_LEAF_B146ADCE1C7A11E9A455E6F387D1CC0E + +// Copyright (c) 2018 Emil Dotchevski +// Copyright (c) 2018 Second Spectrum, 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 + +namespace boost { namespace leaf { + + class error_category: public std::error_category + { + bool equivalent( int, std::error_condition const & ) const noexcept + { + return false; + } + + bool equivalent( std::error_code const &, int ) const noexcept + { + return false; + } + + char const * name() const noexcept + { + return "LEAF error, use with leaf::handle_some or leaf::handle_all."; + } + + std::string message( int condition ) const + { + return name(); + } + }; + + namespace leaf_detail + { + inline error_category const & get_error_category() noexcept + { + static error_category cat; + return cat; + } + + inline error_category const & get_error_category0() noexcept + { + static error_category cat; + return cat; + } + } + + inline std::error_code error_id::to_error_code() const noexcept + { + return id_ ? + std::error_code( int(id_), leaf_detail::get_error_category() ) : + std::error_code( -1, leaf_detail::get_error_category0() ); + } + + inline error_id get_error_id( std::error_code const & ec ) noexcept + { + std::error_category const & cat = ec.category(); + if( &cat==&leaf_detail::get_error_category() ) + return error_id(ec.value()); + else if( &cat==&leaf_detail::get_error_category0() ) + { + assert(ec.value()==-1); + return error_id(0); + } + else + return leaf::next_error(); + } + + inline bool succeeded( std::error_code const & ec ) + { + return !ec; + } + +} } + +#endif diff --git a/include/boost/leaf/handle.hpp b/include/boost/leaf/handle.hpp index 6722d70..663d9e7 100644 --- a/include/boost/leaf/handle.hpp +++ b/include/boost/leaf/handle.hpp @@ -7,25 +7,40 @@ // 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 namespace boost { namespace leaf { + template + class result; + + template + bool succeeded( result const & r ) + { + return bool(r); + } + template typename std::remove_reference()().value())>::type handle_all( TryBlock && try_block, Handler && ... handler ) { using namespace leaf_detail; typename deduce_static_store::type>::type ss; ss.set_reset(true); - if( auto r = std::forward(try_block)() ) - return *r; + auto r = std::forward(try_block)(); + if( succeeded(r) ) + return r.value(); else - return ss.handle_error(error_info(r.error()), std::forward(handler)...); + return ss.handle_error(error_info(get_error_id(r)), std::forward(handler)...); } namespace leaf_detail { + template + struct dependent_type_result_void + { + using type = result; + }; + template ::mp_args> struct handler_wrapper; @@ -51,7 +66,7 @@ namespace boost { namespace leaf { f_(std::forward(f)) { } - result operator()( A... a ) const + typename dependent_type_result_void::type operator()( A... a ) const { f_(a...); return { }; @@ -65,18 +80,24 @@ namespace boost { namespace leaf { using namespace leaf_detail; using R = typename function_traits::return_type; typename deduce_static_store::type>::type ss; - if( auto r = std::forward(try_block)() ) + + auto r = std::forward(try_block)(); + if( succeeded(r) ) { ss.set_reset(true); return r; } - else if( auto rr = ss.handle_error(error_info(r.error()), handler_wrapper(std::forward(handler))..., [&r] { return r; } ) ) - { - ss.set_reset(true); - return rr; - } else - return rr; + { + auto rr = ss.handle_error(error_info(get_error_id(r)), handler_wrapper(std::forward(handler))..., [&r] { return r; } ); + if( succeeded(rr) ) + { + ss.set_reset(true); + return rr; + } + else + return rr; + } } } } diff --git a/include/boost/leaf/result.hpp b/include/boost/leaf/result.hpp index 99882b4..6396746 100644 --- a/include/boost/leaf/result.hpp +++ b/include/boost/leaf/result.hpp @@ -35,9 +35,9 @@ namespace boost { namespace leaf { dynamic_store_ptr cap_; }; - leaf_detail::result_variant which_; + mutable leaf_detail::result_variant which_; - void destroy() noexcept + void destroy() const noexcept { switch( which_ ) { @@ -219,7 +219,7 @@ namespace boost { namespace leaf { } template - error_id error( E && ... e ) noexcept + error_id error( E && ... e ) const noexcept { switch( which_ ) { @@ -286,6 +286,12 @@ namespace boost { namespace leaf { using base::error; }; + template + error_id get_error_id( result const & r ) + { + return r.error(); + } + } } #endif diff --git a/meson.build b/meson.build index bf0091a..adf64c4 100644 --- a/meson.build +++ b/meson.build @@ -52,8 +52,10 @@ tests = [ 'defer_nested_success_result_test', 'diagnostic_info_test', 'function_traits_test', + 'handle_all_error_code_test', 'handle_all_test', 'handle_some_basic_test', + 'handle_some_error_code_test', 'handle_some_test', 'is_error_type_test', 'optional_test', diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 86df7df..004457b 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -45,8 +45,10 @@ run defer_nested_success_exception_test.cpp ; run defer_nested_success_result_test.cpp ; run diagnostic_info_test.cpp ; run function_traits_test.cpp ; +run handle_all_error_code_test.cpp ; run handle_all_test.cpp ; run handle_some_basic_test.cpp ; +run handle_some_error_code_test.cpp ; run handle_some_test.cpp ; run is_error_type_test.cpp ; run optional_test.cpp ; diff --git a/test/defer_basic_test.cpp b/test/defer_basic_test.cpp index 4d1e839..653257e 100644 --- a/test/defer_basic_test.cpp +++ b/test/defer_basic_test.cpp @@ -6,6 +6,7 @@ #include #include +#include #include "boost/core/lightweight_test.hpp" namespace leaf = boost::leaf; diff --git a/test/defer_nested_error_result_test.cpp b/test/defer_nested_error_result_test.cpp index 7589d01..e47ee33 100644 --- a/test/defer_nested_error_result_test.cpp +++ b/test/defer_nested_error_result_test.cpp @@ -6,6 +6,7 @@ #include #include +#include #include "boost/core/lightweight_test.hpp" namespace leaf = boost::leaf; diff --git a/test/defer_nested_new_error_result_test.cpp b/test/defer_nested_new_error_result_test.cpp index 6465426..6a307c4 100644 --- a/test/defer_nested_new_error_result_test.cpp +++ b/test/defer_nested_new_error_result_test.cpp @@ -6,6 +6,7 @@ #include #include +#include #include "boost/core/lightweight_test.hpp" namespace leaf = boost::leaf; diff --git a/test/defer_nested_success_result_test.cpp b/test/defer_nested_success_result_test.cpp index ed35d04..462922f 100644 --- a/test/defer_nested_success_result_test.cpp +++ b/test/defer_nested_success_result_test.cpp @@ -6,6 +6,7 @@ #include #include +#include #include "boost/core/lightweight_test.hpp" namespace leaf = boost::leaf; diff --git a/test/handle_all_error_code_test.cpp b/test/handle_all_error_code_test.cpp new file mode 100644 index 0000000..fb5ef90 --- /dev/null +++ b/test/handle_all_error_code_test.cpp @@ -0,0 +1,70 @@ +// Copyright (c) 2018 Emil Dotchevski +// Copyright (c) 2018 Second Spectrum, 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 "boost/core/lightweight_test.hpp" +#include + +namespace leaf = boost::leaf; + +template struct info { int value; }; + +int main() +{ + { + int r = leaf::handle_all( + [ ] + { + return std::error_code(); + }, + [ ] + { + return ENOENT; + } ); + BOOST_TEST(!r); + } + { + int r = leaf::handle_all( + [&] + { + std::error_code ec = leaf::new_error(info<1>{1}).to_error_code(); + BOOST_TEST(ec); + BOOST_TEST(ec.message()=="LEAF error, use with leaf::handle_some or leaf::handle_all."); + BOOST_TEST(!std::strcmp(ec.category().name(),"LEAF error, use with leaf::handle_some or leaf::handle_all.")); + return ec; + }, + [ ]( info<1> const & x ) + { + BOOST_TEST(x.value==1); + return 1; + }, + [ ] + { + return 2; + } ); + BOOST_TEST(r==1); + } + { + int r = leaf::handle_all( + [&] + { + return leaf::new_error(info<2>{2},std::error_code(ENOENT,std::system_category())).to_error_code(); + }, + [ ]( info<2> const & x, std::error_code const & ec ) + { + BOOST_TEST(x.value==2); + BOOST_TEST(ec==std::error_code(ENOENT,std::system_category())); + return 1; + }, + [ ] + { + return 2; + } ); + BOOST_TEST(r==1); + } + return boost::report_errors(); +} diff --git a/test/handle_all_test.cpp b/test/handle_all_test.cpp index aa0d3a0..a6d9a91 100644 --- a/test/handle_all_test.cpp +++ b/test/handle_all_test.cpp @@ -5,6 +5,7 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include +#include #include "boost/core/lightweight_test.hpp" namespace leaf = boost::leaf; diff --git a/test/handle_some_basic_test.cpp b/test/handle_some_basic_test.cpp index f3a3439..9784eef 100644 --- a/test/handle_some_basic_test.cpp +++ b/test/handle_some_basic_test.cpp @@ -5,6 +5,7 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include +#include #include "boost/core/lightweight_test.hpp" namespace leaf = boost::leaf; diff --git a/test/handle_some_error_code_test.cpp b/test/handle_some_error_code_test.cpp new file mode 100644 index 0000000..ef0d9cd --- /dev/null +++ b/test/handle_some_error_code_test.cpp @@ -0,0 +1,56 @@ +// Copyright (c) 2018 Emil Dotchevski +// Copyright (c) 2018 Second Spectrum, 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 "boost/core/lightweight_test.hpp" +#include + +namespace leaf = boost::leaf; + +template struct info { int value; }; + +int main() +{ + { + int what=0; + std::error_code r = leaf::handle_some( + [&] + { + std::error_code ec = leaf::new_error(info<1>{1}).to_error_code(); + BOOST_TEST(ec); + BOOST_TEST(ec.message()=="LEAF error, use with leaf::handle_some or leaf::handle_all."); + BOOST_TEST(!std::strcmp(ec.category().name(),"LEAF error, use with leaf::handle_some or leaf::handle_all.")); + return ec; + }, + [&]( info<1> const & x ) + { + what = 1; + BOOST_TEST(x.value==1); + return std::error_code(ENOENT,std::system_category()); + } ); + BOOST_TEST(r==std::error_code(ENOENT,std::system_category())); + BOOST_TEST(what==1); + } + { + int what=0; + std::error_code ec = leaf::handle_some( + [&] + { + return leaf::new_error(info<2>{2},std::error_code(ENOENT,std::system_category())).to_error_code(); + }, + [&]( info<2> const & x, std::error_code const & ec ) + { + what = 2; + BOOST_TEST(x.value==2); + BOOST_TEST(ec==std::error_code(ENOENT,std::system_category())); + return ec; + } ); + BOOST_TEST(ec==std::error_code(ENOENT,std::system_category())); + BOOST_TEST(what==2); + } + return boost::report_errors(); +} diff --git a/test/handle_some_test.cpp b/test/handle_some_test.cpp index 3ccea70..51c57a5 100644 --- a/test/handle_some_test.cpp +++ b/test/handle_some_test.cpp @@ -5,6 +5,7 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include +#include #include "boost/core/lightweight_test.hpp" namespace leaf = boost::leaf; diff --git a/test/preload_basic_test.cpp b/test/preload_basic_test.cpp index f31e2c3..95c6551 100644 --- a/test/preload_basic_test.cpp +++ b/test/preload_basic_test.cpp @@ -6,6 +6,7 @@ #include #include +#include #include "boost/core/lightweight_test.hpp" namespace leaf = boost::leaf; diff --git a/test/preload_nested_error_result_test.cpp b/test/preload_nested_error_result_test.cpp index 3f229c3..6e7fbb3 100644 --- a/test/preload_nested_error_result_test.cpp +++ b/test/preload_nested_error_result_test.cpp @@ -6,6 +6,7 @@ #include #include +#include #include "boost/core/lightweight_test.hpp" namespace leaf = boost::leaf; diff --git a/test/preload_nested_new_error_result_test.cpp b/test/preload_nested_new_error_result_test.cpp index 97e8235..da786e5 100644 --- a/test/preload_nested_new_error_result_test.cpp +++ b/test/preload_nested_new_error_result_test.cpp @@ -6,6 +6,7 @@ #include #include +#include #include "boost/core/lightweight_test.hpp" namespace leaf = boost::leaf; diff --git a/test/preload_nested_success_result_test.cpp b/test/preload_nested_success_result_test.cpp index 5a64739..80fa5d6 100644 --- a/test/preload_nested_success_result_test.cpp +++ b/test/preload_nested_success_result_test.cpp @@ -6,6 +6,7 @@ #include #include +#include #include "boost/core/lightweight_test.hpp" namespace leaf = boost::leaf;