Commit a57269f8 authored by neverlord's avatar neverlord

arg_match

parent e2562a99
...@@ -172,6 +172,7 @@ nobase_library_include_HEADERS = \ ...@@ -172,6 +172,7 @@ nobase_library_include_HEADERS = \
cppa/util/a_matches_b.hpp \ cppa/util/a_matches_b.hpp \
cppa/util/any_tuple_iterator.hpp \ cppa/util/any_tuple_iterator.hpp \
cppa/util/apply.hpp \ cppa/util/apply.hpp \
cppa/util/arg_match_t.hpp \
cppa/util/at.hpp \ cppa/util/at.hpp \
cppa/util/callable_trait.hpp \ cppa/util/callable_trait.hpp \
cppa/util/comparable.hpp \ cppa/util/comparable.hpp \
......
...@@ -249,3 +249,4 @@ benchmarks/mailbox_performance.cpp ...@@ -249,3 +249,4 @@ benchmarks/mailbox_performance.cpp
benchmarks/mixed_case.cpp benchmarks/mixed_case.cpp
cppa/util/default_deallocator.hpp cppa/util/default_deallocator.hpp
cppa/util/producer_consumer_list.hpp cppa/util/producer_consumer_list.hpp
cppa/util/arg_match_t.hpp
...@@ -31,19 +31,27 @@ ...@@ -31,19 +31,27 @@
#ifndef TDATA_HPP #ifndef TDATA_HPP
#define TDATA_HPP #define TDATA_HPP
#include <typeinfo>
#include "cppa/get.hpp" #include "cppa/get.hpp"
#include "cppa/util/at.hpp" #include "cppa/util/at.hpp"
#include "cppa/util/wrapped.hpp" #include "cppa/util/wrapped.hpp"
#include "cppa/util/type_list.hpp" #include "cppa/util/type_list.hpp"
#include "cppa/util/arg_match_t.hpp"
#include "cppa/util/filter_type_list.hpp" #include "cppa/util/filter_type_list.hpp"
#include "cppa/detail/abstract_tuple.hpp" #include "cppa/detail/abstract_tuple.hpp"
namespace cppa {
class uniform_type_info;
uniform_type_info const* uniform_typeid(std::type_info const&);
} // namespace cppa
namespace cppa { namespace detail { namespace cppa { namespace detail {
/* /*
* just like std::tuple (but derives from ref_counted?) * "enhanced std::tuple"
*/ */
template<typename...> template<typename...>
struct tdata; struct tdata;
...@@ -54,6 +62,11 @@ struct tdata<> ...@@ -54,6 +62,11 @@ struct tdata<>
util::void_type head; util::void_type head;
constexpr tdata() { }
// swallow "arg_match" silently
constexpr tdata(util::wrapped<util::arg_match_t> const&) { }
tdata<>& tail() tdata<>& tail()
{ {
throw std::out_of_range(""); throw std::out_of_range("");
...@@ -69,6 +82,11 @@ struct tdata<> ...@@ -69,6 +82,11 @@ struct tdata<>
throw std::out_of_range(""); throw std::out_of_range("");
} }
inline uniform_type_info const* type_at(size_t) const
{
throw std::out_of_range("");
}
inline bool operator==(tdata const&) const inline bool operator==(tdata const&) const
{ {
return true; return true;
...@@ -76,6 +94,9 @@ struct tdata<> ...@@ -76,6 +94,9 @@ struct tdata<>
}; };
template<typename... X, typename... Y>
void tdata_set(tdata<X...>& rhs, tdata<Y...> const& lhs);
template<typename Head, typename... Tail> template<typename Head, typename... Tail>
struct tdata<Head, Tail...> : tdata<Tail...> struct tdata<Head, Tail...> : tdata<Tail...>
{ {
...@@ -92,6 +113,10 @@ struct tdata<Head, Tail...> : tdata<Tail...> ...@@ -92,6 +113,10 @@ struct tdata<Head, Tail...> : tdata<Tail...>
template<typename... Args> template<typename... Args>
tdata(Head const& v0, Args const&... vals) : super(vals...), head(v0) { } tdata(Head const& v0, Args const&... vals) : super(vals...), head(v0) { }
// allow partial initialization
template<typename... Args>
tdata(Head&& v0, Args const&... vals) : super(vals...), head(std::move(v0)) { }
// allow initialization with wrapped<Head> (uses the default constructor) // allow initialization with wrapped<Head> (uses the default constructor)
template<typename... Args> template<typename... Args>
tdata(util::wrapped<Head> const&, Args const&... vals) tdata(util::wrapped<Head> const&, Args const&... vals)
...@@ -99,6 +124,13 @@ struct tdata<Head, Tail...> : tdata<Tail...> ...@@ -99,6 +124,13 @@ struct tdata<Head, Tail...> : tdata<Tail...>
{ {
} }
// allow (partial) initialization from a different tdata
template<typename... Y>
tdata(tdata<Y...> const& other) : super(other.tail()), head(other.head) { }
template<typename... Y>
tdata(tdata<Y...>&& other) : super(std::move(other.tail())), head(std::move(other.head)) { }
// allow initialization with a function pointer or reference // allow initialization with a function pointer or reference
// returning a wrapped<Head> // returning a wrapped<Head>
template<typename...Args> template<typename...Args>
...@@ -107,6 +139,13 @@ struct tdata<Head, Tail...> : tdata<Tail...> ...@@ -107,6 +139,13 @@ struct tdata<Head, Tail...> : tdata<Tail...>
{ {
} }
template<typename... Y>
tdata& operator=(tdata<Y...> const& other)
{
tdata_set(*this, other);
return *this;
}
inline tdata<Tail...>& tail() inline tdata<Tail...>& tail()
{ {
// upcast // upcast
...@@ -124,13 +163,28 @@ struct tdata<Head, Tail...> : tdata<Tail...> ...@@ -124,13 +163,28 @@ struct tdata<Head, Tail...> : tdata<Tail...>
return head == other.head && tail() == other.tail(); return head == other.head && tail() == other.tail();
} }
inline void const* at(size_t pos) const inline void const* at(size_t p) const
{ {
return (pos == 0) ? &head : super::at(pos - 1); return (p == 0) ? &head : super::at(p-1);
}
inline uniform_type_info const* type_at(size_t p) const
{
return (p == 0) ? uniform_typeid(typeid(Head)) : super::type_at(p-1);
} }
}; };
template<typename... X>
void tdata_set(tdata<X...>&, tdata<> const&) { }
template<typename... X, typename... Y>
void tdata_set(tdata<X...>& rhs, tdata<Y...> const& lhs)
{
rhs.head = lhs.head;
tdata_set(rhs.tail(), lhs.tail());
}
template<size_t N, typename... Tn> template<size_t N, typename... Tn>
struct tdata_upcast_helper; struct tdata_upcast_helper;
......
...@@ -68,24 +68,30 @@ class event_based_actor_base : public abstract_event_based_actor ...@@ -68,24 +68,30 @@ class event_based_actor_base : public abstract_event_based_actor
d_this()->do_become(bhvr); d_this()->do_become(bhvr);
} }
inline void become(invoke_rules* behavior) inline void become(invoke_rules* bhvr)
{ {
d_this()->do_become(behavior, false); d_this()->do_become(bhvr, false);
} }
inline void become(timed_invoke_rules* behavior) inline void become(timed_invoke_rules* bhvr)
{ {
d_this()->do_become(behavior, false); d_this()->do_become(bhvr, false);
} }
inline void become(invoke_rules&& behavior) inline void become(invoke_rules&& bhvr)
{ {
d_this()->do_become(new invoke_rules(std::move(behavior)), true); d_this()->do_become(new invoke_rules(std::move(bhvr)), true);
} }
inline void become(timed_invoke_rules&& behavior) inline void become(timed_invoke_rules&& bhvr)
{ {
d_this()->do_become(new timed_invoke_rules(std::move(behavior)), true); d_this()->do_become(new timed_invoke_rules(std::move(bhvr)), true);
}
inline void become(behavior&& bhvr)
{
if (bhvr.is_left()) become(std::move(bhvr.left()));
else become(std::move(bhvr.right()));
} }
template<typename Head, typename... Tail> template<typename Head, typename... Tail>
......
...@@ -31,6 +31,10 @@ ...@@ -31,6 +31,10 @@
#ifndef FSM_ACTOR_HPP #ifndef FSM_ACTOR_HPP
#define FSM_ACTOR_HPP #define FSM_ACTOR_HPP
#include <type_traits>
#include "cppa/util/rm_ref.hpp"
#include "cppa/util/enable_if.hpp"
#include "cppa/event_based_actor.hpp" #include "cppa/event_based_actor.hpp"
namespace cppa { namespace cppa {
......
...@@ -41,12 +41,16 @@ ...@@ -41,12 +41,16 @@
#include "cppa/any_tuple.hpp" #include "cppa/any_tuple.hpp"
#include "cppa/invoke_rules.hpp" #include "cppa/invoke_rules.hpp"
#include "cppa/util/type_list.hpp" #include "cppa/util/pop_back.hpp"
#include "cppa/util/duration.hpp" #include "cppa/util/duration.hpp"
#include "cppa/util/type_list.hpp"
#include "cppa/util/enable_if.hpp"
#include "cppa/util/arg_match_t.hpp"
#include "cppa/util/eval_first_n.hpp" #include "cppa/util/eval_first_n.hpp"
#include "cppa/util/callable_trait.hpp" #include "cppa/util/callable_trait.hpp"
#include "cppa/util/type_list_apply.hpp" #include "cppa/util/type_list_apply.hpp"
#include "cppa/util/filter_type_list.hpp" #include "cppa/util/filter_type_list.hpp"
#include "cppa/util/concat_type_lists.hpp"
#include "cppa/detail/boxed.hpp" #include "cppa/detail/boxed.hpp"
#include "cppa/detail/unboxed.hpp" #include "cppa/detail/unboxed.hpp"
...@@ -80,32 +84,69 @@ template<typename... TypeList> ...@@ -80,32 +84,69 @@ template<typename... TypeList>
class invoke_rule_builder class invoke_rule_builder
{ {
typedef typename util::type_list_apply<util::type_list<TypeList...>, typedef util::arg_match_t arg_match_t;
typedef util::type_list<TypeList...> raw_types;
static const bool is_complete =
!std::is_same<arg_match_t, typename raw_types::back_type>::value;
typedef typename util::if_else_c<is_complete == false,
typename util::pop_back<raw_types>::type,
util::wrapped<raw_types> >::type
types;
static_assert(types::template find<arg_match_t>::value == -1,
"arg_match is allowed only as last parameter for on()");
typedef typename util::type_list_apply<types,
detail::implicit_conversions>::type detail::implicit_conversions>::type
converted_type_list; converted_types;
typedef typename pattern_type_from_type_list<converted_type_list>::type typedef typename pattern_type_from_type_list<converted_types>::type
pattern_type; pattern_type;
typedef std::unique_ptr<pattern_type> pattern_ptr_type; std::unique_ptr<pattern_type> m_ptr;
pattern_ptr_type m_pattern;
typedef typename pattern_type::tuple_view_type tuple_view_type; typedef typename pattern_type::tuple_view_type tuple_view_type;
template<typename F>
invoke_rules cr_rules(F&& f, std::integral_constant<bool,true>)
{
typedef invokable_impl<tuple_view_type, pattern_type, F> impl;
return invokable_ptr(new impl(std::move(m_ptr),std::forward<F>(f)));
}
template<typename F>
invoke_rules cr_rules(F&& f, std::integral_constant<bool,false>)
{
using namespace ::cppa::util;
typedef typename get_callable_trait<F>::type ctrait;
typedef typename ctrait::arg_types raw_types;
static_assert(raw_types::size > 0, "functor has no arguments");
typedef typename type_list_apply<raw_types,rm_ref>::type new_types;
typedef typename concat_type_lists<converted_types,new_types>::type types;
typedef typename pattern_type_from_type_list<types>::type epattern;
typedef typename epattern::tuple_view_type tuple_view_type;
typedef invokable_impl<tuple_view_type, epattern, F> impl;
std::unique_ptr<epattern> pptr(extend_pattern<epattern>(m_ptr.get()));
return invokable_ptr(new impl(std::move(pptr), std::forward<F>(f)));
}
public: public:
template<typename... Args> template<typename... Args>
invoke_rule_builder(Args const&... args) invoke_rule_builder(Args const&... args)
: m_pattern(new pattern_type(args...)) : m_ptr(new pattern_type(args...))
{ {
} }
template<typename F> template<typename F>
invoke_rules operator>>(F&& f) invoke_rules operator>>(F&& f)
{ {
typedef invokable_impl<tuple_view_type, pattern_type, F> impl; std::integral_constant<bool,is_complete> token;
return invokable_ptr(new impl(std::move(m_pattern),std::forward<F>(f))); return cr_rules(std::forward<F>(f), token);
} }
}; };
...@@ -146,7 +187,9 @@ constexpr typename detail::boxed<T>::type val() ...@@ -146,7 +187,9 @@ constexpr typename detail::boxed<T>::type val()
return typename detail::boxed<T>::type(); return typename detail::boxed<T>::type();
} }
constexpr anything any_vals = anything(); constexpr anything any_vals;// = anything();
constexpr typename detail::boxed<util::arg_match_t>::type arg_match;
constexpr detail::on_the_fly_invoke_rule_builder on_arg_match; constexpr detail::on_the_fly_invoke_rule_builder on_arg_match;
......
...@@ -47,6 +47,8 @@ ...@@ -47,6 +47,8 @@
namespace cppa { namespace cppa {
struct dont_initialize_pattern { };
template<typename... Types> template<typename... Types>
class pattern; class pattern;
...@@ -59,6 +61,8 @@ class pattern<T0, Tn...> ...@@ -59,6 +61,8 @@ class pattern<T0, Tn...>
public: public:
pattern(dont_initialize_pattern const&) { }
static constexpr size_t size = sizeof...(Tn) + 1; static constexpr size_t size = sizeof...(Tn) + 1;
typedef util::type_list<T0, Tn...> tpl_args; typedef util::type_list<T0, Tn...> tpl_args;
...@@ -101,7 +105,7 @@ class pattern<T0, Tn...> ...@@ -101,7 +105,7 @@ class pattern<T0, Tn...>
return detail::do_match(arg0, arg1); return detail::do_match(arg0, arg1);
} }
private: // private:
detail::tdata<T0, Tn...> m_data; detail::tdata<T0, Tn...> m_data;
cppa::uniform_type_info const* m_utis[size]; cppa::uniform_type_info const* m_utis[size];
...@@ -109,6 +113,25 @@ class pattern<T0, Tn...> ...@@ -109,6 +113,25 @@ class pattern<T0, Tn...>
}; };
template<class ExtendedType, class BasicType>
ExtendedType* extend_pattern(BasicType* p)
{
ExtendedType* et = new ExtendedType(dont_initialize_pattern());
et->m_data = p->m_data;
for (size_t i = 0; i < BasicType::size; ++i)
{
et->m_utis[i] = p->m_utis[i];
et->m_data_ptr[i] = (p->m_data_ptr[i]) ? et->m_data.at(i)
: nullptr;
}
for (size_t i = BasicType::size; i < ExtendedType::size; ++i)
{
et->m_data_ptr[i] = nullptr;
et->m_utis[i] = et->m_data.type_at(i);
}
return et;
}
template<typename TypeList> template<typename TypeList>
struct pattern_type_from_type_list; struct pattern_type_from_type_list;
......
#ifndef ARG_MATCH_T_HPP
#define ARG_MATCH_T_HPP
namespace cppa { namespace util { struct arg_match_t { }; } }
#endif // ARG_MATCH_T_HPP
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <typeinfo> #include <typeinfo>
#include "cppa/util/if_else.hpp"
#include "cppa/util/void_type.hpp" #include "cppa/util/void_type.hpp"
namespace cppa { namespace cppa {
...@@ -51,8 +52,14 @@ template<> ...@@ -51,8 +52,14 @@ template<>
struct type_list<> struct type_list<>
{ {
typedef void_type head_type; typedef void_type head_type;
typedef void_type back_type;
typedef type_list<> tail_type; typedef type_list<> tail_type;
static const size_t size = 0; static const size_t size = 0;
template<typename, int = 0>
struct find
{
static const int value = -1;
};
}; };
template<typename Head, typename... Tail> template<typename Head, typename... Tail>
...@@ -65,6 +72,11 @@ struct type_list<Head, Tail...> ...@@ -65,6 +72,11 @@ struct type_list<Head, Tail...>
typedef type_list<Tail...> tail_type; typedef type_list<Tail...> tail_type;
typedef typename if_else_c<sizeof...(Tail) == 0,
Head,
wrapped<typename tail_type::back_type> >::type
back_type;
static const size_t size = sizeof...(Tail) + 1; static const size_t size = sizeof...(Tail) + 1;
type_list() type_list()
...@@ -88,6 +100,14 @@ struct type_list<Head, Tail...> ...@@ -88,6 +100,14 @@ struct type_list<Head, Tail...>
} }
} }
template<typename What, int Pos = 0>
struct find
{
static const int value = std::is_same<What,Head>::value
? Pos
: type_list<Tail...>::template find<What,Pos+1>::value;
};
private: private:
uti_ptr m_arr[size]; uti_ptr m_arr[size];
......
...@@ -183,6 +183,54 @@ abstract_event_based_actor* event_testee2() ...@@ -183,6 +183,54 @@ abstract_event_based_actor* event_testee2()
return new impl; return new impl;
} }
struct chopstick : public fsm_actor<chopstick>
{
behavior init_state;
behavior taken_by(actor_ptr hakker)
{
return
(
on<atom("take")>() >> [=]()
{
reply(atom("busy"));
},
on(atom("put"), hakker) >> [=]()
{
become(&init_state);
},
on(atom("break")) >> [=]()
{
become_void();
}
);
}
chopstick()
{
init_state =
(
on(atom("take"), arg_match) >> [=](actor_ptr hakker)
{
if (hakker)
{
become(taken_by(hakker));
reply(atom("taken"));
}
},
on(atom("break")) >> [=]()
{
become_void();
},
others() >> [=]()
{
}
);
}
};
class testee_actor : public scheduled_actor class testee_actor : public scheduled_actor
{ {
...@@ -322,6 +370,17 @@ size_t test__spawn() ...@@ -322,6 +370,17 @@ size_t test__spawn()
spawn(testee1); spawn(testee1);
spawn(event_testee2()); spawn(event_testee2());
auto cstk = spawn(new chopstick);
send(cstk, atom("take"), self);
receive
(
on(atom("taken")) >> [&]()
{
send(cstk, atom("put"), self);
send(cstk, atom("break"));
}
);
await_all_others_done(); await_all_others_done();
CPPA_CHECK_EQUAL(behavior_test<testee_actor>(), "init_state"); CPPA_CHECK_EQUAL(behavior_test<testee_actor>(), "init_state");
......
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