Commit d36dc898 authored by Dominik Charousset's avatar Dominik Charousset

Replace `match_expr` with `match_case` tuples

The main objective of this change is to make CAF stack traces readable,
reducing the amount of "template vomit" visible at runtime to a bare minimum.
As a side effect, this patch streamlines the implementation quite a bit to have
an easier time maintaining it in the future.

Also `others()` can now be written as simply `others`.
parent 35e6b342
...@@ -146,7 +146,7 @@ behavior broker_impl(broker* self, connection_handle hdl, const actor& buddy) { ...@@ -146,7 +146,7 @@ behavior broker_impl(broker* self, connection_handle hdl, const actor& buddy) {
// send composed message to our buddy // send composed message to our buddy
self->send(buddy, atm, ival); self->send(buddy, atm, ival);
}, },
others() >> [=] { others >> [=] {
cout << "unexpected: " << to_string(self->current_message()) << endl; cout << "unexpected: " << to_string(self->current_message()) << endl;
} }
}; };
...@@ -164,7 +164,7 @@ behavior server(broker* self, const actor& buddy) { ...@@ -164,7 +164,7 @@ behavior server(broker* self, const actor& buddy) {
aout(self) << "quit server (only accept 1 connection)" << endl; aout(self) << "quit server (only accept 1 connection)" << endl;
self->quit(); self->quit();
}, },
others() >> [=] { others >> [=] {
cout << "unexpected: " << to_string(self->current_message()) << endl; cout << "unexpected: " << to_string(self->current_message()) << endl;
} }
}; };
...@@ -190,7 +190,7 @@ int main(int argc, char** argv) { ...@@ -190,7 +190,7 @@ int main(int argc, char** argv) {
print_on_exit(ping_actor, "ping"); print_on_exit(ping_actor, "ping");
send_as(io_actor, ping_actor, kickoff_atom::value, io_actor); send_as(io_actor, ping_actor, kickoff_atom::value, io_actor);
}, },
others() >> [] { others >> [] {
cerr << "use with eihter '-s PORT' as server or '-c HOST PORT' as client" cerr << "use with eihter '-s PORT' as server or '-c HOST PORT' as client"
<< endl; << endl;
} }
......
...@@ -61,7 +61,7 @@ behavior server(broker* self) { ...@@ -61,7 +61,7 @@ behavior server(broker* self) {
*counter = 0; *counter = 0;
self->delayed_send(self, std::chrono::seconds(1), tick_atom::value); self->delayed_send(self, std::chrono::seconds(1), tick_atom::value);
}, },
others() >> [=] { others >> [=] {
aout(self) << "unexpected: " << to_string(self->current_message()) << endl; aout(self) << "unexpected: " << to_string(self->current_message()) << endl;
} }
}; };
...@@ -83,7 +83,7 @@ int main(int argc, const char **argv) { ...@@ -83,7 +83,7 @@ int main(int argc, const char **argv) {
// kill server // kill server
anon_send_exit(server_actor, exit_reason::user_shutdown); anon_send_exit(server_actor, exit_reason::user_shutdown);
}, },
others() >> [] { others >> [] {
cerr << "use with '-p PORT' as server on port" << endl; cerr << "use with '-p PORT' as server on port" << endl;
} }
}); });
......
...@@ -25,7 +25,7 @@ void blocking_calculator(blocking_actor* self) { ...@@ -25,7 +25,7 @@ void blocking_calculator(blocking_actor* self) {
[](minus_atom, int a, int b) { [](minus_atom, int a, int b) {
return a - b; return a - b;
}, },
others() >> [=] { others >> [=] {
cout << "unexpected: " << to_string(self->current_message()) << endl; cout << "unexpected: " << to_string(self->current_message()) << endl;
} }
); );
...@@ -40,7 +40,7 @@ behavior calculator(event_based_actor* self) { ...@@ -40,7 +40,7 @@ behavior calculator(event_based_actor* self) {
[](minus_atom, int a, int b) { [](minus_atom, int a, int b) {
return a - b; return a - b;
}, },
others() >> [=] { others >> [=] {
cout << "unexpected: " << to_string(self->current_message()) << endl; cout << "unexpected: " << to_string(self->current_message()) << endl;
} }
}; };
......
...@@ -143,7 +143,7 @@ void client_repl(const string& host, uint16_t port) { ...@@ -143,7 +143,7 @@ void client_repl(const string& host, uint16_t port) {
<< endl; << endl;
} }
}, },
others() >> [] { others >> [] {
cout << "*** usage: connect <host> <port>" << endl; cout << "*** usage: connect <host> <port>" << endl;
} }
}); });
......
...@@ -59,7 +59,7 @@ void client(event_based_actor* self, const string& name) { ...@@ -59,7 +59,7 @@ void client(event_based_actor* self, const string& name) {
[=](const group_down_msg& g) { [=](const group_down_msg& g) {
cout << "*** chatroom offline: " << to_string(g.source) << endl; cout << "*** chatroom offline: " << to_string(g.source) << endl;
}, },
others() >> [=]() { others >> [=]() {
cout << "unexpected: " << to_string(self->current_message()) << endl; cout << "unexpected: " << to_string(self->current_message()) << endl;
} }
); );
...@@ -143,7 +143,7 @@ int main(int argc, char** argv) { ...@@ -143,7 +143,7 @@ int main(int argc, char** argv) {
" /quit quit the program\n" " /quit quit the program\n"
" /help print this text\n" << flush; " /help print this text\n" << flush;
}, },
others() >> [&] { others >> [&] {
if (!s_last_line.empty()) { if (!s_last_line.empty()) {
anon_send(client_actor, broadcast_atom::value, s_last_line); anon_send(client_actor, broadcast_atom::value, s_last_line);
} }
......
...@@ -50,6 +50,7 @@ set (LIBCAF_CORE_SRCS ...@@ -50,6 +50,7 @@ set (LIBCAF_CORE_SRCS
src/get_root_uuid.cpp src/get_root_uuid.cpp
src/group.cpp src/group.cpp
src/group_manager.cpp src/group_manager.cpp
src/match_case.cpp
src/local_actor.cpp src/local_actor.cpp
src/logging.cpp src/logging.cpp
src/mailbox_based_actor.cpp src/mailbox_based_actor.cpp
......
...@@ -46,7 +46,6 @@ ...@@ -46,7 +46,6 @@
#include "caf/to_string.hpp" #include "caf/to_string.hpp"
#include "caf/actor_addr.hpp" #include "caf/actor_addr.hpp"
#include "caf/attachable.hpp" #include "caf/attachable.hpp"
#include "caf/match_expr.hpp"
#include "caf/message_id.hpp" #include "caf/message_id.hpp"
#include "caf/replies_to.hpp" #include "caf/replies_to.hpp"
#include "caf/serializer.hpp" #include "caf/serializer.hpp"
......
...@@ -26,11 +26,11 @@ ...@@ -26,11 +26,11 @@
#include "caf/none.hpp" #include "caf/none.hpp"
#include "caf/duration.hpp" #include "caf/duration.hpp"
#include "caf/match_expr.hpp"
#include "caf/timeout_definition.hpp" #include "caf/timeout_definition.hpp"
#include "caf/detail/type_list.hpp" #include "caf/detail/type_list.hpp"
#include "caf/detail/type_traits.hpp" #include "caf/detail/type_traits.hpp"
#include "caf/detail/behavior_impl.hpp"
namespace caf { namespace caf {
...@@ -59,17 +59,16 @@ class behavior { ...@@ -59,17 +59,16 @@ class behavior {
* The list of arguments can contain match expressions, message handlers, * The list of arguments can contain match expressions, message handlers,
* and up to one timeout (if set, the timeout has to be the last argument). * and up to one timeout (if set, the timeout has to be the last argument).
*/ */
template <class T, class... Ts> template <class V, class... Vs>
behavior(const T& arg, Ts&&... args) { behavior(V v, Vs... vs) {
assign(arg, std::forward<Ts>(args)...); assign(std::move(v), std::move(vs)...);
} }
/** /**
* Creates a behavior from `tdef` without message handler. * Creates a behavior from `tdef` without message handler.
*/ */
template <class F> template <class F>
behavior(const timeout_definition<F>& tdef) behavior(timeout_definition<F> tdef) : m_impl(detail::make_behavior(tdef)) {
: m_impl(detail::new_default_behavior(tdef.timeout, tdef.handler)) {
// nop // nop
} }
...@@ -77,22 +76,29 @@ class behavior { ...@@ -77,22 +76,29 @@ class behavior {
* Creates a behavior using `d` and `f` as timeout definition * Creates a behavior using `d` and `f` as timeout definition
* without message handler. * without message handler.
*/ */
template <class F> //template <class F>
behavior(const duration& d, F f) //behavior(duration d, F f) : m_impl(detail::make_behavior(d, f)) {
: m_impl(detail::new_default_behavior(d, f)) {
// nop // nop
} //}
/** /**
* Assigns new handlers. * Assigns new handlers.
*/ */
template <class T, class... Ts> template <class... Vs>
void assign(T&& v, Ts&&... vs) { void assign(Vs... vs) {
m_impl = detail::match_expr_concat( m_impl = detail::make_behavior(vs...);
detail::lift_to_match_expr(std::forward<T>(v)),
detail::lift_to_match_expr(std::forward<Ts>(vs))...);
} }
/**
* Equal to `*this = other`.
*/
void assign(message_handler other);
/**
* Equal to `*this = other`.
*/
void assign(behavior other);
/** /**
* Invokes the timeout callback if set. * Invokes the timeout callback if set.
*/ */
...@@ -136,22 +142,14 @@ class behavior { ...@@ -136,22 +142,14 @@ class behavior {
// nop // nop
} }
void assign(detail::behavior_impl*);
/** @endcond */ /** @endcond */
private: private:
impl_ptr m_impl; impl_ptr m_impl;
}; };
/**
* Creates a behavior from a match expression and a timeout definition.
* @relates behavior
*/
template <class... Cs, typename F>
behavior operator,(const match_expr<Cs...>& lhs,
const timeout_definition<F>& rhs) {
return {lhs, rhs};
}
} // namespace caf } // namespace caf
#endif // CAF_BEHAVIOR_HPP #endif // CAF_BEHAVIOR_HPP
...@@ -31,33 +31,31 @@ namespace detail { ...@@ -31,33 +31,31 @@ namespace detail {
// this utterly useless function works around a bug in Clang that causes // this utterly useless function works around a bug in Clang that causes
// the compiler to reject the trailing return type of apply_args because // the compiler to reject the trailing return type of apply_args because
// "get" is not defined (it's found during ADL) // "get" is not defined (it's found during ADL)
template<long Pos, class... Ts> template<long Pos, class... Vs>
typename tl_at<type_list<Ts...>, Pos>::type get(const type_list<Ts...>&); typename tl_at<type_list<Vs...>, Pos>::type get(const type_list<Vs...>&);
template <class F, long... Is, class Tuple> template <class F, long... Is, class Tuple>
inline auto apply_args(F& f, detail::int_list<Is...>, Tuple&& tup) auto apply_args(F& f, detail::int_list<Is...>, Tuple&& tup)
-> decltype(f(get<Is>(tup)...)) { -> decltype(f(get<Is>(tup)...)) {
return f(get<Is>(tup)...); return f(get<Is>(tup)...);
} }
template <class F, class Tuple, class... Ts> template <class F, class Tuple, class... Vs>
inline auto apply_args_prefixed(F& f, detail::int_list<>, Tuple&, Ts&&... args) auto apply_args_prefixed(F& f, detail::int_list<>, Tuple&, Vs&&... vs)
-> decltype(f(std::forward<Ts>(args)...)) { -> decltype(f(std::forward<Vs>(vs)...)) {
return f(std::forward<Ts>(args)...); return f(std::forward<Vs>(vs)...);
} }
template <class F, long... Is, class Tuple, class... Ts> template <class F, long... Is, class Tuple, class... Vs>
inline auto apply_args_prefixed(F& f, detail::int_list<Is...>, Tuple& tup, auto apply_args_prefixed(F& f, detail::int_list<Is...>, Tuple& tup, Vs&&... vs)
Ts&&... args) -> decltype(f(std::forward<Vs>(vs)..., get<Is>(tup)...)) {
-> decltype(f(std::forward<Ts>(args)..., get<Is>(tup)...)) { return f(std::forward<Vs>(vs)..., get<Is>(tup)...);
return f(std::forward<Ts>(args)..., get<Is>(tup)...);
} }
template <class F, long... Is, class Tuple, class... Ts> template <class F, long... Is, class Tuple, class... Vs>
inline auto apply_args_suffxied(F& f, detail::int_list<Is...>, Tuple& tup, auto apply_args_suffxied(F& f, detail::int_list<Is...>, Tuple& tup, Vs&&... vs)
Ts&&... args) -> decltype(f(get<Is>(tup)..., std::forward<Vs>(vs)...)) {
-> decltype(f(get<Is>(tup)..., std::forward<Ts>(args)...)) { return f(get<Is>(tup)..., std::forward<Vs>(vs)...);
return f(get<Is>(tup)..., std::forward<Ts>(args)...);
} }
} // namespace detail } // namespace detail
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "caf/none.hpp" #include "caf/none.hpp"
#include "caf/variant.hpp" #include "caf/variant.hpp"
#include "caf/optional.hpp" #include "caf/optional.hpp"
#include "caf/match_case.hpp"
#include "caf/intrusive_ptr.hpp" #include "caf/intrusive_ptr.hpp"
#include "caf/atom.hpp" #include "caf/atom.hpp"
...@@ -41,6 +42,8 @@ ...@@ -41,6 +42,8 @@
#include "caf/detail/int_list.hpp" #include "caf/detail/int_list.hpp"
#include "caf/detail/apply_args.hpp" #include "caf/detail/apply_args.hpp"
#include "caf/detail/type_traits.hpp" #include "caf/detail/type_traits.hpp"
#include "caf/detail/tail_argument_token.hpp"
#include "caf/detail/optional_message_visitor.hpp"
namespace caf { namespace caf {
...@@ -52,115 +55,10 @@ using bhvr_invoke_result = optional<message>; ...@@ -52,115 +55,10 @@ using bhvr_invoke_result = optional<message>;
namespace caf { namespace caf {
namespace detail { namespace detail {
template <class T>
struct is_message_id_wrapper {
template <class U>
static char (&test(typename U::message_id_wrapper_tag))[1];
template <class U>
static char (&test(...))[2];
static constexpr bool value = sizeof(test<T>(0)) == 1;
};
template <class T>
struct is_response_promise : std::false_type { };
template <>
struct is_response_promise<response_promise> : std::true_type { };
template <class T>
struct is_response_promise<typed_response_promise<T>> : std::true_type { };
template <class T>
struct optional_message_visitor_enable_tpl {
static constexpr bool value =
!detail::is_one_of<
typename std::remove_const<T>::type,
none_t,
unit_t,
skip_message_t,
optional<skip_message_t>
>::value
&& !is_message_id_wrapper<T>::value
&& !std::is_convertible<T, message>::value
&& !is_response_promise<T>::value;
};
struct optional_message_visitor : static_visitor<bhvr_invoke_result> {
inline bhvr_invoke_result operator()(const none_t&) const {
return none;
}
inline bhvr_invoke_result operator()(const skip_message_t&) const {
return none;
}
inline bhvr_invoke_result operator()(const unit_t&) const {
return message{};
}
inline bhvr_invoke_result operator()(const optional<skip_message_t>& val) const {
if (val) return none;
return message{};
}
inline bhvr_invoke_result operator()(const response_promise&) const {
return message{};
}
template <class T>
inline bhvr_invoke_result operator()(const typed_response_promise<T>&) const {
return message{};
}
template <class T, class... Ts>
typename std::enable_if<
optional_message_visitor_enable_tpl<T>::value,
bhvr_invoke_result
>::type
operator()(T& v, Ts&... vs) const {
return make_message(std::move(v), std::move(vs)...);
}
template <class T>
typename std::enable_if<
is_message_id_wrapper<T>::value,
bhvr_invoke_result
>::type
operator()(T& value) const {
return make_message(atom("MESSAGE_ID"),
value.get_message_id().integer_value());
}
inline bhvr_invoke_result operator()(message& value) const {
return std::move(value);
}
template <class L, class R>
bhvr_invoke_result operator()(either_or_t<L, R>& value) const {
return std::move(value.value);
}
template <class... Ts>
bhvr_invoke_result operator()(std::tuple<Ts...>& value) const {
return detail::apply_args(*this, detail::get_indices(value), value);
}
template <class T>
typename std::enable_if<
std::is_convertible<T, message>::value,
bhvr_invoke_result
>::type
operator()(const T& value) const {
return static_cast<message>(value);
}
};
template <class... Ts> template <class... Ts>
struct has_skip_message { struct has_skip_message {
static constexpr bool value = static constexpr bool value =
detail::disjunction<std::is_same<Ts, skip_message_t>::value...>::value; disjunction<std::is_same<Ts, skip_message_t>::value...>::value;
}; };
class behavior_impl : public ref_counted { class behavior_impl : public ref_counted {
...@@ -168,10 +66,10 @@ class behavior_impl : public ref_counted { ...@@ -168,10 +66,10 @@ class behavior_impl : public ref_counted {
using pointer = intrusive_ptr<behavior_impl>; using pointer = intrusive_ptr<behavior_impl>;
~behavior_impl(); ~behavior_impl();
behavior_impl() = default;
behavior_impl(duration tout);
virtual bhvr_invoke_result invoke(message&) = 0; behavior_impl(duration tout = duration{});
virtual bhvr_invoke_result invoke(message&);
inline bhvr_invoke_result invoke(message&& arg) { inline bhvr_invoke_result invoke(message&& arg) {
message tmp(std::move(arg)); message tmp(std::move(arg));
...@@ -188,48 +86,53 @@ class behavior_impl : public ref_counted { ...@@ -188,48 +86,53 @@ class behavior_impl : public ref_counted {
pointer or_else(const pointer& other); pointer or_else(const pointer& other);
private: protected:
duration m_timeout; duration m_timeout;
match_case_info* m_begin;
match_case_info* m_end;
}; };
struct dummy_match_expr { template <size_t Pos, size_t Size>
inline variant<none_t> invoke(const message&) const { struct defaut_bhvr_impl_init {
return none; template <class Array, class Tuple>
static void init(Array& arr, Tuple& tup) {
auto& x = arr[Pos];
x.ptr = &std::get<Pos>(tup);
x.has_wildcard = x.ptr->has_wildcard();
x.type_token = x.ptr->type_token();
defaut_bhvr_impl_init<Pos + 1, Size>::init(arr, tup);
} }
inline bool can_invoke(const message&) const { };
return false;
} template <size_t Size>
inline variant<none_t> operator()(const message&) const { struct defaut_bhvr_impl_init<Size, Size> {
return none; template <class Array, class Tuple>
static void init(Array&, Tuple&) {
// nop
} }
}; };
template <class MatchExpr, class F = std::function<void()>>
template <class Tuple>
class default_behavior_impl : public behavior_impl { class default_behavior_impl : public behavior_impl {
public: public:
template <class Expr> static constexpr size_t num_cases = std::tuple_size<Tuple>::value;
default_behavior_impl(Expr&& expr, const timeout_definition<F>& d)
: behavior_impl(d.timeout) default_behavior_impl(Tuple tup) : m_cases(std::move(tup)) {
, m_expr(std::forward<Expr>(expr)) init();
, m_fun(d.handler) {}
template <class Expr>
default_behavior_impl(Expr&& expr, duration tout, F f)
: behavior_impl(tout),
m_expr(std::forward<Expr>(expr)),
m_fun(f) {
// nop
} }
bhvr_invoke_result invoke(message& msg) override { template <class F>
auto res = m_expr(msg); default_behavior_impl(Tuple tup, timeout_definition<F> d)
optional_message_visitor omv; : behavior_impl(d.timeout),
return apply_visitor(omv, res); m_cases(std::move(tup)),
m_fun(d.handler) {
init();
} }
typename behavior_impl::pointer typename behavior_impl::pointer
copy(const generic_timeout_definition& tdef) const override { copy(const generic_timeout_definition& tdef) const override {
return new default_behavior_impl<MatchExpr>(m_expr, tdef); return new default_behavior_impl<Tuple>(m_cases, tdef);
} }
void handle_timeout() override { void handle_timeout() override {
...@@ -237,29 +140,107 @@ class default_behavior_impl : public behavior_impl { ...@@ -237,29 +140,107 @@ class default_behavior_impl : public behavior_impl {
} }
private: private:
MatchExpr m_expr; void init() {
F m_fun; defaut_bhvr_impl_init<0, num_cases>::init(m_arr, m_cases);
m_begin = m_arr.data();
m_end = m_begin + m_arr.size();
}
Tuple m_cases;
std::array<match_case_info, num_cases> m_arr;
std::function<void()> m_fun;
}; };
template <class MatchExpr, typename F> // eor = end of recursion
default_behavior_impl<MatchExpr, F>* // ra = reorganize arguments
new_default_behavior(const MatchExpr& mexpr, duration d, F f) {
return new default_behavior_impl<MatchExpr, F>(mexpr, d, f); template <class R, class... Ts>
R* make_behavior_eor(std::tuple<Ts...> match_cases) {
return new R(std::move(match_cases));
}
template <class R, class... Ts, class F>
R* make_behavior_eor(std::tuple<Ts...> match_cases, timeout_definition<F>& td) {
return new R(std::move(match_cases), std::move(td));
} }
template <class F, bool IsMC = std::is_base_of<match_case, F>::value>
struct lift_to_mctuple {
using type = std::tuple<trivial_match_case<F>>;
};
template <class T>
struct lift_to_mctuple<T, true> {
using type = std::tuple<T>;
};
template <class... Ts>
struct lift_to_mctuple<std::tuple<Ts...>, false> {
using type = std::tuple<Ts...>;
};
template <class F> template <class F>
behavior_impl* new_default_behavior(duration d, F f) { struct lift_to_mctuple<timeout_definition<F>, false> {
dummy_match_expr nop; using type = std::tuple<>;
return new default_behavior_impl<dummy_match_expr, F>(nop, d, std::move(f)); };
template <class T, class... Ts>
struct join_std_tuples;
template <class T>
struct join_std_tuples<T> {
using type = T;
};
template <class... Ts, class... Us, class... Rs>
struct join_std_tuples<std::tuple<Ts...>, std::tuple<Us...>, Rs...>
: join_std_tuples<std::tuple<Ts..., Us...>, Rs...> {
// nop
};
// this function reorganizes its arguments to shift the timeout definition
// to the front (receives it at the tail)
template <class R, class F, class... Vs>
R* make_behavior_ra(timeout_definition<F>& tdef,
tail_argument_token&, Vs... vs) {
return make_behavior_eor<R>(std::tuple_cat(to_match_case_tuple(vs)...), tdef);
} }
behavior_impl* new_default_behavior(duration d, std::function<void()> fun); template <class R, class... Vs>
R* make_behavior_ra(tail_argument_token&, Vs... vs) {
return make_behavior_eor<R>(std::tuple_cat(to_match_case_tuple(vs)...));
}
using behavior_impl_ptr = intrusive_ptr<behavior_impl>; // for some reason, this call is ambigious on GCC without enable_if
template <class R, class V, class... Vs>
typename std::enable_if<
!std::is_same<V, tail_argument_token>::value,
R*
>::type
make_behavior_ra(V& v, Vs&... vs) {
return make_behavior_ra<R>(vs..., v);
}
// implemented in message_handler.cpp // this function reorganizes its arguments to shift the timeout definition
// message_handler combine(behavior_impl_ptr, behavior_impl_ptr); // to the front (receives it at the tail)
// behavior_impl_ptr extract(const message_handler&); template <class... Vs>
default_behavior_impl<
typename join_std_tuples<
typename lift_to_mctuple<Vs>::type...
>::type
>*
make_behavior(Vs&... vs) {
using result_type =
default_behavior_impl<
typename join_std_tuples<
typename lift_to_mctuple<Vs>::type...
>::type
>;
tail_argument_token eoa;
return make_behavior_ra<result_type>(vs..., eoa);
}
using behavior_impl_ptr = intrusive_ptr<behavior_impl>;
} // namespace detail } // namespace detail
} // namespace caf } // namespace caf
......
...@@ -56,6 +56,28 @@ struct il_right<int_list<Is...>, N> { ...@@ -56,6 +56,28 @@ struct il_right<int_list<Is...>, N> {
sizeof...(Is), Is...>::type; sizeof...(Is), Is...>::type;
}; };
template <bool Done, size_t Num, class List, long... Is>
struct il_take_impl;
template <class List, long... Is>
struct il_take_impl<true, 0, List, Is...> {
using type = List;
};
template <size_t Num, long... Rs, long I, long... Is>
struct il_take_impl<false, Num, int_list<Rs...>, I, Is...> {
using type = typename il_take_impl<Num == 1, Num - 1, int_list<Rs..., I>, Is...>::type;
};
template <class List, size_t N>
struct il_take;
template <long... Is, size_t N>
struct il_take<int_list<Is...>, N> {
using type = typename il_take_impl<N == 0, N, int_list<>, Is...>::type;
};
/** /**
* Creates indices for `List` beginning at `Pos`. * Creates indices for `List` beginning at `Pos`.
*/ */
......
...@@ -31,25 +31,21 @@ namespace detail { ...@@ -31,25 +31,21 @@ namespace detail {
template <class Left, typename Right> template <class Left, typename Right>
struct left_or_right { struct left_or_right {
using type = Left; using type = Left;
}; };
template <class Right> template <class Right>
struct left_or_right<unit_t, Right> { struct left_or_right<unit_t, Right> {
using type = Right; using type = Right;
}; };
template <class Right> template <class Right>
struct left_or_right<unit_t&, Right> { struct left_or_right<unit_t&, Right> {
using type = Right; using type = Right;
}; };
template <class Right> template <class Right>
struct left_or_right<const unit_t&, Right> { struct left_or_right<const unit_t&, Right> {
using type = Right; using type = Right;
}; };
/** /**
...@@ -58,13 +54,11 @@ struct left_or_right<const unit_t&, Right> { ...@@ -58,13 +54,11 @@ struct left_or_right<const unit_t&, Right> {
template <class Left, typename Right> template <class Left, typename Right>
struct if_not_left { struct if_not_left {
using type = unit_t; using type = unit_t;
}; };
template <class Right> template <class Right>
struct if_not_left<unit_t, Right> { struct if_not_left<unit_t, Right> {
using type = Right; using type = Right;
}; };
} // namespace detail } // namespace detail
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2015 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_DETAIL_MESSAGE_CASE_BUILDER_HPP
#define CAF_DETAIL_MESSAGE_CASE_BUILDER_HPP
#include <type_traits>
#include "caf/duration.hpp"
#include "caf/match_case.hpp"
#include "caf/timeout_definition.hpp"
namespace caf {
namespace detail {
class timeout_definition_builder {
public:
constexpr timeout_definition_builder(const duration& d) : m_tout(d) {
// nop
}
template <class F>
timeout_definition<F> operator>>(F f) const {
return {m_tout, std::move(f)};
}
private:
duration m_tout;
};
class message_case_builder { };
class trivial_match_case_builder : public message_case_builder {
public:
constexpr trivial_match_case_builder() {
// nop
}
template <class F>
trivial_match_case<F> operator>>(F f) const {
return {std::move(f)};
}
};
class catch_all_match_case_builder : public message_case_builder {
public:
constexpr catch_all_match_case_builder() {
// nop
}
const catch_all_match_case_builder& operator()() const {
return *this;
}
template <class F>
catch_all_match_case<F> operator>>(F f) const {
return {std::move(f)};
}
};
template <class Left, class Right>
class message_case_pair_builder : public message_case_builder {
public:
message_case_pair_builder(Left l, Right r)
: m_left(std::move(l)),
m_right(std::move(r)) {
// nop
}
template <class F>
auto operator>>(F f) const
-> std::tuple<decltype(*static_cast<Left*>(nullptr) >> f),
decltype(*static_cast<Right*>(nullptr) >> f)> {
return std::make_tuple(m_left >> f, m_right >> f);
}
private:
Left m_left;
Right m_right;
};
struct tuple_maker {
template <class... Ts>
inline auto operator()(Ts&&... args)
-> decltype(std::make_tuple(std::forward<Ts>(args)...)) {
return std::make_tuple(std::forward<Ts>(args)...);
}
};
struct variadic_ctor {};
template <class Expr, class Transformers, class Pattern>
struct get_advanced_match_case {
using ctrait = typename get_callable_trait<Expr>::type;
using filtered_pattern =
typename tl_filter_not_type<
Pattern,
anything
>::type;
using padded_transformers =
typename tl_pad_right<
Transformers,
tl_size<filtered_pattern>::value
>::type;
using base_signature =
typename tl_map<
filtered_pattern,
std::add_const,
std::add_lvalue_reference
>::type;
using padded_expr_args =
typename tl_map_conditional<
typename tl_pad_left<
typename ctrait::arg_types,
tl_size<filtered_pattern>::value
>::type,
std::is_lvalue_reference,
false,
std::add_const,
std::add_lvalue_reference
>::type;
// override base signature with required argument types of Expr
// and result types of transformation
using partial_fun_signature =
typename tl_zip<
typename tl_map<
padded_transformers,
map_to_result_type,
rm_optional,
std::add_lvalue_reference
>::type,
typename tl_zip<
padded_expr_args,
base_signature,
left_or_right
>::type,
left_or_right
>::type;
// 'inherit' mutable references from partial_fun_signature
// for arguments without transformation
using projection_signature =
typename tl_zip<
typename tl_zip<
padded_transformers,
partial_fun_signature,
if_not_left
>::type,
base_signature,
deduce_ref_type
>::type;
using type =
advanced_match_case_impl<
Expr,
Pattern,
padded_transformers,
projection_signature
>;
};
template <class X, class Y>
struct pattern_projection_zipper {
using type = Y;
};
template <class Y>
struct pattern_projection_zipper<anything, Y> {
using type = none_t;
};
template <class Projections, class Pattern,
bool UsesArgMatch =
std::is_same<
arg_match_t,
typename tl_back<Pattern>::type
>::value>
class advanced_match_case_builder : public message_case_builder {
public:
using guards_tuple =
typename tl_apply<
// discard projection if at the same index in Pattern is a wildcard
typename tl_filter_not_type<
typename tl_zip<Pattern, Projections, pattern_projection_zipper>::type,
none_t
>::type,
std::tuple
>::type;
advanced_match_case_builder() = default;
template <class... Fs>
advanced_match_case_builder(variadic_ctor, Fs... fs)
: m_guards(make_guards(Pattern{}, fs...)) {
// nop
}
advanced_match_case_builder(guards_tuple arg1) : m_guards(std::move(arg1)) {
// nop
}
template <class F>
typename get_advanced_match_case<F, Projections, Pattern>::type
operator>>(F f) const {
return {f, m_guards};
}
private:
template <class... Fs>
static guards_tuple make_guards(tail_argument_token&, Fs&... fs) {
return std::make_tuple(std::move(fs)...);
}
template <class T, class F, class... Fs>
static guards_tuple make_guards(std::pair<wrapped<T>, F> x, Fs&&... fs) {
return make_guards(std::forward<Fs>(fs)..., x.second);
}
template <class F, class... Fs>
static guards_tuple make_guards(std::pair<wrapped<anything>, F>, Fs&&... fs) {
return make_guards(std::forward<Fs>(fs)...);
}
template <class... Ts, class... Fs>
static guards_tuple make_guards(type_list<Ts...>, Fs&... fs) {
tail_argument_token eoa;
return make_guards(std::make_pair(wrapped<Ts>(), std::ref(fs))..., eoa);
}
guards_tuple m_guards;
};
template <class Projections, class Pattern>
struct advanced_match_case_builder<Projections, Pattern, true>
: public message_case_builder {
public:
using guards_tuple =
typename detail::tl_apply<
typename tl_pop_back<Projections>::type,
std::tuple
>::type;
using pattern = typename tl_pop_back<Pattern>::type;
advanced_match_case_builder() = default;
template <class... Fs>
advanced_match_case_builder(variadic_ctor, Fs... fs)
: m_guards(make_guards(Pattern{}, fs...)) {
// nop
}
advanced_match_case_builder(guards_tuple arg1) : m_guards(std::move(arg1)) {
// nop
}
template <class F>
typename get_advanced_match_case<
F,
Projections,
typename tl_concat<
pattern,
typename tl_map<
typename get_callable_trait<F>::arg_types,
std::decay
>::type
>::type
>::type
operator>>(F f) const {
using padding =
typename tl_apply<
typename tl_replicate<get_callable_trait<F>::num_args, unit_t>::type,
std::tuple
>::type;
return {f, std::tuple_cat(m_guards, padding{})};
}
private:
static guards_tuple make_guards(tail_argument_token&) {
return {};
}
template <class F, class... Fs>
static guards_tuple make_guards(std::pair<wrapped<arg_match_t>, F>,
tail_argument_token&, Fs&... fs) {
return std::make_tuple(std::move(fs)...);
}
template <class T, class F, class... Fs>
static guards_tuple make_guards(std::pair<wrapped<T>, F> x, Fs&&... fs) {
return make_guards(std::forward<Fs>(fs)..., x.second);
}
template <class F, class... Fs>
static guards_tuple make_guards(std::pair<wrapped<anything>, F>, Fs&&... fs) {
return make_guards(std::forward<Fs>(fs)...);
}
template <class... Ts, class... Fs>
static guards_tuple make_guards(type_list<Ts...>, Fs&... fs) {
tail_argument_token eoa;
return make_guards(std::make_pair(wrapped<Ts>(), std::ref(fs))..., eoa);
}
guards_tuple m_guards;
};
template <class Left, class Right>
typename std::enable_if<
std::is_base_of<message_case_builder, Left>::value
&& std::is_base_of<message_case_builder, Right>::value,
message_case_pair_builder<Left, Right>
>::type
operator||(Left l, Right r) {
return {l, r};
}
} // namespace detail
} // namespace caf
#endif // CAF_DETAIL_MESSAGE_CASE_BUILDER_HPP
...@@ -17,201 +17,120 @@ ...@@ -17,201 +17,120 @@
* http://www.boost.org/LICENSE_1_0.txt. * * http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/ ******************************************************************************/
#ifndef CAF_DETAIL_LIFTED_FUN_HPP #ifndef CAF_DETAIL_OPTIONAL_MESSAGE_VISITOR_HPP
#define CAF_DETAIL_LIFTED_FUN_HPP #define CAF_DETAIL_OPTIONAL_MESSAGE_VISITOR_HPP
#include "caf/none.hpp" #include "caf/none.hpp"
#include "caf/unit.hpp"
#include "caf/optional.hpp" #include "caf/optional.hpp"
#include "caf/skip_message.hpp" #include "caf/skip_message.hpp"
#include "caf/static_visitor.hpp"
#include "caf/response_promise.hpp"
#include "caf/typed_response_promise.hpp"
#include "caf/detail/int_list.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/detail/tuple_zip.hpp"
#include "caf/detail/apply_args.hpp"
#include "caf/detail/type_traits.hpp" #include "caf/detail/type_traits.hpp"
#include "caf/detail/left_or_right.hpp"
namespace caf { namespace caf {
namespace detail { namespace detail {
struct lifted_fun_zipper {
template <class F, typename T> template <class T>
auto operator()(const F& fun, T& arg) -> decltype(fun(arg)) const { struct is_message_id_wrapper {
return fun(arg); template <class U>
} static char (&test(typename U::message_id_wrapper_tag))[1];
// forward everything as reference if no guard/transformation is set template <class U>
template <class T> static char (&test(...))[2];
auto operator()(const unit_t&, T& arg) const -> decltype(std::ref(arg)) { static constexpr bool value = sizeof(test<T>(0)) == 1;
return std::ref(arg);
}
}; };
template <class T> template <class T>
T& unopt(T& v) { struct is_response_promise : std::false_type { };
return v;
} template <>
struct is_response_promise<response_promise> : std::true_type { };
template <class T>
struct is_response_promise<typed_response_promise<T>> : std::true_type { };
template <class T> template <class T>
T& unopt(optional<T>& v) { struct optional_message_visitor_enable_tpl {
return *v; static constexpr bool value =
} !is_one_of<
typename std::remove_const<T>::type,
inline bool has_none() { none_t,
return false; unit_t,
} skip_message_t,
optional<skip_message_t>
template <class T, class... Ts> >::value
bool has_none(const T&, const Ts&... vs) { && !is_message_id_wrapper<T>::value
return has_none(vs...); && !is_response_promise<T>::value;
} };
template <class T, class... Ts> class optional_message_visitor : public static_visitor<optional<message>> {
bool has_none(const optional<T>& v, const Ts&... vs) {
return !v || has_none(vs...);
}
// allows F to have fewer arguments than the lifted_fun calling it
template <class R, typename F>
class lifted_fun_invoker {
public: public:
using arg_types = typename get_callable_trait<F>::arg_types; optional_message_visitor() = default;
static constexpr size_t num_args = tl_size<arg_types>::value;
using opt_msg = optional<message>;
lifted_fun_invoker(F& fun) : f(fun) { inline opt_msg operator()(const none_t&) const {
// nop return none;
} }
template <class... Ts> inline opt_msg operator()(const skip_message_t&) const {
typename std::enable_if<sizeof...(Ts) == num_args, R>::type
operator()(Ts&... vs) const {
if (has_none(vs...)) {
return none; return none;
} }
return f(unopt(vs)...);
inline opt_msg operator()(const unit_t&) const {
return message{};
} }
template <class T, class... Ts> inline opt_msg operator()(const optional<skip_message_t>& val) const {
typename std::enable_if<(sizeof...(Ts) + 1 > num_args), R>::type if (val) {
operator()(T& v, Ts&... vs) const {
if (has_none(v)) {
return none; return none;
} }
return (*this)(vs...); return message{};
} }
private: inline opt_msg operator()(const response_promise&) const {
F& f; return message{};
};
template <class F>
class lifted_fun_invoker<bool, F> {
public:
using arg_types = typename get_callable_trait<F>::arg_types;
static constexpr size_t num_args = tl_size<arg_types>::value;
lifted_fun_invoker(F& fun) : f(fun) {
// nop
} }
template <class... Ts> template <class T>
typename std::enable_if<sizeof...(Ts) == num_args, bool>::type inline opt_msg operator()(const typed_response_promise<T>&) const {
operator()(Ts&&... vs) const { return message{};
if (has_none(vs...)) {
return false;
}
f(unopt(vs)...);
return true;
} }
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<
operator()(T&& arg, Ts&&... vs) const { optional_message_visitor_enable_tpl<T>::value,
if (has_none(arg)) { opt_msg
return false; >::type
} operator()(T& v, Ts&... vs) const {
return (*this)(vs...); return make_message(std::move(v), std::move(vs)...);
} }
private: template <class T>
F& f; typename std::enable_if<
}; is_message_id_wrapper<T>::value,
opt_msg
/** >::type
* A lifted functor consists of a set of projections, a plain-old operator()(T& value) const {
* functor and its signature. Note that the signature of the lifted return make_message(atom("MESSAGE_ID"),
* functor might differ from the underlying functor, because value.get_message_id().integer_value());
* of the projections.
*/
template <class F, class ListOfProjections, class... Args>
class lifted_fun {
public:
using plain_result_type = typename get_callable_trait<F>::result_type;
using result_type =
typename std::conditional<
std::is_reference<plain_result_type>::value,
plain_result_type,
typename std::remove_const<plain_result_type>::type
>::type;
// Let F be "R (Ts...)" then lifted_fun<F...> returns optional<R>
// unless R is void in which case bool is returned
using optional_result_type =
typename std::conditional<
std::is_same<result_type, void>::value,
bool,
optional<result_type>
>::type;
using projections_list = ListOfProjections;
using projections = typename tl_apply<projections_list, std::tuple>::type;
using arg_types = type_list<Args...>;
lifted_fun() = default;
lifted_fun(const lifted_fun&) = default;
lifted_fun& operator=(lifted_fun&&) = default;
lifted_fun& operator=(const lifted_fun&) = default;
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)) { template <class L, class R>
// nop opt_msg operator()(either_or_t<L, R>& value) const {
return std::move(value.value);
} }
/** template <class... Ts>
* Invokes `fun` with a lifted_fun of `args.... opt_msg operator()(std::tuple<Ts...>& value) const {
*/ return apply_args(*this, get_indices(value), value);
optional_result_type operator()(Args... args) {
auto indices = get_indices(m_ps);
lifted_fun_zipper zip;
lifted_fun_invoker<optional_result_type, F> invoke{m_fun};
return apply_args(invoke, indices,
tuple_zip(zip, indices, m_ps,
std::forward_as_tuple(args...)));
} }
private:
F m_fun;
projections m_ps;
};
template <class F, class ListOfProjections, class List>
struct get_lifted_fun;
template <class F, class ListOfProjections, class... Ts>
struct get_lifted_fun<F, ListOfProjections, type_list<Ts...>> {
using type = lifted_fun<F, ListOfProjections, Ts...>;
}; };
} // namespace detail } // namespace detail
} // namespace caf } // namespace caf
#endif // CAF_DETAIL_LIFTED_FUN_HPP #endif // CAF_DETAIL_OPTIONAL_MESSAGE_VISITOR_HPP
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2015 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_DETAIL_TAIL_ARGUMENT_TOKEN
#define CAF_DETAIL_TAIL_ARGUMENT_TOKEN
namespace caf {
namespace detail {
struct tail_argument_token { };
} // namespace detail
} // namespace caf
#endif // CAF_DETAIL_TAIL_ARGUMENT_TOKEN
...@@ -17,8 +17,8 @@ ...@@ -17,8 +17,8 @@
* http://www.boost.org/LICENSE_1_0.txt. * * http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/ ******************************************************************************/
#ifndef CAF_DETAIL_MATCHES_HPP #ifndef CAF_DETAIL_TRY_MATCH_HPP
#define CAF_DETAIL_MATCHES_HPP #define CAF_DETAIL_TRY_MATCH_HPP
#include <array> #include <array>
#include <numeric> #include <numeric>
...@@ -93,4 +93,4 @@ bool try_match(const message& msg, const meta_element* pattern_begin, ...@@ -93,4 +93,4 @@ bool try_match(const message& msg, const meta_element* pattern_begin,
} // namespace detail } // namespace detail
} // namespace caf } // namespace caf
#endif // CAF_DETAIL_MATCHES_HPP #endif // CAF_DETAIL_TRY_MATCH_HPP
...@@ -29,8 +29,8 @@ namespace detail { ...@@ -29,8 +29,8 @@ namespace detail {
template <class F, long... Is, class Tup0, class Tup1> template <class F, long... Is, class Tup0, class Tup1>
auto tuple_zip(F& f, detail::int_list<Is...>, Tup0&& tup0, Tup1&& tup1) auto tuple_zip(F& f, detail::int_list<Is...>, Tup0&& tup0, Tup1&& tup1)
-> decltype(std::make_tuple(f(std::get<Is>(tup0), std::get<Is>(tup1))...)) { -> decltype(std::make_tuple(f(get<Is>(tup0), get<Is>(tup1))...)) {
return std::make_tuple(f(std::get<Is>(tup0), std::get<Is>(tup1))...); return std::make_tuple(f(get<Is>(tup0), get<Is>(tup1))...);
} }
} // namespace detail } // namespace detail
......
...@@ -223,12 +223,29 @@ struct tl_slice { ...@@ -223,12 +223,29 @@ struct tl_slice {
}; };
/** /**
* Zips two lists of equal size. * Creates a new list containing the last `N` elements.
*
* Creates a list formed from the two lists `ListA` and `ListB,`
* e.g., tl_zip<type_list<int, double>, type_list<float, string>>::type
* is type_list<type_pair<int, float>, type_pair<double, string>>.
*/ */
template <class List, size_t NewSize, size_t OldSize = tl_size<List>::value>
struct tl_right {
static constexpr size_t first_idx = OldSize > NewSize ? OldSize - NewSize : 0;
using type = typename tl_slice<List, first_idx, OldSize>::type;
};
template <class List, size_t N>
struct tl_right<List, N, N> {
using type = List;
};
template <size_t N>
struct tl_right<empty_type_list, N, 0> {
using type = empty_type_list;
};
template <>
struct tl_right<empty_type_list, 0, 0> {
using type = empty_type_list;
};
template <class ListA, class ListB, template <class ListA, class ListB,
template <class, typename> class Fun = to_type_pair> template <class, typename> class Fun = to_type_pair>
struct tl_zip_impl; struct tl_zip_impl;
...@@ -241,7 +258,14 @@ struct tl_zip_impl<type_list<LhsElements...>, type_list<RhsElements...>, Fun> { ...@@ -241,7 +258,14 @@ struct tl_zip_impl<type_list<LhsElements...>, type_list<RhsElements...>, Fun> {
using type = type_list<typename Fun<LhsElements, RhsElements>::type...>; using type = type_list<typename Fun<LhsElements, RhsElements>::type...>;
}; };
template <class ListA, class ListB, template <class, typename> class Fun> /**
* Zips two lists of equal size.
*
* Creates a list formed from the two lists `ListA` and `ListB,`
* e.g., tl_zip<type_list<int, double>, type_list<float, string>>::type
* is type_list<type_pair<int, float>, type_pair<double, string>>.
*/
template <class ListA, class ListB, template <class, class> class Fun>
struct tl_zip { struct tl_zip {
static constexpr size_t sizea = tl_size<ListA>::value; static constexpr size_t sizea = tl_size<ListA>::value;
static constexpr size_t sizeb = tl_size<ListB>::value; static constexpr size_t sizeb = tl_size<ListB>::value;
...@@ -254,6 +278,19 @@ struct tl_zip { ...@@ -254,6 +278,19 @@ struct tl_zip {
>::type; >::type;
}; };
/**
* Equal to `zip(right(ListA, N), right(ListB, N), Fun)`.
*/
template <class ListA, class ListB, template <class, class> class Fun, size_t N>
struct tl_zip_right {
using type =
typename tl_zip_impl<
typename tl_right<ListA, N>::type,
typename tl_right<ListB, N>::type,
Fun
>::type;
};
template <class ListA, class ListB, template <class ListA, class ListB,
typename PadA = unit_t, typename PadB = unit_t, typename PadA = unit_t, typename PadB = unit_t,
template <class, typename> class Fun = to_type_pair> template <class, typename> class Fun = to_type_pair>
...@@ -509,7 +546,14 @@ struct tl_push_front; ...@@ -509,7 +546,14 @@ struct tl_push_front;
template <class... ListTs, class What> template <class... ListTs, class What>
struct tl_push_front<type_list<ListTs...>, What> { struct tl_push_front<type_list<ListTs...>, What> {
using type = type_list<What, ListTs...>; using type = type_list<What, ListTs...>;
};
/**
* Alias for `tl_push_front<List, What>`.
*/
template <class What, class List>
struct tl_cons : tl_push_front<List, What> {
// nop
}; };
// list map(list, trait) // list map(list, trait)
...@@ -760,21 +804,6 @@ struct tl_is_distinct { ...@@ -760,21 +804,6 @@ struct tl_is_distinct {
tl_size<L>::value == tl_size<typename tl_distinct<L>::type>::value; tl_size<L>::value == tl_size<typename tl_distinct<L>::type>::value;
}; };
/**
* Creates a new list containing the last `N` elements.
*/
template <class List, size_t N>
struct tl_right {
static constexpr size_t list_size = tl_size<List>::value;
static constexpr size_t first_idx = (list_size > N) ? (list_size - N) : 0;
using type = typename tl_slice<List, first_idx, list_size>::type;
};
template <size_t N>
struct tl_right<empty_type_list, N> {
using type = empty_type_list;
};
// list resize(list, size, fill_type) // list resize(list, size, fill_type)
template <class List, bool OldSizeLessNewSize, size_t OldSize, size_t NewSize, template <class List, bool OldSizeLessNewSize, size_t OldSize, size_t NewSize,
...@@ -993,6 +1022,16 @@ struct tl_equal { ...@@ -993,6 +1022,16 @@ struct tl_equal {
&& tl_is_strict_subset<ListB, ListA>::value; && tl_is_strict_subset<ListB, ListA>::value;
}; };
template <size_t N, class T>
struct tl_replicate {
using type = typename tl_cons<T, typename tl_replicate<N - 1, T>::type>::type;
};
template <class T>
struct tl_replicate<0, T> {
using type = type_list<>;
};
} // namespace detail } // namespace detail
} // namespace caf } // namespace caf
......
...@@ -382,6 +382,7 @@ struct get_callable_trait { ...@@ -382,6 +382,7 @@ struct get_callable_trait {
using result_type = typename type::result_type; using result_type = typename type::result_type;
using arg_types = typename type::arg_types; using arg_types = typename type::arg_types;
using fun_type = typename type::fun_type; using fun_type = typename type::fun_type;
static constexpr size_t num_args = tl_size<arg_types>::value;
}; };
/** /**
......
...@@ -22,39 +22,41 @@ ...@@ -22,39 +22,41 @@
#include <memory> #include <memory>
#include "caf/atom.hpp"
#include "caf/detail/wrapped.hpp" #include "caf/detail/wrapped.hpp"
namespace caf { namespace caf {
namespace detail { namespace detail {
// strips `wrapped` and converts `atom_constant` to `atom_value`
template <class T> template <class T>
struct unboxed { struct unboxed {
using type = T; using type = T;
}; };
template <class T> template <class T>
struct unboxed<detail::wrapped<T>> { struct unboxed<detail::wrapped<T>> {
using type = typename detail::wrapped<T>::type; using type = typename detail::wrapped<T>::type;
}; };
template <class T> template <class T>
struct unboxed<detail::wrapped<T>(&)()> { struct unboxed<detail::wrapped<T>(&)()> {
using type = typename detail::wrapped<T>::type; using type = typename detail::wrapped<T>::type;
}; };
template <class T> template <class T>
struct unboxed<detail::wrapped<T>()> { struct unboxed<detail::wrapped<T>()> {
using type = typename detail::wrapped<T>::type; using type = typename detail::wrapped<T>::type;
}; };
template <class T> template <class T>
struct unboxed<detail::wrapped<T>(*)()> { struct unboxed<detail::wrapped<T>(*)()> {
using type = typename detail::wrapped<T>::type; using type = typename detail::wrapped<T>::type;
};
template <atom_value V>
struct unboxed<atom_constant<V>> {
using type = atom_value;
}; };
} // namespace detail } // namespace detail
......
...@@ -26,13 +26,11 @@ namespace detail { ...@@ -26,13 +26,11 @@ namespace detail {
template <class T> template <class T>
struct wrapped { struct wrapped {
using type = T; using type = T;
}; };
template <class T> template <class T>
struct wrapped<wrapped<T>> { struct wrapped<wrapped<T>> {
using type = typename wrapped<T>::type; using type = typename wrapped<T>::type;
}; };
} // namespace detail } // namespace detail
......
...@@ -28,6 +28,9 @@ namespace caf { ...@@ -28,6 +28,9 @@ namespace caf {
template <class> template <class>
class intrusive_ptr; class intrusive_ptr;
template <class>
class optional;
// classes // classes
class actor; class actor;
class group; class group;
......
...@@ -34,7 +34,6 @@ ...@@ -34,7 +34,6 @@
#include "caf/behavior.hpp" #include "caf/behavior.hpp"
#include "caf/spawn_fwd.hpp" #include "caf/spawn_fwd.hpp"
#include "caf/message_id.hpp" #include "caf/message_id.hpp"
#include "caf/match_expr.hpp"
#include "caf/exit_reason.hpp" #include "caf/exit_reason.hpp"
#include "caf/typed_actor.hpp" #include "caf/typed_actor.hpp"
#include "caf/spawn_options.hpp" #include "caf/spawn_options.hpp"
......
This diff is collapsed.
This diff is collapsed.
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <utility> #include <utility>
#include <type_traits> #include <type_traits>
#include "caf/fwd.hpp"
#include "caf/none.hpp" #include "caf/none.hpp"
#include "caf/intrusive_ptr.hpp" #include "caf/intrusive_ptr.hpp"
...@@ -46,6 +47,8 @@ namespace caf { ...@@ -46,6 +47,8 @@ namespace caf {
*/ */
class message_handler { class message_handler {
public: public:
friend class behavior;
message_handler() = default; message_handler() = default;
message_handler(message_handler&&) = default; message_handler(message_handler&&) = default;
message_handler(const message_handler&) = default; message_handler(const message_handler&) = default;
...@@ -88,13 +91,17 @@ class message_handler { ...@@ -88,13 +91,17 @@ class message_handler {
/** /**
* Assigns new message handlers. * Assigns new message handlers.
*/ */
template <class T, class... Ts> template <class... Vs>
void assign(T&& v, Ts&&... vs) { void assign(Vs... vs) {
m_impl = detail::match_expr_concat( static_assert(sizeof...(Vs) > 0, "assign without arguments called");
detail::lift_to_match_expr(std::forward<T>(v)), m_impl = detail::make_behavior(vs...);
detail::lift_to_match_expr(std::forward<Ts>(vs))...);
} }
/**
* Equal to `*this = other`.
*/
void assign(message_handler other);
/** /**
* Runs this handler and returns its (optional) result. * Runs this handler and returns its (optional) result.
*/ */
...@@ -110,7 +117,8 @@ class message_handler { ...@@ -110,7 +117,8 @@ class message_handler {
template <class... Ts> template <class... Ts>
typename std::conditional< typename std::conditional<
detail::disjunction<may_have_timeout< detail::disjunction<may_have_timeout<
typename std::decay<Ts>::type>::value...>::value, typename std::decay<Ts>::type>::value...
>::value,
behavior, behavior,
message_handler message_handler
>::type >::type
...@@ -124,35 +132,13 @@ class message_handler { ...@@ -124,35 +132,13 @@ class message_handler {
if (m_impl) { if (m_impl) {
return m_impl->or_else(tmp.as_behavior_impl()); return m_impl->or_else(tmp.as_behavior_impl());
} }
return tmp; return tmp.as_behavior_impl();
} }
private: private:
impl_ptr m_impl; impl_ptr m_impl;
}; };
/**
* Enables concatenation of message handlers by using a list
* of commata separated handlers.
* @relates message_handler
*/
template <class... Cases>
message_handler operator,(const match_expr<Cases...>& mexpr,
const message_handler& pfun) {
return mexpr.as_behavior_impl()->or_else(pfun.as_behavior_impl());
}
/**
* Enables concatenation of message handlers by using a list
* of commata separated handlers.
* @relates message_handler
*/
template <class... Cases>
message_handler operator,(const message_handler& pfun,
const match_expr<Cases...>& mexpr) {
return pfun.as_behavior_impl()->or_else(mexpr.as_behavior_impl());
}
} // namespace caf } // namespace caf
#endif // CAF_PARTIAL_FUNCTION_HPP #endif // CAF_PARTIAL_FUNCTION_HPP
This diff is collapsed.
...@@ -59,7 +59,6 @@ class invoke_policy { ...@@ -59,7 +59,6 @@ class invoke_policy {
inactive_timeout, // a currently inactive timeout inactive_timeout, // a currently inactive timeout
expired_sync_response, // a sync response that already timed out expired_sync_response, // a sync response that already timed out
timeout, // triggers currently active timeout timeout, // triggers currently active timeout
timeout_response, // triggers timeout of a sync message
ordinary, // an asynchronous message or sync. request ordinary, // an asynchronous message or sync. request
sync_response // a synchronous response sync_response // a synchronous response
}; };
...@@ -76,7 +75,6 @@ class invoke_policy { ...@@ -76,7 +75,6 @@ class invoke_policy {
behavior& fun, behavior& fun,
message_id awaited_response) { message_id awaited_response) {
CAF_LOG_TRACE(""); CAF_LOG_TRACE("");
bool handle_sync_failure_on_mismatch = true;
switch (this->filter_msg(self, *node)) { switch (this->filter_msg(self, *node)) {
case msg_type::normal_exit: case msg_type::normal_exit:
CAF_LOG_DEBUG("dropped normal exit signal"); CAF_LOG_DEBUG("dropped normal exit signal");
...@@ -105,25 +103,29 @@ class invoke_policy { ...@@ -105,25 +103,29 @@ class invoke_policy {
} }
return im_success; return im_success;
} }
case msg_type::timeout_response:
handle_sync_failure_on_mismatch = false;
CAF_ANNOTATE_FALLTHROUGH;
case msg_type::sync_response: case msg_type::sync_response:
CAF_LOG_DEBUG("handle as synchronous response: " CAF_LOG_DEBUG("handle as synchronous response: "
<< CAF_TARG(node->msg, to_string) << ", " << CAF_TARG(node->msg, to_string) << ", "
<< CAF_MARG(node->mid, integer_value) << ", " << CAF_MARG(node->mid, integer_value) << ", "
<< CAF_MARG(awaited_response, integer_value)); << CAF_MARG(awaited_response, integer_value));
if (awaited_response.valid() && node->mid == awaited_response) { if (awaited_response.valid() && node->mid == awaited_response) {
bool is_sync_tout = node->msg.match_elements<sync_timeout_msg>();
node.swap(self->current_mailbox_element()); node.swap(self->current_mailbox_element());
auto res = invoke_fun(self, fun); auto res = invoke_fun(self, fun);
if (!res && handle_sync_failure_on_mismatch) { node.swap(self->current_mailbox_element());
self->mark_arrived(awaited_response);
self->remove_handler(awaited_response);
if (!res) {
if (is_sync_tout) {
CAF_LOG_WARNING("sync timeout occured in actor "
<< "with ID " << self->id());
self->handle_sync_timeout();
} else {
CAF_LOG_WARNING("sync failure occured in actor " CAF_LOG_WARNING("sync failure occured in actor "
<< "with ID " << self->id()); << "with ID " << self->id());
self->handle_sync_failure(); self->handle_sync_failure();
} }
self->mark_arrived(awaited_response); }
self->remove_handler(awaited_response);
node.swap(self->current_mailbox_element());
return im_success; return im_success;
} }
return im_skipped; return im_skipped;
...@@ -220,7 +222,7 @@ class invoke_policy { ...@@ -220,7 +222,7 @@ class invoke_policy {
response_promise fhdl = hdl ? *hdl : self->make_response_promise(); response_promise fhdl = hdl ? *hdl : self->make_response_promise();
behavior inner = *ref_opt; behavior inner = *ref_opt;
ref_opt->assign( 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;
auto inner_res = cpy(self->current_message()); auto inner_res = cpy(self->current_message());
...@@ -243,9 +245,6 @@ class invoke_policy { ...@@ -243,9 +245,6 @@ class invoke_policy {
const message& msg = node.msg; const message& msg = node.msg;
auto mid = node.mid; auto mid = node.mid;
if (mid.is_response()) { if (mid.is_response()) {
if (msg.match_elements<sync_timeout_msg>()) {
return msg_type::timeout_response;
}
return self->awaits(mid) ? msg_type::sync_response return self->awaits(mid) ? msg_type::sync_response
: msg_type::expired_sync_response; : msg_type::expired_sync_response;
} }
......
...@@ -68,17 +68,9 @@ class response_handle<Self, message, nonblocking_response_handle_tag> { ...@@ -68,17 +68,9 @@ class response_handle<Self, message, nonblocking_response_handle_tag> {
// nop // nop
} }
template <class T, class... Ts> template <class... Vs>
continue_helper then(T arg, Ts&&... args) const { continue_helper then(Vs&&... vs) const {
auto selfptr = m_self; behavior bhvr{std::forward<Vs>(vs)...};
behavior bhvr{
std::move(arg),
std::forward<Ts>(args)...,
on<sync_timeout_msg>() >> [selfptr]() -> skip_message_t {
selfptr->handle_sync_timeout();
return skip_message();
}
};
m_self->bhvr_stack().push_back(std::move(bhvr), m_mid); m_self->bhvr_stack().push_back(std::move(bhvr), m_mid);
return {m_mid}; return {m_mid};
} }
...@@ -113,17 +105,12 @@ class response_handle<Self, TypedOutputPair, nonblocking_response_handle_tag> { ...@@ -113,17 +105,12 @@ class response_handle<Self, TypedOutputPair, nonblocking_response_handle_tag> {
static_assert(sizeof...(Fs) > 0, "at least one functor is requried"); static_assert(sizeof...(Fs) > 0, "at least one functor is requried");
static_assert(detail::conjunction<detail::is_callable<Fs>::value...>::value, static_assert(detail::conjunction<detail::is_callable<Fs>::value...>::value,
"all arguments must be callable"); "all arguments must be callable");
static_assert(detail::conjunction<!is_match_expr<Fs>::value...>::value, static_assert(detail::conjunction<
"match expressions are not allowed in this context"); !std::is_base_of<match_case, Fs>::value...
>::value,
"match cases are not allowed in this context");
detail::type_checker<TypedOutputPair, Fs...>::check(); detail::type_checker<TypedOutputPair, Fs...>::check();
auto selfptr = m_self; behavior tmp{std::move(fs)...};
behavior tmp{
fs...,
on<sync_timeout_msg>() >> [selfptr]() -> skip_message_t {
selfptr->handle_sync_timeout();
return {};
}
};
m_self->bhvr_stack().push_back(std::move(tmp), m_mid); m_self->bhvr_stack().push_back(std::move(tmp), m_mid);
return {m_mid}; return {m_mid};
} }
...@@ -151,17 +138,9 @@ class response_handle<Self, message, blocking_response_handle_tag> { ...@@ -151,17 +138,9 @@ class response_handle<Self, message, blocking_response_handle_tag> {
m_self->dequeue_response(bhvr, m_mid); m_self->dequeue_response(bhvr, m_mid);
} }
template <class T, class... Ts> template <class... Vs>
void await(T arg, Ts&&... args) const { void await(Vs&&... vs) const {
auto selfptr = m_self; behavior bhvr{std::forward<Vs>(vs)...};
behavior bhvr{
std::move(arg),
std::forward<Ts>(args)...,
on<sync_timeout_msg>() >> [selfptr]() -> skip_message_t {
selfptr->handle_sync_timeout();
return {};
}
};
m_self->dequeue_response(bhvr, m_mid); m_self->dequeue_response(bhvr, m_mid);
} }
...@@ -199,17 +178,12 @@ class response_handle<Self, OutputPair, blocking_response_handle_tag> { ...@@ -199,17 +178,12 @@ class response_handle<Self, OutputPair, blocking_response_handle_tag> {
"wrong number of functors"); "wrong number of functors");
static_assert(detail::conjunction<detail::is_callable<Fs>::value...>::value, static_assert(detail::conjunction<detail::is_callable<Fs>::value...>::value,
"all arguments must be callable"); "all arguments must be callable");
static_assert(detail::conjunction<!is_match_expr<Fs>::value...>::value, static_assert(detail::conjunction<
"match expressions are not allowed in this context"); !std::is_base_of<match_case, Fs>::value...
>::value,
"match cases are not allowed in this context");
detail::type_checker<OutputPair, Fs...>::check(); detail::type_checker<OutputPair, Fs...>::check();
auto selfptr = m_self; behavior tmp{std::move(fs)...};
behavior tmp{
fs...,
on<sync_timeout_msg>() >> [selfptr]() -> skip_message_t {
selfptr->handle_sync_timeout();
return {};
}
};
m_self->dequeue_response(tmp, m_mid); m_self->dequeue_response(tmp, m_mid);
} }
......
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
#ifndef CAF_MATCH_HINT_HPP #ifndef CAF_MATCH_HINT_HPP
#define CAF_MATCH_HINT_HPP #define CAF_MATCH_HINT_HPP
#include <ostream>
namespace caf { namespace caf {
/** /**
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2015 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_STATIC_VISITOR_HPP
#define CAF_STATIC_VISITOR_HPP
namespace caf {
template <class Result = void>
struct static_visitor {
using result_type = Result;
};
} // namespace caf
#endif // CAF_STATIC_VISITOR_HPP
...@@ -17,12 +17,11 @@ ...@@ -17,12 +17,11 @@
* http://www.boost.org/LICENSE_1_0.txt. * * http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/ ******************************************************************************/
#ifndef TYPED_BEHAVIOR_HPP #ifndef CAF_TYPED_BEHAVIOR_HPP
#define TYPED_BEHAVIOR_HPP #define CAF_TYPED_BEHAVIOR_HPP
#include "caf/either.hpp" #include "caf/either.hpp"
#include "caf/behavior.hpp" #include "caf/behavior.hpp"
#include "caf/match_expr.hpp"
#include "caf/system_messages.hpp" #include "caf/system_messages.hpp"
#include "caf/typed_continue_helper.hpp" #include "caf/typed_continue_helper.hpp"
...@@ -179,13 +178,16 @@ class behavior_stack_based_impl; ...@@ -179,13 +178,16 @@ class behavior_stack_based_impl;
template <class... Rs> template <class... Rs>
class typed_behavior { class typed_behavior {
public:
template <class... OtherRs> template <class... OtherRs>
friend class typed_actor; friend class typed_actor;
template <class, class, class> template <class, class, class>
friend class mixin::behavior_stack_based_impl; friend class mixin::behavior_stack_based_impl;
template <class...> template <class...>
friend class functor_based_typed_actor; friend class functor_based_typed_actor;
public:
typed_behavior(typed_behavior&&) = default; typed_behavior(typed_behavior&&) = default;
typed_behavior(const typed_behavior&) = default; typed_behavior(const typed_behavior&) = default;
typed_behavior& operator=(typed_behavior&&) = default; typed_behavior& operator=(typed_behavior&&) = default;
...@@ -193,17 +195,9 @@ class typed_behavior { ...@@ -193,17 +195,9 @@ class typed_behavior {
using signatures = detail::type_list<Rs...>; using signatures = detail::type_list<Rs...>;
template <class T, class... Ts> template <class... Vs>
typed_behavior(T arg, Ts&&... args) { typed_behavior(Vs... vs) {
set(match_expr_collect( set(detail::make_behavior(vs...));
detail::lift_to_match_expr(std::move(arg)),
detail::lift_to_match_expr(std::forward<Ts>(args))...));
}
template <class... Cs>
typed_behavior& operator=(match_expr<Cs...> expr) {
set(std::move(expr));
return *this;
} }
explicit operator bool() const { explicit operator bool() const {
...@@ -213,29 +207,33 @@ class typed_behavior { ...@@ -213,29 +207,33 @@ class typed_behavior {
/** /**
* Invokes the timeout callback. * Invokes the timeout callback.
*/ */
inline void handle_timeout() { m_bhvr.handle_timeout(); } void handle_timeout() {
m_bhvr.handle_timeout();
}
/** /**
* Returns the duration after which receives using * Returns the duration after which receives using
* this behavior should time out. * this behavior should time out.
*/ */
inline const duration& timeout() const { return m_bhvr.timeout(); } const duration& timeout() const {
return m_bhvr.timeout();
}
private: private:
typed_behavior() = default; typed_behavior() = default;
behavior& unbox() { return m_bhvr; } behavior& unbox() { return m_bhvr; }
template <class... Cs> template <class... Ts>
void set(match_expr<Cs...>&& expr) { void set(detail::default_behavior_impl<std::tuple<Ts...>>* ptr) {
using mpi = using mpi =
typename detail::tl_filter_not< typename detail::tl_filter_not<
detail::type_list<typename detail::deduce_mpi<Cs>::type...>, detail::type_list<typename detail::deduce_mpi<Ts>::type...>,
detail::is_hidden_msg_handler detail::is_hidden_msg_handler
>::type; >::type;
detail::static_asserter<signatures, mpi, detail::ctm>::verify_match(); detail::static_asserter<signatures, mpi, detail::ctm>::verify_match();
// final (type-erasure) step // final (type-erasure) step
m_bhvr = std::move(expr); m_bhvr.assign(static_cast<detail::behavior_impl*>(ptr));
} }
behavior m_bhvr; behavior m_bhvr;
...@@ -243,4 +241,4 @@ class typed_behavior { ...@@ -243,4 +241,4 @@ class typed_behavior {
} // namespace caf } // namespace caf
#endif // TYPED_BEHAVIOR_HPP #endif // CAF_TYPED_BEHAVIOR_HPP
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
#ifndef CAF_VARIANT_HPP #ifndef CAF_VARIANT_HPP
#define CAF_VARIANT_HPP #define CAF_VARIANT_HPP
#include "caf/static_visitor.hpp"
#include "caf/detail/type_list.hpp" #include "caf/detail/type_list.hpp"
#include "caf/detail/type_traits.hpp" #include "caf/detail/type_traits.hpp"
#include "caf/detail/variant_data.hpp" #include "caf/detail/variant_data.hpp"
...@@ -296,11 +298,6 @@ const T* get(const variant<Us...>* value) { ...@@ -296,11 +298,6 @@ const T* get(const variant<Us...>* value) {
return get<T>(const_cast<variant<Us...>*>(value)); return get<T>(const_cast<variant<Us...>*>(value));
} }
template <class Result = void>
struct static_visitor {
using result_type = Result;
};
/** /**
* @relates variant * @relates variant
*/ */
......
...@@ -107,7 +107,7 @@ class timer_actor : public detail::proper_actor<blocking_actor, ...@@ -107,7 +107,7 @@ class timer_actor : public detail::proper_actor<blocking_actor,
[&](const exit_msg&) { [&](const exit_msg&) {
done = true; done = true;
}, },
others() >> [&] { others >> [&] {
CAF_LOG_ERROR("unexpected: " << to_string(msg_ptr->msg)); CAF_LOG_ERROR("unexpected: " << to_string(msg_ptr->msg));
} }
}; };
...@@ -183,7 +183,7 @@ void printer_loop(blocking_actor* self) { ...@@ -183,7 +183,7 @@ void printer_loop(blocking_actor* self) {
[&](const exit_msg&) { [&](const exit_msg&) {
running = false; running = false;
}, },
others() >> [&] { others >> [&] {
std::cerr << "*** unexpected: " << to_string(self->current_message()) std::cerr << "*** unexpected: " << to_string(self->current_message())
<< std::endl; << std::endl;
} }
......
...@@ -28,4 +28,17 @@ behavior::behavior(const message_handler& mh) : m_impl(mh.as_behavior_impl()) { ...@@ -28,4 +28,17 @@ behavior::behavior(const message_handler& mh) : m_impl(mh.as_behavior_impl()) {
// nop // nop
} }
void behavior::assign(message_handler other) {
m_impl.swap(other.m_impl);
}
void behavior::assign(behavior other) {
m_impl.swap(other.m_impl);
}
void behavior::assign(detail::behavior_impl* ptr) {
CAF_REQUIRE(ptr != nullptr);
m_impl.reset(ptr);
}
} // namespace caf } // namespace caf
...@@ -26,7 +26,7 @@ namespace detail { ...@@ -26,7 +26,7 @@ namespace detail {
namespace { namespace {
class combinator : public behavior_impl { class combinator final : 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);
...@@ -50,6 +50,12 @@ class combinator : public behavior_impl { ...@@ -50,6 +50,12 @@ class combinator : public behavior_impl {
// nop // nop
} }
protected:
match_case** get_cases(size_t&) {
// never called
return nullptr;
}
private: private:
pointer first; pointer first;
pointer second; pointer second;
...@@ -61,7 +67,24 @@ behavior_impl::~behavior_impl() { ...@@ -61,7 +67,24 @@ behavior_impl::~behavior_impl() {
// nop // nop
} }
behavior_impl::behavior_impl(duration tout) : m_timeout(tout) { behavior_impl::behavior_impl(duration tout)
: m_timeout(tout),
m_begin(nullptr),
m_end(nullptr) {
// nop
}
bhvr_invoke_result behavior_impl::invoke(message& msg) {
auto msg_token = msg.type_token();
bhvr_invoke_result res;
std::find_if(m_begin, m_end, [&](const match_case_info& x) {
return (x.has_wildcard || x.type_token == msg_token)
&& x.ptr->invoke(res, msg) != match_case::no_match;
});
return res;
}
void behavior_impl::handle_timeout() {
// nop // nop
} }
...@@ -70,10 +93,5 @@ behavior_impl::pointer behavior_impl::or_else(const pointer& other) { ...@@ -70,10 +93,5 @@ behavior_impl::pointer behavior_impl::or_else(const pointer& other) {
return new combinator(this, other); return new combinator(this, other);
} }
behavior_impl* new_default_behavior(duration d, std::function<void()> fun) {
dummy_match_expr nop;
return new default_behavior_impl<dummy_match_expr>(nop, d, std::move(fun));
}
} // namespace detail } // namespace detail
} // namespace caf } // namespace caf
...@@ -159,7 +159,7 @@ class local_broker : public event_based_actor { ...@@ -159,7 +159,7 @@ class local_broker : public event_based_actor {
} }
} }
}, },
others() >> [=] { others >> [=] {
auto msg = current_message(); auto msg = current_message();
CAF_LOGC_TRACE("caf::local_broker", "init$others", CAF_LOGC_TRACE("caf::local_broker", "init$others",
CAF_TARG(msg, to_string)); CAF_TARG(msg, to_string));
...@@ -248,7 +248,7 @@ class proxy_broker : public event_based_actor { ...@@ -248,7 +248,7 @@ class proxy_broker : public event_based_actor {
} }
behavior make_behavior() { behavior make_behavior() {
return {others() >> [=] { return {others >> [=] {
m_group->send_all_subscribers(current_sender(), current_message(), m_group->send_all_subscribers(current_sender(), current_message(),
host()); host());
}}; }};
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2015 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/match_case.hpp"
namespace caf {
match_case::~match_case() {
// nop
}
match_case::match_case(bool hw, uint32_t tt) : m_has_wildcard(hw), m_token(tt) {
// nop
}
} // namespace caf
...@@ -28,30 +28,8 @@ message_handler::message_handler(impl_ptr ptr) : m_impl(std::move(ptr)) { ...@@ -28,30 +28,8 @@ message_handler::message_handler(impl_ptr ptr) : m_impl(std::move(ptr)) {
// nop // nop
} }
void detail::behavior_impl::handle_timeout() { void message_handler::assign(message_handler what) {
// nop m_impl.swap(what.m_impl);
}
} // namespace caf
namespace caf {
namespace detail {
behavior_impl_ptr combine(behavior_impl_ptr lhs, const message_handler& rhs) {
return lhs->or_else(rhs.as_behavior_impl());
}
behavior_impl_ptr combine(const message_handler& lhs, behavior_impl_ptr rhs) {
return lhs.as_behavior_impl()->or_else(rhs);
}
message_handler combine(behavior_impl_ptr lhs, behavior_impl_ptr rhs) {
return lhs->or_else(rhs);
}
behavior_impl_ptr extract(const message_handler& arg) {
return arg.as_behavior_impl();
} }
} // namespace util
} // namespace caf } // namespace caf
...@@ -216,7 +216,7 @@ behavior basp_broker::make_behavior() { ...@@ -216,7 +216,7 @@ behavior basp_broker::make_behavior() {
return make_message(ok_atom::value, request_id); return make_message(ok_atom::value, request_id);
}, },
// catch-all error handler // catch-all error handler
others() >> [=] { others >> [=] {
CAF_LOG_ERROR("received unexpected message: " CAF_LOG_ERROR("received unexpected message: "
<< to_string(current_message())); << to_string(current_message()));
} }
......
...@@ -340,12 +340,12 @@ void broker::close_all() { ...@@ -340,12 +340,12 @@ void broker::close_all() {
} }
} }
bool broker::valid(connection_handle handle) { bool broker::valid(connection_handle hdl) {
return m_scribes.count(handle) > 0; return m_scribes.count(hdl) > 0;
} }
bool broker::valid(accept_handle handle) { bool broker::valid(accept_handle hdl) {
return m_doormen.count(handle) > 0; return m_doormen.count(hdl) > 0;
} }
std::vector<connection_handle> broker::connections() const { std::vector<connection_handle> broker::connections() const {
......
...@@ -21,7 +21,6 @@ add_unit_test(atom) ...@@ -21,7 +21,6 @@ add_unit_test(atom)
add_unit_test(metaprogramming) add_unit_test(metaprogramming)
add_unit_test(intrusive_containers) add_unit_test(intrusive_containers)
add_unit_test(match) add_unit_test(match)
add_unit_test(match_expr)
add_unit_test(message) add_unit_test(message)
add_unit_test(serialization) add_unit_test(serialization)
add_unit_test(uniform_type) add_unit_test(uniform_type)
......
...@@ -31,7 +31,7 @@ behavior ping_behavior(local_actor* self, size_t num_pings) { ...@@ -31,7 +31,7 @@ behavior ping_behavior(local_actor* self, size_t num_pings) {
} }
return make_message(ping_atom::value, value); return make_message(ping_atom::value, value);
}, },
others() >> [=] { others >> [=] {
CAF_LOGF_ERROR("unexpected; " << to_string(self->current_message())); CAF_LOGF_ERROR("unexpected; " << to_string(self->current_message()));
self->quit(exit_reason::user_shutdown); self->quit(exit_reason::user_shutdown);
} }
...@@ -44,7 +44,7 @@ behavior pong_behavior(local_actor* self) { ...@@ -44,7 +44,7 @@ behavior pong_behavior(local_actor* self) {
CAF_PRINT("received {'ping', " << value << "}"); CAF_PRINT("received {'ping', " << value << "}");
return make_message(pong_atom::value, value + 1); return make_message(pong_atom::value, value + 1);
}, },
others() >> [=] { others >> [=] {
CAF_LOGF_ERROR("unexpected; " << to_string(self->current_sender())); CAF_LOGF_ERROR("unexpected; " << to_string(self->current_sender()));
self->quit(exit_reason::user_shutdown); self->quit(exit_reason::user_shutdown);
} }
......
...@@ -38,7 +38,7 @@ void testee::on_exit() { ...@@ -38,7 +38,7 @@ void testee::on_exit() {
behavior testee::make_behavior() { behavior testee::make_behavior() {
return { return {
others() >> [=] { others >> [=] {
return current_message(); return current_message();
} }
}; };
......
...@@ -102,7 +102,7 @@ int main() { ...@@ -102,7 +102,7 @@ int main() {
CAF_CHECK(matched_pattern[0] && matched_pattern[1] && matched_pattern[2]); CAF_CHECK(matched_pattern[0] && matched_pattern[1] && matched_pattern[2]);
self->receive( self->receive(
// "erase" message { atom("b"), atom("a"), atom("c"), 23.f } // "erase" message { atom("b"), atom("a"), atom("c"), 23.f }
others() >> CAF_CHECKPOINT_CB(), others >> CAF_CHECKPOINT_CB(),
after(std::chrono::seconds(0)) >> CAF_UNEXPECTED_TOUT_CB() after(std::chrono::seconds(0)) >> CAF_UNEXPECTED_TOUT_CB()
); );
atom_value x = atom("abc"); atom_value x = atom("abc");
...@@ -112,7 +112,7 @@ int main() { ...@@ -112,7 +112,7 @@ int main() {
self->send(self, msg); self->send(self, msg);
self->receive( self->receive(
on(atom("abc")) >> CAF_CHECKPOINT_CB(), on(atom("abc")) >> CAF_CHECKPOINT_CB(),
others() >> CAF_UNEXPECTED_MSG_CB_REF(self) others >> CAF_UNEXPECTED_MSG_CB_REF(self)
); );
test_typed_atom_interface(); test_typed_atom_interface();
return CAF_TEST_RESULT(); return CAF_TEST_RESULT();
......
...@@ -46,9 +46,9 @@ void ping(event_based_actor* self, size_t num_pings) { ...@@ -46,9 +46,9 @@ void ping(event_based_actor* self, size_t num_pings) {
} }
return std::make_tuple(ping_atom::value, value + 1); return std::make_tuple(ping_atom::value, value + 1);
}, },
others() >> CAF_UNEXPECTED_MSG_CB(self)); others >> CAF_UNEXPECTED_MSG_CB(self));
}, },
others() >> CAF_UNEXPECTED_MSG_CB(self) others >> CAF_UNEXPECTED_MSG_CB(self)
); );
} }
...@@ -67,12 +67,12 @@ void pong(event_based_actor* self) { ...@@ -67,12 +67,12 @@ void pong(event_based_actor* self) {
CAF_PRINT("received down_msg{" << dm.reason << "}"); CAF_PRINT("received down_msg{" << dm.reason << "}");
self->quit(dm.reason); self->quit(dm.reason);
}, },
others() >> CAF_UNEXPECTED_MSG_CB(self) others >> CAF_UNEXPECTED_MSG_CB(self)
); );
// reply to 'ping' // reply to 'ping'
return std::make_tuple(pong_atom::value, value); return std::make_tuple(pong_atom::value, value);
}, },
others() >> CAF_UNEXPECTED_MSG_CB(self)); others >> CAF_UNEXPECTED_MSG_CB(self));
} }
void peer_fun(broker* self, connection_handle hdl, const actor& buddy) { void peer_fun(broker* self, connection_handle hdl, const actor& buddy) {
...@@ -125,7 +125,7 @@ void peer_fun(broker* self, connection_handle hdl, const actor& buddy) { ...@@ -125,7 +125,7 @@ void peer_fun(broker* self, connection_handle hdl, const actor& buddy) {
self->quit(dm.reason); self->quit(dm.reason);
} }
}, },
others() >> CAF_UNEXPECTED_MSG_CB(self) others >> CAF_UNEXPECTED_MSG_CB(self)
); );
} }
...@@ -141,7 +141,7 @@ behavior peer_acceptor_fun(broker* self, const actor& buddy) { ...@@ -141,7 +141,7 @@ behavior peer_acceptor_fun(broker* self, const actor& buddy) {
on(atom("publish")) >> [=] { on(atom("publish")) >> [=] {
return self->add_tcp_doorman(0, "127.0.0.1").second; return self->add_tcp_doorman(0, "127.0.0.1").second;
}, },
others() >> CAF_UNEXPECTED_MSG_CB(self) others >> CAF_UNEXPECTED_MSG_CB(self)
}; };
} }
...@@ -186,7 +186,7 @@ int main(int argc, char** argv) { ...@@ -186,7 +186,7 @@ int main(int argc, char** argv) {
on() >> [&] { on() >> [&] {
run_server(true, argv[0]); run_server(true, argv[0]);
}, },
others() >> [&] { others >> [&] {
cerr << "usage: " << argv[0] << " [-c PORT]" << endl; cerr << "usage: " << argv[0] << " [-c PORT]" << endl;
} }
}); });
......
...@@ -41,7 +41,7 @@ void test_constructor_attach() { ...@@ -41,7 +41,7 @@ void test_constructor_attach() {
quit(reason); quit(reason);
} }
}, },
others() >> [=] { others >> [=] {
forward_to(m_testee); forward_to(m_testee);
} }
}; };
......
...@@ -14,7 +14,7 @@ class exception_testee : public event_based_actor { ...@@ -14,7 +14,7 @@ class exception_testee : public event_based_actor {
} }
behavior make_behavior() override { behavior make_behavior() override {
return { return {
others() >> [] { others >> [] {
throw std::runtime_error("whatever"); throw std::runtime_error("whatever");
} }
}; };
......
...@@ -49,8 +49,8 @@ void fill_mb(message_builder& mb, const T& v, const Ts&... vs) { ...@@ -49,8 +49,8 @@ void fill_mb(message_builder& mb, const T& v, const Ts&... vs) {
fill_mb(mb.append(v), vs...); fill_mb(mb.append(v), vs...);
} }
template <class Expr, class... Ts> template <class... Ts>
ptrdiff_t invoked(Expr& expr, const Ts&... args) { ptrdiff_t invoked(message_handler expr, const Ts&... args) {
vector<message> msgs; vector<message> msgs;
msgs.push_back(make_message(args...)); msgs.push_back(make_message(args...));
message_builder mb; message_builder mb;
...@@ -106,9 +106,7 @@ void test_custom_projections() { ...@@ -106,9 +106,7 @@ void test_custom_projections() {
guard_called = true; guard_called = true;
return arg; return arg;
}; };
auto expr = ( auto expr = on(guard) >> f(0);
on(guard) >> f(0)
);
CAF_CHECK_EQUAL(invoked(expr, 42), 0); CAF_CHECK_EQUAL(invoked(expr, 42), 0);
CAF_CHECK_EQUAL(guard_called, true); CAF_CHECK_EQUAL(guard_called, true);
} }
......
#include "test.hpp"
#include "caf/all.hpp"
#include "caf/detail/safe_equal.hpp"
using std::cout;
using std::endl;
using namespace caf;
#define CAF_CHECK_VARIANT(Handler, Message, Type, Expected) \
{ \
auto msg = Message; \
auto res = Handler(msg); \
if (get<Type>(&res) == nullptr) { \
CAF_FAILURE("result has invalid type"); \
} else if (!caf::detail::safe_equal(*get<Type>(&res), Expected)) { \
CAF_FAILURE("expected " << Expected << " found " << *get<Type>(&res)); \
} else { \
CAF_CHECKPOINT(); \
} \
} \
static_cast<void>(0)
#define CAF_CHECK_VARIANT_UNIT(Handler, Message) \
{ \
auto msg = Message; \
auto res = Handler(msg); \
if (get<unit_t>(&res) == nullptr) { \
CAF_FAILURE("result has invalid type"); \
} else { \
CAF_CHECKPOINT(); \
} \
} \
static_cast<void>(0)
#define CAF_CHECK_OPT_MSG(Handler, Message, Type, Expected) \
{ \
auto msg = Message; \
auto res = Handler(msg); \
if (!res) { \
CAF_FAILURE("result is none"); \
} else if (!res->match_element<Type>(0)) { \
CAF_FAILURE("result has invalid type: expected: " \
<< typeid(Expected).name() \
<< ", found: " << typeid(Type).name()); \
} else if (!caf::detail::safe_equal(res->get_as<Type>(0), Expected)) { \
CAF_FAILURE("expected " << Expected << " found " \
<< res->get_as<Type>(0)); \
} else { \
CAF_CHECKPOINT(); \
} \
} \
static_cast<void>(0)
#define CAF_CHECK_OPT_MSG_VOID(Call) \
{ \
auto res = Call; \
if (!res) { \
CAF_FAILURE("result has invalid type: optional is none"); \
} else if (!res->empty()) { \
CAF_FAILURE("result has invalid type: tuple is not empty"); \
} else { \
CAF_CHECKPOINT(); \
} \
} \
static_cast<void>(0)
#define CAF_CHECK_OPT_MSG_NONE(Call) \
{ \
auto res = Call; \
if (res) { \
if (res->empty()) { \
CAF_FAILURE("result has invalid type: expected none, " \
<< "found an empty tuple"); \
} else { \
CAF_FAILURE("result has invalid type: expected none, " \
<< "found a non-empty tuple "); \
} \
} else { \
CAF_CHECKPOINT(); \
} \
} \
static_cast<void>(0)
struct printer {
inline void operator()() const{
cout << endl;
}
template<typename V, typename... Vs>
void operator()(const optional<V>& v, const Vs&... vs) const {
if (v) {
cout << *v << " ";
} else {
cout << "[none] ";
}
(*this)(vs...);
}
template<typename V, typename... Vs>
void operator()(const V& v, const Vs&... vs) const {
cout << v << " ";
(*this)(vs...);
}
};
int main() {
CAF_TEST(test_match_expr);
auto g = guarded(std::equal_to<int>{}, 5);
auto t0 = std::make_tuple(unit, g, unit);
auto t1 = std::make_tuple(4, 5, 6);
auto t2 = std::make_tuple(5, 6, 7);
detail::lifted_fun_zipper zip;
auto is = detail::get_indices(t2);
auto r0 = detail::tuple_zip(zip, is, t0, t1);
printer p;
detail::apply_args(p, is, r0);
{ // --- types only ---
// check on() usage
auto m0 = on<int>() >> [](int) {};
// auto m0r0 = m0(make_message(1));
CAF_CHECK_VARIANT_UNIT(m0, make_message(1));
// check lifted functor
auto m1 = detail::lift_to_match_expr([](float) {});
CAF_CHECK_VARIANT_UNIT(m1, make_message(1.f));
// check _.or_else(_)
auto m2 = m0.or_else(m1);
CAF_CHECK_VARIANT_UNIT(m2, make_message(1));
CAF_CHECK_VARIANT_UNIT(m2, make_message(1.f));
// check use of match_expr_concat
auto m3 = detail::match_expr_concat(
m0, m1, detail::lift_to_match_expr([](double) {}));
CAF_CHECK_OPT_MSG_VOID(m3->invoke(make_message(1)));
CAF_CHECK_OPT_MSG_VOID(m3->invoke(make_message(1.f)));
CAF_CHECK_OPT_MSG_VOID(m3->invoke(make_message(1.)));
CAF_CHECK_OPT_MSG_NONE(m3->invoke(make_message("1")));
}
{ // --- same with guards ---
auto m0 = on(1) >> [](int i) { CAF_CHECK_EQUAL(i, 1); };
CAF_CHECK_VARIANT_UNIT(m0, make_message(1));
// check lifted functor
auto m1 = on(1.f) >> [](float) {};
CAF_CHECK_VARIANT_UNIT(m1, make_message(1.f));
// check _.or_else(_)
auto m2 = m0.or_else(m1);
CAF_CHECK_VARIANT_UNIT(m2, make_message(1));
CAF_CHECK_VARIANT_UNIT(m2, make_message(1.f));
// check use of match_expr_concat
auto m3 = detail::match_expr_concat(m0, m1, on(1.) >> [](double) {});
CAF_CHECK_OPT_MSG_VOID(m3->invoke(make_message(1)));
CAF_CHECK_OPT_MSG_NONE(m3->invoke(make_message(2)));
CAF_CHECK_OPT_MSG_VOID(m3->invoke(make_message(1.f)));
CAF_CHECK_OPT_MSG_NONE(m3->invoke(make_message(2.f)));
CAF_CHECK_OPT_MSG_VOID(m3->invoke(make_message(1.)));
CAF_CHECK_OPT_MSG_NONE(m3->invoke(make_message(2.)));
CAF_CHECK_OPT_MSG_NONE(m3->invoke(make_message("1")));
}
{ // --- mixin it up with message_handler
// check on() usage
message_handler m0{on<int>() >> [](int) {}};
CAF_CHECK_OPT_MSG_VOID(m0(make_message(1)));
// check lifted functor
auto m1 = detail::lift_to_match_expr([](float) {});
CAF_CHECK_VARIANT_UNIT(m1, make_message(1.f));
// check _.or_else(_)
auto m2 = m0.or_else(m1);
CAF_CHECK_OPT_MSG_VOID(m2(make_message(1)));
CAF_CHECK_OPT_MSG_VOID(m2(make_message(1.f)));
// check use of match_expr_concat
auto m3 = detail::match_expr_concat(
m0, m1, detail::lift_to_match_expr([](double) {}));
CAF_CHECK_OPT_MSG_VOID(m3->invoke(make_message(1)));
CAF_CHECK_OPT_MSG_VOID(m3->invoke(make_message(1.)));
CAF_CHECK_OPT_MSG_VOID(m3->invoke(make_message(1.f)));
}
{ // --- use match_expr with result ---
auto m4 = on<int>() >> [](int i) { return i; };
CAF_CHECK_VARIANT(m4, make_message(42), int, 42);
auto m5 = on<float>() >> [](float f) { return f; };
CAF_CHECK_VARIANT(m5, make_message(4.2f), float, 4.2f);
auto m6 = m4.or_else(m5);
CAF_CHECK_VARIANT(m6, make_message(4.2f), float, 4.2f);
CAF_CHECK_VARIANT(m6, make_message(42), int, 42);
}
{ // --- storing some match_expr in a behavior ---
behavior m5{on(1) >> [] { return 2; }, on(1.f) >> [] { return 2.f; },
on(1.) >> [] { return 2.; }};
CAF_CHECK_OPT_MSG(m5, make_message(1), int, 2);
CAF_CHECK_OPT_MSG(m5, make_message(1.), double, 2.);
CAF_CHECK_OPT_MSG(m5, make_message(1.f), float, 2.f);
}
return CAF_TEST_RESULT();
}
...@@ -26,7 +26,7 @@ testee::~testee() { ...@@ -26,7 +26,7 @@ testee::~testee() {
behavior testee::make_behavior() { behavior testee::make_behavior() {
return { return {
others() >> [=] { others >> [=] {
CAF_CHECK_EQUAL(current_message().cvals()->get_reference_count(), 2); CAF_CHECK_EQUAL(current_message().cvals()->get_reference_count(), 2);
quit(); quit();
return std::move(current_message()); return std::move(current_message());
...@@ -68,7 +68,7 @@ behavior tester::make_behavior() { ...@@ -68,7 +68,7 @@ behavior tester::make_behavior() {
CAF_CHECK_EQUAL(current_message().cvals()->get_reference_count(), 1); CAF_CHECK_EQUAL(current_message().cvals()->get_reference_count(), 1);
quit(); quit();
}, },
others() >> CAF_UNEXPECTED_MSG_CB(this) others >> CAF_UNEXPECTED_MSG_CB(this)
}; };
} }
......
...@@ -38,19 +38,14 @@ void test_or_else() { ...@@ -38,19 +38,14 @@ void test_or_else() {
CAF_PRINT("run_testee: handle_a.or_else(handle_b), on(\"c\") ..."); CAF_PRINT("run_testee: handle_a.or_else(handle_b), on(\"c\") ...");
run_testee( run_testee(
spawn([=] { spawn([=] {
return ( return handle_a.or_else(handle_b).or_else(on("c") >> [] { return 3; });
handle_a.or_else(handle_b),
on("c") >> [] { return 3; }
);
}) })
); );
CAF_PRINT("run_testee: on(\"a\") ..., handle_b.or_else(handle_c)"); CAF_PRINT("run_testee: on(\"a\") ..., handle_b.or_else(handle_c)");
run_testee( run_testee(
spawn([=] { spawn([=] {
return ( return message_handler{on("a") >> [] { return 1; }}.
on("a") >> [] { return 1; }, or_else(handle_b).or_else(handle_c);
handle_b.or_else(handle_c)
);
}) })
); );
} }
......
...@@ -27,7 +27,7 @@ using string_pair = std::pair<std::string, std::string>; ...@@ -27,7 +27,7 @@ using string_pair = std::pair<std::string, std::string>;
using actor_vector = vector<actor>; using actor_vector = vector<actor>;
void reflector(event_based_actor* self) { void reflector(event_based_actor* self) {
self->become(others() >> [=] { self->become(others >> [=] {
CAF_PRINT("reflect and quit"); CAF_PRINT("reflect and quit");
self->quit(); self->quit();
return self->current_message(); return self->current_message();
...@@ -71,7 +71,7 @@ void spawn5_server_impl(event_based_actor* self, actor client, group grp) { ...@@ -71,7 +71,7 @@ void spawn5_server_impl(event_based_actor* self, actor client, group grp) {
self->quit(); self->quit();
} }
}, },
others() >> [=] { others >> [=] {
CAF_UNEXPECTED_MSG(self); CAF_UNEXPECTED_MSG(self);
self->quit(exit_reason::user_defined); self->quit(exit_reason::user_defined);
}, },
...@@ -91,7 +91,7 @@ void spawn5_server_impl(event_based_actor* self, actor client, group grp) { ...@@ -91,7 +91,7 @@ void spawn5_server_impl(event_based_actor* self, actor client, group grp) {
} }
); );
}, },
others() >> [=] { others >> [=] {
CAF_UNEXPECTED_MSG(self); CAF_UNEXPECTED_MSG(self);
self->quit(exit_reason::user_defined); self->quit(exit_reason::user_defined);
}, },
...@@ -423,7 +423,7 @@ int main(int argc, char** argv) { ...@@ -423,7 +423,7 @@ int main(int argc, char** argv) {
on() >> [&] { on() >> [&] {
test_remote_actor(argv[0], true); test_remote_actor(argv[0], true);
}, },
others() >> [&] { others >> [&] {
CAF_PRINTERR("usage: " << argv[0] << " [-s PORT|-c PORT1 PORT2 GROUP_PORT]"); CAF_PRINTERR("usage: " << argv[0] << " [-s PORT|-c PORT1 PORT2 GROUP_PORT]");
} }
}); });
......
...@@ -10,7 +10,7 @@ using namespace caf; ...@@ -10,7 +10,7 @@ using namespace caf;
void test_serial_reply() { void test_serial_reply() {
auto mirror_behavior = [=](event_based_actor* self) { auto mirror_behavior = [=](event_based_actor* self) {
self->become(others() >> [=]() -> message { self->become(others >> [=]() -> message {
CAF_PRINT("return self->current_message()"); CAF_PRINT("return self->current_message()");
return self->current_message(); return self->current_message();
}); });
...@@ -63,7 +63,7 @@ void test_serial_reply() { ...@@ -63,7 +63,7 @@ void test_serial_reply() {
on(atom("hiho")) >> [] { on(atom("hiho")) >> [] {
CAF_CHECKPOINT(); CAF_CHECKPOINT();
}, },
others() >> CAF_UNEXPECTED_MSG_CB_REF(self) others >> CAF_UNEXPECTED_MSG_CB_REF(self)
); );
self->send_exit(master, exit_reason::user_shutdown); self->send_exit(master, exit_reason::user_shutdown);
} }
......
...@@ -7,7 +7,7 @@ using namespace caf; ...@@ -7,7 +7,7 @@ using namespace caf;
void test_simple_reply_response() { void test_simple_reply_response() {
auto s = spawn([](event_based_actor* self) -> behavior { auto s = spawn([](event_based_actor* self) -> behavior {
return ( return (
others() >> [=]() -> message { others >> [=]() -> message {
CAF_CHECK(self->current_message() == make_message(ok_atom::value)); CAF_CHECK(self->current_message() == make_message(ok_atom::value));
self->quit(); self->quit();
return self->current_message(); return self->current_message();
...@@ -17,7 +17,7 @@ void test_simple_reply_response() { ...@@ -17,7 +17,7 @@ void test_simple_reply_response() {
scoped_actor self; scoped_actor self;
self->send(s, ok_atom::value); self->send(s, ok_atom::value);
self->receive( self->receive(
others() >> [&] { others >> [&] {
CAF_CHECK(self->current_message() == make_message(ok_atom::value)); CAF_CHECK(self->current_message() == make_message(ok_atom::value));
} }
); );
......
...@@ -106,7 +106,7 @@ actor spawn_event_testee2(actor parent) { ...@@ -106,7 +106,7 @@ actor spawn_event_testee2(actor parent) {
struct chopstick : public sb_actor<chopstick> { struct chopstick : public sb_actor<chopstick> {
behavior taken_by(actor whom) { behavior taken_by(actor whom) {
return ( return {
on<atom("take")>() >> [=] { on<atom("take")>() >> [=] {
return atom("busy"); return atom("busy");
}, },
...@@ -116,7 +116,7 @@ struct chopstick : public sb_actor<chopstick> { ...@@ -116,7 +116,7 @@ struct chopstick : public sb_actor<chopstick> {
on(atom("break")) >> [=] { on(atom("break")) >> [=] {
quit(); quit();
} }
); };
} }
behavior available; behavior available;
...@@ -271,7 +271,7 @@ echo_actor::~echo_actor() { ...@@ -271,7 +271,7 @@ echo_actor::~echo_actor() {
behavior echo_actor::make_behavior() { behavior echo_actor::make_behavior() {
return { return {
others() >> [=]() -> message { others >> [=]() -> message {
quit(exit_reason::normal); quit(exit_reason::normal);
return current_message(); return current_message();
} }
...@@ -295,7 +295,7 @@ simple_mirror::~simple_mirror() { ...@@ -295,7 +295,7 @@ simple_mirror::~simple_mirror() {
behavior simple_mirror::make_behavior() { behavior simple_mirror::make_behavior() {
return { return {
others() >> [=] { others >> [=] {
CAF_CHECKPOINT(); CAF_CHECKPOINT();
return current_message(); return current_message();
} }
...@@ -306,7 +306,7 @@ behavior high_priority_testee(event_based_actor* self) { ...@@ -306,7 +306,7 @@ behavior high_priority_testee(event_based_actor* self) {
self->send(self, atom("b")); self->send(self, atom("b"));
self->send(message_priority::high, self, atom("a")); self->send(message_priority::high, self, atom("a"));
// 'a' must be self->received before 'b' // 'a' must be self->received before 'b'
return ( return {
on(atom("b")) >> [=] { on(atom("b")) >> [=] {
CAF_FAILURE("received 'b' before 'a'"); CAF_FAILURE("received 'b' before 'a'");
self->quit(); self->quit();
...@@ -318,11 +318,11 @@ behavior high_priority_testee(event_based_actor* self) { ...@@ -318,11 +318,11 @@ behavior high_priority_testee(event_based_actor* self) {
CAF_CHECKPOINT(); CAF_CHECKPOINT();
self->quit(); self->quit();
}, },
others() >> CAF_UNEXPECTED_MSG_CB(self) others >> CAF_UNEXPECTED_MSG_CB(self)
); );
}, },
others() >> CAF_UNEXPECTED_MSG_CB(self) others >> CAF_UNEXPECTED_MSG_CB(self)
); };
} }
struct high_priority_testee_class : event_based_actor { struct high_priority_testee_class : event_based_actor {
...@@ -349,13 +349,13 @@ struct slave : event_based_actor { ...@@ -349,13 +349,13 @@ struct slave : event_based_actor {
behavior make_behavior() override { behavior make_behavior() override {
link_to(master); link_to(master);
trap_exit(true); trap_exit(true);
return ( return {
[=](const exit_msg& msg) { [=](const exit_msg& msg) {
CAF_PRINT("slave: received exit message"); CAF_PRINT("slave: received exit message");
quit(msg.reason); quit(msg.reason);
}, },
others() >> CAF_UNEXPECTED_MSG_CB(this) others >> CAF_UNEXPECTED_MSG_CB(this)
); };
} }
actor master; actor master;
...@@ -382,7 +382,7 @@ void test_spawn() { ...@@ -382,7 +382,7 @@ void test_spawn() {
CAF_PRINT("test self->receive with zero timeout"); CAF_PRINT("test self->receive with zero timeout");
self->receive ( self->receive (
others() >> CAF_UNEXPECTED_MSG_CB_REF(self), others >> CAF_UNEXPECTED_MSG_CB_REF(self),
after(chrono::seconds(0)) >> [] { /* mailbox empty */ } after(chrono::seconds(0)) >> [] { /* mailbox empty */ }
); );
self->await_all_other_actors_done(); self->await_all_other_actors_done();
...@@ -393,7 +393,7 @@ void test_spawn() { ...@@ -393,7 +393,7 @@ void test_spawn() {
self->send(mirror, "hello mirror"); self->send(mirror, "hello mirror");
self->receive ( self->receive (
on("hello mirror") >> CAF_CHECKPOINT_CB(), on("hello mirror") >> CAF_CHECKPOINT_CB(),
others() >> CAF_UNEXPECTED_MSG_CB_REF(self) others >> CAF_UNEXPECTED_MSG_CB_REF(self)
); );
self->send_exit(mirror, exit_reason::user_shutdown); self->send_exit(mirror, exit_reason::user_shutdown);
self->receive ( self->receive (
...@@ -403,7 +403,7 @@ void test_spawn() { ...@@ -403,7 +403,7 @@ void test_spawn() {
} }
else { CAF_UNEXPECTED_MSG_CB_REF(self); } else { CAF_UNEXPECTED_MSG_CB_REF(self); }
}, },
others() >> CAF_UNEXPECTED_MSG_CB_REF(self) others >> CAF_UNEXPECTED_MSG_CB_REF(self)
); );
self->await_all_other_actors_done(); self->await_all_other_actors_done();
CAF_CHECKPOINT(); CAF_CHECKPOINT();
...@@ -414,7 +414,7 @@ void test_spawn() { ...@@ -414,7 +414,7 @@ void test_spawn() {
self->send(mirror, "hello mirror"); self->send(mirror, "hello mirror");
self->receive ( self->receive (
on("hello mirror") >> CAF_CHECKPOINT_CB(), on("hello mirror") >> CAF_CHECKPOINT_CB(),
others() >> CAF_UNEXPECTED_MSG_CB_REF(self) others >> CAF_UNEXPECTED_MSG_CB_REF(self)
); );
self->send_exit(mirror, exit_reason::user_shutdown); self->send_exit(mirror, exit_reason::user_shutdown);
self->receive ( self->receive (
...@@ -424,7 +424,7 @@ void test_spawn() { ...@@ -424,7 +424,7 @@ void test_spawn() {
} }
else { CAF_UNEXPECTED_MSG(self); } else { CAF_UNEXPECTED_MSG(self); }
}, },
others() >> CAF_UNEXPECTED_MSG_CB_REF(self) others >> CAF_UNEXPECTED_MSG_CB_REF(self)
); );
self->await_all_other_actors_done(); self->await_all_other_actors_done();
CAF_CHECKPOINT(); CAF_CHECKPOINT();
...@@ -436,7 +436,7 @@ void test_spawn() { ...@@ -436,7 +436,7 @@ void test_spawn() {
self->send(mirror, "hello mirror"); self->send(mirror, "hello mirror");
self->receive ( self->receive (
on("hello mirror") >> CAF_CHECKPOINT_CB(), on("hello mirror") >> CAF_CHECKPOINT_CB(),
others() >> CAF_UNEXPECTED_MSG_CB_REF(self) others >> CAF_UNEXPECTED_MSG_CB_REF(self)
); );
self->send_exit(mirror, exit_reason::user_shutdown); self->send_exit(mirror, exit_reason::user_shutdown);
self->receive ( self->receive (
...@@ -446,7 +446,7 @@ void test_spawn() { ...@@ -446,7 +446,7 @@ void test_spawn() {
} }
else { CAF_UNEXPECTED_MSG(self); } else { CAF_UNEXPECTED_MSG(self); }
}, },
others() >> CAF_UNEXPECTED_MSG_CB_REF(self) others >> CAF_UNEXPECTED_MSG_CB_REF(self)
); );
self->await_all_other_actors_done(); self->await_all_other_actors_done();
CAF_CHECKPOINT(); CAF_CHECKPOINT();
...@@ -457,7 +457,7 @@ void test_spawn() { ...@@ -457,7 +457,7 @@ void test_spawn() {
self->send(mecho, "hello echo"); self->send(mecho, "hello echo");
self->receive ( self->receive (
on("hello echo") >> [] { }, on("hello echo") >> [] { },
others() >> CAF_UNEXPECTED_MSG_CB_REF(self) others >> CAF_UNEXPECTED_MSG_CB_REF(self)
); );
self->await_all_other_actors_done(); self->await_all_other_actors_done();
CAF_CHECKPOINT(); CAF_CHECKPOINT();
...@@ -488,7 +488,7 @@ void test_spawn() { ...@@ -488,7 +488,7 @@ void test_spawn() {
self->send(cstk, atom("put"), self); self->send(cstk, atom("put"), self);
self->send(cstk, atom("break")); self->send(cstk, atom("break"));
}, },
others() >> CAF_UNEXPECTED_MSG_CB_REF(self) others >> CAF_UNEXPECTED_MSG_CB_REF(self)
); );
self->await_all_other_actors_done(); self->await_all_other_actors_done();
CAF_CHECKPOINT(); CAF_CHECKPOINT();
...@@ -509,7 +509,7 @@ void test_spawn() { ...@@ -509,7 +509,7 @@ void test_spawn() {
} }
); );
}, },
others() >> CAF_UNEXPECTED_MSG_CB_REF(s) others >> CAF_UNEXPECTED_MSG_CB_REF(s)
); );
}); });
self->monitor(sync_testee); self->monitor(sync_testee);
...@@ -537,7 +537,7 @@ void test_spawn() { ...@@ -537,7 +537,7 @@ void test_spawn() {
self->sync_send(sync_testee, "!?").await( self->sync_send(sync_testee, "!?").await(
on<sync_exited_msg>() >> CAF_CHECKPOINT_CB(), on<sync_exited_msg>() >> CAF_CHECKPOINT_CB(),
others() >> CAF_UNEXPECTED_MSG_CB_REF(self), others >> CAF_UNEXPECTED_MSG_CB_REF(self),
after(chrono::milliseconds(1)) >> CAF_UNEXPECTED_TOUT_CB() after(chrono::milliseconds(1)) >> CAF_UNEXPECTED_TOUT_CB()
); );
...@@ -572,7 +572,7 @@ void test_spawn() { ...@@ -572,7 +572,7 @@ void test_spawn() {
self->send(bob, 1, "hello actor"); self->send(bob, 1, "hello actor");
self->receive ( self->receive (
on(4, "hello actor from Bob from Joe") >> CAF_CHECKPOINT_CB(), on(4, "hello actor from Bob from Joe") >> CAF_CHECKPOINT_CB(),
others() >> CAF_UNEXPECTED_MSG_CB_REF(self) others >> CAF_UNEXPECTED_MSG_CB_REF(self)
); );
// kill joe and bob // kill joe and bob
auto poison_pill = make_message(atom("done")); auto poison_pill = make_message(atom("done"));
...@@ -595,7 +595,7 @@ void test_spawn() { ...@@ -595,7 +595,7 @@ void test_spawn() {
m_pal = spawn<kr34t0r>("Bob", this); m_pal = spawn<kr34t0r>("Bob", this);
} }
return { return {
others() >> [=] { others >> [=] {
// forward message and die // forward message and die
send(m_pal, current_message()); send(m_pal, current_message());
quit(); quit();
...@@ -661,7 +661,7 @@ void test_spawn() { ...@@ -661,7 +661,7 @@ void test_spawn() {
} }
behavior make_behavior() override { behavior make_behavior() override {
return { return {
others() >> CAF_UNEXPECTED_MSG_CB(this) others >> CAF_UNEXPECTED_MSG_CB(this)
}; };
} }
}; };
...@@ -697,7 +697,7 @@ void test_spawn() { ...@@ -697,7 +697,7 @@ void test_spawn() {
CAF_CHECK(val == atom("FooBar")); CAF_CHECK(val == atom("FooBar"));
flags |= 0x08; flags |= 0x08;
}, },
others() >> [&]() { others >> [&]() {
CAF_FAILURE("unexpected message: " << to_string(self->current_message())); CAF_FAILURE("unexpected message: " << to_string(self->current_message()));
}, },
after(chrono::milliseconds(500)) >> [&]() { after(chrono::milliseconds(500)) >> [&]() {
...@@ -808,7 +808,7 @@ void test_constructor_attach() { ...@@ -808,7 +808,7 @@ void test_constructor_attach() {
quit(reason); quit(reason);
} }
}, },
others() >> [=] { others >> [=] {
forward_to(m_testee); forward_to(m_testee);
} }
}; };
...@@ -829,7 +829,7 @@ class exception_testee : public event_based_actor { ...@@ -829,7 +829,7 @@ class exception_testee : public event_based_actor {
} }
behavior make_behavior() override { behavior make_behavior() override {
return { return {
others() >> [] { others >> [] {
throw std::runtime_error("whatever"); throw std::runtime_error("whatever");
} }
}; };
...@@ -929,7 +929,7 @@ int main() { ...@@ -929,7 +929,7 @@ int main() {
// test setting exit reasons for scoped actors // test setting exit reasons for scoped actors
{ // lifetime scope of self { // lifetime scope of self
scoped_actor self; scoped_actor self;
self->spawn<linked>([]() -> behavior { return others() >> [] {}; }); self->spawn<linked>([]() -> behavior { return others >> [] {}; });
self->planned_exit_reason(exit_reason::user_defined); self->planned_exit_reason(exit_reason::user_defined);
} }
await_all_actors_done(); await_all_actors_done();
......
...@@ -25,7 +25,7 @@ using hi_there_atom = atom_constant<atom("HiThere")>; ...@@ -25,7 +25,7 @@ using hi_there_atom = atom_constant<atom("HiThere")>;
struct sync_mirror : event_based_actor { struct sync_mirror : event_based_actor {
behavior make_behavior() override { behavior make_behavior() override {
return { return {
others() >> [=] { others >> [=] {
return current_message(); return current_message();
} }
}; };
...@@ -97,7 +97,7 @@ class A : public popular_actor { ...@@ -97,7 +97,7 @@ class A : public popular_actor {
} }
); );
}, },
others() >> [=] { others >> [=] {
report_failure(); report_failure();
} }
}; };
...@@ -112,7 +112,7 @@ class B : public popular_actor { ...@@ -112,7 +112,7 @@ class B : public popular_actor {
behavior make_behavior() override { behavior make_behavior() override {
return { return {
others() >> [=] { others >> [=] {
CAF_CHECKPOINT(); CAF_CHECKPOINT();
forward_to(buddy()); forward_to(buddy());
quit(); quit();
...@@ -157,9 +157,9 @@ class D : public popular_actor { ...@@ -157,9 +157,9 @@ class D : public popular_actor {
behavior make_behavior() override { behavior make_behavior() override {
return { return {
others() >> [=] { others >> [=] {
return sync_send(buddy(), std::move(current_message())).then( return sync_send(buddy(), std::move(current_message())).then(
others() >> [=]() -> message { others >> [=]() -> message {
quit(); quit();
return std::move(current_message()); return std::move(current_message());
} }
...@@ -199,11 +199,11 @@ class server : public event_based_actor { ...@@ -199,11 +199,11 @@ class server : public event_based_actor {
unbecome(); // await next idle message unbecome(); // await next idle message
}, },
on(idle_atom::value) >> skip_message, on(idle_atom::value) >> skip_message,
others() >> die others >> die
); );
}, },
on(request_atom::value) >> skip_message, on(request_atom::value) >> skip_message,
others() >> die others >> die
}; };
} }
}; };
...@@ -263,7 +263,7 @@ void test_sync_send() { ...@@ -263,7 +263,7 @@ void test_sync_send() {
[&](const down_msg& dm) { [&](const down_msg& dm) {
CAF_CHECK_EQUAL(dm.reason, exit_reason::user_shutdown); CAF_CHECK_EQUAL(dm.reason, exit_reason::user_shutdown);
}, },
others() >> CAF_UNEXPECTED_MSG_CB_REF(self) others >> CAF_UNEXPECTED_MSG_CB_REF(self)
); );
auto mirror = spawn<sync_mirror>(); auto mirror = spawn<sync_mirror>();
bool continuation_called = false; bool continuation_called = false;
...@@ -307,7 +307,7 @@ void test_sync_send() { ...@@ -307,7 +307,7 @@ void test_sync_send() {
CAF_CHECKPOINT(); CAF_CHECKPOINT();
self->timed_sync_send(self, milliseconds(50), no_way_atom::value).await( self->timed_sync_send(self, milliseconds(50), no_way_atom::value).await(
on<sync_timeout_msg>() >> CAF_CHECKPOINT_CB(), on<sync_timeout_msg>() >> CAF_CHECKPOINT_CB(),
others() >> CAF_UNEXPECTED_MSG_CB_REF(self) others >> CAF_UNEXPECTED_MSG_CB_REF(self)
); );
// we should have received two DOWN messages with normal exit reason // we should have received two DOWN messages with normal exit reason
// plus 'NoWay' // plus 'NoWay'
...@@ -321,13 +321,13 @@ void test_sync_send() { ...@@ -321,13 +321,13 @@ void test_sync_send() {
CAF_PRINT("trigger \"actor did not reply to a " CAF_PRINT("trigger \"actor did not reply to a "
"synchronous request message\""); "synchronous request message\"");
}, },
others() >> CAF_UNEXPECTED_MSG_CB_REF(self), others >> CAF_UNEXPECTED_MSG_CB_REF(self),
after(milliseconds(0)) >> CAF_UNEXPECTED_TOUT_CB() after(milliseconds(0)) >> CAF_UNEXPECTED_TOUT_CB()
); );
CAF_CHECKPOINT(); CAF_CHECKPOINT();
// mailbox should be empty now // mailbox should be empty now
self->receive( self->receive(
others() >> CAF_UNEXPECTED_MSG_CB_REF(self), others >> CAF_UNEXPECTED_MSG_CB_REF(self),
after(milliseconds(0)) >> CAF_CHECKPOINT_CB() after(milliseconds(0)) >> CAF_CHECKPOINT_CB()
); );
// check wheter continuations are invoked correctly // check wheter continuations are invoked correctly
...@@ -371,7 +371,7 @@ void test_sync_send() { ...@@ -371,7 +371,7 @@ void test_sync_send() {
CAF_CHECKPOINT(); CAF_CHECKPOINT();
CAF_CHECK_EQUAL(s->current_sender(), work); CAF_CHECK_EQUAL(s->current_sender(), work);
}, },
others() >> [&] { others >> [&] {
CAF_PRINTERR("unexpected message: " << to_string(s->current_message())); CAF_PRINTERR("unexpected message: " << to_string(s->current_message()));
} }
); );
...@@ -383,19 +383,19 @@ void test_sync_send() { ...@@ -383,19 +383,19 @@ void test_sync_send() {
CAF_CHECKPOINT(); CAF_CHECKPOINT();
CAF_CHECK_EQUAL(s->current_sender(), work); CAF_CHECK_EQUAL(s->current_sender(), work);
}, },
others() >> CAF_UNEXPECTED_MSG_CB(s) others >> CAF_UNEXPECTED_MSG_CB(s)
); );
s->send(s, "Ever danced with the devil in the pale moonlight?"); s->send(s, "Ever danced with the devil in the pale moonlight?");
// response: {'EXIT', exit_reason::user_shutdown} // response: {'EXIT', exit_reason::user_shutdown}
s->receive_loop( s->receive_loop(
others() >> CAF_UNEXPECTED_MSG_CB(s) others >> CAF_UNEXPECTED_MSG_CB(s)
); );
}); });
self->receive( self->receive(
[&](const down_msg& dm) { [&](const down_msg& dm) {
CAF_CHECK_EQUAL(dm.reason, exit_reason::user_shutdown); CAF_CHECK_EQUAL(dm.reason, exit_reason::user_shutdown);
}, },
others() >> CAF_UNEXPECTED_MSG_CB_REF(self) others >> CAF_UNEXPECTED_MSG_CB_REF(self)
); );
} }
......
...@@ -38,7 +38,7 @@ class dummy : public event_based_actor { ...@@ -38,7 +38,7 @@ class dummy : public event_based_actor {
} }
behavior make_behavior() override { behavior make_behavior() override {
return { return {
others() >> CAF_UNEXPECTED_MSG_CB(this) others >> CAF_UNEXPECTED_MSG_CB(this)
}; };
} }
}; };
......
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