1#ifndef HALCHECK_LIB_EFFECT_HPP
2#define HALCHECK_LIB_EFFECT_HPP
10#include <halcheck/lib/functional.hpp>
11#include <halcheck/lib/optional.hpp>
12#include <halcheck/lib/scope.hpp>
13#include <halcheck/lib/tuple.hpp>
14#include <halcheck/lib/type_traits.hpp>
15#include <halcheck/lib/utility.hpp>
23namespace halcheck {
namespace lib {
25#ifdef HALCHECK_DOXYGEN
45 member_t<T> operator()(T args)
const {
46 return std::move(args).fallback();
49 template<typename T, HALCHECK_REQUIRE(!lib::is_detected<member_t, T>())>
50 free_t<T>
operator()(T args)
const {
51 return fallback(std::move(args));
97 static thread_local const context *current;
100 lib::move_only_function<lib::finally_t<>(
bool)> fallback()
const;
103 template<
typename Effect>
117 template<typename T, HALCHECK_REQUIRE(lib::is_effect<T>())>
120 if (i < current->
size() && (*current)[i]) {
121 auto &entry = *(*current)[i];
122 assert(entry.func &&
"entry.func should not be null");
123 assert(entry.context &&
"entry.context should not be null");
126 return (*
reinterpret_cast<base<T> *
>(entry.func))(std::move(args));
130 return lib::fallback(std::move(args));
157 template<
typename Self,
typename... Effects>
158 class handler :
private base<clone_effect>,
private base<Effects>... {
170 reset(reset &&other) noexcept : next(std::move(other.next)), old(other.old) {
171 assert(current == &other.next);
175 reset(
const reset &) =
delete;
176 reset &operator=(reset &&) =
delete;
177 reset &operator=(
const reset &) =
delete;
180 void operator()()
const { current = old; }
191 explicit owning_reset(
handler *self)
192 : self(std::move(*
static_cast<Self *
>(self))), next(this->self.install()),
197 : self(std::move(other.self)), next((current = other.old, self.install())),
200 owning_reset(
const owning_reset &) =
delete;
201 owning_reset &operator=(owning_reset &&) =
delete;
202 owning_reset &operator=(
const owning_reset &) =
delete;
203 ~owning_reset() =
default;
205 void operator()()
const { current = old; }
252 auto output = *current;
253 output.
resize(
std::max({output.size(), index<clone_effect>(), index<Effects>()...}) + 1);
254 output[index<clone_effect>()] = entry{
static_cast<base<clone_effect> *
>(
this), current};
255 lib::ignore = {(output[index<Effects>()] = entry{
static_cast<base<Effects> *
>(
this), current})...};
263 auto handler1 = outer(owning);
265 return std::move(handler1) + std::move(copy).handle();
267 return std::move(handler1) +
copy.handle();
272 *
static_cast<Self *
>(
this));
330 lib::move_only_function<lib::finally_t<>(
bool)> _impl;
lib::invoke_result_t< F, Args... > handle(F func, Args &&...args)
Invokes a function, handling any effects using this handler.
Definition effect.hpp:245
scope handle() &
Overrides the behaviour of a set of effects.
Definition effect.hpp:220
owning_scope handle() &&
Overrides the behaviour of a set of effects.
Definition effect.hpp:227
An effect handler defines the behaviour of a set of effects.
Definition effect.hpp:158
lib::invoke_result_t< F, Args... > handle(F func, Args &&...args)
Invokes a function, handling any effects using this state.
Definition effect.hpp:324
lib::finally_t handle() &&
Overrides the current set of effect handlers.
state(lib::in_place_t)
Copies the current set of effect handlers.
lib::finally_t handle() &
Overrides the current set of effect handlers.
state()=default
Constructs the default state object.
A state determines the behaviour of all effects.
Definition effect.hpp:279
static state save()
Copies the current set of effect handlers.
Definition effect.hpp:337
static lib::effect_result_t< T > invoke(Args &&...args)
Invokes an effect.
Definition effect.hpp:147
static lib::effect_result_t< T > invoke(T args)
Invokes an effect.
Definition effect.hpp:118
Provides operations for simulating scoped-algebraic effects (a.k.a. resumable exceptions....
Definition effect.hpp:79
Calls a function upon destruction.
Definition scope.hpp:26
lib::invoke_result_t< decltype(lib::fallback), const T & > effect_result_t
Evaluates to the result type of the given effect.
Definition effect.hpp:61
HALCHECK_INLINE_CONSTEXPR struct halcheck::lib::@20 invoke
An implementation of std::invoke.
decltype(lib::invoke(std::declval< F >(), std::declval< Args >()...)) invoke_result_t
An implementation of std::invoke_result_t.
Definition invoke.hpp:42
HALCHECK_INLINE_CONSTEXPR struct halcheck::lib::@26 empty
Determines if a range is empty.
HALCHECK_INLINE_CONSTEXPR struct halcheck::lib::@25 size
Obtains the size of a range.
lib::finally_t< F > finally(F func)
Definition scope.hpp:157
static const lib::ignore_t ignore
A version of std::ignore usable with initializer lists.
Definition tuple.hpp:38
#define HALCHECK_REQUIRE(...)
Expands to a template argument that is only valid if the given argument evaluates to true.
Definition type_traits.hpp:24
T exchange(T &value, U &&next)
An implementation of std::exchange.
Definition utility.hpp:41
static constexpr in_place_t in_place
An implementation of std::in_place.
Definition utility.hpp:33
An implementation of std::conjunction.
Definition type_traits.hpp:59
An implementation of std::in_place_t.
Definition utility.hpp:26
Determines if a type is constructible from a given set of argument types using initiailizer-list-styl...
Definition type_traits.hpp:280
An implementation of std::experimental::is_detected.
Definition type_traits.hpp:247
Determines if a given type is an effect.
Definition effect.hpp:73
An implementation of std::is_invocable.
Definition invoke.hpp:66