2
0
mirror of https://github.com/boostorg/leaf.git synced 2026-01-19 04:22:08 +00:00

Context activation/deactivation/propagation refactored.

This commit is contained in:
Emil Dotchevski
2019-12-29 18:13:10 -08:00
parent 96477366c3
commit 30cfe9fce1
26 changed files with 1104 additions and 573 deletions

View File

@@ -1,5 +1,5 @@
# Copyright 2016-2018 Peter Dimov
# Copyright 2018-2019 Emil Dotchevski
# Copyright 2016 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt)
@@ -52,7 +52,7 @@ matrix:
include:
- os: linux
- os: linux
env: DOC=1
script:
- |-
@@ -137,6 +137,10 @@ matrix:
compiler: clang++
env: TOOLSET=clang COMPILER=clang++ CXXSTD=11,14,1z
- os: osx
compiler: clang++
env: UBSAN=1 TOOLSET=clang COMPILER=clang++ CXXSTD=11,14,1z UBSAN_OPTIONS=print_stacktrace=1
- os: linux
compiler: g++-4.9
env: TOOLSET=gcc COMPILER=g++-4.9 CXXSTD=11
@@ -169,7 +173,7 @@ matrix:
- os: linux
compiler: g++-7
env: TOOLSET=gcc COMPILER=g++-7 CXXSTD=11,14,1z
env: TOOLSET=gcc COMPILER=g++-7 CXXSTD=11,14,17
addons:
apt:
packages:
@@ -187,6 +191,26 @@ matrix:
sources:
- ubuntu-toolchain-r-test
- os: linux
compiler: g++-9
env: TOOLSET=gcc COMPILER=g++-9 CXXSTD=11,14,17,2a
addons:
apt:
packages:
- g++-9
sources:
- ubuntu-toolchain-r-test
- os: linux
compiler: g++-9
env: UBSAN=1 TOOLSET=gcc COMPILER=g++-9 CXXSTD=11,14,17,2a UBSAN_OPTIONS=print_stacktrace=1 LINKFLAGS=-fuse-ld=gold
addons:
apt:
packages:
- g++-9
sources:
- ubuntu-toolchain-r-test
- os: linux
compiler: /usr/bin/clang++
env: TOOLSET=clang COMPILER=/usr/bin/clang++ CXXSTD=11
@@ -203,6 +227,10 @@ matrix:
packages:
- clang-3.4
- os: linux
compiler: clang++
env: TOOLSET=clang COMPILER=clang++ CXXSTD=11
- os: linux
compiler: clang++-3.5
env: TOOLSET=clang COMPILER=clang++-3.5 CXXSTD=11,14,1z
@@ -213,7 +241,6 @@ matrix:
- libstdc++-4.9-dev
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.5
- os: linux
compiler: clang++-3.6
@@ -222,9 +249,9 @@ matrix:
apt:
packages:
- clang-3.6
- libstdc++-4.9-dev
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.6
- os: linux
compiler: clang++-3.7
@@ -247,7 +274,6 @@ matrix:
- libstdc++-4.9-dev
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.8
- os: linux
compiler: clang++-3.9
@@ -259,7 +285,6 @@ matrix:
- libstdc++-4.9-dev
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.9
- os: linux
compiler: clang++-4.0
@@ -294,6 +319,52 @@ matrix:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-6.0
- os: linux
compiler: clang++-7
env: TOOLSET=clang COMPILER=clang++-7 CXXSTD=11,14,17,2a
addons:
apt:
packages:
- clang-7
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-7
- os: linux
compiler: clang++-8
env: TOOLSET=clang COMPILER=clang++-8 CXXSTD=11,14,17,2a
addons:
apt:
packages:
- clang-8
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-8
- os: linux
dist: xenial
compiler: clang++-9
env: TOOLSET=clang COMPILER=clang++-9 CXXSTD=11,14,17,2a
addons:
apt:
packages:
- clang-9
sources:
- ubuntu-toolchain-r-test
- sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
- os: linux
compiler: clang++-8
env: UBSAN=1 TOOLSET=clang COMPILER=clang++-8 CXXSTD=11,14,17,2a UBSAN_OPTIONS=print_stacktrace=1
addons:
apt:
packages:
- clang-8
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-8
install:
- gem install asciidoctor
- gem install coderay
@@ -316,23 +387,10 @@ install:
script:
- |-
echo "using $TOOLSET : : $COMPILER ;" > ~/user-config.jam
- ../../b2 test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug
- ../../b2 test toolset=$TOOLSET cxxstd=$CXXSTD variant=release
- ../../b2 test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug-diagnostics0
- ../../b2 test toolset=$TOOLSET cxxstd=$CXXSTD variant=release-diagnostics0
- ../../b2 exception-handling=off rtti=off test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug
- ../../b2 exception-handling=off rtti=off test toolset=$TOOLSET cxxstd=$CXXSTD variant=release
- ../../b2 exception-handling=off rtti=off test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug-diagnostics0
- ../../b2 exception-handling=off rtti=off test toolset=$TOOLSET cxxstd=$CXXSTD variant=release-diagnostics0
- ../../b2 threading=single test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug
- ../../b2 threading=single test toolset=$TOOLSET cxxstd=$CXXSTD variant=release
- ../../b2 threading=single test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug-diagnostics0
- ../../b2 threading=single test toolset=$TOOLSET cxxstd=$CXXSTD variant=release-diagnostics0
- ../../b2 threading=single exception-handling=off rtti=off test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug
- ../../b2 threading=single exception-handling=off rtti=off test toolset=$TOOLSET cxxstd=$CXXSTD variant=release
- ../../b2 threading=single exception-handling=off rtti=off test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug-diagnostics0
- ../../b2 threading=single exception-handling=off rtti=off test toolset=$TOOLSET cxxstd=$CXXSTD variant=release-diagnostics0
# - cd bld/debug && meson test
- ../../b2 test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug,release,debug-diagnostics0,release-diagnostics0 ${UBSAN:+cxxflags=-fsanitize=undefined cxxflags=-fno-sanitize-recover=undefined linkflags=-fsanitize=undefined debug-symbols=on} ${LINKFLAGS:+linkflags=$LINKFLAGS}
- ../../b2 exception-handling=off rtti=off test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug,release,debug-diagnostics0,release-diagnostics0 ${UBSAN:+cxxflags=-fsanitize=undefined cxxflags=-fno-sanitize-recover=undefined linkflags=-fsanitize=undefined debug-symbols=on} ${LINKFLAGS:+linkflags=$LINKFLAGS}
- ../../b2 threading=single test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug,release,debug-diagnostics0,release-diagnostics0 ${UBSAN:+cxxflags=-fsanitize=undefined cxxflags=-fno-sanitize-recover=undefined linkflags=-fsanitize=undefined debug-symbols=on} ${LINKFLAGS:+linkflags=$LINKFLAGS}
- ../../b2 threading=single exception-handling=off rtti=off test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug,release,debug-diagnostics0,release-diagnostics0 ${UBSAN:+cxxflags=-fsanitize=undefined cxxflags=-fno-sanitize-recover=undefined linkflags=-fsanitize=undefined debug-symbols=on} ${LINKFLAGS:+linkflags=$LINKFLAGS}
notifications:
email:

27
.vscode/tasks.json vendored
View File

@@ -167,6 +167,33 @@
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test context_deduction_test"
}
},
{
"label": "ctx_handle_all_test",
"type": "shell",
"command": "cd ${workspaceRoot}/bld/debug && meson test ctx_handle_all_test",
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
"windows": {
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test ctx_handle_all_test"
}
},
{
"label": "ctx_handle_exception_test",
"type": "shell",
"command": "cd ${workspaceRoot}/bld/debug && meson test ctx_handle_exception_test",
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
"windows": {
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test ctx_handle_exception_test"
}
},
{
"label": "ctx_handle_some_test",
"type": "shell",
"command": "cd ${workspaceRoot}/bld/debug && meson test ctx_handle_some_test",
"problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] },
"windows": {
"command": "${workspaceRoot}/.vscode/msvc.bat && cd ${workspaceRoot}/bld/debug && meson test ctx_handle_some_test"
}
},
{
"label": "ctx_remote_handle_all_test",
"type": "shell",

View File

@@ -1634,21 +1634,16 @@ namespace boost { namespace leaf {
public:
virtual void activate() noexcept = 0;
virtual void deactivate( bool propagate_errors ) noexcept = 0;
virtual void deactivate() noexcept = 0;
virtual bool is_active() const noexcept = 0;
virtual void propagate() noexcept = 0;
virtual void print( std::ostream & ) const = 0;
};
//////////////////////////////////////////
enum class on_deactivation
{
propagate,
propagate_if_uncaught_exception,
capture_do_not_propagate
};
template <class Ctx>
class context_activator
{
@@ -1657,17 +1652,15 @@ namespace boost { namespace leaf {
public:
context_activator( Ctx & ctx, on_deactivation on_deactivate ) noexcept;
explicit context_activator( Ctx & ctx ) noexcept;
context_activator( context_activator && ) noexcept;
~context_activator() noexcept;
void set_on_deactivate( on_deactivation on_deactivate ) noexcept;
};
} }
template <class Ctx>
context_activator<Ctx> activate_context( Ctx & ctx, on_deactivation on_deactivate ) noexcept;
context_activator<Ctx> activate_context( Ctx & ctx ) noexcept;
#define LEAF_NEW_ERROR(...) ....
#define LEAF_AUTO(v,r) ....
@@ -1936,9 +1929,11 @@ namespace boost { namespace leaf {
~context() noexcept;
void activate() noexcept;
void deactivate( bool propagate_errors ) noexcept;
void deactivate() noexcept;
bool is_active() const noexcept;
void propagate () noexcept;
void print( std::ostream & os ) const;
// Note: <boost/leaf/context.hpp> leaves the rest of the member functions undefined.
@@ -1949,29 +1944,29 @@ namespace boost { namespace leaf {
template <class R, class... H>
typename std::decay<decltype(std::declval<R>().value())>::type
handle_all( R &, H && ... ) const;
handle_all( R &, H && ... );
template <class R, class RemoteH>
typename std::decay<decltype(std::declval<R>().value())>::type
remote_handle_all( R &, RemoteH && ) const;
remote_handle_all( R &, RemoteH && );
template <class R, class... H>
R handle_some( R &&, H && ... ) const;
R handle_some( R &&, H && ... );
template <class R, class RemoteH>
R remote_handle_some( R &&, RemoteH && ) const;
R remote_handle_some( R &&, RemoteH && );
template <class R, class... H>
R handle_current_exception( H && ... ) const;
R handle_current_exception( H && ... );
template <class R, class RemoteH>
R remote_handle_current_exception( RemoteH && ) const;
R remote_handle_current_exception( RemoteH && );
template <class R, class... H>
R handle_exception( std::exception_ptr const &, H && ... ) const;
R handle_exception( std::exception_ptr const &, H && ... );
template <class R, class RemoteH>
R remote_handle_exception( std::exception_ptr const &, RemoteH && ) const;
R remote_handle_exception( std::exception_ptr const &, RemoteH && );
};
@@ -2216,9 +2211,9 @@ TIP: See also <<tutorial-accumulate>> from the Tutorial.
namespace boost { namespace leaf {
template <class Ctx>
context_activator<Ctx> activate_context( Ctx & ctx, on_deactivation on_deactivate ) noexcept
context_activator<Ctx> activate_context( Ctx & ctx ) noexcept
{
return context_activator<Ctx>(ctx, on_deactivate);
return context_activator<Ctx>(ctx);
}
} }
@@ -3043,39 +3038,41 @@ namespace boost { namespace leaf {
context() noexcept;
context( context && x ) noexcept;
~context() noexcept final override;
~context() noexcept;
void activate() noexcept final override;
void deactivate( bool propagate_errors ) noexcept final override;
virtual bool is_active() const noexcept = 0;
void activate() noexcept;
void deactivate() noexcept;
bool is_active() const noexcept = 0;
void print( std::ostream & os ) const final override;
void propagate() noexcept = 0;
void print( std::ostream & os ) const;
template <class R, class... H>
typename std::decay<decltype(std::declval<R>().value())>::type
handle_all( R &, H && ... ) const;
handle_all( R &, H && ... );
template <class R, class RemoteH>
typename std::decay<decltype(std::declval<R>().value())>::type
remote_handle_all( R &, RemoteH && ) const;
remote_handle_all( R &, RemoteH && );
template <class R, class... H>
R handle_some( R &&, H && ... ) const;
R handle_some( R &&, H && ... );
template <class R, class RemoteH>
R remote_handle_some( R &&, RemoteH && ) const;
R remote_handle_some( R &&, RemoteH && );
template <class R, class... H>
R handle_current_exception( H && ... ) const;
R handle_current_exception( H && ... );
template <class R, class RemoteH>
R remote_handle_current_exception( RemoteH && ) const;
R remote_handle_current_exception( RemoteH && );
template <class R, class... H>
R handle_exception( std::exception_ptr const &, H && ... ) const;
R handle_exception( std::exception_ptr const &, H && ... );
template <class R, class RemoteH>
R remote_handle_exception( std::exception_ptr const &, RemoteH && ) const;
R remote_handle_exception( std::exception_ptr const &, RemoteH && );
};
template <class RemoteH>
@@ -3096,7 +3093,7 @@ To be able to load up error objects in a `context` object, it must be activated.
To handle an error, call one of the error handling member functions, which match E-objects currently stored in `*this` to the user-supplied handler functions. See <<context::handle_some>> for a description of the handler matching procedure (this works regardless of whether or not the `context` is currently `active`).
When a `context` is deactivated, it detaches from the calling thread, restoring the thread-local pointers to their pre-`activate` values. Typically, at this point the stored E-objects, if any, are either moved to corresponding storage in other `context` objects active in the calling thread (if available) -- or discarded, depending on the `propagate_errors` argument passed to <<context::activate>>.
When a `context` is deactivated, it detaches from the calling thread, restoring the thread-local pointers to their pre-`activate` values. Typically, at this point the stored E-objects, if any, are either discarded (by default) or moved to corresponding storage in other `context` objects active in the calling thread (if available), by calling <<context::propagate>>.
TIP: `context` objects can be moved, as long as they aren't active. Moving an active `context` results in undefined behavior.
@@ -3162,7 +3159,7 @@ When an E-object is <<tutorial-loading,loaded>>, it is moved in the last activat
namespace boost { namespace leaf {
template <class... E>
void context<E...>::deactivate( bool propagate_errors ) noexcept final override;
void context<E...>::deactivate() noexcept;
} }
----
@@ -3177,11 +3174,6 @@ Ensures: :: * `!<<context::is_active,is_active>>()`.
When a context is deactivated, the thread-local pointers that currently point to each individual E-object storage in it are restored to their original value prior to calling <<context::activate>>.
What happens to the E-objects currently stored in `*this` depends on `propagate_errors`:
* If `propagate_errors` is `false`, any stored E-objects are discarded.
* If `propagate_errors` is `true`, each stored E-object is moved to the storage pointed by the restored corresponding thread-local pointer. If that pointer is `0`, the stored E-object is discarded.
'''
[[context::is_active]]
@@ -3202,6 +3194,29 @@ Returns: :: `true` if the `*this` is active in any thread, `false` otherwise.
'''
[[context::propagate]]
==== `propagate`
.#include <boost/leaf/context.hpp>
[source,c++]
----
namespace boost { namespace leaf {
template <class... E>
void context<E...>::propagate() noexcept;
} }
----
Preconditions: ::
`<<context::is_active,is_active>>()` or `*this` must be the last deactivated `context` object in the calling thread. That is, it is valid to call `propagate` while `is_active()` is true, or immediately after calling `<<context::deactivate,deactivate>>()`.
Effects: ::
Each stored E-object is moved to the storage (within other active `context` objects) pointed by the corresponding thread-local pointer, set when a `context` is activated -- or discarded, if the corresponding thread-local pointer is null.
'''
[[context::handle_all]]
==== `handle_all`
@@ -3213,7 +3228,7 @@ namespace boost { namespace leaf {
template <class... E>
template <class R, class... H>
typename std::decay<decltype(std::declval<R>().value())>::type
context<E...>::handle_all( R && r, H && ... h ) const;
context<E...>::handle_all( R && r, H && ... h );
} }
----
@@ -3251,7 +3266,7 @@ namespace boost { namespace leaf {
template <class... E>
template <class R, class... H>
R context<E...>::handle_current_exception( H && ... h ) const;
R context<E...>::handle_current_exception( H && ... h );
} }
----
@@ -3287,7 +3302,7 @@ namespace boost { namespace leaf {
template <class... E>
template <class R, class... H>
R context<E...>::handle_exception( std::exception_ptr const & ep, H && ... h ) const
R context<E...>::handle_exception( std::exception_ptr const & ep, H && ... h )
{
try
{
@@ -3317,7 +3332,7 @@ namespace boost { namespace leaf {
template <class... E>
template <class R, class... H>
R context<E...>::handle_some( R && r, H && ... h ) const;
R context<E...>::handle_some( R && r, H && ... h );
} }
----
@@ -3613,7 +3628,7 @@ else
namespace boost { namespace leaf {
template <class... E>
void context<E...>::print( std::ostream & os ) const final override;
void context<E...>::print( std::ostream & os ) const;
} }
----
@@ -3633,7 +3648,7 @@ namespace boost { namespace leaf {
template <class... E>
template <class R, class RemoteH>
typename std::decay<decltype(std::declval<R>().value())>::type
context<E...>::remote_handle_all( R & r, RemoteH && h ) const;
context<E...>::remote_handle_all( R & r, RemoteH && h );
} }
----
@@ -3699,7 +3714,7 @@ namespace boost { namespace leaf {
template <class... E>
template <class R, class RemoteH>
R context<E...>::remote_handle_current_exception( RemoteH && h ) const;
R context<E...>::remote_handle_current_exception( RemoteH && h );
} }
----
@@ -3760,7 +3775,7 @@ namespace boost { namespace leaf {
template <class... E>
template <class R, class RemoteH>
R context<E...>::remote_handle_exception( std::exception_ptr const & ep, RemoteH && h ) const;
R context<E...>::remote_handle_exception( std::exception_ptr const & ep, RemoteH && h );
} }
----
@@ -3794,7 +3809,7 @@ namespace boost { namespace leaf {
template <class... E>
template <class R, class RemoteH>
R context<E...>::remote_handle_some( R && r, RemoteH && h ) const;
R context<E...>::remote_handle_some( R && r, RemoteH && h );
} }
----
@@ -3857,13 +3872,6 @@ TIP: Because LEAF does not invoke the user-defined `handle_error` function direc
----
namespace boost { namespace leaf {
enum class on_deactivation
{
propagate,
propagate_if_uncaught_exception,
capture_do_not_propagate
};
template <class Ctx>
class context_activator
{
@@ -3872,11 +3880,9 @@ namespace boost { namespace leaf {
public:
context_activator( Ctx & ctx, on_deactivation on_deactivate ) noexcept;
explicit context_activator( Ctx & ctx ) noexcept;
context_activator( context_activator && ) noexcept;
~context_activator() noexcept;
void set_on_deactivate( on_deactivation on_deactivate ) noexcept;
};
} }
@@ -3884,11 +3890,12 @@ namespace boost { namespace leaf {
`context_activator` is a simple class that activates and deactivates a <<context>> using RAII:
* The constructor stores a reference to `ctx` and calls <<context::activate>>.
* The destructor behavior depends on the `on_deactivation` state:
** `on_deactivation::propagate` instructs `~context_activator` to call <<context::deactivate>> with `true`;
** `on_deactivation::propagate_if_uncaught_exception` instructs `~context_activator` to call `deactivate` with the value returned from `std::uncaught_exception()`;
** `on_deactivation::capture_do_not_propagate` instructs `~context_activator` to call `deactivate` with `false`.
If `<<context::is_active,ctx.is_active>>`() is `true` at the time the `context_activator` is initialized, the constructor and the destructor have no effects. Otherwise:
* The constructor stores a reference to `ctx` and calls `<<context::activate,ctx.activate>>`().
* The destructor:
** If `ctx.is_active()` is false, has no effects (that is, it is valid to call <<context::deactivate>> manually, before the `context_activator` object expires);
** Otherwise, calls `<<context::deactivate,ctx.deactivate>>`() and, if there are new uncaught exceptions since the constructor was called, the destructor calls `<<context::propagate,ctx.propagate>>`().
For automatic deduction of `Ctx`, use <<activate_context>>.
@@ -4412,9 +4419,11 @@ namespace boost { namespace leaf {
public:
virtual void activate() noexcept = 0;
virtual void deactivate( bool propagate_errors ) noexcept = 0;
virtual void deactivate() noexcept = 0;
virtual bool is_active() const noexcept = 0;
virtual void propagate() noexcept = 0;
virtual void print( std::ostream & ) const = 0;
};

View File

@@ -124,7 +124,7 @@ auto async_demo_rpc(AsyncStream &stream, ErrorContext &error_context, Completion
void operator()(error_code ec, std::size_t /*bytes_transferred*/ = 0) {
leaf::result<bool> result_continue_execution;
{
auto active_context = activate_context(m_error_context, leaf::on_deactivation::do_not_propagate);
auto active_context = activate_context(m_error_context);
auto load = leaf::preload(e_last_operation{m_data.response ? "async_demo_rpc::continuation-write"
: "async_demo_rpc::continuation-read"});
if (ec == http::error::end_of_stream) {
@@ -539,7 +539,7 @@ int main(int argc, char **argv) {
async_demo_rpc(socket, error_context, [&](leaf::result<void> result) {
// Note: In case we wanted to add some additional information to the error associated with the result
// we would need to activate the error-context
auto active_context = activate_context(error_context, leaf::on_deactivation::do_not_propagate);
auto active_context = activate_context(error_context);
if (result) {
std::cout << "Server: Client work completed successfully" << std::endl;
rv = 0;

View File

@@ -119,10 +119,10 @@
#if __cplusplus > 201402L
# define LEAF_CONSTEXPR constexpr
# define LEAF_UNCAUGHT_EXCEPTIONS std::uncaught_exceptions
# define LEAF_STD_UNCAUGHT_EXCEPTIONS 1
#else
# define LEAF_CONSTEXPR
# define LEAF_UNCAUGHT_EXCEPTIONS std::uncaught_exception
# define LEAF_STD_UNCAUGHT_EXCEPTIONS 0
#endif
#endif
@@ -1129,20 +1129,22 @@ namespace boost { namespace leaf {
assert(x.top_==0);
}
~slot() noexcept
{
assert(top_==0);
}
LEAF_CONSTEXPR void activate() noexcept
{
assert(top_==0);
assert(top_==0 || *top_!=this);
top_ = &tl_slot_ptr<E>();
prev_ = *top_;
*top_ = this;
}
LEAF_CONSTEXPR void deactivate( bool propagate_errors ) noexcept;
LEAF_CONSTEXPR void deactivate() noexcept
{
assert(top_!=0 && *top_==this);
*top_ = prev_;
}
LEAF_CONSTEXPR void propagate() noexcept;
using impl::put;
using impl::has_value;
@@ -1182,28 +1184,25 @@ namespace boost { namespace leaf {
#endif
template <class E>
LEAF_CONSTEXPR inline void slot<E>::deactivate( bool propagate_errors ) noexcept
LEAF_CONSTEXPR inline void slot<E>::propagate() noexcept
{
assert(top_!=0);
if( propagate_errors )
if( prev_ )
{
impl & this_ = *this;
impl & that_ = *prev_;
that_ = std::move(this_);
}
assert(top_!=0 && (*top_==prev_ || *top_==this));
if( prev_ )
{
impl & this_ = *this;
impl & that_ = *prev_;
that_ = std::move(this_);
}
#if LEAF_DIAGNOSTICS
else
{
int c = tl_unexpected_enabled_counter();
assert(c>=0);
if( c )
if( int err_id = impl::key() )
load_unexpected(err_id, std::move(*this).value(err_id));
}
else
{
int c = tl_unexpected_enabled_counter();
assert(c>=0);
if( c )
if( int err_id = impl::key() )
load_unexpected(err_id, std::move(*this).value(err_id));
}
#endif
*top_ = prev_;
top_ = 0;
}
template <class E>
@@ -1494,7 +1493,8 @@ namespace boost { namespace leaf {
public:
virtual error_id propagate_captured_errors() noexcept = 0;
virtual void activate() noexcept = 0;
virtual void deactivate( bool propagate_errors ) noexcept = 0;
virtual void deactivate() noexcept = 0;
virtual void propagate() noexcept = 0;
virtual bool is_active() const noexcept = 0;
virtual void print( std::ostream & ) const = 0;
error_id captured_id_;
@@ -1504,77 +1504,61 @@ namespace boost { namespace leaf {
////////////////////////////////////////////
enum class on_deactivation
{
propagate,
do_not_propagate,
propagate_if_uncaught_exception
};
template <class Ctx>
class context_activator
{
context_activator( context_activator const & ) = delete;
context_activator & operator=( context_activator const & ) = delete;
#if !defined(LEAF_NO_EXCEPTIONS) && LEAF_STD_UNCAUGHT_EXCEPTIONS
int const uncaught_exceptions_;
#endif
Ctx * ctx_;
bool const ctx_was_active_;
on_deactivation on_deactivate_;
public:
LEAF_CONSTEXPR LEAF_ALWAYS_INLINE context_activator(Ctx & ctx, on_deactivation on_deactivate) noexcept:
ctx_(&ctx),
ctx_was_active_(ctx.is_active()),
on_deactivate_(on_deactivate)
explicit LEAF_CONSTEXPR LEAF_ALWAYS_INLINE context_activator(Ctx & ctx) noexcept:
#if !defined(LEAF_NO_EXCEPTIONS) && LEAF_STD_UNCAUGHT_EXCEPTIONS
uncaught_exceptions_(std::uncaught_exceptions()),
#endif
ctx_(ctx.is_active() ? 0 : &ctx)
{
if( !ctx_was_active_ )
ctx.activate();
if( ctx_ )
ctx_->activate();
}
LEAF_CONSTEXPR LEAF_ALWAYS_INLINE context_activator( context_activator && x ) noexcept:
ctx_(x.ctx_),
ctx_was_active_(x.ctx_was_active_),
on_deactivate_(x.on_deactivate_)
#if !defined(LEAF_NO_EXCEPTIONS) && LEAF_STD_UNCAUGHT_EXCEPTIONS
uncaught_exceptions_(x.uncaught_exceptions_),
#endif
ctx_(x.ctx_)
{
x.ctx_ = 0;
}
LEAF_ALWAYS_INLINE ~context_activator() noexcept
{
if( ctx_ )
{
assert(
on_deactivate_ == on_deactivation::propagate ||
on_deactivate_ == on_deactivation::do_not_propagate ||
on_deactivate_ == on_deactivation::propagate_if_uncaught_exception);
if( !ctx_was_active_ )
if( on_deactivate_ == on_deactivation::propagate_if_uncaught_exception )
{
#ifdef LEAF_NO_EXCEPTIONS
ctx_->deactivate(false);
#else
bool has_exception = LEAF_UNCAUGHT_EXCEPTIONS();
ctx_->deactivate(has_exception);
if( !has_exception )
(void) leaf_detail::new_id();
if( !ctx_ )
return;
if( ctx_->is_active() )
ctx_->deactivate();
#ifndef LEAF_NO_EXCEPTIONS
# if LEAF_STD_UNCAUGHT_EXCEPTIONS
if( std::uncaught_exceptions() > uncaught_exceptions_ )
# else
if( std::uncaught_exception() )
# endif
ctx_->propagate();
else
(void) leaf_detail::new_id();
#endif
}
else
ctx_->deactivate(on_deactivate_ == on_deactivation::propagate);
}
}
LEAF_CONSTEXPR LEAF_ALWAYS_INLINE void set_on_deactivate( on_deactivation on_deactivate ) noexcept
{
on_deactivate_ = on_deactivate;
}
};
template <class Ctx>
LEAF_CONSTEXPR LEAF_ALWAYS_INLINE context_activator<Ctx> activate_context( Ctx & ctx, on_deactivation on_deactivate ) noexcept
LEAF_CONSTEXPR LEAF_ALWAYS_INLINE context_activator<Ctx> activate_context(Ctx & ctx) noexcept
{
return context_activator<Ctx>(ctx, on_deactivate);
return context_activator<Ctx>(ctx);
}
////////////////////////////////////////////
@@ -1660,7 +1644,7 @@ namespace boost { namespace leaf {
{
public:
virtual error_id get_error_id() const = 0;
virtual error_id get_error_id() const noexcept = 0;
protected:
@@ -1674,7 +1658,7 @@ namespace boost { namespace leaf {
public exception_base,
public error_id
{
error_id get_error_id() const final override
error_id get_error_id() const noexcept final override
{
return *this;
}
@@ -1754,7 +1738,11 @@ namespace boost { namespace leaf {
else
{
#ifndef LEAF_NO_EXCEPTIONS
if( LEAF_UNCAUGHT_EXCEPTIONS() )
# if LEAF_STD_UNCAUGHT_EXCEPTIONS
if( std::uncaught_exceptions() )
# else
if( std::uncaught_exception() )
# endif
return leaf_detail::new_id();
#endif
return 0;
@@ -2068,7 +2056,7 @@ namespace boost { namespace leaf {
[[noreturn]] void unload_and_rethrow_original_exception() const
{
assert(ctx_->captured_id_);
auto active_context = activate_context(*ctx_, on_deactivation::propagate);
auto active_context = activate_context(*ctx_);
id_factory<>::current_id = ctx_->captured_id_.value();
std::rethrow_exception(ex_);
}
@@ -2082,7 +2070,7 @@ namespace boost { namespace leaf {
template <class R, class F, class... A>
inline decltype(std::declval<F>()(std::forward<A>(std::declval<A>())...)) capture_impl(is_result_tag<R, false>, context_ptr && ctx, F && f, A... a)
{
auto active_context = activate_context(*ctx, on_deactivation::do_not_propagate);
auto active_context = activate_context(*ctx);
augment_id aug;
try
{
@@ -2107,7 +2095,7 @@ namespace boost { namespace leaf {
template <class R, class F, class... A>
inline decltype(std::declval<F>()(std::forward<A>(std::declval<A>())...)) capture_impl(is_result_tag<R, true>, context_ptr && ctx, F && f, A... a)
{
auto active_context = activate_context(*ctx, on_deactivation::do_not_propagate);
auto active_context = activate_context(*ctx);
augment_id aug;
try
{
@@ -2172,14 +2160,14 @@ namespace boost { namespace leaf {
template <class R, class F, class... A>
inline decltype(std::declval<F>()(std::forward<A>(std::declval<A>())...)) capture_impl(is_result_tag<R, false>, context_ptr && ctx, F && f, A... a) noexcept
{
auto active_context = activate_context(*ctx, on_deactivation::do_not_propagate);
auto active_context = activate_context(*ctx);
return std::forward<F>(f)(std::forward<A>(a)...);
}
template <class R, class F, class... A>
inline decltype(std::declval<F>()(std::forward<A>(std::declval<A>())...)) capture_impl(is_result_tag<R, true>, context_ptr && ctx, F && f, A... a) noexcept
{
auto active_context = activate_context(*ctx, on_deactivation::do_not_propagate);
auto active_context = activate_context(*ctx);
if( auto r = std::forward<F>(f)(std::forward<A>(a)...) )
return r;
else
@@ -2398,18 +2386,25 @@ namespace boost { namespace leaf {
std::get<I-1>(tup).activate();
}
LEAF_CONSTEXPR static void deactivate( Tuple & tup, bool propagate_errors ) noexcept
LEAF_CONSTEXPR static void deactivate( Tuple & tup ) noexcept
{
std::get<I-1>(tup).deactivate(propagate_errors);
tuple_for_each<I-1,Tuple>::deactivate(tup, propagate_errors);
std::get<I-1>(tup).deactivate();
tuple_for_each<I-1,Tuple>::deactivate(tup);
}
LEAF_CONSTEXPR static void propagate( Tuple & tup, int err_id ) noexcept
LEAF_CONSTEXPR static void propagate( Tuple & tup ) noexcept
{
auto & sl = std::get<I-1>(tup);
sl.propagate();
tuple_for_each<I-1,Tuple>::propagate(tup);
}
LEAF_CONSTEXPR static void propagate_captured( Tuple & tup, int err_id ) noexcept
{
auto & sl = std::get<I-1>(tup);
if( sl.has_value(err_id) )
leaf_detail::load_slot(err_id, std::move(sl).value(err_id));
tuple_for_each<I-1,Tuple>::propagate(tup, err_id);
tuple_for_each<I-1,Tuple>::propagate_captured(tup, err_id);
}
static void print( std::ostream & os, void const * tup, int key_to_print )
@@ -2424,8 +2419,9 @@ namespace boost { namespace leaf {
struct tuple_for_each<0, Tuple>
{
LEAF_CONSTEXPR static void activate( Tuple & ) noexcept { }
LEAF_CONSTEXPR static void deactivate( Tuple &, bool ) noexcept { }
LEAF_CONSTEXPR static void propagate( Tuple & tup, int ) noexcept { }
LEAF_CONSTEXPR static void deactivate( Tuple & ) noexcept { }
LEAF_CONSTEXPR static void propagate( Tuple & tup ) noexcept { }
LEAF_CONSTEXPR static void propagate_captured( Tuple & tup, int ) noexcept { }
static void print( std::ostream &, void const *, int ) { }
};
}
@@ -2606,7 +2602,7 @@ namespace boost { namespace leaf {
is_active_ = true;
}
LEAF_CONSTEXPR void deactivate( bool propagate_errors ) noexcept
LEAF_CONSTEXPR void deactivate() noexcept
{
using namespace leaf_detail;
assert(is_active());
@@ -2619,7 +2615,12 @@ namespace boost { namespace leaf {
if( unexpected_requested<Tup>::value )
--tl_unexpected_enabled_counter();
#endif
tuple_for_each<std::tuple_size<Tup>::value,Tup>::deactivate(tup_, propagate_errors);
tuple_for_each<std::tuple_size<Tup>::value,Tup>::deactivate(tup_);
}
LEAF_CONSTEXPR void propagate() noexcept
{
tuple_for_each<std::tuple_size<Tup>::value,Tup>::propagate(tup_);
}
LEAF_CONSTEXPR bool is_active() const noexcept
@@ -2632,57 +2633,69 @@ namespace boost { namespace leaf {
leaf_detail::tuple_for_each<std::tuple_size<Tup>::value,Tup>::print(os, &tup_, 0);
}
template <class R, class... H>
LEAF_CONSTEXPR typename std::decay<decltype(std::declval<R>().value())>::type handle_all_( R &, H && ... );
template <class R, class RemoteH>
LEAF_CONSTEXPR typename std::decay<decltype(std::declval<R>().value())>::type remote_handle_all_( R &, RemoteH && );
template <class R, class... H>
LEAF_CONSTEXPR R handle_some_( R &&, H && ... );
template <class R, class RemoteH>
LEAF_CONSTEXPR R remote_handle_some_( R &&, RemoteH && );
template <class TryBlock, class... H>
decltype(std::declval<TryBlock>()()) try_catch_( TryBlock &&, H && ... );
template <class TryBlock, class RemoteH>
decltype(std::declval<TryBlock>()()) remote_try_catch_( TryBlock &&, RemoteH && );
template <class R, class... H>
LEAF_CONSTEXPR R handle_current_exception_( H && ... );
template <class R, class RemoteH>
LEAF_CONSTEXPR R remote_handle_current_exception_( RemoteH && );
template <class R, class... H>
LEAF_CONSTEXPR R handle_exception_( std::exception_ptr const &, H && ... );
template <class R, class RemoteH>
LEAF_CONSTEXPR R remote_handle_exception_( std::exception_ptr const &, RemoteH && );
protected:
LEAF_CONSTEXPR error_id propagate_captured_errors( error_id err_id ) noexcept
{
tuple_for_each<std::tuple_size<Tup>::value,Tup>::propagate(tup_, err_id.value());
tuple_for_each<std::tuple_size<Tup>::value,Tup>::propagate_captured(tup_, err_id.value());
return err_id;
}
template <class TryBlock, class... H>
LEAF_CONSTEXPR typename std::decay<decltype(std::declval<TryBlock>()().value())>::type try_handle_all_( TryBlock &&, H && ... ) const;
template <class TryBlock, class RemoteH>
LEAF_CONSTEXPR typename std::decay<decltype(std::declval<TryBlock>()().value())>::type remote_try_handle_all_( TryBlock &&, RemoteH && ) const;
template <class TryBlock, class... H, class Ctx>
LEAF_CONSTEXPR typename std::decay<decltype(std::declval<TryBlock>()())>::type try_handle_some_( context_activator<Ctx> &, TryBlock &&, H && ... ) const;
template <class TryBlock, class RemoteH, class Ctx>
LEAF_CONSTEXPR typename std::decay<decltype(std::declval<TryBlock>()())>::type remote_try_handle_some_( context_activator<Ctx> &, TryBlock &&, RemoteH && ) const;
public:
template <class R, class... H>
LEAF_CONSTEXPR typename std::decay<decltype(std::declval<R>().value())>::type handle_all( R &, H && ... ) const;
LEAF_CONSTEXPR typename std::decay<decltype(std::declval<R>().value())>::type handle_all( R &, H && ... );
template <class R, class RemoteH>
LEAF_CONSTEXPR typename std::decay<decltype(std::declval<R>().value())>::type remote_handle_all( R &, RemoteH && ) const;
LEAF_CONSTEXPR typename std::decay<decltype(std::declval<R>().value())>::type remote_handle_all( R &, RemoteH && );
template <class R, class... H>
LEAF_CONSTEXPR R handle_some( R &&, H && ... ) const;
LEAF_CONSTEXPR R handle_some( R &&, H && ... );
template <class R, class RemoteH>
LEAF_CONSTEXPR R remote_handle_some( R &&, RemoteH && ) const;
template <class TryBlock, class... H>
decltype(std::declval<TryBlock>()()) try_catch_( TryBlock &&, H && ... ) const;
template <class TryBlock, class RemoteH>
decltype(std::declval<TryBlock>()()) remote_try_catch_( TryBlock &&, RemoteH && ) const;
LEAF_CONSTEXPR R remote_handle_some( R &&, RemoteH && );
template <class R, class... H>
LEAF_CONSTEXPR R handle_current_exception( H && ... ) const;
LEAF_CONSTEXPR R handle_current_exception( H && ... );
template <class R, class RemoteH>
LEAF_CONSTEXPR R remote_handle_current_exception( RemoteH && ) const;
LEAF_CONSTEXPR R remote_handle_current_exception( RemoteH && );
template <class R, class... H>
LEAF_CONSTEXPR R handle_exception( std::exception_ptr const &, H && ... ) const;
LEAF_CONSTEXPR R handle_exception( std::exception_ptr const &, H && ... );
template <class R, class RemoteH>
LEAF_CONSTEXPR R remote_handle_exception( std::exception_ptr const &, RemoteH && ) const;
LEAF_CONSTEXPR R remote_handle_exception( std::exception_ptr const &, RemoteH && );
};
template <class... E>
@@ -2813,7 +2826,8 @@ namespace boost { namespace leaf {
{
error_id propagate_captured_errors() noexcept final override { return Ctx::propagate_captured_errors(captured_id_); }
void activate() noexcept final override { Ctx::activate(); }
void deactivate( bool propagate_errors ) noexcept final override { Ctx::deactivate(propagate_errors); }
void deactivate() noexcept final override { Ctx::deactivate(); }
void propagate() noexcept final override { Ctx::propagate(); }
bool is_active() const noexcept final override { return Ctx::is_active(); }
void print( std::ostream & os ) const final override { return Ctx::print(os); }
};
@@ -3574,102 +3588,80 @@ namespace boost { namespace leaf {
{
template <class... E>
template <class R, class... H>
LEAF_CONSTEXPR inline typename std::decay<decltype(std::declval<R>().value())>::type context_base<E...>::handle_all( R & r, H && ... h ) const
LEAF_CONSTEXPR inline typename std::decay<decltype(std::declval<R>().value())>::type context_base<E...>::handle_all_( R & r, H && ... h )
{
using namespace leaf_detail;
using Ret = typename std::decay<decltype(std::declval<R>().value())>::type;
static_assert(is_result_type<R>::value, "The R type used with a handle_all function must be registered with leaf::is_result_type");
return handle_error_<Ret>(tup(), error_info(r.error()), std::forward<H>(h)...);
assert(is_active());
error_info const ei(r.error());
deactivate();
return handle_error_<Ret>(tup(), ei, std::forward<H>(h)...);
}
template <class... E>
template <class R, class RemoteH>
LEAF_CONSTEXPR inline typename std::decay<decltype(std::declval<R>().value())>::type context_base<E...>::remote_handle_all( R & r, RemoteH && h ) const
LEAF_CONSTEXPR inline typename std::decay<decltype(std::declval<R>().value())>::type context_base<E...>::remote_handle_all_( R & r, RemoteH && h )
{
static_assert(is_result_type<R>::value, "The R type used with a handle_all function must be registered with leaf::is_result_type");
return std::forward<RemoteH>(h)(error_info(r.error(), this)).get();
assert(is_active());
error_info const ei(r.error(), this);
deactivate();
return std::forward<RemoteH>(h)(ei).get();
}
template <class... E>
template <class R, class... H>
LEAF_CONSTEXPR inline R context_base<E...>::handle_some( R && r, H && ... h ) const
LEAF_CONSTEXPR inline R context_base<E...>::handle_some_( R && r, H && ... h )
{
using namespace leaf_detail;
static_assert(is_result_type<R>::value, "The R type used with a handle_some function must be registered with leaf::is_result_type");
return handle_error_<R>(tup(), error_info(r.error()), std::forward<H>(h)...,
assert(is_active());
error_info const ei(r.error());
deactivate();
return handle_error_<R>(tup(), ei, std::forward<H>(h)...,
[&r]()->R { return std::move(r); });
}
template <class... E>
template <class R, class RemoteH>
LEAF_CONSTEXPR inline R context_base<E...>::remote_handle_some( R && r, RemoteH && h ) const
LEAF_CONSTEXPR inline R context_base<E...>::remote_handle_some_( R && r, RemoteH && h )
{
static_assert(is_result_type<R>::value, "The R type used with a handle_some function must be registered with leaf::is_result_type");
return std::forward<RemoteH>(h)(error_info(r.error(), this)).get();
}
////////////////////////////////////////////
template <class... E>
template <class TryBlock, class... H>
LEAF_CONSTEXPR inline typename std::decay<decltype(std::declval<TryBlock>()().value())>::type context_base<E...>::try_handle_all_( TryBlock && try_block, H && ... h ) const
{
using namespace leaf_detail;
static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a try_handle_all function must be registered with leaf::is_result_type");
assert(this->is_active());
if( auto r = std::forward<TryBlock>(try_block)() )
return r.value();
else
return handle_all(r, std::forward<H>(h)...);
assert(is_active());
error_info const ei(r.error(), this);
deactivate();
return std::forward<RemoteH>(h)(ei).get();
}
template <class... E>
template <class TryBlock, class RemoteH>
LEAF_CONSTEXPR inline typename std::decay<decltype(std::declval<TryBlock>()().value())>::type context_base<E...>::remote_try_handle_all_( TryBlock && try_block, RemoteH && h ) const
template <class R, class... H>
LEAF_CONSTEXPR inline typename std::decay<decltype(std::declval<R>().value())>::type context_base<E...>::handle_all( R & r, H && ... h )
{
using namespace leaf_detail;
static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a remote_try_handle_all function must be registered with leaf::is_result_type");
assert(this->is_active());
if( auto r = std::forward<TryBlock>(try_block)() )
return r.value();
else
return remote_handle_all(r, std::forward<RemoteH>(h));
auto active_context = activate_context(*this);
return handle_all_(r, std::forward<H>(h)...);
}
template <class... E>
template <class TryBlock, class... H, class Ctx>
LEAF_CONSTEXPR inline typename std::decay<decltype(std::declval<TryBlock>()())>::type context_base<E...>::try_handle_some_( context_activator<Ctx> & active_context, TryBlock && try_block, H && ... h ) const
template <class R, class RemoteH>
LEAF_CONSTEXPR inline typename std::decay<decltype(std::declval<R>().value())>::type context_base<E...>::remote_handle_all( R & r, RemoteH && h )
{
using namespace leaf_detail;
static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a try_handle_some function must be registered with leaf::is_result_type");
assert(this->is_active());
if( auto r = std::forward<TryBlock>(try_block)() )
return r;
else
{
auto rr = handle_some(std::move(r), std::forward<H>(h)...);
if( !rr )
active_context.set_on_deactivate(on_deactivation::propagate);
return rr;
}
auto active_context = activate_context(*this);
return remote_handle_all_(r, std::forward<RemoteH>(h));
}
template <class... E>
template <class TryBlock, class RemoteH, class Ctx>
LEAF_CONSTEXPR inline typename std::decay<decltype(std::declval<TryBlock>()())>::type context_base<E...>::remote_try_handle_some_( context_activator<Ctx> & active_context, TryBlock && try_block, RemoteH && h ) const
template <class R, class... H>
LEAF_CONSTEXPR inline R context_base<E...>::handle_some( R && r, H && ... h )
{
using namespace leaf_detail;
static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a remote_try_handle_some function must be registered with leaf::is_result_type");
assert(this->is_active());
if( auto r = std::forward<TryBlock>(try_block)() )
return r;
else
{
auto rr = remote_handle_some(std::move(r), std::forward<RemoteH>(h));
if( !rr )
active_context.set_on_deactivate(on_deactivation::propagate);
return rr;
}
auto active_context = activate_context(*this);
return handle_some_(std::forward<R>(r), std::forward<H>(h)...);
}
template <class... E>
template <class R, class RemoteH>
LEAF_CONSTEXPR inline R context_base<E...>::remote_handle_some( R && r, RemoteH && h )
{
auto active_context = activate_context(*this);
return remote_handle_some_(std::forward<R>(r), std::forward<RemoteH>(h));
}
}
@@ -3780,32 +3772,62 @@ namespace boost { namespace leaf {
template <class TryBlock, class... H>
LEAF_CONSTEXPR LEAF_ALWAYS_INLINE typename std::decay<decltype(std::declval<TryBlock>()().value())>::type nocatch_context<E...>::try_handle_all( TryBlock && try_block, H && ... h )
{
auto active_context = activate_context(*this, on_deactivation::do_not_propagate);
return this->try_handle_all_( std::forward<TryBlock>(try_block), std::forward<H>(h)... );
using namespace leaf_detail;
static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a try_handle_all function must be registered with leaf::is_result_type");
auto active_context = activate_context(*this);
if( auto r = std::forward<TryBlock>(try_block)() )
return r.value();
else
return this->handle_all_(r, std::forward<H>(h)...);
}
template <class... E>
template <class TryBlock, class RemoteH>
LEAF_CONSTEXPR LEAF_ALWAYS_INLINE typename std::decay<decltype(std::declval<TryBlock>()().value())>::type nocatch_context<E...>::remote_try_handle_all( TryBlock && try_block, RemoteH && h )
{
auto active_context = activate_context(*this, on_deactivation::do_not_propagate);
return this->remote_try_handle_all_( std::forward<TryBlock>(try_block), std::forward<RemoteH>(h) );
using namespace leaf_detail;
static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a remote_try_handle_all function must be registered with leaf::is_result_type");
auto active_context = activate_context(*this);
if( auto r = std::forward<TryBlock>(try_block)() )
return r.value();
else
return this->remote_handle_all_(r, std::forward<RemoteH>(h));
}
template <class... E>
template <class TryBlock, class... H>
LEAF_CONSTEXPR LEAF_ALWAYS_INLINE typename std::decay<decltype(std::declval<TryBlock>()())>::type nocatch_context<E...>::try_handle_some( TryBlock && try_block, H && ... h )
{
auto active_context = activate_context(*this, on_deactivation::propagate_if_uncaught_exception);
return this->try_handle_some_( active_context, std::forward<TryBlock>(try_block), std::forward<H>(h)... );
using namespace leaf_detail;
static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a try_handle_some function must be registered with leaf::is_result_type");
auto active_context = activate_context(*this);
if( auto r = std::forward<TryBlock>(try_block)() )
return r;
else
{
auto rr = this->handle_some_(std::move(r), std::forward<H>(h)...);
if( !rr )
this->propagate();
return rr;
}
}
template <class... E>
template <class TryBlock, class RemoteH>
LEAF_CONSTEXPR LEAF_ALWAYS_INLINE typename std::decay<decltype(std::declval<TryBlock>()())>::type nocatch_context<E...>::remote_try_handle_some( TryBlock && try_block, RemoteH && h )
{
auto active_context = activate_context(*this, on_deactivation::propagate_if_uncaught_exception);
return this->remote_try_handle_some_( active_context, std::forward<TryBlock>(try_block), std::forward<RemoteH>(h) );
using namespace leaf_detail;
static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a remote_try_handle_some function must be registered with leaf::is_result_type");
auto active_context = activate_context(*this);
if( auto r = std::forward<TryBlock>(try_block)() )
return r;
else
{
auto rr = remote_handle_some_(std::move(r), std::forward<RemoteH>(h));
if( !rr )
this->propagate();
return rr;
}
}
}
@@ -4059,49 +4081,23 @@ namespace boost { namespace leaf {
////////////////////////////////////////
template <class TryBlock, class... H>
LEAF_CONSTEXPR inline decltype(std::declval<TryBlock>()()) try_catch( TryBlock && try_block, H && ... h )
{
using namespace leaf_detail;
context_type_from_handlers<H...> ctx;
auto active_context = activate_context(ctx, on_deactivation::propagate_if_uncaught_exception);
return ctx.try_catch_(
[&]
{
return std::forward<TryBlock>(try_block)();
},
std::forward<H>(h)...);
}
template <class TryBlock, class RemoteH>
LEAF_CONSTEXPR inline decltype(std::declval<TryBlock>()()) remote_try_catch( TryBlock && try_block, RemoteH && h )
{
using namespace leaf_detail;
context_type_from_remote_handler<RemoteH> ctx;
auto active_context = activate_context(ctx, on_deactivation::propagate_if_uncaught_exception);
return ctx.remote_try_catch_(
[&]
{
return std::forward<TryBlock>(try_block)();
},
std::forward<RemoteH>(h));
}
namespace leaf_detail
{
template <class... E>
template <class R, class... H>
LEAF_CONSTEXPR inline R context_base<E...>::handle_current_exception( H && ... h ) const
LEAF_CONSTEXPR inline R context_base<E...>::handle_current_exception_( H && ... h )
{
assert(is_active());
return this->try_catch_(
[]{ throw; },
[]() -> R { throw; },
std::forward<H>(h)...);
}
template <class... E>
template <class R, class RemoteH>
LEAF_CONSTEXPR inline R context_base<E...>::remote_handle_current_exception( RemoteH && h ) const
LEAF_CONSTEXPR inline R context_base<E...>::remote_handle_current_exception_( RemoteH && h )
{
assert(is_active());
return this->remote_try_catch_(
[]() -> R { throw; },
std::forward<RemoteH>(h));
@@ -4109,22 +4105,56 @@ namespace boost { namespace leaf {
template <class... E>
template <class R, class... H>
LEAF_CONSTEXPR inline R context_base<E...>::handle_exception( std::exception_ptr const & ep, H && ... h ) const
LEAF_CONSTEXPR inline R context_base<E...>::handle_exception_( std::exception_ptr const & ep, H && ... h )
{
assert(is_active());
return this->try_catch_(
[&]{ std::rethrow_exception(ep); },
[&]() -> R { std::rethrow_exception(ep); },
std::forward<H>(h)...);
}
template <class... E>
template <class R, class RemoteH>
LEAF_CONSTEXPR inline R context_base<E...>::remote_handle_exception( std::exception_ptr const & ep, RemoteH && h ) const
LEAF_CONSTEXPR inline R context_base<E...>::remote_handle_exception_( std::exception_ptr const & ep, RemoteH && h )
{
assert(is_active());
return this->remote_try_catch_(
[&]() -> R { std::rethrow_exception(ep); },
std::forward<RemoteH>(h));
}
template <class... E>
template <class R, class... H>
LEAF_CONSTEXPR inline R context_base<E...>::handle_current_exception( H && ... h )
{
auto active_context = activate_context(*this);
return handle_current_exception_<R>(std::forward<H>(h)...);
}
template <class... E>
template <class R, class RemoteH>
LEAF_CONSTEXPR inline R context_base<E...>::remote_handle_current_exception( RemoteH && h )
{
auto active_context = activate_context(*this);
return remote_handle_current_exception_<R>(std::forward<RemoteH>(h));
}
template <class... E>
template <class R, class... H>
LEAF_CONSTEXPR inline R context_base<E...>::handle_exception( std::exception_ptr const & ep, H && ... h )
{
auto active_context = activate_context(*this);
return handle_exception_<R>(ep, std::forward<H>(h)...);
}
template <class... E>
template <class R, class RemoteH>
LEAF_CONSTEXPR inline R context_base<E...>::remote_handle_exception( std::exception_ptr const & ep, RemoteH && h )
{
auto active_context = activate_context(*this);
return remote_handle_exception_<R>(ep, std::forward<RemoteH>(h));
}
////////////////////////////////////////
template <class... E>
@@ -4133,7 +4163,7 @@ namespace boost { namespace leaf {
{
using namespace leaf_detail;
static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a try_handle_all function must be registered with leaf::is_result_type");
auto active_context = activate_context(*this, on_deactivation::propagate_if_uncaught_exception);
auto active_context = activate_context(*this);
if( auto r = this->try_catch_(
[&]
{
@@ -4151,7 +4181,7 @@ namespace boost { namespace leaf {
{
using namespace leaf_detail;
static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a try_handle_all function must be registered with leaf::is_result_type");
auto active_context = activate_context(*this, on_deactivation::propagate_if_uncaught_exception);
auto active_context = activate_context(*this);
if( auto r = this->remote_try_catch_(
[&]
{
@@ -4169,7 +4199,7 @@ namespace boost { namespace leaf {
{
using namespace leaf_detail;
static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a try_handle_some function must be registered with leaf::is_result_type");
auto active_context = activate_context(*this, on_deactivation::propagate_if_uncaught_exception);
auto active_context = activate_context(*this);
if( auto r = this->try_catch_(
[&]
{
@@ -4181,7 +4211,7 @@ namespace boost { namespace leaf {
{
auto rr = this->handle_some(std::move(r), std::forward<H>(h)...);
if( !rr )
active_context.set_on_deactivate(on_deactivation::propagate);
this->propagate();
return rr;
}
}
@@ -4190,7 +4220,9 @@ namespace boost { namespace leaf {
template <class TryBlock, class RemoteH>
LEAF_CONSTEXPR inline typename std::decay<decltype(std::declval<TryBlock>()())>::type catch_context<E...>::remote_try_handle_some( TryBlock && try_block, RemoteH && h )
{
auto active_context = activate_context(*this, on_deactivation::propagate_if_uncaught_exception);
using namespace leaf_detail;
static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a remote_try_handle_some function must be registered with leaf::is_result_type");
auto active_context = activate_context(*this);
if( auto r = this->remote_try_catch_(
[&]
{
@@ -4202,7 +4234,7 @@ namespace boost { namespace leaf {
{
auto rr = this->remote_handle_some(std::move(r), std::forward<RemoteH>(h));
if( !rr )
active_context.set_on_deactivate(on_deactivation::propagate);
this->propagate();
return rr;
}
}
@@ -4228,9 +4260,10 @@ namespace boost { namespace leaf {
template <class... E>
template <class TryBlock, class... H>
inline decltype(std::declval<TryBlock>()()) context_base<E...>::try_catch_( TryBlock && try_block, H && ... h ) const
inline decltype(std::declval<TryBlock>()()) context_base<E...>::try_catch_( TryBlock && try_block, H && ... h )
{
using namespace leaf_detail;
assert(is_active());
using R = decltype(std::declval<TryBlock>()());
try
{
@@ -4244,22 +4277,26 @@ namespace boost { namespace leaf {
}
catch( std::exception const & ex )
{
deactivate();
return leaf_detail::handle_error_<R>(this->tup(), error_info(exception_info_(&ex)), std::forward<H>(h)...,
[]() -> R { throw; } );
}
catch(...)
{
deactivate();
return leaf_detail::handle_error_<R>(this->tup(), error_info(exception_info_(0)), std::forward<H>(h)...,
[]() -> R { throw; } );
}
}
catch( std::exception const & ex )
{
deactivate();
return leaf_detail::handle_error_<R>(this->tup(), error_info(exception_info_(&ex)), std::forward<H>(h)...,
[]() -> R { throw; } );
}
catch(...)
{
deactivate();
return leaf_detail::handle_error_<R>(this->tup(), error_info(exception_info_(0)), std::forward<H>(h)...,
[]() -> R { throw; } );
}
@@ -4267,9 +4304,10 @@ namespace boost { namespace leaf {
template <class... E>
template <class TryBlock, class RemoteH>
inline decltype(std::declval<TryBlock>()()) context_base<E...>::remote_try_catch_( TryBlock && try_block, RemoteH && h ) const
inline decltype(std::declval<TryBlock>()()) context_base<E...>::remote_try_catch_( TryBlock && try_block, RemoteH && h )
{
using namespace leaf_detail;
assert(is_active());
try
{
return std::forward<TryBlock>(try_block)();
@@ -4282,19 +4320,23 @@ namespace boost { namespace leaf {
}
catch( std::exception const & ex )
{
deactivate();
return std::forward<RemoteH>(h)(error_info(exception_info_(&ex), this)).get();
}
catch(...)
{
deactivate();
return std::forward<RemoteH>(h)(error_info(exception_info_(0), this)).get();
}
}
catch( std::exception const & ex )
{
deactivate();
return std::forward<RemoteH>(h)(error_info(exception_info_(&ex), this)).get();
}
catch(...)
{
deactivate();
return std::forward<RemoteH>(h)(error_info(exception_info_(0), this)).get();
}
}
@@ -4376,6 +4418,36 @@ namespace boost { namespace leaf {
{
}
////////////////////////////////////////
template <class TryBlock, class... H>
LEAF_CONSTEXPR inline decltype(std::declval<TryBlock>()()) try_catch( TryBlock && try_block, H && ... h )
{
using namespace leaf_detail;
context_type_from_handlers<H...> ctx;
auto active_context = activate_context(ctx);
return ctx.try_catch_(
[&]
{
return std::forward<TryBlock>(try_block)();
},
std::forward<H>(h)...);
}
template <class TryBlock, class RemoteH>
LEAF_CONSTEXPR inline decltype(std::declval<TryBlock>()()) remote_try_catch( TryBlock && try_block, RemoteH && h )
{
using namespace leaf_detail;
context_type_from_remote_handler<RemoteH> ctx;
auto active_context = activate_context(ctx);
return ctx.remote_try_catch_(
[&]
{
return std::forward<TryBlock>(try_block)();
},
std::forward<RemoteH>(h));
}
} }
#endif

View File

@@ -36,7 +36,7 @@ namespace boost { namespace leaf {
[[noreturn]] void unload_and_rethrow_original_exception() const
{
assert(ctx_->captured_id_);
auto active_context = activate_context(*ctx_, on_deactivation::propagate);
auto active_context = activate_context(*ctx_);
id_factory<>::current_id = ctx_->captured_id_.value();
std::rethrow_exception(ex_);
}
@@ -50,7 +50,7 @@ namespace boost { namespace leaf {
template <class R, class F, class... A>
inline decltype(std::declval<F>()(std::forward<A>(std::declval<A>())...)) capture_impl(is_result_tag<R, false>, context_ptr && ctx, F && f, A... a)
{
auto active_context = activate_context(*ctx, on_deactivation::do_not_propagate);
auto active_context = activate_context(*ctx);
augment_id aug;
try
{
@@ -75,7 +75,7 @@ namespace boost { namespace leaf {
template <class R, class F, class... A>
inline decltype(std::declval<F>()(std::forward<A>(std::declval<A>())...)) capture_impl(is_result_tag<R, true>, context_ptr && ctx, F && f, A... a)
{
auto active_context = activate_context(*ctx, on_deactivation::do_not_propagate);
auto active_context = activate_context(*ctx);
augment_id aug;
try
{
@@ -140,14 +140,14 @@ namespace boost { namespace leaf {
template <class R, class F, class... A>
inline decltype(std::declval<F>()(std::forward<A>(std::declval<A>())...)) capture_impl(is_result_tag<R, false>, context_ptr && ctx, F && f, A... a) noexcept
{
auto active_context = activate_context(*ctx, on_deactivation::do_not_propagate);
auto active_context = activate_context(*ctx);
return std::forward<F>(f)(std::forward<A>(a)...);
}
template <class R, class F, class... A>
inline decltype(std::declval<F>()(std::forward<A>(std::declval<A>())...)) capture_impl(is_result_tag<R, true>, context_ptr && ctx, F && f, A... a) noexcept
{
auto active_context = activate_context(*ctx, on_deactivation::do_not_propagate);
auto active_context = activate_context(*ctx);
if( auto r = std::forward<F>(f)(std::forward<A>(a)...) )
return r;
else

View File

@@ -109,10 +109,10 @@
#if __cplusplus > 201402L
# define LEAF_CONSTEXPR constexpr
# define LEAF_UNCAUGHT_EXCEPTIONS std::uncaught_exceptions
# define LEAF_STD_UNCAUGHT_EXCEPTIONS 1
#else
# define LEAF_CONSTEXPR
# define LEAF_UNCAUGHT_EXCEPTIONS std::uncaught_exception
# define LEAF_STD_UNCAUGHT_EXCEPTIONS 0
#endif
#endif

View File

@@ -21,18 +21,25 @@ namespace boost { namespace leaf {
std::get<I-1>(tup).activate();
}
LEAF_CONSTEXPR static void deactivate( Tuple & tup, bool propagate_errors ) noexcept
LEAF_CONSTEXPR static void deactivate( Tuple & tup ) noexcept
{
std::get<I-1>(tup).deactivate(propagate_errors);
tuple_for_each<I-1,Tuple>::deactivate(tup, propagate_errors);
std::get<I-1>(tup).deactivate();
tuple_for_each<I-1,Tuple>::deactivate(tup);
}
LEAF_CONSTEXPR static void propagate( Tuple & tup, int err_id ) noexcept
LEAF_CONSTEXPR static void propagate( Tuple & tup ) noexcept
{
auto & sl = std::get<I-1>(tup);
sl.propagate();
tuple_for_each<I-1,Tuple>::propagate(tup);
}
LEAF_CONSTEXPR static void propagate_captured( Tuple & tup, int err_id ) noexcept
{
auto & sl = std::get<I-1>(tup);
if( sl.has_value(err_id) )
leaf_detail::load_slot(err_id, std::move(sl).value(err_id));
tuple_for_each<I-1,Tuple>::propagate(tup, err_id);
tuple_for_each<I-1,Tuple>::propagate_captured(tup, err_id);
}
static void print( std::ostream & os, void const * tup, int key_to_print )
@@ -47,8 +54,9 @@ namespace boost { namespace leaf {
struct tuple_for_each<0, Tuple>
{
LEAF_CONSTEXPR static void activate( Tuple & ) noexcept { }
LEAF_CONSTEXPR static void deactivate( Tuple &, bool ) noexcept { }
LEAF_CONSTEXPR static void propagate( Tuple & tup, int ) noexcept { }
LEAF_CONSTEXPR static void deactivate( Tuple & ) noexcept { }
LEAF_CONSTEXPR static void propagate( Tuple & tup ) noexcept { }
LEAF_CONSTEXPR static void propagate_captured( Tuple & tup, int ) noexcept { }
static void print( std::ostream &, void const *, int ) { }
};
}
@@ -229,7 +237,7 @@ namespace boost { namespace leaf {
is_active_ = true;
}
LEAF_CONSTEXPR void deactivate( bool propagate_errors ) noexcept
LEAF_CONSTEXPR void deactivate() noexcept
{
using namespace leaf_detail;
assert(is_active());
@@ -242,7 +250,12 @@ namespace boost { namespace leaf {
if( unexpected_requested<Tup>::value )
--tl_unexpected_enabled_counter();
#endif
tuple_for_each<std::tuple_size<Tup>::value,Tup>::deactivate(tup_, propagate_errors);
tuple_for_each<std::tuple_size<Tup>::value,Tup>::deactivate(tup_);
}
LEAF_CONSTEXPR void propagate() noexcept
{
tuple_for_each<std::tuple_size<Tup>::value,Tup>::propagate(tup_);
}
LEAF_CONSTEXPR bool is_active() const noexcept
@@ -255,57 +268,69 @@ namespace boost { namespace leaf {
leaf_detail::tuple_for_each<std::tuple_size<Tup>::value,Tup>::print(os, &tup_, 0);
}
template <class R, class... H>
LEAF_CONSTEXPR typename std::decay<decltype(std::declval<R>().value())>::type handle_all_( R &, H && ... );
template <class R, class RemoteH>
LEAF_CONSTEXPR typename std::decay<decltype(std::declval<R>().value())>::type remote_handle_all_( R &, RemoteH && );
template <class R, class... H>
LEAF_CONSTEXPR R handle_some_( R &&, H && ... );
template <class R, class RemoteH>
LEAF_CONSTEXPR R remote_handle_some_( R &&, RemoteH && );
template <class TryBlock, class... H>
decltype(std::declval<TryBlock>()()) try_catch_( TryBlock &&, H && ... );
template <class TryBlock, class RemoteH>
decltype(std::declval<TryBlock>()()) remote_try_catch_( TryBlock &&, RemoteH && );
template <class R, class... H>
LEAF_CONSTEXPR R handle_current_exception_( H && ... );
template <class R, class RemoteH>
LEAF_CONSTEXPR R remote_handle_current_exception_( RemoteH && );
template <class R, class... H>
LEAF_CONSTEXPR R handle_exception_( std::exception_ptr const &, H && ... );
template <class R, class RemoteH>
LEAF_CONSTEXPR R remote_handle_exception_( std::exception_ptr const &, RemoteH && );
protected:
LEAF_CONSTEXPR error_id propagate_captured_errors( error_id err_id ) noexcept
{
tuple_for_each<std::tuple_size<Tup>::value,Tup>::propagate(tup_, err_id.value());
tuple_for_each<std::tuple_size<Tup>::value,Tup>::propagate_captured(tup_, err_id.value());
return err_id;
}
template <class TryBlock, class... H>
LEAF_CONSTEXPR typename std::decay<decltype(std::declval<TryBlock>()().value())>::type try_handle_all_( TryBlock &&, H && ... ) const;
template <class TryBlock, class RemoteH>
LEAF_CONSTEXPR typename std::decay<decltype(std::declval<TryBlock>()().value())>::type remote_try_handle_all_( TryBlock &&, RemoteH && ) const;
template <class TryBlock, class... H, class Ctx>
LEAF_CONSTEXPR typename std::decay<decltype(std::declval<TryBlock>()())>::type try_handle_some_( context_activator<Ctx> &, TryBlock &&, H && ... ) const;
template <class TryBlock, class RemoteH, class Ctx>
LEAF_CONSTEXPR typename std::decay<decltype(std::declval<TryBlock>()())>::type remote_try_handle_some_( context_activator<Ctx> &, TryBlock &&, RemoteH && ) const;
public:
template <class R, class... H>
LEAF_CONSTEXPR typename std::decay<decltype(std::declval<R>().value())>::type handle_all( R &, H && ... ) const;
LEAF_CONSTEXPR typename std::decay<decltype(std::declval<R>().value())>::type handle_all( R &, H && ... );
template <class R, class RemoteH>
LEAF_CONSTEXPR typename std::decay<decltype(std::declval<R>().value())>::type remote_handle_all( R &, RemoteH && ) const;
LEAF_CONSTEXPR typename std::decay<decltype(std::declval<R>().value())>::type remote_handle_all( R &, RemoteH && );
template <class R, class... H>
LEAF_CONSTEXPR R handle_some( R &&, H && ... ) const;
LEAF_CONSTEXPR R handle_some( R &&, H && ... );
template <class R, class RemoteH>
LEAF_CONSTEXPR R remote_handle_some( R &&, RemoteH && ) const;
template <class TryBlock, class... H>
decltype(std::declval<TryBlock>()()) try_catch_( TryBlock &&, H && ... ) const;
template <class TryBlock, class RemoteH>
decltype(std::declval<TryBlock>()()) remote_try_catch_( TryBlock &&, RemoteH && ) const;
LEAF_CONSTEXPR R remote_handle_some( R &&, RemoteH && );
template <class R, class... H>
LEAF_CONSTEXPR R handle_current_exception( H && ... ) const;
LEAF_CONSTEXPR R handle_current_exception( H && ... );
template <class R, class RemoteH>
LEAF_CONSTEXPR R remote_handle_current_exception( RemoteH && ) const;
LEAF_CONSTEXPR R remote_handle_current_exception( RemoteH && );
template <class R, class... H>
LEAF_CONSTEXPR R handle_exception( std::exception_ptr const &, H && ... ) const;
LEAF_CONSTEXPR R handle_exception( std::exception_ptr const &, H && ... );
template <class R, class RemoteH>
LEAF_CONSTEXPR R remote_handle_exception( std::exception_ptr const &, RemoteH && ) const;
LEAF_CONSTEXPR R remote_handle_exception( std::exception_ptr const &, RemoteH && );
};
template <class... E>
@@ -436,7 +461,8 @@ namespace boost { namespace leaf {
{
error_id propagate_captured_errors() noexcept final override { return Ctx::propagate_captured_errors(captured_id_); }
void activate() noexcept final override { Ctx::activate(); }
void deactivate( bool propagate_errors ) noexcept final override { Ctx::deactivate(propagate_errors); }
void deactivate() noexcept final override { Ctx::deactivate(); }
void propagate() noexcept final override { Ctx::propagate(); }
bool is_active() const noexcept final override { return Ctx::is_active(); }
void print( std::ostream & os ) const final override { return Ctx::print(os); }
};

View File

@@ -708,102 +708,80 @@ namespace boost { namespace leaf {
{
template <class... E>
template <class R, class... H>
LEAF_CONSTEXPR inline typename std::decay<decltype(std::declval<R>().value())>::type context_base<E...>::handle_all( R & r, H && ... h ) const
LEAF_CONSTEXPR inline typename std::decay<decltype(std::declval<R>().value())>::type context_base<E...>::handle_all_( R & r, H && ... h )
{
using namespace leaf_detail;
using Ret = typename std::decay<decltype(std::declval<R>().value())>::type;
static_assert(is_result_type<R>::value, "The R type used with a handle_all function must be registered with leaf::is_result_type");
return handle_error_<Ret>(tup(), error_info(r.error()), std::forward<H>(h)...);
assert(is_active());
error_info const ei(r.error());
deactivate();
return handle_error_<Ret>(tup(), ei, std::forward<H>(h)...);
}
template <class... E>
template <class R, class RemoteH>
LEAF_CONSTEXPR inline typename std::decay<decltype(std::declval<R>().value())>::type context_base<E...>::remote_handle_all( R & r, RemoteH && h ) const
LEAF_CONSTEXPR inline typename std::decay<decltype(std::declval<R>().value())>::type context_base<E...>::remote_handle_all_( R & r, RemoteH && h )
{
static_assert(is_result_type<R>::value, "The R type used with a handle_all function must be registered with leaf::is_result_type");
return std::forward<RemoteH>(h)(error_info(r.error(), this)).get();
assert(is_active());
error_info const ei(r.error(), this);
deactivate();
return std::forward<RemoteH>(h)(ei).get();
}
template <class... E>
template <class R, class... H>
LEAF_CONSTEXPR inline R context_base<E...>::handle_some( R && r, H && ... h ) const
LEAF_CONSTEXPR inline R context_base<E...>::handle_some_( R && r, H && ... h )
{
using namespace leaf_detail;
static_assert(is_result_type<R>::value, "The R type used with a handle_some function must be registered with leaf::is_result_type");
return handle_error_<R>(tup(), error_info(r.error()), std::forward<H>(h)...,
assert(is_active());
error_info const ei(r.error());
deactivate();
return handle_error_<R>(tup(), ei, std::forward<H>(h)...,
[&r]()->R { return std::move(r); });
}
template <class... E>
template <class R, class RemoteH>
LEAF_CONSTEXPR inline R context_base<E...>::remote_handle_some( R && r, RemoteH && h ) const
LEAF_CONSTEXPR inline R context_base<E...>::remote_handle_some_( R && r, RemoteH && h )
{
static_assert(is_result_type<R>::value, "The R type used with a handle_some function must be registered with leaf::is_result_type");
return std::forward<RemoteH>(h)(error_info(r.error(), this)).get();
}
////////////////////////////////////////////
template <class... E>
template <class TryBlock, class... H>
LEAF_CONSTEXPR inline typename std::decay<decltype(std::declval<TryBlock>()().value())>::type context_base<E...>::try_handle_all_( TryBlock && try_block, H && ... h ) const
{
using namespace leaf_detail;
static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a try_handle_all function must be registered with leaf::is_result_type");
assert(this->is_active());
if( auto r = std::forward<TryBlock>(try_block)() )
return r.value();
else
return handle_all(r, std::forward<H>(h)...);
assert(is_active());
error_info const ei(r.error(), this);
deactivate();
return std::forward<RemoteH>(h)(ei).get();
}
template <class... E>
template <class TryBlock, class RemoteH>
LEAF_CONSTEXPR inline typename std::decay<decltype(std::declval<TryBlock>()().value())>::type context_base<E...>::remote_try_handle_all_( TryBlock && try_block, RemoteH && h ) const
template <class R, class... H>
LEAF_CONSTEXPR inline typename std::decay<decltype(std::declval<R>().value())>::type context_base<E...>::handle_all( R & r, H && ... h )
{
using namespace leaf_detail;
static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a remote_try_handle_all function must be registered with leaf::is_result_type");
assert(this->is_active());
if( auto r = std::forward<TryBlock>(try_block)() )
return r.value();
else
return remote_handle_all(r, std::forward<RemoteH>(h));
auto active_context = activate_context(*this);
return handle_all_(r, std::forward<H>(h)...);
}
template <class... E>
template <class TryBlock, class... H, class Ctx>
LEAF_CONSTEXPR inline typename std::decay<decltype(std::declval<TryBlock>()())>::type context_base<E...>::try_handle_some_( context_activator<Ctx> & active_context, TryBlock && try_block, H && ... h ) const
template <class R, class RemoteH>
LEAF_CONSTEXPR inline typename std::decay<decltype(std::declval<R>().value())>::type context_base<E...>::remote_handle_all( R & r, RemoteH && h )
{
using namespace leaf_detail;
static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a try_handle_some function must be registered with leaf::is_result_type");
assert(this->is_active());
if( auto r = std::forward<TryBlock>(try_block)() )
return r;
else
{
auto rr = handle_some(std::move(r), std::forward<H>(h)...);
if( !rr )
active_context.set_on_deactivate(on_deactivation::propagate);
return rr;
}
auto active_context = activate_context(*this);
return remote_handle_all_(r, std::forward<RemoteH>(h));
}
template <class... E>
template <class TryBlock, class RemoteH, class Ctx>
LEAF_CONSTEXPR inline typename std::decay<decltype(std::declval<TryBlock>()())>::type context_base<E...>::remote_try_handle_some_( context_activator<Ctx> & active_context, TryBlock && try_block, RemoteH && h ) const
template <class R, class... H>
LEAF_CONSTEXPR inline R context_base<E...>::handle_some( R && r, H && ... h )
{
using namespace leaf_detail;
static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a remote_try_handle_some function must be registered with leaf::is_result_type");
assert(this->is_active());
if( auto r = std::forward<TryBlock>(try_block)() )
return r;
else
{
auto rr = remote_handle_some(std::move(r), std::forward<RemoteH>(h));
if( !rr )
active_context.set_on_deactivate(on_deactivation::propagate);
return rr;
}
auto active_context = activate_context(*this);
return handle_some_(std::forward<R>(r), std::forward<H>(h)...);
}
template <class... E>
template <class R, class RemoteH>
LEAF_CONSTEXPR inline R context_base<E...>::remote_handle_some( R && r, RemoteH && h )
{
auto active_context = activate_context(*this);
return remote_handle_some_(std::forward<R>(r), std::forward<RemoteH>(h));
}
}

View File

@@ -243,20 +243,22 @@ namespace boost { namespace leaf {
assert(x.top_==0);
}
~slot() noexcept
{
assert(top_==0);
}
LEAF_CONSTEXPR void activate() noexcept
{
assert(top_==0);
assert(top_==0 || *top_!=this);
top_ = &tl_slot_ptr<E>();
prev_ = *top_;
*top_ = this;
}
LEAF_CONSTEXPR void deactivate( bool propagate_errors ) noexcept;
LEAF_CONSTEXPR void deactivate() noexcept
{
assert(top_!=0 && *top_==this);
*top_ = prev_;
}
LEAF_CONSTEXPR void propagate() noexcept;
using impl::put;
using impl::has_value;
@@ -296,28 +298,25 @@ namespace boost { namespace leaf {
#endif
template <class E>
LEAF_CONSTEXPR inline void slot<E>::deactivate( bool propagate_errors ) noexcept
LEAF_CONSTEXPR inline void slot<E>::propagate() noexcept
{
assert(top_!=0);
if( propagate_errors )
if( prev_ )
{
impl & this_ = *this;
impl & that_ = *prev_;
that_ = std::move(this_);
}
assert(top_!=0 && (*top_==prev_ || *top_==this));
if( prev_ )
{
impl & this_ = *this;
impl & that_ = *prev_;
that_ = std::move(this_);
}
#if LEAF_DIAGNOSTICS
else
{
int c = tl_unexpected_enabled_counter();
assert(c>=0);
if( c )
if( int err_id = impl::key() )
load_unexpected(err_id, std::move(*this).value(err_id));
}
else
{
int c = tl_unexpected_enabled_counter();
assert(c>=0);
if( c )
if( int err_id = impl::key() )
load_unexpected(err_id, std::move(*this).value(err_id));
}
#endif
*top_ = prev_;
top_ = 0;
}
template <class E>
@@ -608,7 +607,8 @@ namespace boost { namespace leaf {
public:
virtual error_id propagate_captured_errors() noexcept = 0;
virtual void activate() noexcept = 0;
virtual void deactivate( bool propagate_errors ) noexcept = 0;
virtual void deactivate() noexcept = 0;
virtual void propagate() noexcept = 0;
virtual bool is_active() const noexcept = 0;
virtual void print( std::ostream & ) const = 0;
error_id captured_id_;
@@ -618,77 +618,61 @@ namespace boost { namespace leaf {
////////////////////////////////////////////
enum class on_deactivation
{
propagate,
do_not_propagate,
propagate_if_uncaught_exception
};
template <class Ctx>
class context_activator
{
context_activator( context_activator const & ) = delete;
context_activator & operator=( context_activator const & ) = delete;
#if !defined(LEAF_NO_EXCEPTIONS) && LEAF_STD_UNCAUGHT_EXCEPTIONS
int const uncaught_exceptions_;
#endif
Ctx * ctx_;
bool const ctx_was_active_;
on_deactivation on_deactivate_;
public:
LEAF_CONSTEXPR LEAF_ALWAYS_INLINE context_activator(Ctx & ctx, on_deactivation on_deactivate) noexcept:
ctx_(&ctx),
ctx_was_active_(ctx.is_active()),
on_deactivate_(on_deactivate)
explicit LEAF_CONSTEXPR LEAF_ALWAYS_INLINE context_activator(Ctx & ctx) noexcept:
#if !defined(LEAF_NO_EXCEPTIONS) && LEAF_STD_UNCAUGHT_EXCEPTIONS
uncaught_exceptions_(std::uncaught_exceptions()),
#endif
ctx_(ctx.is_active() ? 0 : &ctx)
{
if( !ctx_was_active_ )
ctx.activate();
if( ctx_ )
ctx_->activate();
}
LEAF_CONSTEXPR LEAF_ALWAYS_INLINE context_activator( context_activator && x ) noexcept:
ctx_(x.ctx_),
ctx_was_active_(x.ctx_was_active_),
on_deactivate_(x.on_deactivate_)
#if !defined(LEAF_NO_EXCEPTIONS) && LEAF_STD_UNCAUGHT_EXCEPTIONS
uncaught_exceptions_(x.uncaught_exceptions_),
#endif
ctx_(x.ctx_)
{
x.ctx_ = 0;
}
LEAF_ALWAYS_INLINE ~context_activator() noexcept
{
if( ctx_ )
{
assert(
on_deactivate_ == on_deactivation::propagate ||
on_deactivate_ == on_deactivation::do_not_propagate ||
on_deactivate_ == on_deactivation::propagate_if_uncaught_exception);
if( !ctx_was_active_ )
if( on_deactivate_ == on_deactivation::propagate_if_uncaught_exception )
{
#ifdef LEAF_NO_EXCEPTIONS
ctx_->deactivate(false);
#else
bool has_exception = LEAF_UNCAUGHT_EXCEPTIONS();
ctx_->deactivate(has_exception);
if( !has_exception )
(void) leaf_detail::new_id();
if( !ctx_ )
return;
if( ctx_->is_active() )
ctx_->deactivate();
#ifndef LEAF_NO_EXCEPTIONS
# if LEAF_STD_UNCAUGHT_EXCEPTIONS
if( std::uncaught_exceptions() > uncaught_exceptions_ )
# else
if( std::uncaught_exception() )
# endif
ctx_->propagate();
else
(void) leaf_detail::new_id();
#endif
}
else
ctx_->deactivate(on_deactivate_ == on_deactivation::propagate);
}
}
LEAF_CONSTEXPR LEAF_ALWAYS_INLINE void set_on_deactivate( on_deactivation on_deactivate ) noexcept
{
on_deactivate_ = on_deactivate;
}
};
template <class Ctx>
LEAF_CONSTEXPR LEAF_ALWAYS_INLINE context_activator<Ctx> activate_context( Ctx & ctx, on_deactivation on_deactivate ) noexcept
LEAF_CONSTEXPR LEAF_ALWAYS_INLINE context_activator<Ctx> activate_context(Ctx & ctx) noexcept
{
return context_activator<Ctx>(ctx, on_deactivate);
return context_activator<Ctx>(ctx);
}
////////////////////////////////////////////

View File

@@ -55,7 +55,7 @@ namespace boost { namespace leaf {
{
public:
virtual error_id get_error_id() const = 0;
virtual error_id get_error_id() const noexcept = 0;
protected:
@@ -69,7 +69,7 @@ namespace boost { namespace leaf {
public exception_base,
public error_id
{
error_id get_error_id() const final override
error_id get_error_id() const noexcept final override
{
return *this;
}

View File

@@ -16,32 +16,62 @@ namespace boost { namespace leaf {
template <class TryBlock, class... H>
LEAF_CONSTEXPR LEAF_ALWAYS_INLINE typename std::decay<decltype(std::declval<TryBlock>()().value())>::type nocatch_context<E...>::try_handle_all( TryBlock && try_block, H && ... h )
{
auto active_context = activate_context(*this, on_deactivation::do_not_propagate);
return this->try_handle_all_( std::forward<TryBlock>(try_block), std::forward<H>(h)... );
using namespace leaf_detail;
static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a try_handle_all function must be registered with leaf::is_result_type");
auto active_context = activate_context(*this);
if( auto r = std::forward<TryBlock>(try_block)() )
return r.value();
else
return this->handle_all_(r, std::forward<H>(h)...);
}
template <class... E>
template <class TryBlock, class RemoteH>
LEAF_CONSTEXPR LEAF_ALWAYS_INLINE typename std::decay<decltype(std::declval<TryBlock>()().value())>::type nocatch_context<E...>::remote_try_handle_all( TryBlock && try_block, RemoteH && h )
{
auto active_context = activate_context(*this, on_deactivation::do_not_propagate);
return this->remote_try_handle_all_( std::forward<TryBlock>(try_block), std::forward<RemoteH>(h) );
using namespace leaf_detail;
static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a remote_try_handle_all function must be registered with leaf::is_result_type");
auto active_context = activate_context(*this);
if( auto r = std::forward<TryBlock>(try_block)() )
return r.value();
else
return this->remote_handle_all_(r, std::forward<RemoteH>(h));
}
template <class... E>
template <class TryBlock, class... H>
LEAF_CONSTEXPR LEAF_ALWAYS_INLINE typename std::decay<decltype(std::declval<TryBlock>()())>::type nocatch_context<E...>::try_handle_some( TryBlock && try_block, H && ... h )
{
auto active_context = activate_context(*this, on_deactivation::propagate_if_uncaught_exception);
return this->try_handle_some_( active_context, std::forward<TryBlock>(try_block), std::forward<H>(h)... );
using namespace leaf_detail;
static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a try_handle_some function must be registered with leaf::is_result_type");
auto active_context = activate_context(*this);
if( auto r = std::forward<TryBlock>(try_block)() )
return r;
else
{
auto rr = this->handle_some_(std::move(r), std::forward<H>(h)...);
if( !rr )
this->propagate();
return rr;
}
}
template <class... E>
template <class TryBlock, class RemoteH>
LEAF_CONSTEXPR LEAF_ALWAYS_INLINE typename std::decay<decltype(std::declval<TryBlock>()())>::type nocatch_context<E...>::remote_try_handle_some( TryBlock && try_block, RemoteH && h )
{
auto active_context = activate_context(*this, on_deactivation::propagate_if_uncaught_exception);
return this->remote_try_handle_some_( active_context, std::forward<TryBlock>(try_block), std::forward<RemoteH>(h) );
using namespace leaf_detail;
static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a remote_try_handle_some function must be registered with leaf::is_result_type");
auto active_context = activate_context(*this);
if( auto r = std::forward<TryBlock>(try_block)() )
return r;
else
{
auto rr = remote_handle_some_(std::move(r), std::forward<RemoteH>(h));
if( !rr )
this->propagate();
return rr;
}
}
}

View File

@@ -119,49 +119,23 @@ namespace boost { namespace leaf {
////////////////////////////////////////
template <class TryBlock, class... H>
LEAF_CONSTEXPR inline decltype(std::declval<TryBlock>()()) try_catch( TryBlock && try_block, H && ... h )
{
using namespace leaf_detail;
context_type_from_handlers<H...> ctx;
auto active_context = activate_context(ctx, on_deactivation::propagate_if_uncaught_exception);
return ctx.try_catch_(
[&]
{
return std::forward<TryBlock>(try_block)();
},
std::forward<H>(h)...);
}
template <class TryBlock, class RemoteH>
LEAF_CONSTEXPR inline decltype(std::declval<TryBlock>()()) remote_try_catch( TryBlock && try_block, RemoteH && h )
{
using namespace leaf_detail;
context_type_from_remote_handler<RemoteH> ctx;
auto active_context = activate_context(ctx, on_deactivation::propagate_if_uncaught_exception);
return ctx.remote_try_catch_(
[&]
{
return std::forward<TryBlock>(try_block)();
},
std::forward<RemoteH>(h));
}
namespace leaf_detail
{
template <class... E>
template <class R, class... H>
LEAF_CONSTEXPR inline R context_base<E...>::handle_current_exception( H && ... h ) const
LEAF_CONSTEXPR inline R context_base<E...>::handle_current_exception_( H && ... h )
{
assert(is_active());
return this->try_catch_(
[]{ throw; },
[]() -> R { throw; },
std::forward<H>(h)...);
}
template <class... E>
template <class R, class RemoteH>
LEAF_CONSTEXPR inline R context_base<E...>::remote_handle_current_exception( RemoteH && h ) const
LEAF_CONSTEXPR inline R context_base<E...>::remote_handle_current_exception_( RemoteH && h )
{
assert(is_active());
return this->remote_try_catch_(
[]() -> R { throw; },
std::forward<RemoteH>(h));
@@ -169,22 +143,56 @@ namespace boost { namespace leaf {
template <class... E>
template <class R, class... H>
LEAF_CONSTEXPR inline R context_base<E...>::handle_exception( std::exception_ptr const & ep, H && ... h ) const
LEAF_CONSTEXPR inline R context_base<E...>::handle_exception_( std::exception_ptr const & ep, H && ... h )
{
assert(is_active());
return this->try_catch_(
[&]{ std::rethrow_exception(ep); },
[&]() -> R { std::rethrow_exception(ep); },
std::forward<H>(h)...);
}
template <class... E>
template <class R, class RemoteH>
LEAF_CONSTEXPR inline R context_base<E...>::remote_handle_exception( std::exception_ptr const & ep, RemoteH && h ) const
LEAF_CONSTEXPR inline R context_base<E...>::remote_handle_exception_( std::exception_ptr const & ep, RemoteH && h )
{
assert(is_active());
return this->remote_try_catch_(
[&]() -> R { std::rethrow_exception(ep); },
std::forward<RemoteH>(h));
}
template <class... E>
template <class R, class... H>
LEAF_CONSTEXPR inline R context_base<E...>::handle_current_exception( H && ... h )
{
auto active_context = activate_context(*this);
return handle_current_exception_<R>(std::forward<H>(h)...);
}
template <class... E>
template <class R, class RemoteH>
LEAF_CONSTEXPR inline R context_base<E...>::remote_handle_current_exception( RemoteH && h )
{
auto active_context = activate_context(*this);
return remote_handle_current_exception_<R>(std::forward<RemoteH>(h));
}
template <class... E>
template <class R, class... H>
LEAF_CONSTEXPR inline R context_base<E...>::handle_exception( std::exception_ptr const & ep, H && ... h )
{
auto active_context = activate_context(*this);
return handle_exception_<R>(ep, std::forward<H>(h)...);
}
template <class... E>
template <class R, class RemoteH>
LEAF_CONSTEXPR inline R context_base<E...>::remote_handle_exception( std::exception_ptr const & ep, RemoteH && h )
{
auto active_context = activate_context(*this);
return remote_handle_exception_<R>(ep, std::forward<RemoteH>(h));
}
////////////////////////////////////////
template <class... E>
@@ -193,7 +201,7 @@ namespace boost { namespace leaf {
{
using namespace leaf_detail;
static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a try_handle_all function must be registered with leaf::is_result_type");
auto active_context = activate_context(*this, on_deactivation::propagate_if_uncaught_exception);
auto active_context = activate_context(*this);
if( auto r = this->try_catch_(
[&]
{
@@ -211,7 +219,7 @@ namespace boost { namespace leaf {
{
using namespace leaf_detail;
static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a try_handle_all function must be registered with leaf::is_result_type");
auto active_context = activate_context(*this, on_deactivation::propagate_if_uncaught_exception);
auto active_context = activate_context(*this);
if( auto r = this->remote_try_catch_(
[&]
{
@@ -229,7 +237,7 @@ namespace boost { namespace leaf {
{
using namespace leaf_detail;
static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a try_handle_some function must be registered with leaf::is_result_type");
auto active_context = activate_context(*this, on_deactivation::propagate_if_uncaught_exception);
auto active_context = activate_context(*this);
if( auto r = this->try_catch_(
[&]
{
@@ -241,7 +249,7 @@ namespace boost { namespace leaf {
{
auto rr = this->handle_some(std::move(r), std::forward<H>(h)...);
if( !rr )
active_context.set_on_deactivate(on_deactivation::propagate);
this->propagate();
return rr;
}
}
@@ -250,7 +258,9 @@ namespace boost { namespace leaf {
template <class TryBlock, class RemoteH>
LEAF_CONSTEXPR inline typename std::decay<decltype(std::declval<TryBlock>()())>::type catch_context<E...>::remote_try_handle_some( TryBlock && try_block, RemoteH && h )
{
auto active_context = activate_context(*this, on_deactivation::propagate_if_uncaught_exception);
using namespace leaf_detail;
static_assert(is_result_type<decltype(std::declval<TryBlock>()())>::value, "The return type of the try_block passed to a remote_try_handle_some function must be registered with leaf::is_result_type");
auto active_context = activate_context(*this);
if( auto r = this->remote_try_catch_(
[&]
{
@@ -262,7 +272,7 @@ namespace boost { namespace leaf {
{
auto rr = this->remote_handle_some(std::move(r), std::forward<RemoteH>(h));
if( !rr )
active_context.set_on_deactivate(on_deactivation::propagate);
this->propagate();
return rr;
}
}
@@ -288,9 +298,10 @@ namespace boost { namespace leaf {
template <class... E>
template <class TryBlock, class... H>
inline decltype(std::declval<TryBlock>()()) context_base<E...>::try_catch_( TryBlock && try_block, H && ... h ) const
inline decltype(std::declval<TryBlock>()()) context_base<E...>::try_catch_( TryBlock && try_block, H && ... h )
{
using namespace leaf_detail;
assert(is_active());
using R = decltype(std::declval<TryBlock>()());
try
{
@@ -304,22 +315,26 @@ namespace boost { namespace leaf {
}
catch( std::exception const & ex )
{
deactivate();
return leaf_detail::handle_error_<R>(this->tup(), error_info(exception_info_(&ex)), std::forward<H>(h)...,
[]() -> R { throw; } );
}
catch(...)
{
deactivate();
return leaf_detail::handle_error_<R>(this->tup(), error_info(exception_info_(0)), std::forward<H>(h)...,
[]() -> R { throw; } );
}
}
catch( std::exception const & ex )
{
deactivate();
return leaf_detail::handle_error_<R>(this->tup(), error_info(exception_info_(&ex)), std::forward<H>(h)...,
[]() -> R { throw; } );
}
catch(...)
{
deactivate();
return leaf_detail::handle_error_<R>(this->tup(), error_info(exception_info_(0)), std::forward<H>(h)...,
[]() -> R { throw; } );
}
@@ -327,9 +342,10 @@ namespace boost { namespace leaf {
template <class... E>
template <class TryBlock, class RemoteH>
inline decltype(std::declval<TryBlock>()()) context_base<E...>::remote_try_catch_( TryBlock && try_block, RemoteH && h ) const
inline decltype(std::declval<TryBlock>()()) context_base<E...>::remote_try_catch_( TryBlock && try_block, RemoteH && h )
{
using namespace leaf_detail;
assert(is_active());
try
{
return std::forward<TryBlock>(try_block)();
@@ -342,19 +358,23 @@ namespace boost { namespace leaf {
}
catch( std::exception const & ex )
{
deactivate();
return std::forward<RemoteH>(h)(error_info(exception_info_(&ex), this)).get();
}
catch(...)
{
deactivate();
return std::forward<RemoteH>(h)(error_info(exception_info_(0), this)).get();
}
}
catch( std::exception const & ex )
{
deactivate();
return std::forward<RemoteH>(h)(error_info(exception_info_(&ex), this)).get();
}
catch(...)
{
deactivate();
return std::forward<RemoteH>(h)(error_info(exception_info_(0), this)).get();
}
}
@@ -436,6 +456,36 @@ namespace boost { namespace leaf {
{
}
////////////////////////////////////////
template <class TryBlock, class... H>
LEAF_CONSTEXPR inline decltype(std::declval<TryBlock>()()) try_catch( TryBlock && try_block, H && ... h )
{
using namespace leaf_detail;
context_type_from_handlers<H...> ctx;
auto active_context = activate_context(ctx);
return ctx.try_catch_(
[&]
{
return std::forward<TryBlock>(try_block)();
},
std::forward<H>(h)...);
}
template <class TryBlock, class RemoteH>
LEAF_CONSTEXPR inline decltype(std::declval<TryBlock>()()) remote_try_catch( TryBlock && try_block, RemoteH && h )
{
using namespace leaf_detail;
context_type_from_remote_handler<RemoteH> ctx;
auto active_context = activate_context(ctx);
return ctx.remote_try_catch_(
[&]
{
return std::forward<TryBlock>(try_block)();
},
std::forward<RemoteH>(h));
}
} }
#endif

View File

@@ -29,7 +29,11 @@ namespace boost { namespace leaf {
else
{
#ifndef LEAF_NO_EXCEPTIONS
if( LEAF_UNCAUGHT_EXCEPTIONS() )
# if LEAF_STD_UNCAUGHT_EXCEPTIONS
if( std::uncaught_exceptions() )
# else
if( std::uncaught_exception() )
# endif
return leaf_detail::new_id();
#endif
return 0;

View File

@@ -78,6 +78,9 @@ tests = [
'context_activator_test',
'context_deduction_test',
'capture_result_unload_test',
'ctx_handle_all_test',
'ctx_handle_exception_test',
'ctx_handle_some_test',
'ctx_remote_handle_all_test',
'ctx_remote_handle_exception_test',
'ctx_remote_handle_some_test',
@@ -127,8 +130,9 @@ tests = [
'_hpp_result_test',
'_hpp_all_test',
]
ubsan_args = [ '-fsanitize=undefined', '-fno-sanitize-recover=undefined' ]
foreach t : tests
test(t, executable(t, 'test/'+t+'.cpp', dependencies: [leaf,thread_dep]+mp11 ) )
test(t, executable(t, 'test/'+t+'.cpp', dependencies: [leaf,thread_dep]+mp11, cpp_args: ubsan_args, link_args: ubsan_args) )
endforeach
if exceptions

View File

@@ -45,6 +45,9 @@ run capture_exception_unload_test.cpp ;
run capture_result_async_test.cpp ;
run capture_result_state_test.cpp ;
run capture_result_unload_test.cpp ;
run ctx_handle_all_test.cpp ;
run ctx_handle_exception_test.cpp ;
run ctx_handle_some_test.cpp ;
run ctx_remote_handle_all_test.cpp ;
run ctx_remote_handle_exception_test.cpp ;
run ctx_remote_handle_some_test.cpp ;

View File

@@ -55,6 +55,11 @@ int main()
return leaf::remote_handle_exception( err,
[]( info<1>, info<3> )
{
return 1;
},
[]
{
return 2;
} );
};
BOOST_TEST_EQ(count, 0);
@@ -74,8 +79,8 @@ int main()
ep = std::current_exception();
}
BOOST_TEST_EQ(count, 2);
leaf::remote_try_catch(
[&]
int r = leaf::remote_try_catch(
[&]() -> int
{
std::rethrow_exception(ep);
},
@@ -83,6 +88,7 @@ int main()
{
return error_handler(err);
} );
BOOST_TEST_EQ(r, 1);
ep = std::exception_ptr();
BOOST_TEST_EQ(count, 0);
return boost::report_errors();

View File

@@ -19,7 +19,7 @@ struct info
template <class Ctx>
leaf::result<int> f( Ctx & ctx )
{
auto active_context = activate_context(ctx, leaf::on_deactivation::do_not_propagate);
auto active_context = activate_context(ctx);
return leaf::new_error( info<1>{1} );
}
@@ -43,8 +43,10 @@ int main()
[&]
{
auto ctx = leaf::make_context(&handle_error);
auto active_context = activate_context(ctx, leaf::on_deactivation::propagate);
return f(ctx);
auto active_context = activate_context(ctx);
auto r = f(ctx);
ctx.propagate();
return r;
},
[&]( leaf::error_info const & error )
{

View File

@@ -0,0 +1,51 @@
// Copyright (c) 2018-2019 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/context.hpp>
#include <boost/leaf/handle_error.hpp>
#include <boost/leaf/result.hpp>
#include "lightweight_test.hpp"
#include <iostream>
namespace leaf = boost::leaf;
template <int>
struct info
{
int value;
};
template <class Ctx>
leaf::result<int> f( Ctx & ctx )
{
auto active_context = activate_context(ctx);
return leaf::new_error( info<1>{1} );
}
int main()
{
leaf::context<info<1>, leaf::verbose_diagnostic_info const &> ctx;
{
leaf::result<int> r1 = f(ctx);
BOOST_TEST(!r1);
int r2 = ctx.handle_all(
r1,
[]( info<1> x )
{
BOOST_TEST(x.value==1);
return 1;
},
[]( leaf::verbose_diagnostic_info const & info )
{
std::cout << info;
return 2;
} );
BOOST_TEST_EQ(r2, 1);
}
return boost::report_errors();
}

View File

@@ -0,0 +1,143 @@
// Copyright (c) 2018-2019 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>
#ifdef LEAF_NO_EXCEPTIONS
#include <iostream>
int main()
{
std::cout << "Unit test not applicable." << std::endl;
return 0;
}
#else
#include <boost/leaf/context.hpp>
#include <boost/leaf/handle_exception.hpp>
#include "lightweight_test.hpp"
namespace leaf = boost::leaf;
template <int>
struct info
{
int value;
};
template <class Ctx>
void f( Ctx & ctx )
{
auto active_context = activate_context(ctx);
throw leaf::exception(std::exception(), info<1>{1});
}
int main()
{
{
using Ctx = leaf::context<leaf::catch_<std::exception>, info<1>>;
{
Ctx ctx;
try
{
f(ctx);
}
catch(...)
{
int r = ctx.handle_current_exception<int>(
[]( leaf::catch_<std::exception>, info<1> x )
{
BOOST_TEST(x.value==1);
return 1;
},
[]
{
return 2;
} );
BOOST_TEST_EQ(r, 1);
}
}
{
Ctx ctx;
try
{
f(ctx);
}
catch(...)
{
int r = ctx.handle_exception<int>(
std::current_exception(),
[]( leaf::catch_<std::exception>, info<1> x )
{
BOOST_TEST(x.value==1);
return 1;
},
[]
{
return 2;
} );
BOOST_TEST_EQ(r, 1);
}
}
}
{
using Ctx = leaf::context<leaf::catch_<std::exception>, info<1>>;
{
Ctx ctx;
try
{
f(ctx);
}
catch(...)
{
int r = 0;
ctx.handle_current_exception<void>(
[&]( leaf::catch_<std::exception>, info<1> x )
{
BOOST_TEST(x.value==1);
r = 1;
},
[&]
{
r = 2;
} );
BOOST_TEST_EQ(r, 1);
}
}
{
Ctx ctx;
try
{
f(ctx);
}
catch(...)
{
int r = 0;
ctx.handle_exception<void>(
std::current_exception(),
[&]( leaf::catch_<std::exception>, info<1> x )
{
BOOST_TEST(x.value==1);
r = 1;
},
[&]
{
r = 2;
} );
BOOST_TEST_EQ(r, 1);
}
}
}
return boost::report_errors();
}
#endif

View File

@@ -0,0 +1,49 @@
// Copyright (c) 2018-2019 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/context.hpp>
#include <boost/leaf/handle_error.hpp>
#include <boost/leaf/result.hpp>
#include "lightweight_test.hpp"
namespace leaf = boost::leaf;
template <int>
struct info
{
int value;
};
template <class Ctx>
leaf::result<int> f( Ctx & ctx )
{
auto active_context = activate_context(ctx);
return leaf::new_error( info<1>{1} );
}
int main()
{
leaf::context<info<1>> ctx;
{
leaf::result<int> r1 = f(ctx);
BOOST_TEST(!r1);
leaf::result<int> r2 = ctx.handle_some(
std::move(r1),
[]( info<1> x ) -> leaf::result<int>
{
BOOST_TEST(x.value==1);
return 1;
},
[]
{
return 2;
} );
BOOST_TEST_EQ(r2.value(), 1);
}
return boost::report_errors();
}

View File

@@ -20,7 +20,7 @@ struct info
template <class Ctx>
leaf::result<int> f( Ctx & ctx )
{
auto active_context = activate_context(ctx, leaf::on_deactivation::do_not_propagate);
auto active_context = activate_context(ctx);
return leaf::new_error( info<1>{1} );
}

View File

@@ -31,7 +31,7 @@ struct info
template <class Ctx>
void f( Ctx & ctx )
{
auto active_context = activate_context(ctx, leaf::on_deactivation::do_not_propagate);
auto active_context = activate_context(ctx);
throw leaf::exception(std::exception(), info<1>{1});
}

View File

@@ -19,7 +19,7 @@ struct info
template <class Ctx>
leaf::result<int> f( Ctx & ctx )
{
auto active_context = activate_context(ctx, leaf::on_deactivation::do_not_propagate);
auto active_context = activate_context(ctx);
return leaf::new_error( info<1>{1} );
}

View File

@@ -13,6 +13,8 @@
namespace leaf = boost::leaf;
struct test_info { int value;};
enum class error_code
{
error1=1,
@@ -170,5 +172,38 @@ int main()
}
#endif
///////////////////////////
{
int r = leaf::try_handle_all(
[]() -> leaf::result<int>
{
return leaf::new_error( test_info{42} );
},
[]( test_info const & x )
{
BOOST_TEST_EQ(x.value, 42);
int r = leaf::try_handle_all(
[]() -> leaf::result<int>
{
return leaf::new_error( test_info{43} );
},
[]()
{
return -1;
} );
BOOST_TEST_EQ(r, -1);
BOOST_TEST_EQ(x.value, 42);
return 0;
},
[]()
{
return -1;
} );
BOOST_TEST_EQ(r, 0);
}
///////////////////////////
return boost::report_errors();
}

View File

@@ -246,7 +246,7 @@ int main()
{ // error move -> move
context_type ctx;
auto active_context = activate_context(ctx, leaf::on_deactivation::do_not_propagate);
auto active_context = activate_context(ctx);
leaf::result<val> r1 = leaf::new_error( e_err { } );
BOOST_TEST(!r1);
BOOST_TEST_EQ(err::count, 1);
@@ -261,7 +261,7 @@ int main()
BOOST_TEST_EQ(val::count, 0);
{ // error copy -> move
context_type ctx;
auto active_context = activate_context(ctx, leaf::on_deactivation::propagate);
auto active_context = activate_context(ctx);
leaf::error_id err = leaf::new_error( e_err{ } );
leaf::result<val> r1 = err;
BOOST_TEST(!r1);
@@ -278,7 +278,7 @@ int main()
{ // error move -> assign move
context_type ctx;
auto active_context = activate_context(ctx, leaf::on_deactivation::propagate);
auto active_context = activate_context(ctx);
leaf::result<val> r1 = leaf::new_error( e_err { } );
BOOST_TEST(!r1);
BOOST_TEST_EQ(err::count, 1);
@@ -299,7 +299,7 @@ int main()
BOOST_TEST_EQ(val::count, 0);
{ // error copy -> assign move
context_type ctx;
auto active_context = activate_context(ctx, leaf::on_deactivation::propagate);
auto active_context = activate_context(ctx);
leaf::error_id err = leaf::new_error( e_err{ } );
leaf::result<val> r1 = err;
BOOST_TEST(!r1);
@@ -411,7 +411,7 @@ int main()
{ // void error move -> move
context_type ctx;
auto active_context = activate_context(ctx, leaf::on_deactivation::do_not_propagate);
auto active_context = activate_context(ctx);
leaf::result<void> r1 = leaf::new_error( e_err { } );
BOOST_TEST(!r1);
BOOST_TEST_EQ(err::count, 1);
@@ -424,7 +424,7 @@ int main()
BOOST_TEST_EQ(err::count, 0);
{ // void error copy -> move
context_type ctx;
auto active_context = activate_context(ctx, leaf::on_deactivation::propagate);
auto active_context = activate_context(ctx);
leaf::error_id err = leaf::new_error( e_err{ } );
leaf::result<void> r1 = err;
BOOST_TEST(!r1);
@@ -439,7 +439,7 @@ int main()
{ // void error move -> assign move
context_type ctx;
auto active_context = activate_context(ctx, leaf::on_deactivation::propagate);
auto active_context = activate_context(ctx);
leaf::result<void> r1 = leaf::new_error( e_err { } );
BOOST_TEST(!r1);
BOOST_TEST_EQ(err::count, 1);
@@ -454,7 +454,7 @@ int main()
BOOST_TEST_EQ(err::count, 0);
{ // void error copy -> assign move
context_type ctx;
auto active_context = activate_context(ctx, leaf::on_deactivation::propagate);
auto active_context = activate_context(ctx);
leaf::error_id err = leaf::new_error( e_err{ } );
leaf::result<void> r1 = err;
BOOST_TEST(!r1);