Commit 715e1999 authored by Dominik Charousset's avatar Dominik Charousset

properly implemented skipping for typed actors

parent 81f824fb
...@@ -186,7 +186,6 @@ set(LIBCPPA_SRC ...@@ -186,7 +186,6 @@ set(LIBCPPA_SRC
src/node_id.cpp src/node_id.cpp
src/object.cpp src/object.cpp
src/object_array.cpp src/object_array.cpp
src/on.cpp
src/opt.cpp src/opt.cpp
src/partial_function.cpp src/partial_function.cpp
src/primitive_variant.cpp src/primitive_variant.cpp
......
...@@ -113,7 +113,7 @@ cppa/mailbox_based.hpp ...@@ -113,7 +113,7 @@ cppa/mailbox_based.hpp
cppa/mailbox_element.hpp cppa/mailbox_element.hpp
cppa/match.hpp cppa/match.hpp
cppa/match_expr.hpp cppa/match_expr.hpp
cppa/match_hint.hpp cppa/skip_message.hpp
cppa/memory_cached.hpp cppa/memory_cached.hpp
cppa/memory_managed.hpp cppa/memory_managed.hpp
cppa/message_header.hpp cppa/message_header.hpp
...@@ -293,7 +293,6 @@ src/middleman_event_handler_poll.cpp ...@@ -293,7 +293,6 @@ src/middleman_event_handler_poll.cpp
src/node_id.cpp src/node_id.cpp
src/object.cpp src/object.cpp
src/object_array.cpp src/object_array.cpp
src/on.cpp
src/opencl/actor_facade.cpp src/opencl/actor_facade.cpp
src/opencl/global.cpp src/opencl/global.cpp
src/opencl/opencl_metainfo.cpp src/opencl/opencl_metainfo.cpp
...@@ -349,3 +348,4 @@ unit_testing/test_typed_remote_actor.cpp ...@@ -349,3 +348,4 @@ unit_testing/test_typed_remote_actor.cpp
unit_testing/test_typed_spawn.cpp unit_testing/test_typed_spawn.cpp
unit_testing/test_uniform_type.cpp unit_testing/test_uniform_type.cpp
unit_testing/test_yield_interface.cpp unit_testing/test_yield_interface.cpp
cppa/may_have_timeout.hpp
...@@ -64,8 +64,6 @@ class behavior { ...@@ -64,8 +64,6 @@ class behavior {
inline behavior(impl_ptr ptr); inline behavior(impl_ptr ptr);
static constexpr bool may_have_timeout = true;
/** @endcond */ /** @endcond */
behavior() = default; behavior() = default;
...@@ -88,6 +86,14 @@ class behavior { ...@@ -88,6 +86,14 @@ class behavior {
template<typename... Cs, typename T, typename... Ts> template<typename... Cs, typename T, typename... Ts>
behavior(const match_expr<Cs...>& arg0, const T& arg1, const Ts&... args); behavior(const match_expr<Cs...>& arg0, const T& arg1, const Ts&... args);
template<typename F,
typename Enable = typename std::enable_if<
util::is_callable<F>::value
&& !std::is_same<F, behavior>::value
&& !std::is_same<F, partial_function>::value
>::type>
behavior(F fun);
/** /**
* @brief Invokes the timeout callback. * @brief Invokes the timeout callback.
*/ */
...@@ -137,6 +143,10 @@ inline behavior operator,(const match_expr<Cs...>& lhs, ...@@ -137,6 +143,10 @@ inline behavior operator,(const match_expr<Cs...>& lhs,
* inline and template member function implementations * * inline and template member function implementations *
******************************************************************************/ ******************************************************************************/
template<typename F, typename Enable>
behavior::behavior(F fun)
: m_impl(detail::match_expr_from_functor(std::move(fun)).as_behavior_impl()) { }
template<typename F> template<typename F>
behavior::behavior(const timeout_definition<F>& arg) behavior::behavior(const timeout_definition<F>& arg)
: m_impl(detail::new_default_behavior(arg.timeout, arg.handler)) { } : m_impl(detail::new_default_behavior(arg.timeout, arg.handler)) { }
...@@ -173,11 +183,6 @@ inline auto behavior::as_behavior_impl() const -> const impl_ptr& { ...@@ -173,11 +183,6 @@ inline auto behavior::as_behavior_impl() const -> const impl_ptr& {
return m_impl; return m_impl;
} }
//template<typename F>
//inline behavior behavior::add_continuation(F fun) {
// return {new detail::continuation_decorator<F>(std::move(fun), m_impl)};
//}
} // namespace cppa } // namespace cppa
#endif // CPPA_BEHAVIOR_HPP #endif // CPPA_BEHAVIOR_HPP
...@@ -70,7 +70,7 @@ class blocking_actor ...@@ -70,7 +70,7 @@ class blocking_actor
void operator()(Ts&&... args) { void operator()(Ts&&... args) {
static_assert(sizeof...(Ts) > 0, static_assert(sizeof...(Ts) > 0,
"operator() requires at least one argument"); "operator() requires at least one argument");
behavior bhvr = match_expr_convert(std::forward<Ts>(args)...); behavior bhvr = lift_and_convert(std::forward<Ts>(args)...);
while (m_stmt()) m_dq(bhvr); while (m_stmt()) m_dq(bhvr);
} }
...@@ -85,7 +85,7 @@ class blocking_actor ...@@ -85,7 +85,7 @@ class blocking_actor
template<typename... Ts> template<typename... Ts>
void operator()(Ts&&... args) { void operator()(Ts&&... args) {
behavior bhvr = match_expr_convert(std::forward<Ts>(args)...); behavior bhvr = lift_and_convert(std::forward<Ts>(args)...);
for ( ; begin != end; ++begin) m_dq(bhvr); for ( ; begin != end; ++begin) m_dq(bhvr);
} }
...@@ -111,7 +111,7 @@ class blocking_actor ...@@ -111,7 +111,7 @@ class blocking_actor
template<typename... Ts> template<typename... Ts>
void receive(Ts&&... args) { void receive(Ts&&... args) {
static_assert(sizeof...(Ts), "at least one argument required"); static_assert(sizeof...(Ts), "at least one argument required");
dequeue(match_expr_convert(std::forward<Ts>(args)...)); dequeue(lift_and_convert(std::forward<Ts>(args)...));
} }
/** /**
...@@ -120,7 +120,7 @@ class blocking_actor ...@@ -120,7 +120,7 @@ class blocking_actor
*/ */
template<typename... Ts> template<typename... Ts>
void receive_loop(Ts&&... args) { void receive_loop(Ts&&... args) {
behavior bhvr = match_expr_convert(std::forward<Ts>(args)...); behavior bhvr = lift_and_convert(std::forward<Ts>(args)...);
for (;;) dequeue(bhvr); for (;;) dequeue(bhvr);
} }
...@@ -192,7 +192,7 @@ class blocking_actor ...@@ -192,7 +192,7 @@ class blocking_actor
template<typename... Ts> template<typename... Ts>
do_receive_helper do_receive(Ts&&... args) { do_receive_helper do_receive(Ts&&... args) {
return { make_dequeue_callback() return { make_dequeue_callback()
, match_expr_convert(std::forward<Ts>(args)...)}; , lift_and_convert(std::forward<Ts>(args)...)};
} }
optional<behavior&> sync_handler(message_id msg_id) override { optional<behavior&> sync_handler(message_id msg_id) override {
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "cppa/on.hpp" #include "cppa/on.hpp"
#include "cppa/behavior.hpp" #include "cppa/behavior.hpp"
#include "cppa/message_id.hpp" #include "cppa/message_id.hpp"
#include "cppa/partial_function.hpp"
namespace cppa { namespace cppa {
......
...@@ -78,9 +78,9 @@ struct optional_any_tuple_visitor { ...@@ -78,9 +78,9 @@ struct optional_any_tuple_visitor {
}; };
template<typename... Ts> template<typename... Ts>
struct has_match_hint { struct has_skip_message {
static constexpr bool value = util::disjunction< static constexpr bool value = util::disjunction<
std::is_same<Ts, match_hint>::value... std::is_same<Ts, skip_message_t>::value...
>::value; >::value;
}; };
...@@ -188,13 +188,10 @@ class default_behavior_impl : public behavior_impl { ...@@ -188,13 +188,10 @@ class default_behavior_impl : public behavior_impl {
private: private:
template<typename... Ts> template<typename... Ts>
typename std::enable_if<has_match_hint<Ts...>::value, bhvr_invoke_result>::type typename std::enable_if<has_skip_message<Ts...>::value, bhvr_invoke_result>::type
eval_res(optional_variant<Ts...>&& res) { eval_res(optional_variant<Ts...>&& res) {
if (res) { if (res) {
if (res.template is<match_hint>()) { if (res.template is<skip_message_t>()) {
if (get<match_hint>(res) == match_hint::handle) {
return any_tuple{};
}
return none; return none;
} }
return apply_visitor(optional_any_tuple_visitor{}, res); return apply_visitor(optional_any_tuple_visitor{}, res);
...@@ -203,7 +200,7 @@ class default_behavior_impl : public behavior_impl { ...@@ -203,7 +200,7 @@ class default_behavior_impl : public behavior_impl {
} }
template<typename... Ts> template<typename... Ts>
typename std::enable_if<!has_match_hint<Ts...>::value, bhvr_invoke_result>::type typename std::enable_if<!has_skip_message<Ts...>::value, bhvr_invoke_result>::type
eval_res(optional_variant<Ts...>&& res) { eval_res(optional_variant<Ts...>&& res) {
return apply_visitor(optional_any_tuple_visitor{}, res); return apply_visitor(optional_any_tuple_visitor{}, res);
} }
......
...@@ -93,25 +93,6 @@ class projection { ...@@ -93,25 +93,6 @@ class projection {
projection(const projection&) = default; projection(const projection&) = default;
/**
* @brief Invokes @p fun with a projection of <tt>args...</tt> and stores
* the result of @p fun in @p result.
*/
/*
template<class PartFun>
bool invoke(PartFun& fun, typename PartFun::result_type& result, Ts... args) const {
typename collected_args_tuple<ProjectionFuns, Ts...>::type pargs;
if (collect(pargs, m_funs, std::forward<Ts>(args)...)) {
auto indices = util::get_indices(pargs);
if (is_defined_at(fun, pargs, indices)) {
result = util::apply_args(fun, pargs, indices);
return true;
}
}
return false;
}
*/
/** /**
* @brief Invokes @p fun with a projection of <tt>args...</tt>. * @brief Invokes @p fun with a projection of <tt>args...</tt>.
*/ */
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
#define CPPA_DETAIL_RESPONSE_FUTURE_UTIL_HPP #define CPPA_DETAIL_RESPONSE_FUTURE_UTIL_HPP
#include "cppa/on.hpp" #include "cppa/on.hpp"
#include "cppa/match_hint.hpp" #include "cppa/skip_message.hpp"
#include "cppa/system_messages.hpp" #include "cppa/system_messages.hpp"
#include "cppa/util/type_traits.hpp" #include "cppa/util/type_traits.hpp"
...@@ -42,9 +42,9 @@ namespace detail { ...@@ -42,9 +42,9 @@ namespace detail {
template<typename Actor, typename... Fs> template<typename Actor, typename... Fs>
behavior fs2bhvr(Actor* self, Fs... fs) { behavior fs2bhvr(Actor* self, Fs... fs) {
auto handle_sync_timeout = [self]() -> match_hint { auto handle_sync_timeout = [self]() -> skip_message_t {
self->handle_sync_timeout(); self->handle_sync_timeout();
return match_hint::skip; return {};
}; };
return behavior{ return behavior{
on<sync_timeout_msg>() >> handle_sync_timeout, on<sync_timeout_msg>() >> handle_sync_timeout,
......
...@@ -37,8 +37,8 @@ ...@@ -37,8 +37,8 @@
#include <type_traits> #include <type_traits>
#include "cppa/any_tuple.hpp" #include "cppa/any_tuple.hpp"
#include "cppa/match_hint.hpp"
#include "cppa/match_expr.hpp" #include "cppa/match_expr.hpp"
#include "cppa/skip_message.hpp"
#include "cppa/partial_function.hpp" #include "cppa/partial_function.hpp"
#include "cppa/util/tbind.hpp" #include "cppa/util/tbind.hpp"
...@@ -170,14 +170,8 @@ static inline bool eval_res(const optional<T>& res, bool&) { ...@@ -170,14 +170,8 @@ static inline bool eval_res(const optional<T>& res, bool&) {
return static_cast<bool>(res); return static_cast<bool>(res);
} }
static inline bool eval_res(const optional<match_hint>& res, bool& skipped) { static inline bool eval_res(const optional<skip_message_t>& res, bool& skipped) {
if (res) { if (res) skipped = true;
if (*res == match_hint::skip) {
skipped = true;
return false;
}
return true;
}
return false; return false;
} }
...@@ -240,13 +234,22 @@ size_t run_case(std::vector<T>& vec, ...@@ -240,13 +234,22 @@ size_t run_case(std::vector<T>& vec,
InputIterator& pos, InputIterator& pos,
const InputIterator& end, const InputIterator& end,
Case& target) { Case& target) {
// check that there's no empty match expression
// (would cause indefinite recursion)
static constexpr size_t num_args = util::tl_size<typename Case::pattern_type>::value; static constexpr size_t num_args = util::tl_size<typename Case::pattern_type>::value;
typedef typename Case::second_type partial_fun_type;
typedef typename partial_fun_type::arg_types arg_types;
typedef typename util::tl_map<arg_types, util::rm_const_and_ref>::type plain_args;
static_assert(num_args > 0, static_assert(num_args > 0,
"empty match expressions are not allowed in stream matching"); "empty match expressions are not allowed in stream matching");
static_assert(util::tl_forall<plain_args, util::tbind<std::is_same, T>::template type>::value, typedef typename Case::first_type projection_type;
typedef typename projection_type::arg_types arg_types;
typedef typename util::tl_map<
arg_types,
util::rm_const_and_ref
>::type
plain_args;
static_assert(util::tl_forall<
plain_args,
util::tbind<std::is_same, T>::template type
>::value,
"match_stream<T>: at least one callback argument " "match_stream<T>: at least one callback argument "
"is not of type T"); "is not of type T");
while (vec.size() < num_args) { while (vec.size() < num_args) {
......
...@@ -359,7 +359,6 @@ struct invoke_util ...@@ -359,7 +359,6 @@ struct invoke_util
typename util::tl_filter_not_type<Pattern, anything>::type> { typename util::tl_filter_not_type<Pattern, anything>::type> {
}; };
template<class Pattern, class Projection, class PartialFun> template<class Pattern, class Projection, class PartialFun>
struct projection_partial_function_pair : std::pair<Projection, PartialFun> { struct projection_partial_function_pair : std::pair<Projection, PartialFun> {
template<typename... Ts> template<typename... Ts>
...@@ -629,7 +628,8 @@ struct get_case_result { ...@@ -629,7 +628,8 @@ struct get_case_result {
namespace cppa { namespace cppa {
/** /**
* @brief A match expression encapsulating cases <tt>Cs...</tt>. * @brief A match expression encapsulating cases <tt>Cs...</tt>, whereas
* each case is a @p detail::projection_partial_function_pair.
*/ */
template<class... Cs> template<class... Cs>
class match_expr { class match_expr {
...@@ -638,8 +638,6 @@ class match_expr { ...@@ -638,8 +638,6 @@ class match_expr {
public: public:
static constexpr bool may_have_timeout = false;
typedef util::type_list<Cs...> cases_list; typedef util::type_list<Cs...> cases_list;
typedef typename optional_variant_from_type_list< typedef typename optional_variant_from_type_list<
...@@ -995,6 +993,30 @@ behavior_impl_ptr match_expr_concat(const T& arg, const Ts&... args) { ...@@ -995,6 +993,30 @@ behavior_impl_ptr match_expr_concat(const T& arg, const Ts&... args) {
return concat_rec(dummy, util::empty_type_list{}, arg, args...); return concat_rec(dummy, util::empty_type_list{}, arg, args...);
} }
template<typename F>
match_expr<
typename get_case<
false,
F,
empty_value_guard,
util::empty_type_list,
util::empty_type_list
>::type>
match_expr_from_functor(F fun) {
typedef typename get_case<
false,
F,
empty_value_guard,
util::empty_type_list,
util::empty_type_list
>::type
result_type;
return result_type{typename result_type::first_type{},
typename result_type::second_type{
std::move(fun),
empty_value_guard{}}};
}
} // namespace detail } // namespace detail
} // namespace cppa } // namespace cppa
......
...@@ -27,12 +27,32 @@ ...@@ -27,12 +27,32 @@
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. * * along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/ \******************************************************************************/
#include "cppa/on.hpp"
#ifndef MAY_HAVE_TIMEOUT_HPP
#define MAY_HAVE_TIMEOUT_HPP
namespace cppa { namespace cppa {
match_hint skip_message() { template<typename F>
return match_hint::skip; struct timeout_definition;
}
class behavior;
template<typename T>
struct may_have_timeout {
static constexpr bool value = false;
};
template<>
struct may_have_timeout<behavior> {
static constexpr bool value = true;
};
template<typename F>
struct may_have_timeout<timeout_definition<F>> {
static constexpr bool value = true;
};
} // namespace cppa } // namespace cppa
#endif // MAY_HAVE_TIMEOUT_HPP
...@@ -38,12 +38,12 @@ ...@@ -38,12 +38,12 @@
#include "cppa/unit.hpp" #include "cppa/unit.hpp"
#include "cppa/atom.hpp" #include "cppa/atom.hpp"
#include "cppa/anything.hpp" #include "cppa/anything.hpp"
#include "cppa/behavior.hpp"
#include "cppa/any_tuple.hpp" #include "cppa/any_tuple.hpp"
#include "cppa/guard_expr.hpp" #include "cppa/guard_expr.hpp"
#include "cppa/match_hint.hpp"
#include "cppa/match_expr.hpp" #include "cppa/match_expr.hpp"
#include "cppa/partial_function.hpp" #include "cppa/skip_message.hpp"
#include "cppa/may_have_timeout.hpp"
#include "cppa/timeout_definition.hpp"
#include "cppa/util/duration.hpp" #include "cppa/util/duration.hpp"
#include "cppa/util/type_list.hpp" #include "cppa/util/type_list.hpp"
...@@ -227,11 +227,6 @@ namespace cppa { ...@@ -227,11 +227,6 @@ namespace cppa {
*/ */
constexpr anything any_vals = anything{}; constexpr anything any_vals = anything{};
/**
* @brief Returns {@link match_hint skipped}.
*/
match_hint skip_message();
#ifdef CPPA_DOCUMENTATION #ifdef CPPA_DOCUMENTATION
/** /**
...@@ -418,14 +413,16 @@ constexpr detail::on_the_fly_rvalue_builder on_arg_match; ...@@ -418,14 +413,16 @@ constexpr detail::on_the_fly_rvalue_builder on_arg_match;
// and even more convenience // and even more convenience
template<typename F, class E = typename std::enable_if<util::is_callable<F>::value>::type> template<typename F,
class E = typename std::enable_if<util::is_callable<F>::value>::type>
inline auto lift_to_match_expr(F fun) -> decltype(on_arg_match >> fun) { inline auto lift_to_match_expr(F fun) -> decltype(on_arg_match >> fun) {
return (on_arg_match >> fun); return (on_arg_match >> fun);
} }
template<typename... Cs> template<typename T,
inline match_expr<Cs...> lift_to_match_expr(match_expr<Cs...> expr) { class E = typename std::enable_if<!util::is_callable<T>::value>::type>
return std::move(expr); inline T lift_to_match_expr(T arg) {
return arg;
} }
#endif // CPPA_DOCUMENTATION #endif // CPPA_DOCUMENTATION
......
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
#include "cppa/none.hpp" #include "cppa/none.hpp"
#include "cppa/unit.hpp" #include "cppa/unit.hpp"
#include "cppa/optional.hpp" #include "cppa/optional.hpp"
#include "cppa/match_hint.hpp" #include "cppa/skip_message.hpp"
#include "cppa/util/type_list.hpp" #include "cppa/util/type_list.hpp"
#include "cppa/util/type_traits.hpp" #include "cppa/util/type_traits.hpp"
...@@ -116,8 +116,6 @@ class optional_variant { ...@@ -116,8 +116,6 @@ class optional_variant {
static constexpr int void_pos = util::tl_find<types, void>::value; static constexpr int void_pos = util::tl_find<types, void>::value;
static constexpr bool has_match_hint = util::tl_find<types, match_hint>::value != -1;
/** /**
* @brief Checks whether this objects holds a value of type @p T. * @brief Checks whether this objects holds a value of type @p T.
*/ */
......
...@@ -37,10 +37,12 @@ ...@@ -37,10 +37,12 @@
#include <utility> #include <utility>
#include <type_traits> #include <type_traits>
#include "cppa/on.hpp"
#include "cppa/behavior.hpp" #include "cppa/behavior.hpp"
#include "cppa/any_tuple.hpp" #include "cppa/any_tuple.hpp"
#include "cppa/ref_counted.hpp" #include "cppa/ref_counted.hpp"
#include "cppa/intrusive_ptr.hpp" #include "cppa/intrusive_ptr.hpp"
#include "cppa/may_have_timeout.hpp"
#include "cppa/timeout_definition.hpp" #include "cppa/timeout_definition.hpp"
#include "cppa/util/duration.hpp" #include "cppa/util/duration.hpp"
...@@ -69,8 +71,6 @@ class partial_function { ...@@ -69,8 +71,6 @@ class partial_function {
partial_function(impl_ptr ptr); partial_function(impl_ptr ptr);
static constexpr bool may_have_timeout = false;
/** @endcond */ /** @endcond */
partial_function() = default; partial_function() = default;
...@@ -107,7 +107,9 @@ class partial_function { ...@@ -107,7 +107,9 @@ class partial_function {
*/ */
template<typename... Ts> template<typename... Ts>
typename std::conditional< typename std::conditional<
util::disjunction<util::rm_const_and_ref<Ts>::type::may_have_timeout...>::value, util::disjunction<
may_have_timeout<typename util::rm_const_and_ref<Ts>::type>::value...
>::value,
behavior, behavior,
partial_function partial_function
>::type >::type
...@@ -120,7 +122,11 @@ class partial_function { ...@@ -120,7 +122,11 @@ class partial_function {
}; };
template<typename T> template<typename T>
typename std::conditional<T::may_have_timeout, behavior, partial_function>::type typename std::conditional<
may_have_timeout<T>::value,
behavior,
partial_function
>::type
match_expr_convert(const T& arg) { match_expr_convert(const T& arg) {
return {arg}; return {arg};
} }
...@@ -128,9 +134,9 @@ match_expr_convert(const T& arg) { ...@@ -128,9 +134,9 @@ match_expr_convert(const T& arg) {
template<typename T0, typename T1, typename... Ts> template<typename T0, typename T1, typename... Ts>
typename std::conditional< typename std::conditional<
util::disjunction< util::disjunction<
T0::may_have_timeout, may_have_timeout<T0>::value,
T1::may_have_timeout, may_have_timeout<T1>::value,
Ts::may_have_timeout... may_have_timeout<Ts>::value...
>::value, >::value,
behavior, behavior,
partial_function partial_function
...@@ -139,6 +145,20 @@ match_expr_convert(const T0& arg0, const T1& arg1, const Ts&... args) { ...@@ -139,6 +145,20 @@ match_expr_convert(const T0& arg0, const T1& arg1, const Ts&... args) {
return detail::match_expr_concat(arg0, arg1, args...); return detail::match_expr_concat(arg0, arg1, args...);
} }
// calls match_expr_convert(lift_to_match_expr(args)...)
template<typename... Ts>
typename std::conditional<
util::disjunction<
may_have_timeout<Ts>::value...
>::value,
behavior,
partial_function
>::type
lift_and_convert(Ts&&... args) {
static_assert(sizeof...(Ts) > 0, "at least one argument required");
return match_expr_convert(lift_to_match_expr(std::forward<Ts>(args))...);
}
template<typename... Cases> template<typename... Cases>
partial_function operator,(const match_expr<Cases...>& mexpr, partial_function operator,(const match_expr<Cases...>& mexpr,
const partial_function& pfun) { const partial_function& pfun) {
...@@ -174,7 +194,9 @@ inline optional<any_tuple> partial_function::operator()(T&& arg) { ...@@ -174,7 +194,9 @@ inline optional<any_tuple> partial_function::operator()(T&& arg) {
template<typename... Ts> template<typename... Ts>
typename std::conditional< typename std::conditional<
util::disjunction<util::rm_const_and_ref<Ts>::type::may_have_timeout...>::value, util::disjunction<
may_have_timeout<typename util::rm_const_and_ref<Ts>::type>::value...
>::value,
behavior, behavior,
partial_function partial_function
>::type >::type
......
...@@ -31,8 +31,6 @@ ...@@ -31,8 +31,6 @@
#ifndef CPPA_MATCH_HINT_HPP #ifndef CPPA_MATCH_HINT_HPP
#define CPPA_MATCH_HINT_HPP #define CPPA_MATCH_HINT_HPP
#include <iosfwd>
namespace cppa { namespace cppa {
/** /**
...@@ -40,13 +38,19 @@ namespace cppa { ...@@ -40,13 +38,19 @@ namespace cppa {
* expressions. This type is evaluated by the runtime system of libcppa * expressions. This type is evaluated by the runtime system of libcppa
* and can be used to intentionally skip messages. * and can be used to intentionally skip messages.
*/ */
enum class match_hint { struct skip_message_t { constexpr skip_message_t() { } };
skip,
handle /**
}; * @brief Tells the runtime system to skip a message when used as message
* handler, i.e., causes the runtime to leave the message in
* the mailbox of an actor.
*/
constexpr skip_message_t skip_message() {
return {};
}
// implemented in string_serialization.cpp // implemented in string_serialization.cpp
std::ostream& operator<<(std::ostream&, match_hint); std::ostream& operator<<(std::ostream&, skip_message_t);
} // namespace cppa } // namespace cppa
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "cppa/behavior.hpp" #include "cppa/behavior.hpp"
#include "cppa/match_expr.hpp" #include "cppa/match_expr.hpp"
#include "cppa/typed_continue_helper.hpp"
#include "cppa/detail/typed_actor_util.hpp" #include "cppa/detail/typed_actor_util.hpp"
...@@ -43,51 +44,69 @@ namespace detail { ...@@ -43,51 +44,69 @@ namespace detail {
template<typename... Rs> template<typename... Rs>
class functor_based_typed_actor; class functor_based_typed_actor;
template<typename T> // converts a list of replies_to<...>::with<...> elements to a list of
struct match_hint_to_void { // lists containing the replies_to<...> half only
typedef T type; template<typename List>
}; struct input_only;
template<> template<typename... Ts>
struct match_hint_to_void<match_hint> { struct input_only<util::type_list<Ts...>> {
typedef void type; typedef util::type_list<typename Ts::input_types...> type;
};
template<typename T>
struct infer_result_from_continue_helper {
typedef T type;
}; };
template<typename R> typedef util::type_list<skip_message_t> skip_list;
struct infer_result_from_continue_helper<typed_continue_helper<R>> {
typedef R type;
};
template<class List> template<class List>
struct collapse_infered_list { struct unbox_typed_continue_helper {
// do nothing if List is actually a list, i.e., not a typed_continue_helper
typedef List type; typedef List type;
}; };
template<typename... Ts> template<class List>
struct collapse_infered_list<util::type_list<util::type_list<Ts...>>> { struct unbox_typed_continue_helper<util::type_list<typed_continue_helper<List>>> {
typedef util::type_list<Ts...> type; typedef List type;
}; };
template<typename T> template<typename SList>
struct infer_response_types { struct valid_input_predicate {
typedef typename T::input_types input_types; typedef typename input_only<SList>::type s_inputs;
typedef typename util::tl_map< template<typename Expr>
typename T::output_types, struct inner {
match_hint_to_void, typedef typename Expr::input_types input_types;
infer_result_from_continue_helper typedef typename unbox_typed_continue_helper<
typename Expr::output_types
>::type >::type
output_types; output_types;
typedef typename replies_to_from_type_list< static constexpr int pos = util::tl_find<s_inputs, input_types>::value;
input_types, static_assert(pos != -1, "cannot assign given match expression to "
// continue_helper stores a type list, "typed behavior, because the expression "
// so we need to collapse the list here "contains at least one pattern that is "
typename collapse_infered_list<output_types>::type "not defined in the actor's type");
>::type typedef typename util::tl_at<SList, pos>::type s_element;
type; typedef typename s_element::output_types s_out;
static constexpr bool value =
std::is_same<output_types, s_out>::value
|| std::is_same<output_types, skip_list>::value;
static_assert(value, "wtf");
};
};
// Tests whether the input list (IList) matches the
// signature list (SList) for a typed actor behavior
template<class SList, class IList>
struct valid_input {
// check for each element in IList that there's an element in SList that
// (1) has an identical input type list
// (2) has an identical output type list
// OR the output of the element in IList is skip_message_t
static_assert(util::tl_is_distinct<IList>::value,
"given pattern is not distinct");
static constexpr bool value =
util::tl_size<SList>::value == util::tl_size<IList>::value
&& util::tl_forall<
IList,
valid_input_predicate<SList>::template inner
>::value;
}; };
// this function is called from typed_behavior<...>::set and its whole // this function is called from typed_behavior<...>::set and its whole
...@@ -95,12 +114,12 @@ struct infer_response_types { ...@@ -95,12 +114,12 @@ struct infer_response_types {
// (this function only has the type informations needed to understand the error) // (this function only has the type informations needed to understand the error)
template<class SignatureList, class InputList> template<class SignatureList, class InputList>
void static_check_typed_behavior_input() { void static_check_typed_behavior_input() {
constexpr bool is_equal = util::tl_equal<SignatureList, InputList>::value; constexpr bool is_valid = valid_input<SignatureList, InputList>::value;
// note: it might be worth considering to allow a wildcard in the // note: it might be worth considering to allow a wildcard in the
// InputList if its return type is identical to all "missing" // InputList if its return type is identical to all "missing"
// input types ... however, it might lead to unexpected results // input types ... however, it might lead to unexpected results
// and would cause a lot of not-so-straightforward code here // and would cause a lot of not-so-straightforward code here
static_assert(is_equal, "given pattern cannot be used to initialize " static_assert(is_valid, "given pattern cannot be used to initialize "
"typed behavior (exact match needed)"); "typed behavior (exact match needed)");
} }
...@@ -181,11 +200,7 @@ class typed_behavior { ...@@ -181,11 +200,7 @@ class typed_behavior {
typedef typename util::tl_map< typedef typename util::tl_map<
util::type_list< util::type_list<
typename detail::deduce_signature<Cs>::type... typename detail::deduce_signature<Cs>::type...
>, >
// returning a match_hint from a message handler does
// not send anything back, so we can consider
// match_hint to be void
detail::infer_response_types
>::type >::type
input; input;
// check types // check types
......
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
#include "cppa/util/type_traits.hpp" #include "cppa/util/type_traits.hpp"
#include "cppa/detail/typed_actor_util.hpp"
namespace cppa { namespace cppa {
template<typename OutputList> template<typename OutputList>
......
...@@ -40,7 +40,8 @@ ...@@ -40,7 +40,8 @@
#include "cppa/util/type_list.hpp" #include "cppa/util/type_list.hpp"
#include "cppa/util/type_traits.hpp" #include "cppa/util/type_traits.hpp"
namespace cppa { namespace util { namespace cppa {
namespace util {
/** /**
* @addtogroup MetaProgramming * @addtogroup MetaProgramming
...@@ -59,7 +60,7 @@ template<typename T> struct rm_const_and_ref<const T> { typedef T type; }; ...@@ -59,7 +60,7 @@ template<typename T> struct rm_const_and_ref<const T> { typedef T type; };
template<typename T> struct rm_const_and_ref<T&> { typedef T type; }; template<typename T> struct rm_const_and_ref<T&> { typedef T type; };
template<> struct rm_const_and_ref<void> { }; //template<> struct rm_const_and_ref<void> { };
/** /**
* @brief Joins all bool constants using operator &&. * @brief Joins all bool constants using operator &&.
...@@ -94,7 +95,6 @@ struct disjunction<V0, Vs...> { ...@@ -94,7 +95,6 @@ struct disjunction<V0, Vs...> {
template<> template<>
struct disjunction<> { static constexpr bool value = false; }; struct disjunction<> { static constexpr bool value = false; };
/** /**
* @brief Equal to std::is_same<T, anything>. * @brief Equal to std::is_same<T, anything>.
*/ */
...@@ -496,6 +496,8 @@ struct type_at<0, T0, Ts...> { ...@@ -496,6 +496,8 @@ struct type_at<0, T0, Ts...> {
/** /**
* @} * @}
*/ */
} } // namespace cppa::util
} // namespace util
} // namespace cppa
#endif // CPPA_UTIL_TYPE_TRAITS_HPP #endif // CPPA_UTIL_TYPE_TRAITS_HPP
...@@ -86,5 +86,4 @@ behavior behavior::add_continuation(continuation_fun fun) { ...@@ -86,5 +86,4 @@ behavior behavior::add_continuation(continuation_fun fun) {
return {new continuation_decorator(std::move(fun), m_impl)}; return {new continuation_decorator(std::move(fun), m_impl)};
} }
} // namespace cppa } // namespace cppa
...@@ -38,11 +38,11 @@ ...@@ -38,11 +38,11 @@
#include "cppa/atom.hpp" #include "cppa/atom.hpp"
#include "cppa/object.hpp" #include "cppa/object.hpp"
#include "cppa/to_string.hpp" #include "cppa/to_string.hpp"
#include "cppa/match_hint.hpp"
#include "cppa/serializer.hpp" #include "cppa/serializer.hpp"
#include "cppa/singletons.hpp" #include "cppa/singletons.hpp"
#include "cppa/from_string.hpp" #include "cppa/from_string.hpp"
#include "cppa/deserializer.hpp" #include "cppa/deserializer.hpp"
#include "cppa/skip_message.hpp"
#include "cppa/actor_namespace.hpp" #include "cppa/actor_namespace.hpp"
#include "cppa/primitive_variant.hpp" #include "cppa/primitive_variant.hpp"
#include "cppa/uniform_type_info.hpp" #include "cppa/uniform_type_info.hpp"
...@@ -526,9 +526,8 @@ string to_verbose_string(const exception& e) { ...@@ -526,9 +526,8 @@ string to_verbose_string(const exception& e) {
return oss.str(); return oss.str();
} }
std::ostream& operator<<(std::ostream& out, match_hint mh) { std::ostream& operator<<(std::ostream& out, skip_message_t) {
return out << (mh == match_hint::handle ? "match_hint::handle" return out << "skip_message";
: "match_hint::skip");
} }
} // namespace cppa } // namespace cppa
...@@ -268,17 +268,12 @@ void test_match_stream() { ...@@ -268,17 +268,12 @@ void test_match_stream() {
CPPA_CHECK(name == "foo" || name == "bar"); CPPA_CHECK(name == "foo" || name == "bar");
return name == "foo" || name == "bar"; return name == "foo" || name == "bar";
}, },
on("-p", arg_match) >> [&](const string& port) -> match_hint { on("-p", toint) >> [&](int port) {
auto i = toint(port); CPPA_CHECK_EQUAL(port, 2);
if (i) {
CPPA_CHECK_EQUAL(*i, 2);
return match_hint::handle;
}
else return match_hint::skip;
}, },
on_arg_match >> [](const string& arg) -> match_hint { on_arg_match >> [](const string& arg) -> skip_message_t {
CPPA_FAILURE("unexpected string: " << arg); CPPA_FAILURE("unexpected string: " << arg);
return match_hint::skip; return {};
} }
); );
CPPA_CHECK_EQUAL(success, true); CPPA_CHECK_EQUAL(success, true);
...@@ -291,10 +286,13 @@ void test_behavior() { ...@@ -291,10 +286,13 @@ void test_behavior() {
CPPA_CHECK_EQUAL(static_cast<bool>(pf(tup)), expected_result); \ CPPA_CHECK_EQUAL(static_cast<bool>(pf(tup)), expected_result); \
CPPA_CHECK_EQUAL(last_invoked_fun, str); \ CPPA_CHECK_EQUAL(last_invoked_fun, str); \
} }
auto not_42 = [](int i) -> optional<int> {
if (i != 42) return i;
return none;
};
behavior bhvr1 { behavior bhvr1 {
on<int>() >> [&](int i) -> match_hint { on(not_42) >> [&](int) {
last_invoked_fun = "<int>@1"; last_invoked_fun = "<int>@1";
return (i == 42) ? match_hint::skip : match_hint::handle;
}, },
on<float>() >> [&] { on<float>() >> [&] {
last_invoked_fun = "<float>@2"; last_invoked_fun = "<float>@2";
...@@ -306,7 +304,7 @@ void test_behavior() { ...@@ -306,7 +304,7 @@ void test_behavior() {
last_invoked_fun = "<*>@4"; last_invoked_fun = "<*>@4";
} }
}; };
bhvr_check(bhvr1, make_any_tuple(42), false, "<int>@1"); bhvr_check(bhvr1, make_any_tuple(42), true, "<int>@3");
bhvr_check(bhvr1, make_any_tuple(24), true, "<int>@1"); bhvr_check(bhvr1, make_any_tuple(24), true, "<int>@1");
bhvr_check(bhvr1, make_any_tuple(2.f), true, "<float>@2"); bhvr_check(bhvr1, make_any_tuple(2.f), true, "<float>@2");
bhvr_check(bhvr1, make_any_tuple(""), true, "<*>@4"); bhvr_check(bhvr1, make_any_tuple(""), true, "<*>@4");
......
...@@ -217,16 +217,16 @@ void test_sync_send() { ...@@ -217,16 +217,16 @@ void test_sync_send() {
self->send_exit(mirror, exit_reason::user_shutdown); self->send_exit(mirror, exit_reason::user_shutdown);
self->await_all_other_actors_done(); self->await_all_other_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
auto non_normal_down_msg = [](down_msg dm) -> optional<down_msg> {
if (dm.reason != exit_reason::normal) return dm;
return none;
};
auto await_success_message = [&] { auto await_success_message = [&] {
self->receive ( self->receive (
on(atom("success")) >> CPPA_CHECKPOINT_CB(), on(atom("success")) >> CPPA_CHECKPOINT_CB(),
on(atom("failure")) >> CPPA_FAILURE_CB("A didn't receive sync response"), on(atom("failure")) >> CPPA_FAILURE_CB("A didn't receive sync response"),
on_arg_match >> [&](const down_msg& dm) -> match_hint { on(non_normal_down_msg) >> [&](const down_msg& dm) {
if (dm.reason != exit_reason::normal) {
CPPA_FAILURE("A exited for reason " << dm.reason); CPPA_FAILURE("A exited for reason " << dm.reason);
return match_hint::handle;
}
return match_hint::skip;
} }
); );
}; };
......
...@@ -137,7 +137,7 @@ typedef typed_actor< ...@@ -137,7 +137,7 @@ typedef typed_actor<
replies_to<get_state_msg>::with<string>, replies_to<get_state_msg>::with<string>,
replies_to<string>::with<void>, replies_to<string>::with<void>,
replies_to<float>::with<void>, replies_to<float>::with<void>,
replies_to<int>::with<void> replies_to<int>::with<int>
> >
event_testee_type; event_testee_type;
...@@ -162,12 +162,11 @@ class event_testee : public event_testee_type::base { ...@@ -162,12 +162,11 @@ class event_testee : public event_testee_type::base {
on<get_state_msg>() >> [] { on<get_state_msg>() >> [] {
return "wait4int"; return "wait4int";
}, },
on<int>() >> [=] { on<int>() >> [=]() -> int {
become(wait4float()); become(wait4float());
return 42;
}, },
(on<float>() || on<string>()) >> [] { (on<float>() || on<string>()) >> skip_message
return match_hint::skip;
}
}; };
} }
...@@ -179,9 +178,7 @@ class event_testee : public event_testee_type::base { ...@@ -179,9 +178,7 @@ class event_testee : public event_testee_type::base {
on<float>() >> [=] { on<float>() >> [=] {
become(wait4string()); become(wait4string());
}, },
(on<string>() || on<int>()) >> [] { (on<string>() || on<int>()) >> skip_message
return match_hint::skip;
}
}; };
} }
...@@ -208,11 +205,18 @@ void test_event_testee() { ...@@ -208,11 +205,18 @@ void test_event_testee() {
set<string> iface{"cppa::replies_to<get_state_msg>::with<@str>", set<string> iface{"cppa::replies_to<get_state_msg>::with<@str>",
"cppa::replies_to<@str>::with<void>", "cppa::replies_to<@str>::with<void>",
"cppa::replies_to<float>::with<void>", "cppa::replies_to<float>::with<void>",
"cppa::replies_to<@i32>::with<void>"}; "cppa::replies_to<@i32>::with<@i32>"};
CPPA_CHECK(sub_et->interface() == iface); CPPA_CHECK(sub_et->interface() == iface);
self->send(sub_et, get_state_msg{}); self->send(sub_et, get_state_msg{});
// we expect three 42s
int i = 0;
self->receive_for(i, 3) (
[](int value) {
CPPA_CHECK_EQUAL(value, 42);
}
);
self->receive ( self->receive (
on_arg_match >> [&](const string& str) { [&](const string& str) {
result = str; result = str;
}, },
after(chrono::minutes(1)) >> [&]() { after(chrono::minutes(1)) >> [&]() {
......
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