-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
183 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -307,6 +307,7 @@ read_condition(T const& x) | |
// end | ||
|
||
#define ALIA_END \ | ||
; \ | ||
} \ | ||
} \ | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
#ifndef ALIA_FLOW_TRY_CATCH_HPP | ||
#define ALIA_FLOW_TRY_CATCH_HPP | ||
|
||
#include <alia/flow/events.hpp> | ||
#include <alia/flow/macros.hpp> | ||
|
||
namespace alia { | ||
|
||
template<class CallOperator> | ||
struct call_operator_arg_type | ||
{ | ||
}; | ||
template<class Class, class Return, class Arg> | ||
struct call_operator_arg_type<Return (Class::*)(Arg) const> | ||
{ | ||
typedef Arg type; | ||
}; | ||
|
||
template<class Lambda> | ||
struct lambda_arg_type : call_operator_arg_type<decltype(&Lambda::operator())> | ||
{ | ||
}; | ||
|
||
template<class Clause, class = void_t<>> | ||
struct is_concrete_clause : std::false_type | ||
{ | ||
}; | ||
template<class Clause> | ||
struct is_concrete_clause< | ||
Clause, | ||
void_t<typename lambda_arg_type<Clause>::type>> : std::true_type | ||
{ | ||
}; | ||
|
||
template<class Context, class Lambda> | ||
std::enable_if_t<is_concrete_clause<std::decay_t<Lambda>>::value, bool> | ||
invoke_catch_clause( | ||
Context ctx, | ||
std::exception_ptr exception, | ||
data_block& block, | ||
Lambda&& concrete) | ||
{ | ||
try | ||
{ | ||
std::rethrow_exception(exception); | ||
} | ||
catch (typename lambda_arg_type<std::decay_t<Lambda>>::type arg) | ||
{ | ||
scoped_data_block scoped_block(ctx, block); | ||
concrete(arg); | ||
return true; | ||
} | ||
catch (...) | ||
{ | ||
return false; | ||
} | ||
}; | ||
|
||
template<class Context, class Lambda> | ||
std::enable_if_t<!is_concrete_clause<std::decay_t<Lambda>>::value, bool> | ||
invoke_catch_clause( | ||
Context ctx, | ||
std::exception_ptr exception, | ||
data_block& block, | ||
Lambda&& lambda) | ||
{ | ||
scoped_data_block scoped_block(ctx, block); | ||
lambda(); | ||
return true; | ||
} | ||
|
||
struct try_block_data | ||
{ | ||
counter_type last_refresh = 0; | ||
std::exception_ptr exception; | ||
}; | ||
|
||
struct try_block | ||
{ | ||
try_block(alia::context ctx) : ctx_(ctx) | ||
{ | ||
get_cached_data(ctx, &data_); | ||
on_refresh(ctx, [&](auto ctx) { | ||
auto refresh_counter = get<system_tag>(ctx).refresh_counter; | ||
if (data_->last_refresh != refresh_counter) | ||
{ | ||
data_->exception = nullptr; | ||
data_->last_refresh = refresh_counter; | ||
} | ||
}); | ||
uncaught_ = data_->exception ? true : false; | ||
} | ||
|
||
void | ||
operator<<(function_view<void()> body) | ||
{ | ||
ALIA_IF_(ctx_, !data_->exception) | ||
{ | ||
try | ||
{ | ||
body(); | ||
} | ||
catch (alia::traversal_abortion&) | ||
{ | ||
throw; | ||
} | ||
catch (...) | ||
{ | ||
data_->exception = std::current_exception(); | ||
mark_dirty_component(ctx_); | ||
} | ||
} | ||
ALIA_END | ||
} | ||
|
||
context ctx_; | ||
try_block_data* data_; | ||
bool uncaught_; | ||
}; | ||
|
||
struct catch_block | ||
{ | ||
catch_block(try_block& tb) : try_block_(&tb) | ||
{ | ||
} | ||
|
||
template<class Body> | ||
void | ||
operator<<(Body&& body) | ||
{ | ||
auto ctx = try_block_->ctx_; | ||
data_block* block; | ||
get_data_node(ctx, &block); | ||
if (try_block_->uncaught_) | ||
{ | ||
if (invoke_catch_clause( | ||
ctx, try_block_->data_->exception, *block, body)) | ||
{ | ||
try_block_->uncaught_ = false; | ||
return; | ||
} | ||
} | ||
if (get_data_traversal(ctx).cache_clearing_enabled) | ||
{ | ||
block->clear_cache(); | ||
} | ||
} | ||
|
||
try_block* try_block_; | ||
}; | ||
|
||
#define ALIA_TRY_(ctx) \ | ||
ALIA_DISABLE_MACRO_WARNINGS \ | ||
{ \ | ||
{ \ | ||
alia::try_block _alia_try_block(ctx); \ | ||
{ \ | ||
_alia_try_block << [&]() ALIA_UNDISABLE_MACRO_WARNINGS | ||
|
||
#define ALIA_TRY ALIA_TRY_(ctx) | ||
|
||
#define ALIA_CATCH_(ctx, pattern) \ | ||
ALIA_DISABLE_MACRO_WARNINGS; \ | ||
} \ | ||
{ \ | ||
alia::catch_block _alia_catch_block(_alia_try_block); \ | ||
_alia_catch_block << [&](pattern) ALIA_UNDISABLE_MACRO_WARNINGS | ||
|
||
#define ALIA_CATCH(pattern) ALIA_CATCH_(ctx, pattern) | ||
|
||
#ifndef ALIA_STRICT_MACROS | ||
#define alia_try_(ctx) ALIA_TRY_(ctx) | ||
#define alia_try ALIA_TRY | ||
#define alia_catch_(ctx, pattern) ALIA_CATCH_(ctx, pattern) | ||
#define alia_catch(pattern) ALIA_CATCH(pattern) | ||
#endif | ||
|
||
} // namespace alia | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters