Commit 57ca0479 authored by Dominik Charousset's avatar Dominik Charousset

Merge branch 'topic/message-lifetime' into develop

parents a376b31a e789e5f5
...@@ -173,8 +173,6 @@ class behavior_impl : public ref_counted { ...@@ -173,8 +173,6 @@ class behavior_impl : public ref_counted {
virtual bhvr_invoke_result invoke(message&) = 0; virtual bhvr_invoke_result invoke(message&) = 0;
virtual bhvr_invoke_result invoke(const message&) = 0;
inline bhvr_invoke_result invoke(message&& arg) { inline bhvr_invoke_result invoke(message&& arg) {
message tmp(std::move(arg)); message tmp(std::move(arg));
return invoke(tmp); return invoke(tmp);
...@@ -206,7 +204,7 @@ struct dummy_match_expr { ...@@ -206,7 +204,7 @@ struct dummy_match_expr {
} }
}; };
template <class MatchExpr, typename F> template <class MatchExpr, class F = std::function<void()>>
class default_behavior_impl : public behavior_impl { class default_behavior_impl : public behavior_impl {
public: public:
template <class Expr> template <class Expr>
...@@ -223,25 +221,18 @@ class default_behavior_impl : public behavior_impl { ...@@ -223,25 +221,18 @@ class default_behavior_impl : public behavior_impl {
// nop // nop
} }
bhvr_invoke_result invoke(message& tup) { bhvr_invoke_result invoke(message& msg) override {
auto res = m_expr(tup); auto res = m_expr(msg);
optional_message_visitor omv;
return apply_visitor(omv, res);
}
bhvr_invoke_result invoke(const message& tup) {
auto res = m_expr(tup);
optional_message_visitor omv; optional_message_visitor omv;
return apply_visitor(omv, res); return apply_visitor(omv, res);
} }
typename behavior_impl::pointer typename behavior_impl::pointer
copy(const generic_timeout_definition& tdef) const { copy(const generic_timeout_definition& tdef) const override {
return new default_behavior_impl<MatchExpr, std::function<void()>>(m_expr, return new default_behavior_impl<MatchExpr>(m_expr, tdef);
tdef);
} }
void handle_timeout() { void handle_timeout() override {
m_fun(); m_fun();
} }
......
...@@ -35,21 +35,16 @@ ...@@ -35,21 +35,16 @@
namespace caf { namespace caf {
namespace detail { namespace detail {
class lifted_fun_zipper { struct lifted_fun_zipper {
public:
template <class F, typename T> template <class F, typename T>
auto operator()(const F& fun, T& arg) -> decltype(fun(arg)) const { auto operator()(const F& fun, T& arg) -> decltype(fun(arg)) const {
return fun(arg); return fun(arg);
} }
// forward everything as reference if no guard/transformation is set // forward everything as reference if no guard/transformation is set
template <class T> template <class T>
auto operator()(const unit_t&, T& arg) const -> decltype(std::ref(arg)) { auto operator()(const unit_t&, T& arg) const -> decltype(std::ref(arg)) {
return std::ref(arg); return std::ref(arg);
} }
}; };
template <class T> template <class T>
...@@ -67,62 +62,64 @@ inline bool has_none() { ...@@ -67,62 +62,64 @@ inline bool has_none() {
} }
template <class T, class... Ts> template <class T, class... Ts>
inline bool has_none(const T&, const Ts&... vs) { bool has_none(const T&, const Ts&... vs) {
return has_none(vs...); return has_none(vs...);
} }
template <class T, class... Ts> template <class T, class... Ts>
inline bool has_none(const optional<T>& v, const Ts&... vs) { bool has_none(const optional<T>& v, const Ts&... vs) {
return !v || has_none(vs...); return !v || has_none(vs...);
} }
// allows F to have fewer arguments than the lifted_fun calling it // allows F to have fewer arguments than the lifted_fun calling it
template <class R, typename F> template <class R, typename F>
class lifted_fun_invoker { class lifted_fun_invoker {
public:
using arg_types = typename get_callable_trait<F>::arg_types; using arg_types = typename get_callable_trait<F>::arg_types;
static constexpr size_t num_args = tl_size<arg_types>::value; static constexpr size_t num_args = tl_size<arg_types>::value;
public: lifted_fun_invoker(F& fun) : f(fun) {
// nop
lifted_fun_invoker(F& fun) : f(fun) {} }
template <class... Ts> template <class... Ts>
typename std::enable_if<sizeof...(Ts) == num_args, R>::type typename std::enable_if<sizeof...(Ts) == num_args, R>::type
operator()(Ts&... vs) const { operator()(Ts&... vs) const {
if (has_none(vs...)) return none; if (has_none(vs...)) {
return none;
}
return f(unopt(vs)...); return f(unopt(vs)...);
} }
template <class T, class... Ts> template <class T, class... Ts>
typename std::enable_if<(sizeof...(Ts) + 1 > num_args), R>::type typename std::enable_if<(sizeof...(Ts) + 1 > num_args), R>::type
operator()(T& v, Ts&... vs) const { operator()(T& v, Ts&... vs) const {
if (has_none(v)) return none; if (has_none(v)) {
return none;
}
return (*this)(vs...); return (*this)(vs...);
} }
private: private:
F& f; F& f;
}; };
template <class F> template <class F>
class lifted_fun_invoker<bool, F> { class lifted_fun_invoker<bool, F> {
public:
using arg_types = typename get_callable_trait<F>::arg_types; using arg_types = typename get_callable_trait<F>::arg_types;
static constexpr size_t num_args = tl_size<arg_types>::value; static constexpr size_t num_args = tl_size<arg_types>::value;
public: lifted_fun_invoker(F& fun) : f(fun) {
// nop
lifted_fun_invoker(F& fun) : f(fun) {} }
template <class... Ts> template <class... Ts>
typename std::enable_if<sizeof...(Ts) == num_args, bool>::type typename std::enable_if<sizeof...(Ts) == num_args, bool>::type
operator()(Ts&&... vs) const { operator()(Ts&&... vs) const {
if (has_none(vs...)) return false; if (has_none(vs...)) {
return false;
}
f(unopt(vs)...); f(unopt(vs)...);
return true; return true;
} }
...@@ -130,14 +127,14 @@ class lifted_fun_invoker<bool, F> { ...@@ -130,14 +127,14 @@ class lifted_fun_invoker<bool, F> {
template <class T, class... Ts> template <class T, class... Ts>
typename std::enable_if<(sizeof...(Ts) + 1 > num_args), bool>::type typename std::enable_if<(sizeof...(Ts) + 1 > num_args), bool>::type
operator()(T&& arg, Ts&&... vs) const { operator()(T&& arg, Ts&&... vs) const {
if (has_none(arg)) return false; if (has_none(arg)) {
return false;
}
return (*this)(vs...); return (*this)(vs...);
} }
private: private:
F& f; F& f;
}; };
/** /**
...@@ -181,7 +178,9 @@ class lifted_fun { ...@@ -181,7 +178,9 @@ class lifted_fun {
lifted_fun& operator=(const lifted_fun&) = default; lifted_fun& operator=(const lifted_fun&) = default;
lifted_fun(F f) : m_fun(std::move(f)) {} lifted_fun(F f) : m_fun(std::move(f)) {
// nop
}
lifted_fun(F f, projections ps) : m_fun(std::move(f)), m_ps(std::move(ps)) { lifted_fun(F f, projections ps) : m_fun(std::move(f)), m_ps(std::move(ps)) {
// nop // nop
......
...@@ -251,10 +251,13 @@ struct is_legal_tuple_type { ...@@ -251,10 +251,13 @@ struct is_legal_tuple_type {
* Checks wheter `T` is a non-const reference. * Checks wheter `T` is a non-const reference.
*/ */
template <class T> template <class T>
struct is_mutable_ref { struct is_mutable_ref : std::false_type { };
static constexpr bool value = std::is_reference<T>::value
&& !std::is_const<T>::value; template <class T>
}; struct is_mutable_ref<const T&> : std::false_type { };
template <class T>
struct is_mutable_ref<T&> : std::true_type { };
/** /**
* Checks whether `T::static_type_name()` exists. * Checks whether `T::static_type_name()` exists.
......
...@@ -43,13 +43,6 @@ ...@@ -43,13 +43,6 @@
namespace caf { namespace caf {
namespace detail { namespace detail {
template <long N>
struct long_constant {
static constexpr long value = N;
};
using minus1l = long_constant<-1l>;
template <class T1, typename T2> template <class T1, typename T2>
T2& deduce_const(T1&, T2& rhs) { T2& deduce_const(T1&, T2& rhs) {
return rhs; return rhs;
...@@ -186,25 +179,10 @@ struct get_case<false, Expr, Trans, Pattern> { ...@@ -186,25 +179,10 @@ struct get_case<false, Expr, Trans, Pattern> {
>::type; >::type;
}; };
template <class Fun> inline variant<none_t, unit_t> unroll_expr_result_unbox(bool value) {
struct has_bool_result { if (value) {
using result_type = typename Fun::result_type; return unit;
static constexpr bool value = std::is_same<bool, result_type>::value; }
using token_type = std::integral_constant<bool, value>;
};
template <class T>
bool unroll_expr_result_valid(const T&) {
return true;
}
template <class T>
bool unroll_expr_result_valid(const optional<T>& opt) {
return static_cast<bool>(opt);
}
inline variant<none_t, unit_t> unroll_expr_result_unbox(bool& value) {
if (value) return unit;
return none; return none;
} }
...@@ -213,34 +191,28 @@ T& unroll_expr_result_unbox(optional<T>& opt) { ...@@ -213,34 +191,28 @@ T& unroll_expr_result_unbox(optional<T>& opt) {
return *opt; return *opt;
} }
template <class Result, class PPFPs, class Msg> template <class Result>
Result unroll_expr(PPFPs&, minus1l, Msg&) { struct unroll_expr {
// end of recursion Result operator()(message&) const {
return none; // end of recursion
} return none;
template <class Result, class PPFPs, long N, class Msg>
Result unroll_expr(PPFPs& fs, long_constant<N>, Msg& msg) {
{ // recursively evaluate sub expressions
Result res = unroll_expr<Result>(fs, long_constant<N - 1>{}, msg);
if (!get<none_t>(&res)) {
return res;
}
} }
auto& f = get<N>(fs);
using ft = typename std::decay<decltype(f)>::type; template <class F, class... Fs>
meta_elements<typename ft::pattern> ms; Result operator()(message& msg, F& f, Fs&... fs) const {
typename ft::intermediate_tuple targs; meta_elements<typename F::pattern> ms;
if ((ft::has_wildcard || ft::type_token == msg.type_token()) typename F::intermediate_tuple targs;
&& try_match(msg, ms.arr.data(), ms.arr.size(), targs.data)) { if ((F::has_wildcard || F::type_token == msg.type_token())
auto is = detail::get_indices(targs); && try_match(msg, ms.arr.data(), ms.arr.size(), targs.data)) {
auto res = detail::apply_args(f, is, deduce_const(msg, targs)); auto is = detail::get_indices(targs);
if (unroll_expr_result_valid(res)) { auto res = detail::apply_args(f, is, deduce_const(msg, targs));
return std::move(unroll_expr_result_unbox(res)); if (res) {
return std::move(unroll_expr_result_unbox(res));
}
} }
return (*this)(msg, fs...);
} }
return none; };
}
template <bool IsManipulator, typename T0, typename T1> template <bool IsManipulator, typename T0, typename T1>
struct mexpr_fwd_ { struct mexpr_fwd_ {
...@@ -269,20 +241,12 @@ struct mexpr_fwd { ...@@ -269,20 +241,12 @@ struct mexpr_fwd {
>::type; >::type;
}; };
// detach_if_needed(message tup, bool do_detach) inline void detach_if_needed(message& msg, std::true_type) {
inline message& detach_if_needed(message& tup, std::true_type) { msg.force_detach();
tup.force_detach();
return tup;
}
inline message detach_if_needed(const message& tup, std::true_type) {
message cpy{tup};
cpy.force_detach();
return cpy;
} }
inline const message& detach_if_needed(const message& tup, std::false_type) { inline void detach_if_needed(const message&, std::false_type) {
return tup; // nop
} }
inline void* fetch_native_data(message& msg, std::true_type) { inline void* fetch_native_data(message& msg, std::true_type) {
...@@ -298,14 +262,12 @@ struct is_manipulator_case { ...@@ -298,14 +262,12 @@ struct is_manipulator_case {
// static constexpr bool value = T::second_type::manipulates_args; // static constexpr bool value = T::second_type::manipulates_args;
using arg_types = typename T::arg_types; using arg_types = typename T::arg_types;
static constexpr bool value = tl_exists<arg_types, is_mutable_ref>::value; static constexpr bool value = tl_exists<arg_types, is_mutable_ref>::value;
}; };
template <class T> template <class T>
struct get_case_result { struct get_case_result {
// using type = typename T::second_type::result_type; // using type = typename T::second_type::result_type;
using type = typename T::result_type; using type = typename T::result_type;
}; };
} // namespace detail } // namespace detail
...@@ -319,7 +281,6 @@ struct match_result_from_type_list; ...@@ -319,7 +281,6 @@ struct match_result_from_type_list;
template <class... Ts> template <class... Ts>
struct match_result_from_type_list<detail::type_list<Ts...>> { struct match_result_from_type_list<detail::type_list<Ts...>> {
using type = variant<none_t, typename lift_void<Ts>::type...>; using type = variant<none_t, typename lift_void<Ts>::type...>;
}; };
/** /**
...@@ -343,11 +304,6 @@ class match_expr { ...@@ -343,11 +304,6 @@ class match_expr {
>::type >::type
>::type; >::type;
static constexpr bool has_manipulator =
detail::tl_exists<cases_list, detail::is_manipulator_case>::value;
using idx_token_type = detail::long_constant<sizeof...(Cs) - 1l>;
template <class T, class... Ts> template <class T, class... Ts>
match_expr(T v, Ts&&... vs) : m_cases(std::move(v), std::forward<Ts>(vs)...) { match_expr(T v, Ts&&... vs) : m_cases(std::move(v), std::forward<Ts>(vs)...) {
// nop // nop
...@@ -357,17 +313,16 @@ class match_expr { ...@@ -357,17 +313,16 @@ class match_expr {
match_expr(const match_expr&) = default; match_expr(const match_expr&) = default;
result_type operator()(const message& tup) { result_type operator()(message& msg) {
return apply(tup); using mutator_token = std::integral_constant<bool,
} detail::tl_exists<
cases_list,
result_type operator()(message& tup) { detail::is_manipulator_case
return apply(tup); >::value>;
} detail::detach_if_needed(msg, mutator_token{});
auto indices = detail::get_indices(m_cases);
result_type operator()(message&& tup) { detail::unroll_expr<result_type> f;
message tmp{tup}; return detail::apply_args_prefixed(f, indices, m_cases, msg);
return apply(tmp);
} }
template <class... Ds> template <class... Ds>
...@@ -395,20 +350,6 @@ class match_expr { ...@@ -395,20 +350,6 @@ class match_expr {
// std::tuple<type_list<...>, ...>, // std::tuple<type_list<...>, ...>,
// ...> // ...>
std::tuple<Cs...> m_cases; std::tuple<Cs...> m_cases;
static constexpr size_t cache_size = 10;
using cache_element = std::pair<const std::type_info*, uint64_t>;
template <class Msg>
result_type apply(Msg& msg) {
idx_token_type idx_token;
std::integral_constant<bool, has_manipulator> mutator_token;
// returns either a reference or a new object
using detached = decltype(detail::detach_if_needed(msg, mutator_token));
detached mref = detail::detach_if_needed(msg, mutator_token);
return detail::unroll_expr<result_type>(m_cases, idx_token, mref);
}
}; };
template <class T> template <class T>
...@@ -507,22 +448,26 @@ behavior_impl_ptr match_expr_concat(const T0& arg0, const T1& arg1, ...@@ -507,22 +448,26 @@ behavior_impl_ptr match_expr_concat(const T0& arg0, const T1& arg1,
// some more convenience functions // some more convenience functions
template <class F, template <class T,
class E = typename std::enable_if<is_callable<F>::value>::type> class E = typename std::enable_if<
match_expr<typename get_case<false, F, type_list<>, type_list<>>::type> is_callable<T>::value && !is_match_expr<T>::value
lift_to_match_expr(F fun) { >::type>
match_expr<typename get_case<false, T, type_list<>, type_list<>>::type>
lift_to_match_expr(T arg) {
using result_type = using result_type =
typename get_case< typename get_case<
false, false,
F, T,
detail::empty_type_list, detail::empty_type_list,
detail::empty_type_list detail::empty_type_list
>::type; >::type;
return result_type{std::move(fun)}; return result_type{std::move(arg)};
} }
template <class T, template <class T,
class E = typename std::enable_if<!is_callable<T>::value>::type> class E = typename std::enable_if<
!is_callable<T>::value || is_match_expr<T>::value
>::type>
T lift_to_match_expr(T arg) { T lift_to_match_expr(T arg) {
return arg; return arg;
} }
......
...@@ -160,7 +160,7 @@ class invoke_policy { ...@@ -160,7 +160,7 @@ class invoke_policy {
if (ref_opt) { if (ref_opt) {
auto fhdl = fetch_response_promise(self, hdl); auto fhdl = fetch_response_promise(self, hdl);
behavior inner = *ref_opt; behavior inner = *ref_opt;
*ref_opt = behavior { ref_opt->assign(
others() >> [=] { others() >> [=] {
// inner is const inside this lambda and mutable a C++14 feature // inner is const inside this lambda and mutable a C++14 feature
behavior cpy = inner; behavior cpy = inner;
...@@ -169,7 +169,7 @@ class invoke_policy { ...@@ -169,7 +169,7 @@ class invoke_policy {
fhdl.deliver(*inner_res); fhdl.deliver(*inner_res);
} }
} }
}; );
} }
} else { } else {
// respond by using the result of 'fun' // respond by using the result of 'fun'
......
...@@ -24,9 +24,10 @@ ...@@ -24,9 +24,10 @@
#include "caf/detail/type_traits.hpp" #include "caf/detail/type_traits.hpp"
#include "caf/detail/variant_data.hpp" #include "caf/detail/variant_data.hpp"
#define CAF_VARIANT_CASE(x) \ #define CAF_VARIANT_CASE(x) \
case x: return visitor(from.get(std::integral_constant<int, \ case x: \
x < max_type_id ? x : max_type_id >())) return visitor(from.get( \
std::integral_constant<int, (x < max_type_id ? x : max_type_id)>()))
namespace caf { namespace caf {
...@@ -36,7 +37,7 @@ struct variant_assign_helper { ...@@ -36,7 +37,7 @@ struct variant_assign_helper {
T& lhs; T& lhs;
variant_assign_helper(T& lhs_ref) : lhs(lhs_ref) { } variant_assign_helper(T& lhs_ref) : lhs(lhs_ref) { }
template <class U> template <class U>
inline void operator()(const U& rhs) const { void operator()(const U& rhs) const {
lhs = rhs; lhs = rhs;
} }
}; };
...@@ -47,17 +48,18 @@ struct variant_move_helper { ...@@ -47,17 +48,18 @@ struct variant_move_helper {
T& lhs; T& lhs;
variant_move_helper(T& lhs_ref) : lhs(lhs_ref) { } variant_move_helper(T& lhs_ref) : lhs(lhs_ref) { }
template <class U> template <class U>
inline void operator()(U& rhs) const { void operator()(U& rhs) const {
lhs = std::move(rhs); lhs = std::move(rhs);
} }
}; };
template <class T, typename U, template <class T, class U,
bool Enable = std::is_integral<T>::value && std::is_integral<U>::value> bool Enable = std::is_integral<T>::value
&& std::is_integral<U>::value>
struct is_equal_int_type { struct is_equal_int_type {
static constexpr bool value = static constexpr bool value = sizeof(T) == sizeof(U)
sizeof(T) == sizeof(U) && std::is_signed<T>::value
&& std::is_signed<T>::value == std::is_signed<U>::value; == std::is_signed<U>::value;
}; };
template <class T, typename U> template <class T, typename U>
...@@ -70,26 +72,25 @@ struct is_equal_int_type<T, U, false> : std::false_type { }; ...@@ -70,26 +72,25 @@ struct is_equal_int_type<T, U, false> : std::false_type { };
* `uint8_t != unsigned char on some compilers. * `uint8_t != unsigned char on some compilers.
*/ */
template <class T, typename U> template <class T, typename U>
struct is_same_ish : std::conditional< struct is_same_ish
std::is_same<T, U>::value, : std::conditional<
std::true_type, std::is_same<T, U>::value,
is_equal_int_type<T, U> std::true_type,
>::type { }; is_equal_int_type<T, U>
>::type { };
/** /**
* A variant represents always a valid value of one of the types `Ts...`. * A variant represents always a valid value of one of the types `Ts...`.
*/ */
template <class... Ts> template <class... Ts>
class variant { class variant {
public: public:
using types = detail::type_list<Ts...>; using types = detail::type_list<Ts...>;
static constexpr int max_type_id = sizeof...(Ts) - 1; static constexpr int max_type_id = sizeof...(Ts) - 1;
static_assert(!detail::tl_exists<types, std::is_reference>::value, static_assert(!detail::tl_exists<types, std::is_reference>::value,
"Cannot create a variant of references"); "Cannot create a variant of references");
variant& operator=(const variant& other) { variant& operator=(const variant& other) {
variant_assign_helper<variant> helper{*this}; variant_assign_helper<variant> helper{*this};
...@@ -134,20 +135,19 @@ class variant { ...@@ -134,20 +135,19 @@ class variant {
} }
/** @cond PRIVATE */ /** @cond PRIVATE */
template <int Pos> template <int Pos>
inline bool is(std::integral_constant<int, Pos>) const { bool is(std::integral_constant<int, Pos>) const {
return m_type == Pos; return m_type == Pos;
} }
template <int Pos> template <int Pos>
inline const typename detail::tl_at<types, Pos>::type& const typename detail::tl_at<types, Pos>::type&
get(std::integral_constant<int, Pos> token) const { get(std::integral_constant<int, Pos> token) const {
return m_data.get(token); return m_data.get(token);
} }
template <int Pos> template <int Pos>
inline typename detail::tl_at<types, Pos>::type& typename detail::tl_at<types, Pos>::type&
get(std::integral_constant<int, Pos> token) { get(std::integral_constant<int, Pos> token) {
return m_data.get(token); return m_data.get(token);
} }
...@@ -161,11 +161,9 @@ class variant { ...@@ -161,11 +161,9 @@ class variant {
typename Visitor::result_type apply(Visitor& visitor) { typename Visitor::result_type apply(Visitor& visitor) {
return apply_impl(*this, visitor); return apply_impl(*this, visitor);
} }
/** @endcond */ /** @endcond */
private: private:
template <class Self, typename Visitor> template <class Self, typename Visitor>
static typename Visitor::result_type apply_impl(Self& from, Visitor& visitor) { static typename Visitor::result_type apply_impl(Self& from, Visitor& visitor) {
switch (from.m_type) { switch (from.m_type) {
...@@ -222,30 +220,29 @@ class variant { ...@@ -222,30 +220,29 @@ class variant {
} }
template <class... Us> template <class... Us>
inline void set(const variant<Us...>& other) { void set(const variant<Us...>& other) {
using namespace detail; using namespace detail;
static_assert(tl_is_strict_subset<type_list<Us...>, types>::value, static_assert(tl_is_strict_subset<type_list<Us...>, types>::value,
"cannot set variant of type A to variant of type B " "cannot set variant of type A to variant of type B "
"unless the element types of A are a strict subset of " "unless the element types of A are a strict subset of "
"the element types of B"); "the element types of B");
variant_assign_helper<variant> helper{*this}; variant_assign_helper<variant> helper{*this};
other.apply(helper); other.apply(helper);
} }
template <class... Us> template <class... Us>
inline void set(variant<Us...>&& other) { void set(variant<Us...>&& other) {
using namespace detail; using namespace detail;
static_assert(tl_is_strict_subset<type_list<Us...>, types>::value, static_assert(tl_is_strict_subset<type_list<Us...>, types>::value,
"cannot set variant of type A to variant of type B " "cannot set variant of type A to variant of type B "
"unless the element types of A are a strict subset of " "unless the element types of A are a strict subset of "
"the element types of B"); "the element types of B");
variant_move_helper<variant> helper{*this}; variant_move_helper<variant> helper{*this};
other.apply(helper); other.apply(helper);
} }
int m_type; int m_type;
detail::variant_data<typename lift_void<Ts>::type...> m_data; detail::variant_data<typename lift_void<Ts>::type...> m_data;
}; };
/** /**
...@@ -254,9 +251,10 @@ class variant { ...@@ -254,9 +251,10 @@ class variant {
template <class T, class... Us> template <class T, class... Us>
T& get(variant<Us...>& value) { T& get(variant<Us...>& value) {
using namespace detail; using namespace detail;
constexpr int type_id = tl_find_if<type_list<Us...>, constexpr int type_id = tl_find_if<
tbind<is_same_ish, T>::template type type_list<Us...>,
>::value; tbind<is_same_ish, T>::template type
>::value;
std::integral_constant<int, type_id> token; std::integral_constant<int, type_id> token;
// silence compiler error about "binding to unrelated types" such as // silence compiler error about "binding to unrelated types" such as
// 'signed char' to 'char' (which is obvious bullshit) // 'signed char' to 'char' (which is obvious bullshit)
...@@ -278,11 +276,14 @@ const T& get(const variant<Us...>& value) { ...@@ -278,11 +276,14 @@ const T& get(const variant<Us...>& value) {
template <class T, class... Us> template <class T, class... Us>
T* get(variant<Us...>* value) { T* get(variant<Us...>* value) {
using namespace detail; using namespace detail;
constexpr int type_id = tl_find_if<type_list<Us...>, constexpr int type_id = tl_find_if<
tbind<is_same_ish, T>::template type type_list<Us...>,
>::value; tbind<is_same_ish, T>::template type
>::value;
std::integral_constant<int, type_id> token; std::integral_constant<int, type_id> token;
if (value->is(token)) return &get<T>(*value); if (value->is(token)) {
return &get<T>(*value);
}
return nullptr; return nullptr;
} }
......
...@@ -30,14 +30,7 @@ class combinator : public behavior_impl { ...@@ -30,14 +30,7 @@ class combinator : public behavior_impl {
public: public:
bhvr_invoke_result invoke(message& arg) { bhvr_invoke_result invoke(message& arg) {
auto res = first->invoke(arg); auto res = first->invoke(arg);
if (!res) return second->invoke(arg); return res ? res : second->invoke(arg);
return res;
}
bhvr_invoke_result invoke(const message& arg) {
auto res = first->invoke(arg);
if (!res) return second->invoke(arg);
return res;
} }
void handle_timeout() { void handle_timeout() {
...@@ -78,9 +71,8 @@ behavior_impl::pointer behavior_impl::or_else(const pointer& other) { ...@@ -78,9 +71,8 @@ behavior_impl::pointer behavior_impl::or_else(const pointer& other) {
} }
behavior_impl* new_default_behavior(duration d, std::function<void()> fun) { behavior_impl* new_default_behavior(duration d, std::function<void()> fun) {
using impl = default_behavior_impl<dummy_match_expr, std::function<void()>>;
dummy_match_expr nop; dummy_match_expr nop;
return new impl(nop, d, std::move(fun)); return new default_behavior_impl<dummy_match_expr>(nop, d, std::move(fun));
} }
} // namespace detail } // namespace detail
......
...@@ -74,6 +74,7 @@ message_data* message_data::ptr::get_detached() { ...@@ -74,6 +74,7 @@ message_data* message_data::ptr::get_detached() {
if (!p->unique()) { if (!p->unique()) {
auto np = p->copy(); auto np = p->copy();
m_ptr.reset(np); m_ptr.reset(np);
CAF_REQUIRE(np->unique());
return np; return np;
} }
return p; return p;
......
...@@ -25,7 +25,7 @@ ref_counted::~ref_counted() { ...@@ -25,7 +25,7 @@ ref_counted::~ref_counted() {
// nop // nop
} }
ref_counted::ref_counted(const ref_counted&) { ref_counted::ref_counted(const ref_counted&) : m_rc(0) {
// nop; don't copy reference count // nop; don't copy reference count
} }
......
...@@ -35,6 +35,7 @@ add_unit_test(constructor_attach) ...@@ -35,6 +35,7 @@ add_unit_test(constructor_attach)
add_unit_test(custom_exception_handler) add_unit_test(custom_exception_handler)
add_unit_test(typed_spawn) add_unit_test(typed_spawn)
add_unit_test(actor_lifetime) add_unit_test(actor_lifetime)
add_unit_test(message_lifetime)
add_unit_test(local_group) add_unit_test(local_group)
add_unit_test(sync_send) add_unit_test(sync_send)
add_unit_test(broker) add_unit_test(broker)
......
#include <atomic>
#include <iostream>
#include "test.hpp"
#include "caf/all.hpp"
using std::cout;
using std::endl;
using namespace caf;
class testee : public event_based_actor {
public:
testee();
~testee();
behavior make_behavior() override;
};
testee::testee() {
// nop
}
testee::~testee() {
// nop
}
behavior testee::make_behavior() {
return {
others() >> [=] {
CAF_CHECK_EQUAL(last_dequeued().cvals()->get_reference_count(), 2);
quit();
return last_dequeued();
}
};
}
class tester : public event_based_actor {
public:
tester(actor aut);
~tester();
behavior make_behavior() override;
private:
actor m_aut;
message m_msg;
};
tester::tester(actor aut) :
m_aut(std::move(aut)),
m_msg(make_message(1, 2, 3)) {
// nop
}
tester::~tester() {
// nop
}
behavior tester::make_behavior() {
monitor(m_aut);
send(m_aut, m_msg);
return {
on(1, 2, 3) >> [=] {
CAF_CHECK_EQUAL(last_dequeued().cvals()->get_reference_count(), 2);
CAF_CHECK(last_dequeued().cvals().get() == m_msg.cvals().get());
},
[=](const down_msg& dm) {
CAF_CHECK(dm.source == m_aut);
CAF_CHECK_EQUAL(dm.reason, exit_reason::normal);
CAF_CHECK_EQUAL(last_dequeued().cvals()->get_reference_count(), 1);
quit();
},
others() >> CAF_UNEXPECTED_MSG_CB(this)
};
}
void test_message_lifetime_in_scoped_actor() {
auto msg = make_message(1, 2, 3);
scoped_actor self;
self->send(self, msg);
self->receive(
on(1, 2, 3) >> [&] {
CAF_CHECK_EQUAL(msg.cvals()->get_reference_count(), 2);
CAF_CHECK_EQUAL(self->last_dequeued().cvals()->get_reference_count(), 2);
CAF_CHECK(self->last_dequeued().cvals().get() == msg.cvals().get());
}
);
CAF_CHECK_EQUAL(msg.cvals()->get_reference_count(), 1);
msg = make_message(42);
self->send(self, msg);
self->receive(
[&](int& value) {
CAF_CHECK_EQUAL(msg.cvals()->get_reference_count(), 1);
CAF_CHECK_EQUAL(self->last_dequeued().cvals()->get_reference_count(), 1);
CAF_CHECK(self->last_dequeued().cvals().get() != msg.cvals().get());
value = 10;
}
);
CAF_CHECK_EQUAL(msg.get_as<int>(0), 42);
}
void test_message_lifetime() {
test_message_lifetime_in_scoped_actor();
if (CAF_TEST_RESULT() != 0) {
return;
}
// put some preassure on the scheduler (check for thread safety)
for (size_t i = 0; i < 100; ++i) {
spawn<tester>(spawn<testee>());
}
}
int main() {
CAF_TEST(test_message_lifetime);
test_message_lifetime();
await_all_actors_done();
shutdown();
return CAF_TEST_RESULT();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment