Commit 332f9eee authored by neverlord's avatar neverlord

new guard and pattern matching implementation

parent d3d55a4c
...@@ -122,6 +122,7 @@ nobase_library_include_HEADERS = \ ...@@ -122,6 +122,7 @@ nobase_library_include_HEADERS = \
cppa/detail/post_office_msg.hpp \ cppa/detail/post_office_msg.hpp \
cppa/detail/primitive_member.hpp \ cppa/detail/primitive_member.hpp \
cppa/detail/projection.hpp \ cppa/detail/projection.hpp \
cppa/detail/pseudo_tuple.hpp \
cppa/detail/ptype_to_type.hpp \ cppa/detail/ptype_to_type.hpp \
cppa/detail/receive_loop_helper.hpp \ cppa/detail/receive_loop_helper.hpp \
cppa/detail/ref_counted_impl.hpp \ cppa/detail/ref_counted_impl.hpp \
...@@ -159,6 +160,7 @@ nobase_library_include_HEADERS = \ ...@@ -159,6 +160,7 @@ nobase_library_include_HEADERS = \
cppa/intrusive_ptr.hpp \ cppa/intrusive_ptr.hpp \
cppa/local_actor.hpp \ cppa/local_actor.hpp \
cppa/match.hpp \ cppa/match.hpp \
cppa/match_expr.hpp \
cppa/object.hpp \ cppa/object.hpp \
cppa/on.hpp \ cppa/on.hpp \
cppa/option.hpp \ cppa/option.hpp \
...@@ -190,11 +192,9 @@ nobase_library_include_HEADERS = \ ...@@ -190,11 +192,9 @@ nobase_library_include_HEADERS = \
cppa/util/compare_tuples.hpp \ cppa/util/compare_tuples.hpp \
cppa/util/conjunction.hpp \ cppa/util/conjunction.hpp \
cppa/util/deduce_ref_type.hpp \ cppa/util/deduce_ref_type.hpp \
cppa/util/disable_if.hpp \
cppa/util/disjunction.hpp \ cppa/util/disjunction.hpp \
cppa/util/duration.hpp \ cppa/util/duration.hpp \
cppa/util/element_at.hpp \ cppa/util/element_at.hpp \
cppa/util/enable_if.hpp \
cppa/util/fiber.hpp \ cppa/util/fiber.hpp \
cppa/util/fixed_vector.hpp \ cppa/util/fixed_vector.hpp \
cppa/util/if_else.hpp \ cppa/util/if_else.hpp \
......
...@@ -57,18 +57,18 @@ struct testee : fsm_actor<testee> ...@@ -57,18 +57,18 @@ struct testee : fsm_actor<testee>
send(parent, atom("result"), (uint32_t) 1); send(parent, atom("result"), (uint32_t) 1);
become_void(); become_void();
}, },
on(atom("spread"), arg_match) >> [=](int x) on<atom("spread"), int>() >> [=](int x)
{ {
any_tuple msg = make_cow_tuple(atom("spread"), x - 1); any_tuple msg = make_cow_tuple(atom("spread"), x - 1);
spawn(new testee(this)) << msg; spawn(new testee(this)) << msg;
spawn(new testee(this)) << msg; spawn(new testee(this)) << msg;
become become
( (
on(atom("result"), arg_match) >> [=](uint32_t r1) on<atom("result"), uint32_t>() >> [=](uint32_t r1)
{ {
become become
( (
on(atom("result"), arg_match) >> [=](uint32_t r2) on<atom("result"), uint32_t>() >> [=](uint32_t r2)
{ {
send(parent, atom("result"), r1 + r2); send(parent, atom("result"), r1 + r2);
become_void(); become_void();
...@@ -89,18 +89,18 @@ void stacked_testee(actor_ptr parent) ...@@ -89,18 +89,18 @@ void stacked_testee(actor_ptr parent)
{ {
send(parent, atom("result"), (uint32_t) 1); send(parent, atom("result"), (uint32_t) 1);
}, },
on(atom("spread"), arg_match) >> [&](int x) on<atom("spread"), int>() >> [&](int x)
{ {
any_tuple msg = make_cow_tuple(atom("spread"), x-1); any_tuple msg = make_cow_tuple(atom("spread"), x-1);
spawn(stacked_testee, self) << msg; spawn(stacked_testee, self) << msg;
spawn(stacked_testee, self) << msg; spawn(stacked_testee, self) << msg;
receive receive
( (
on(atom("result"), arg_match) >> [&](uint32_t v1) on<atom("result"), uint32_t>() >> [&](uint32_t v1)
{ {
receive receive
( (
on(atom("result"),arg_match) >> [&](uint32_t v2) on<atom("result"),uint32_t>() >> [&](uint32_t v2)
{ {
send(parent, atom("result"), v1 + v2); send(parent, atom("result"), v1 + v2);
} }
......
...@@ -30,7 +30,6 @@ cppa/on.hpp ...@@ -30,7 +30,6 @@ cppa/on.hpp
unit_testing/test__serialization.cpp unit_testing/test__serialization.cpp
cppa/serializer.hpp cppa/serializer.hpp
cppa/deserializer.hpp cppa/deserializer.hpp
cppa/util/enable_if.hpp
cppa/object.hpp cppa/object.hpp
cppa/detail/object_impl.hpp cppa/detail/object_impl.hpp
cppa/detail/swap_bytes.hpp cppa/detail/swap_bytes.hpp
...@@ -76,7 +75,6 @@ src/to_uniform_name.cpp ...@@ -76,7 +75,6 @@ src/to_uniform_name.cpp
cppa/detail/default_uniform_type_info_impl.hpp cppa/detail/default_uniform_type_info_impl.hpp
src/object.cpp src/object.cpp
cppa/util/comparable.hpp cppa/util/comparable.hpp
cppa/util/disable_if.hpp
cppa/primitive_variant.hpp cppa/primitive_variant.hpp
cppa/primitive_type.hpp cppa/primitive_type.hpp
cppa/util/pt_token.hpp cppa/util/pt_token.hpp
...@@ -268,3 +266,5 @@ cppa/util/deduce_ref_type.hpp ...@@ -268,3 +266,5 @@ cppa/util/deduce_ref_type.hpp
cppa/detail/projection.hpp cppa/detail/projection.hpp
cppa/detail/value_guard.hpp cppa/detail/value_guard.hpp
cppa/detail/tuple_iterator.hpp cppa/detail/tuple_iterator.hpp
cppa/match_expr.hpp
cppa/detail/pseudo_tuple.hpp
...@@ -41,7 +41,6 @@ ...@@ -41,7 +41,6 @@
#include "cppa/process_information.hpp" #include "cppa/process_information.hpp"
#include "cppa/util/rm_ref.hpp" #include "cppa/util/rm_ref.hpp"
#include "cppa/util/enable_if.hpp"
namespace cppa { namespace cppa {
...@@ -94,7 +93,9 @@ class actor : public channel ...@@ -94,7 +93,9 @@ class actor : public channel
template<typename T> template<typename T>
bool attach(std::unique_ptr<T>&& ptr, bool attach(std::unique_ptr<T>&& ptr,
typename util::enable_if<std::is_base_of<attachable,T>>::type* = 0); typename std::enable_if<
std::is_base_of<attachable,T>::value
>::type* = 0);
/** /**
* @brief Forces this actor to subscribe to the group @p what. * @brief Forces this actor to subscribe to the group @p what.
...@@ -238,7 +239,9 @@ inline bool actor::is_proxy() const ...@@ -238,7 +239,9 @@ inline bool actor::is_proxy() const
template<typename T> template<typename T>
bool actor::attach(std::unique_ptr<T>&& ptr, bool actor::attach(std::unique_ptr<T>&& ptr,
typename util::enable_if<std::is_base_of<attachable,T>>::type*) typename std::enable_if<
std::is_base_of<attachable,T>::value
>::type*)
{ {
return attach(static_cast<attachable*>(ptr.release())); return attach(static_cast<attachable*>(ptr.release()));
} }
......
...@@ -31,13 +31,13 @@ ...@@ -31,13 +31,13 @@
#ifndef ANY_TUPLE_HPP #ifndef ANY_TUPLE_HPP
#define ANY_TUPLE_HPP #define ANY_TUPLE_HPP
#include <type_traits>
#include "cppa/cow_tuple.hpp" #include "cppa/cow_tuple.hpp"
#include "cppa/config.hpp" #include "cppa/config.hpp"
#include "cppa/cow_ptr.hpp" #include "cppa/cow_ptr.hpp"
#include "cppa/util/rm_ref.hpp" #include "cppa/util/rm_ref.hpp"
#include "cppa/util/enable_if.hpp"
#include "cppa/util/disable_if.hpp"
#include "cppa/util/is_iterable.hpp" #include "cppa/util/is_iterable.hpp"
#include "cppa/detail/tuple_view.hpp" #include "cppa/detail/tuple_view.hpp"
...@@ -162,7 +162,11 @@ class any_tuple ...@@ -162,7 +162,11 @@ class any_tuple
template<typename T> template<typename T>
static inline any_tuple view(T&& value, static inline any_tuple view(T&& value,
typename util::enable_if<util::is_iterable<typename util::rm_ref<T>::type> >::type* = 0) typename std::enable_if<
util::is_iterable<
typename util::rm_ref<T>::type
>::value
>::type* = 0)
{ {
static constexpr bool can_optimize = std::is_reference<T>::value static constexpr bool can_optimize = std::is_reference<T>::value
&& !std::is_const<T>::value; && !std::is_const<T>::value;
...@@ -172,7 +176,11 @@ class any_tuple ...@@ -172,7 +176,11 @@ class any_tuple
template<typename T> template<typename T>
static inline any_tuple view(T&& value, static inline any_tuple view(T&& value,
typename util::disable_if<util::is_iterable<typename util::rm_ref<T>::type> >::type* = 0) typename std::enable_if<
util::is_iterable<
typename util::rm_ref<T>::type
>::value == false
>::type* = 0)
{ {
typedef typename util::rm_ref<T>::type vtype; typedef typename util::rm_ref<T>::type vtype;
typedef typename detail::implicit_conversions<vtype>::type converted; typedef typename detail::implicit_conversions<vtype>::type converted;
......
...@@ -34,12 +34,15 @@ ...@@ -34,12 +34,15 @@
#include <functional> #include <functional>
#include <type_traits> #include <type_traits>
#include "cppa/match_expr.hpp"
#include "cppa/partial_function.hpp"
#include "cppa/util/tbind.hpp" #include "cppa/util/tbind.hpp"
#include "cppa/util/rm_ref.hpp" #include "cppa/util/rm_ref.hpp"
#include "cppa/util/if_else.hpp" #include "cppa/util/if_else.hpp"
#include "cppa/util/duration.hpp" #include "cppa/util/duration.hpp"
#include "cppa/util/type_list.hpp" #include "cppa/util/type_list.hpp"
#include "cppa/partial_function.hpp" #include "cppa/util/disjunction.hpp"
namespace cppa { namespace cppa {
...@@ -58,18 +61,27 @@ class behavior ...@@ -58,18 +61,27 @@ class behavior
behavior() = default; behavior() = default;
behavior(behavior&&) = default; behavior(behavior&&) = default;
behavior& operator=(behavior&&) = default;
inline behavior(partial_function&& fun) : m_fun(std::move(fun)) inline behavior(partial_function&& fun) : m_fun(std::move(fun))
{ {
} }
template<typename... Cases>
behavior(match_expr<Cases...> const& me) : m_fun(me) { }
inline behavior(util::duration tout, std::function<void()>&& handler) inline behavior(util::duration tout, std::function<void()>&& handler)
: m_timeout(tout), m_timeout_handler(std::move(handler)) : m_timeout(tout), m_timeout_handler(std::move(handler))
{ {
} }
behavior& operator=(behavior&&) = default;
//behavior& operator=(partial_function&& pfun)
//{
// m_fun = std::move(pfun);
// return *this;
//}
inline void handle_timeout() const inline void handle_timeout() const
{ {
m_timeout_handler(); m_timeout_handler();
...@@ -80,31 +92,11 @@ class behavior ...@@ -80,31 +92,11 @@ class behavior
return m_timeout; return m_timeout;
} }
inline void operator()(any_tuple const& value)
{
m_fun(value);
}
inline partial_function& get_partial_function() inline partial_function& get_partial_function()
{ {
return m_fun; return m_fun;
} }
inline behavior& splice(behavior&& what)
{
m_fun.splice(std::move(what.get_partial_function()));
m_timeout = what.m_timeout;
m_timeout_handler = std::move(what.m_timeout_handler);
return *this;
}
template<class... Args>
inline behavior& splice(partial_function&& arg0, Args&&... args)
{
m_fun.splice(std::move(arg0));
return splice(std::forward<Args>(args)...);
}
private: private:
// terminates recursion // terminates recursion
...@@ -116,16 +108,69 @@ class behavior ...@@ -116,16 +108,69 @@ class behavior
}; };
template<typename... Lhs>
behavior operator,(match_expr<Lhs...> const& lhs,
behavior&& rhs)
{
rhs.get_partial_function() = lhs;
return std::move(rhs);
}
template<typename Arg0>
behavior bhvr_collapse(Arg0&& arg)
{
return {std::forward<Arg0>(arg)};
}
template<typename Arg0, typename Arg1, typename... Args>
behavior bhvr_collapse(Arg0&& arg0, Arg1&& arg1, Args&&... args)
{
return bhvr_collapse((std::forward<Arg0>(arg0), std::forward<Arg1>(arg1)),
std::forward<Args>(args)...);
}
template<typename... Args>
typename std::enable_if<
util::disjunction<std::is_same<behavior, Args>...>::value,
behavior
>::type
match_expr_concat(Args&&... args)
{
return bhvr_collapse(std::forward<Args>(args)...);
}
template<typename... Args>
typename std::enable_if<
util::disjunction<
std::is_same<
behavior,
typename util::rm_ref<Args>::type
>...
>::value == false,
partial_function
>::type
match_expr_concat(Args&&... args)
{
return mexpr_concat_convert(std::forward<Args>(args)...);
}
inline partial_function match_expr_concat(partial_function&& pfun)
{
return std::move(pfun);
}
inline behavior match_expr_concat(behavior&& bhvr)
{
return std::move(bhvr);
}
namespace detail { namespace detail {
template<typename... Ts> template<typename... Ts>
struct select_bhvr struct select_bhvr
{ {
static constexpr bool timed = static constexpr bool timed =
util::tl_exists< util::disjunction<std::is_same<behavior, Ts>...>::value;
util::type_list<Ts...>,
util::tbind<std::is_same, behavior>::type
>::value;
typedef typename util::if_else_c<timed, typedef typename util::if_else_c<timed,
behavior, behavior,
util::wrapped<partial_function> >::type util::wrapped<partial_function> >::type
......
...@@ -55,8 +55,6 @@ ...@@ -55,8 +55,6 @@
#include "cppa/event_based_actor.hpp" #include "cppa/event_based_actor.hpp"
#include "cppa/util/rm_ref.hpp" #include "cppa/util/rm_ref.hpp"
#include "cppa/util/enable_if.hpp"
#include "cppa/util/disable_if.hpp"
#include "cppa/detail/actor_count.hpp" #include "cppa/detail/actor_count.hpp"
#include "cppa/detail/get_behavior.hpp" #include "cppa/detail/get_behavior.hpp"
...@@ -512,9 +510,11 @@ inline actor_ptr spawn(abstract_event_based_actor* what) ...@@ -512,9 +510,11 @@ inline actor_ptr spawn(abstract_event_based_actor* what)
template<scheduling_hint Hint, typename F, typename... Args> template<scheduling_hint Hint, typename F, typename... Args>
auto //actor_ptr auto //actor_ptr
spawn(F&& what, Args const&... args) spawn(F&& what, Args const&... args)
-> typename util::disable_if_c< std::is_convertible<typename util::rm_ref<F>::type, scheduled_actor*>::value -> typename std::enable_if<
|| std::is_convertible<typename util::rm_ref<F>::type, event_based_actor*>::value, !std::is_convertible<typename util::rm_ref<F>::type, scheduled_actor*>::value
actor_ptr>::type && !std::is_convertible<typename util::rm_ref<F>::type, event_based_actor*>::value,
actor_ptr
>::type
{ {
typedef typename util::rm_ref<F>::type ftype; typedef typename util::rm_ref<F>::type ftype;
std::integral_constant<bool, std::is_function<ftype>::value> is_fun; std::integral_constant<bool, std::is_function<ftype>::value> is_fun;
...@@ -529,9 +529,11 @@ spawn(F&& what, Args const&... args) ...@@ -529,9 +529,11 @@ spawn(F&& what, Args const&... args)
template<typename F, typename... Args> template<typename F, typename... Args>
auto // actor_ptr auto // actor_ptr
spawn(F&& what, Args const&... args) spawn(F&& what, Args const&... args)
-> typename util::disable_if_c< std::is_convertible<typename util::rm_ref<F>::type, scheduled_actor*>::value -> typename std::enable_if<
|| std::is_convertible<typename util::rm_ref<F>::type, event_based_actor*>::value, !std::is_convertible<typename util::rm_ref<F>::type, scheduled_actor*>::value
actor_ptr>::type && !std::is_convertible<typename util::rm_ref<F>::type, event_based_actor*>::value,
actor_ptr
>::type
{ {
return spawn<scheduled>(std::forward<F>(what), args...); return spawn<scheduled>(std::forward<F>(what), args...);
} }
...@@ -590,7 +592,10 @@ inline void send(self_type const&, Arg0 const& arg0, Args const&... args) ...@@ -590,7 +592,10 @@ inline void send(self_type const&, Arg0 const& arg0, Args const&... args)
} }
template<class C> template<class C>
typename util::enable_if<std::is_base_of<channel, C>, intrusive_ptr<C>&>::type typename std::enable_if<
std::is_base_of<channel, C>::value,
intrusive_ptr<C>&
>::type
operator<<(intrusive_ptr<C>& whom, any_tuple const& what) operator<<(intrusive_ptr<C>& whom, any_tuple const& what)
{ {
if (whom) whom->enqueue(self, what); if (whom) whom->enqueue(self, what);
...@@ -598,7 +603,10 @@ operator<<(intrusive_ptr<C>& whom, any_tuple const& what) ...@@ -598,7 +603,10 @@ operator<<(intrusive_ptr<C>& whom, any_tuple const& what)
} }
template<class C> template<class C>
typename util::enable_if<std::is_base_of<channel, C>, intrusive_ptr<C>>::type typename std::enable_if<
std::is_base_of<channel, C>::value,
intrusive_ptr<C>
>::type
operator<<(intrusive_ptr<C>&& whom, any_tuple const& what) operator<<(intrusive_ptr<C>&& whom, any_tuple const& what)
{ {
intrusive_ptr<C> tmp(std::move(whom)); intrusive_ptr<C> tmp(std::move(whom));
...@@ -607,7 +615,10 @@ operator<<(intrusive_ptr<C>&& whom, any_tuple const& what) ...@@ -607,7 +615,10 @@ operator<<(intrusive_ptr<C>&& whom, any_tuple const& what)
} }
template<class C> template<class C>
typename util::enable_if<std::is_base_of<channel, C>, intrusive_ptr<C>&>::type typename std::enable_if<
std::is_base_of<channel, C>::value,
intrusive_ptr<C>&
>::type
operator<<(intrusive_ptr<C>& whom, any_tuple&& what) operator<<(intrusive_ptr<C>& whom, any_tuple&& what)
{ {
if (whom) whom->enqueue(self, std::move(what)); if (whom) whom->enqueue(self, std::move(what));
...@@ -615,7 +626,10 @@ operator<<(intrusive_ptr<C>& whom, any_tuple&& what) ...@@ -615,7 +626,10 @@ operator<<(intrusive_ptr<C>& whom, any_tuple&& what)
} }
template<class C> template<class C>
typename util::enable_if<std::is_base_of<channel, C>, intrusive_ptr<C>>::type typename std::enable_if<
std::is_base_of<channel, C>::value,
intrusive_ptr<C>
>::type
operator<<(intrusive_ptr<C>&& whom, any_tuple&& what) operator<<(intrusive_ptr<C>&& whom, any_tuple&& what)
{ {
intrusive_ptr<C> tmp(std::move(whom)); intrusive_ptr<C> tmp(std::move(whom));
......
...@@ -263,7 +263,7 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T ...@@ -263,7 +263,7 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T
// pr.first = getter member const function pointer // pr.first = getter member const function pointer
// pr.second = setter member function pointer // pr.second = setter member function pointer
template<typename GRes, typename SRes, typename SArg, class C, typename... Args> template<typename GRes, typename SRes, typename SArg, class C, typename... Args>
typename util::enable_if<util::is_primitive<typename util::rm_ref<GRes>::type> >::type typename std::enable_if<util::is_primitive<typename util::rm_ref<GRes>::type>::value>::type
push_back(const std::pair<GRes (C::*)() const, SRes (C::*)(SArg)>& pr, push_back(const std::pair<GRes (C::*)() const, SRes (C::*)(SArg)>& pr,
Args&&... args) Args&&... args)
{ {
...@@ -273,7 +273,7 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T ...@@ -273,7 +273,7 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T
} }
template<typename R, class C, typename... Args> template<typename R, class C, typename... Args>
typename util::enable_if<util::is_primitive<R> >::type typename std::enable_if<util::is_primitive<R>::value>::type
push_back(R C::*mem_ptr, Args&&... args) push_back(R C::*mem_ptr, Args&&... args)
{ {
m_members.push_back({ new primitive_member<R>(), mem_ptr }); m_members.push_back({ new primitive_member<R>(), mem_ptr });
...@@ -281,7 +281,7 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T ...@@ -281,7 +281,7 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T
} }
template< typename R, class C,typename... Args> template< typename R, class C,typename... Args>
typename util::enable_if<is_stl_compliant_list<R> >::type typename std::enable_if<is_stl_compliant_list<R>::value>::type
push_back(R C::*mem_ptr, Args&&... args) push_back(R C::*mem_ptr, Args&&... args)
{ {
m_members.push_back({ new list_member<R>(), mem_ptr }); m_members.push_back({ new list_member<R>(), mem_ptr });
...@@ -289,7 +289,7 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T ...@@ -289,7 +289,7 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T
} }
template<typename R, class C, typename... Args> template<typename R, class C, typename... Args>
typename util::enable_if<is_stl_compliant_map<R> >::type typename std::enable_if<is_stl_compliant_map<R>::value>::type
push_back(R C::*mem_ptr, Args&&... args) push_back(R C::*mem_ptr, Args&&... args)
{ {
m_members.push_back({ new map_member<R>(), mem_ptr }); m_members.push_back({ new map_member<R>(), mem_ptr });
...@@ -297,7 +297,7 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T ...@@ -297,7 +297,7 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T
} }
template<typename R, class C, typename... Args> template<typename R, class C, typename... Args>
typename util::enable_if<is_invalid<R>>::type typename std::enable_if<is_invalid<R>::value>::type
push_back(R C::*mem_ptr, Args&&... args) push_back(R C::*mem_ptr, Args&&... args)
{ {
static_assert(util::is_primitive<R>::value, static_assert(util::is_primitive<R>::value,
...@@ -306,25 +306,25 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T ...@@ -306,25 +306,25 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T
} }
template<typename P> template<typename P>
void init_(typename util::enable_if<util::is_primitive<P>>::type* = 0) void init_(typename std::enable_if<util::is_primitive<P>::value>::type* = 0)
{ {
m_members.push_back(member::fake_member(new primitive_member<P>())); m_members.push_back(member::fake_member(new primitive_member<P>()));
} }
template<typename Map> template<typename Map>
void init_(typename util::enable_if<is_stl_compliant_map<Map>>::type* = 0) void init_(typename std::enable_if<is_stl_compliant_map<Map>::value>::type* = 0)
{ {
m_members.push_back(member::fake_member(new map_member<Map>)); m_members.push_back(member::fake_member(new map_member<Map>));
} }
template<typename List> template<typename List>
void init_(typename util::enable_if<is_stl_compliant_list<List>>::type* = 0) void init_(typename std::enable_if<is_stl_compliant_list<List>::value>::type* = 0)
{ {
m_members.push_back(member::fake_member(new list_member<List>)); m_members.push_back(member::fake_member(new list_member<List>));
} }
template<typename X> template<typename X>
void init_(typename util::enable_if<is_invalid<X>>::type* = 0) void init_(typename std::enable_if<is_invalid<X>::value>::type* = 0)
{ {
// T is neither primitive nor a STL compliant list/map, // T is neither primitive nor a STL compliant list/map,
// so it has to be an announced type // so it has to be an announced type
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "cppa/util/rm_option.hpp" #include "cppa/util/rm_option.hpp"
#include "cppa/util/type_list.hpp" #include "cppa/util/type_list.hpp"
#include "cppa/util/apply_args.hpp"
#include "cppa/util/apply_tuple.hpp" #include "cppa/util/apply_tuple.hpp"
#include "cppa/util/left_or_right.hpp" #include "cppa/util/left_or_right.hpp"
...@@ -71,6 +72,9 @@ class projection ...@@ -71,6 +72,9 @@ class projection
typedef typename tdata_from_type_list<ProjectionFuns>::type fun_container; typedef typename tdata_from_type_list<ProjectionFuns>::type fun_container;
projection() = default;
projection(fun_container&& args) : m_funs(std::move(args)) { }
projection(fun_container const& args) : m_funs(args) { } projection(fun_container const& args) : m_funs(args) { }
...@@ -170,6 +174,7 @@ class projection<util::type_list<> > ...@@ -170,6 +174,7 @@ class projection<util::type_list<> >
fun(); fun();
return true; return true;
} }
}; };
template<class ProjectionFuns, class List> template<class ProjectionFuns, class List>
......
...@@ -28,32 +28,64 @@ ...@@ -28,32 +28,64 @@
\******************************************************************************/ \******************************************************************************/
#ifndef ENABLE_IF_HPP #ifndef PSEUDO_TUPLE_HPP
#define ENABLE_IF_HPP #define PSEUDO_TUPLE_HPP
namespace cppa { namespace util { #include "cppa/util/at.hpp"
template<bool Stmt, typename T = void> namespace cppa { namespace detail {
struct enable_if_c
template<typename... T>
struct pseudo_tuple
{ {
typedef void* ptr_type;
typedef void const* const_ptr_type;
ptr_type data[sizeof...(T) > 0 ? sizeof...(T) : 1];
inline const_ptr_type at(size_t p) const
{
return data[p];
}
inline ptr_type mutable_at(size_t p)
{
return const_cast<ptr_type>(data[p]);
}
inline void*& operator[](size_t p)
{
return data[p];
}
}; };
template<typename T> template<class List>
struct enable_if_c<true, T> struct pseudo_tuple_from_type_list;
template<typename... Ts>
struct pseudo_tuple_from_type_list<util::type_list<Ts...> >
{ {
typedef T type; typedef pseudo_tuple<Ts...> type;
}; };
/** } } // namespace cppa::detail
* @ingroup MetaProgramming
* @brief SFINAE trick to enable a template function based on its namespace cppa {
* template parameters.
*/ template<size_t N, typename... Tn>
template<class Trait, typename T = void> typename util::at<N, Tn...>::type const& get(detail::pseudo_tuple<Tn...> const& tv)
struct enable_if : enable_if_c<Trait::value, T>
{ {
}; static_assert(N < sizeof...(Tn), "N >= tv.size()");
return *reinterpret_cast<typename util::at<N, Tn...>::type const*>(tv.at(N));
}
template<size_t N, typename... Tn>
typename util::at<N, Tn...>::type& get_ref(detail::pseudo_tuple<Tn...>& tv)
{
static_assert(N < sizeof...(Tn), "N >= tv.size()");
return *reinterpret_cast<typename util::at<N, Tn...>::type*>(tv.mutable_at(N));
}
} } // namespace cppa::util } // namespace cppa
#endif // ENABLE_IF_HPP #endif // PSEUDO_TUPLE_HPP
...@@ -66,18 +66,14 @@ struct receive_while_helper ...@@ -66,18 +66,14 @@ struct receive_while_helper
while (m_stmt()) sptr->dequeue(fun); while (m_stmt()) sptr->dequeue(fun);
} }
void operator()(behavior&& bhvr) template<typename Arg0, typename... Args>
void operator()(Arg0&& arg0, Args&&... args)
{ {
behavior tmp{std::move(bhvr)}; auto tmp = match_expr_concat(std::forward<Arg0>(arg0),
std::forward<Args>(args)...);
(*this)(tmp); (*this)(tmp);
} }
template<typename... Args>
void operator()(partial_function&& arg0, Args&&... args)
{
typename select_bhvr<Args...>::type tmp;
(*this)(tmp.splice(std::move(arg0), std::forward<Args>(args)...));
}
}; };
...@@ -104,19 +100,14 @@ class receive_for_helper ...@@ -104,19 +100,14 @@ class receive_for_helper
for ( ; begin != end; ++begin) sptr->dequeue(fun); for ( ; begin != end; ++begin) sptr->dequeue(fun);
} }
void operator()(behavior&& bhvr) template<typename Arg0, typename... Args>
void operator()(Arg0&& arg0, Args&&... args)
{ {
behavior tmp{std::move(bhvr)}; auto tmp = match_expr_concat(std::forward<Arg0>(arg0),
std::forward<Args>(args)...);
(*this)(tmp); (*this)(tmp);
} }
template<typename... Args>
void operator()(partial_function&& arg0, Args&&... args)
{
typename select_bhvr<Args...>::type tmp;
(*this)(tmp.splice(std::move(arg0), std::forward<Args>(args)...));
}
}; };
class do_receive_helper class do_receive_helper
...@@ -126,14 +117,10 @@ class do_receive_helper ...@@ -126,14 +117,10 @@ class do_receive_helper
public: public:
do_receive_helper(behavior&& bhvr) : m_bhvr(std::move(bhvr)) template<typename... Args>
{ do_receive_helper(Args&&... args)
} : m_bhvr(match_expr_concat(std::forward<Args>(args)...))
template<typename Arg0, typename... Args>
do_receive_helper(Arg0&& arg0, Args&&... args)
{ {
m_bhvr.splice(std::forward<Arg0>(arg0), std::forward<Args>(args)...);
} }
do_receive_helper(do_receive_helper&&) = default; do_receive_helper(do_receive_helper&&) = default;
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <typeinfo> #include <typeinfo>
#include <functional> #include <functional>
#include <type_traits>
#include "cppa/get.hpp" #include "cppa/get.hpp"
#include "cppa/option.hpp" #include "cppa/option.hpp"
...@@ -40,8 +41,6 @@ ...@@ -40,8 +41,6 @@
#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/enable_if.hpp"
#include "cppa/util/disable_if.hpp"
#include "cppa/util/arg_match_t.hpp" #include "cppa/util/arg_match_t.hpp"
#include "cppa/detail/boxed.hpp" #include "cppa/detail/boxed.hpp"
...@@ -151,7 +150,8 @@ struct tdata<> ...@@ -151,7 +150,8 @@ struct tdata<>
tdata(Args&&...) tdata(Args&&...)
{ {
typedef util::type_list<typename util::rm_ref<Args>::type...> incoming; typedef util::type_list<typename util::rm_ref<Args>::type...> incoming;
static_assert(util::tl_forall<incoming, boxed_or_void>::value, typedef typename util::tl_filter_not_type<incoming, tdata>::type iargs;
static_assert(util::tl_forall<iargs, boxed_or_void>::value,
"Additional unboxed arguments provided"); "Additional unboxed arguments provided");
} }
...@@ -163,10 +163,6 @@ struct tdata<> ...@@ -163,10 +163,6 @@ struct tdata<>
inline const_iterator end() const { return {this}; } inline const_iterator end() const { return {this}; }
inline const_iterator cend() const { return {this}; } inline const_iterator cend() const { return {this}; }
inline tdata(tdata&) { }
inline tdata(tdata&&) { }
inline tdata(tdata const&) { }
inline size_t size() const { return num_elements; } inline size_t size() const { return num_elements; }
tdata<>& tail() { return *this; } tdata<>& tail() { return *this; }
...@@ -276,15 +272,22 @@ struct tdata<Head, Tail...> : tdata<Tail...> ...@@ -276,15 +272,22 @@ struct tdata<Head, Tail...> : tdata<Tail...>
//tdata(Head const& v0, Tail const&... vals) : super(vals...), head(v0) { } //tdata(Head const& v0, Tail const&... vals) : super(vals...), head(v0) { }
template<typename Arg0, typename... Args> tdata(Head arg) : super(), head(std::move(arg)) { }
tdata(Arg0&& arg0, Args&&... args)
: super(std::forward<Args>(args)...) template<typename Arg0, typename Arg1, typename... Args>
tdata(Arg0&& arg0, Arg1&& arg1, Args&&... args)
: super(std::forward<Arg1>(arg1), std::forward<Args>(args)...)
, head(td_filter<Head>(std::forward<Arg0>(arg0))) , head(td_filter<Head>(std::forward<Arg0>(arg0)))
{ {
} }
tdata(tdata const&) = default; tdata(tdata const&) = default;
tdata(tdata&& other)
: super(std::move(other.tail())), head(std::move(other.head))
{
}
// allow (partial) initialization from a different tdata // allow (partial) initialization from a different tdata
template<typename... Y> template<typename... Y>
......
...@@ -62,18 +62,12 @@ class event_based_actor_base : public abstract_event_based_actor ...@@ -62,18 +62,12 @@ class event_based_actor_base : public abstract_event_based_actor
} }
/** @brief Sets the actor's behavior. */ /** @brief Sets the actor's behavior. */
template<typename... Args> template<typename Arg0, typename... Args>
void become(partial_function&& arg0, Args&&... args) void become(Arg0&& arg0, Args&&... args)
{ {
auto ptr = new behavior; behavior tmp = match_expr_concat(std::forward<Arg0>(arg0),
ptr->splice(std::move(arg0), std::forward<Args>(args)...); std::forward<Args>(args)...);
d_this()->do_become(ptr, true); d_this()->do_become(new behavior(std::move(tmp)), true);
}
/** @brief Sets the actor's behavior to @p bhvr. */
inline void become(behavior&& bhvr)
{
d_this()->do_become(new behavior(std::move(bhvr)), true);
} }
}; };
......
...@@ -34,7 +34,6 @@ ...@@ -34,7 +34,6 @@
#include <type_traits> #include <type_traits>
#include "cppa/util/rm_ref.hpp" #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 {
......
...@@ -38,10 +38,13 @@ ...@@ -38,10 +38,13 @@
namespace cppa { namespace cppa {
// forward declaration of detail::tdata // forward declaration of details
namespace detail { template<typename...> class tdata; } namespace detail {
template<typename...> class tdata;
template<typename...> struct pseudo_tuple;
}
// forward declaration of tuple // forward declaration of cow_tuple
template<typename...> class cow_tuple; template<typename...> class cow_tuple;
// forward declaration of get(detail::tdata<...> const&) // forward declaration of get(detail::tdata<...> const&)
...@@ -52,6 +55,10 @@ typename util::at<N, Tn...>::type const& get(detail::tdata<Tn...> const&); ...@@ -52,6 +55,10 @@ typename util::at<N, Tn...>::type const& get(detail::tdata<Tn...> const&);
template<size_t N, typename... Tn> template<size_t N, typename... Tn>
typename util::at<N, Tn...>::type const& get(cow_tuple<Tn...> const&); typename util::at<N, Tn...>::type const& get(cow_tuple<Tn...> const&);
// forward declarations of get(detail::pseudo_tuple<...>&)
template<size_t N, typename... Tn>
typename util::at<N, Tn...>::type const& get(detail::pseudo_tuple<Tn...> const& tv);
// forward declarations of get_ref(detail::tdata<...>&) // forward declarations of get_ref(detail::tdata<...>&)
template<size_t N, typename... Tn> template<size_t N, typename... Tn>
typename util::at<N, Tn...>::type& get_ref(detail::tdata<Tn...>&); typename util::at<N, Tn...>::type& get_ref(detail::tdata<Tn...>&);
...@@ -60,6 +67,10 @@ typename util::at<N, Tn...>::type& get_ref(detail::tdata<Tn...>&); ...@@ -60,6 +67,10 @@ typename util::at<N, Tn...>::type& get_ref(detail::tdata<Tn...>&);
template<size_t N, typename... Tn> template<size_t N, typename... Tn>
typename util::at<N, Tn...>::type& get_ref(cow_tuple<Tn...>&); typename util::at<N, Tn...>::type& get_ref(cow_tuple<Tn...>&);
// forward declarations of get_ref(detail::pseudo_tuple<...>&)
template<size_t N, typename... Tn>
typename util::at<N, Tn...>::type& get_ref(detail::pseudo_tuple<Tn...>& tv);
// support container-like access for type lists containing tokens // support container-like access for type lists containing tokens
template<size_t N, typename... Ts> template<size_t N, typename... Ts>
typename util::at<N, Ts...>::type get(util::type_list<Ts...> const&) typename util::at<N, Ts...>::type get(util::type_list<Ts...> const&)
......
...@@ -41,7 +41,6 @@ ...@@ -41,7 +41,6 @@
#include "cppa/util/at.hpp" #include "cppa/util/at.hpp"
#include "cppa/util/void_type.hpp" #include "cppa/util/void_type.hpp"
#include "cppa/util/enable_if.hpp"
#include "cppa/util/apply_tuple.hpp" #include "cppa/util/apply_tuple.hpp"
#include "cppa/detail/tdata.hpp" #include "cppa/detail/tdata.hpp"
...@@ -427,7 +426,7 @@ template<operator_id OP, typename T1, typename T2> ...@@ -427,7 +426,7 @@ template<operator_id OP, typename T1, typename T2>
guard_expr<OP, typename detail::strip_and_convert<T1>::type, guard_expr<OP, typename detail::strip_and_convert<T1>::type,
typename detail::strip_and_convert<T2>::type> typename detail::strip_and_convert<T2>::type>
ge_concatenate(T1 first, T2 second, ge_concatenate(T1 first, T2 second,
typename util::enable_if_c< typename std::enable_if<
is_ge_type<T1>::value || is_ge_type<T2>::value is_ge_type<T1>::value || is_ge_type<T2>::value
>::type* = 0) >::type* = 0)
{ {
......
...@@ -36,7 +36,6 @@ ...@@ -36,7 +36,6 @@
#include <stdexcept> #include <stdexcept>
#include <type_traits> #include <type_traits>
#include "cppa/util/enable_if.hpp"
#include "cppa/util/comparable.hpp" #include "cppa/util/comparable.hpp"
namespace cppa { namespace cppa {
......
...@@ -43,12 +43,16 @@ struct match_helper ...@@ -43,12 +43,16 @@ struct match_helper
any_tuple tup; any_tuple tup;
match_helper(any_tuple&& t) : tup(std::move(t)) { } match_helper(any_tuple&& t) : tup(std::move(t)) { }
match_helper(match_helper&&) = default; match_helper(match_helper&&) = default;
template<class... Args> void operator()(partial_function&& arg)
void operator()(partial_function&& pf, Args&&... args)
{ {
partial_function tmp; partial_function tmp{std::move(arg)};
tmp.splice(std::move(pf), std::forward<Args>(args)...); tmp(tup);
tmp(std::move(tup)); }
template<class Arg0, class... Args>
void operator()(Arg0&& arg0, Args&&... args)
{
(*this)(mexpr_concat_convert(std::forward<Arg0>(arg0),
std::forward<Args>(args)...));
} }
}; };
...@@ -61,16 +65,20 @@ struct match_each_helper ...@@ -61,16 +65,20 @@ struct match_each_helper
Iterator e; Iterator e;
match_each_helper(Iterator first, Iterator last) : i(first), e(last) { } match_each_helper(Iterator first, Iterator last) : i(first), e(last) { }
match_each_helper(match_each_helper&&) = default; match_each_helper(match_each_helper&&) = default;
template<typename... Args> void operator()(partial_function&& arg)
void operator()(partial_function&& arg0, Args&&... args)
{ {
partial_function tmp; partial_function tmp{std::move(arg)};
tmp.splice(std::move(arg0), std::forward<Args>(args)...);
for (; i != e; ++i) for (; i != e; ++i)
{ {
tmp(any_tuple::view(*i)); tmp(any_tuple::view(*i));
} }
} }
template<class Arg0, class... Args>
void operator()(Arg0&& arg0, Args&&... args)
{
(*this)(mexpr_concat_convert(std::forward<Arg0>(arg0),
std::forward<Args>(args)...));
}
}; };
template<class Container> template<class Container>
...@@ -81,16 +89,20 @@ struct copying_match_each_helper ...@@ -81,16 +89,20 @@ struct copying_match_each_helper
Container vec; Container vec;
copying_match_each_helper(Container tmp) : vec(std::move(tmp)) { } copying_match_each_helper(Container tmp) : vec(std::move(tmp)) { }
copying_match_each_helper(copying_match_each_helper&&) = default; copying_match_each_helper(copying_match_each_helper&&) = default;
template<typename... Args> void operator()(partial_function&& arg)
void operator()(partial_function&& arg0, Args&&... args)
{ {
partial_function tmp; partial_function tmp{std::move(arg)};
tmp.splice(std::move(arg0), std::forward<Args>(args)...);
for (auto& i : vec) for (auto& i : vec)
{ {
tmp(any_tuple::view(i)); tmp(any_tuple::view(i));
} }
} }
template<class Arg0, class... Args>
void operator()(Arg0&& arg0, Args&&... args)
{
(*this)(mexpr_concat_convert(std::forward<Arg0>(arg0),
std::forward<Args>(args)...));
}
}; };
template<typename Iterator, typename Projection> template<typename Iterator, typename Projection>
...@@ -107,16 +119,20 @@ struct pmatch_each_helper ...@@ -107,16 +119,20 @@ struct pmatch_each_helper
: i(first), e(last), p(std::forward<PJ>(proj)) : i(first), e(last), p(std::forward<PJ>(proj))
{ {
} }
template<typename... Args> void operator()(partial_function&& arg)
void operator()(partial_function&& arg0, Args&&... args)
{ {
partial_function tmp; partial_function tmp{std::move(arg)};
tmp.splice(std::move(arg0), std::forward<Args>(args)...);
for (; i != e; ++i) for (; i != e; ++i)
{ {
tmp(any_tuple::view(p(*i))); tmp(any_tuple::view(p(*i)));
} }
} }
template<class Arg0, class... Args>
void operator()(Arg0&& arg0, Args&&... args)
{
(*this)(mexpr_concat_convert(std::forward<Arg0>(arg0),
std::forward<Args>(args)...));
}
}; };
} } // namespace cppa::detail } } // namespace cppa::detail
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011, 2012 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation, either version 3 of the License *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef MATCH_EXPR_HPP
#define MATCH_EXPR_HPP
#include "cppa/option.hpp"
#include "cppa/pattern.hpp"
#include "cppa/guard_expr.hpp"
#include "cppa/partial_function.hpp"
#include "cppa/tpartial_function.hpp"
#include "cppa/util/rm_ref.hpp"
#include "cppa/util/type_list.hpp"
#include "cppa/util/rm_option.hpp"
#include "cppa/util/purge_refs.hpp"
#include "cppa/util/left_or_right.hpp"
#include "cppa/util/deduce_ref_type.hpp"
#include "cppa/detail/projection.hpp"
#include "cppa/detail/value_guard.hpp"
#include "cppa/detail/pseudo_tuple.hpp"
namespace cppa { namespace detail {
// covers wildcard_position::multiple and wildcard_position::in_between
template<wildcard_position, class Pattern, class FilteredPattern>
struct invoke_policy_impl
{
typedef FilteredPattern filtered_pattern;
template<class Tuple>
static bool can_invoke(std::type_info const& type_token,
Tuple const& tup)
{
typedef typename match_impl_from_type_list<Tuple, Pattern>::type mimpl;
return type_token == typeid(filtered_pattern) || mimpl::_(tup);
}
template<class Target, typename PtrType, class Tuple>
static bool invoke(Target& target,
std::type_info const& type_token,
detail::tuple_impl_info,
PtrType*,
Tuple& tup)
{
typedef typename match_impl_from_type_list<
typename std::remove_const<Tuple>::type,
Pattern
>::type
mimpl;
util::fixed_vector<size_t, filtered_pattern::size> mv;
if (type_token == typeid(filtered_pattern) || mimpl::_(tup, mv))
{
typedef typename pseudo_tuple_from_type_list<filtered_pattern>::type
ttup_type;
ttup_type ttup;
// if we strip const here ...
for (size_t i = 0; i < filtered_pattern::size; ++i)
{
ttup[i] = const_cast<void*>(tup.at(mv[i]));
}
// ... we restore it here again
typedef typename util::if_else<
std::is_const<Tuple>,
ttup_type const&,
util::wrapped<ttup_type&>
>::type
ttup_ref;
ttup_ref ttup_fwd = ttup;
return util::unchecked_apply_tuple<bool>(target, ttup_fwd);
}
return false;
}
};
template<class Pattern, typename... Ts>
struct invoke_policy_impl<wildcard_position::nil,
Pattern, util::type_list<Ts...> >
{
typedef util::type_list<Ts...> filtered_pattern;
typedef detail::tdata<Ts...> native_data_type;
typedef typename detail::static_types_array<Ts...> arr_type;
template<class Target, class Tup>
static bool invoke(std::integral_constant<bool, false>, Target&, Tup&)
{
return false;
}
template<class Target, class Tup>
static bool invoke(std::integral_constant<bool, true>,
Target& target, Tup& tup)
{
return util::unchecked_apply_tuple<bool>(target, tup);
}
template<class Target, typename PtrType, class Tuple>
static bool invoke(Target& target,
std::type_info const&,
detail::tuple_impl_info,
PtrType*,
Tuple& tup,
typename std::enable_if<
std::is_same<
typename std::remove_const<Tuple>::type,
detail::abstract_tuple
>::value == false
>::type* = 0)
{
static constexpr bool can_apply =
util::tl_binary_forall<
typename util::tl_map<
typename Tuple::types,
util::purge_refs
>::type,
filtered_pattern,
std::is_same
>::value;
return invoke(std::integral_constant<bool, can_apply>{}, target, tup);
}
template<class Target, typename PtrType, typename Tuple>
static bool invoke(Target& target,
std::type_info const& arg_types,
detail::tuple_impl_info timpl,
PtrType* native_arg,
Tuple& tup,
typename std::enable_if<
std::is_same<
typename std::remove_const<Tuple>::type,
detail::abstract_tuple
>::value
>::type* = 0)
{
if (arg_types == typeid(filtered_pattern))
{
if (native_arg)
{
typedef typename util::if_else_c<
std::is_const<PtrType>::value,
native_data_type const*,
util::wrapped<native_data_type*>
>::type
cast_type;
auto arg = reinterpret_cast<cast_type>(native_arg);
return util::unchecked_apply_tuple<bool>(target, *arg);
}
// 'fall through'
}
else if (timpl == detail::dynamically_typed)
{
auto& arr = arr_type::arr;
if (tup.size() != filtered_pattern::size)
{
return false;
}
for (size_t i = 0; i < filtered_pattern::size; ++i)
{
if (arr[i] != tup.type_at(i))
{
return false;
}
}
// 'fall through'
}
else
{
return false;
}
typedef pseudo_tuple<Ts...> ttup_type;
ttup_type ttup;
// if we strip const here ...
for (size_t i = 0; i < sizeof...(Ts); ++i)
ttup[i] = const_cast<void*>(tup.at(i));
// ... we restore it here again
typedef typename util::if_else<
std::is_const<PtrType>,
ttup_type const&,
util::wrapped<ttup_type&>
>::type
ttup_ref;
ttup_ref ttup_fwd = ttup;
return util::unchecked_apply_tuple<bool>(target, ttup_fwd);
}
template<class Tuple>
static bool can_invoke(std::type_info const& arg_types, Tuple const&)
{
return arg_types == typeid(filtered_pattern);
}
};
template<>
struct invoke_policy_impl<wildcard_position::leading,
util::type_list<anything>,
util::type_list<> >
{
template<class Tuple>
static inline bool can_invoke(std::type_info const&,
Tuple const&)
{
return true;
}
template<class Target, typename PtrType, typename Tuple>
static bool invoke(Target& target,
std::type_info const&,
detail::tuple_impl_info,
PtrType*,
Tuple&)
{
return target();
}
};
template<class Pattern, typename... Ts>
struct invoke_policy_impl<wildcard_position::trailing,
Pattern, util::type_list<Ts...> >
{
typedef util::type_list<Ts...> filtered_pattern;
template<class Tuple>
static bool can_invoke(std::type_info const& arg_types,
Tuple const& tup)
{
if (arg_types == typeid(filtered_pattern))
{
return true;
}
typedef detail::static_types_array<Ts...> arr_type;
auto& arr = arr_type::arr;
if (tup.size() < filtered_pattern::size)
{
return false;
}
for (size_t i = 0; i < filtered_pattern::size; ++i)
{
if (arr[i] != tup.type_at(i))
{
return false;
}
}
return true;
}
template<class Target, typename PtrType, class Tuple>
static bool invoke(Target& target,
std::type_info const& arg_types,
detail::tuple_impl_info,
PtrType*,
Tuple& tup)
{
if (!can_invoke(arg_types, tup)) return false;
typedef pseudo_tuple<Ts...> ttup_type;
ttup_type ttup;
for (size_t i = 0; i < sizeof...(Ts); ++i)
ttup[i] = const_cast<void*>(tup.at(i));
// ensure const-correctness
typedef typename util::if_else<
std::is_const<Tuple>,
ttup_type const&,
util::wrapped<ttup_type&>
>::type
ttup_ref;
ttup_ref ttup_fwd = ttup;
return util::unchecked_apply_tuple<bool>(target, ttup_fwd);
}
};
template<class Pattern, typename... Ts>
struct invoke_policy_impl<wildcard_position::leading,
Pattern, util::type_list<Ts...> >
{
typedef util::type_list<Ts...> filtered_pattern;
template<class Tuple>
static bool can_invoke(std::type_info const& arg_types,
Tuple const& tup)
{
if (arg_types == typeid(filtered_pattern))
{
return true;
}
typedef detail::static_types_array<Ts...> arr_type;
auto& arr = arr_type::arr;
if (tup.size() < filtered_pattern::size)
{
return false;
}
size_t i = tup.size() - filtered_pattern::size;
size_t j = 0;
while (j < filtered_pattern::size)
{
if (arr[i++] != tup.type_at(j++))
{
return false;
}
}
return true;
}
template<class Target, typename PtrType, class Tuple>
static bool invoke(Target& target,
std::type_info const& arg_types,
detail::tuple_impl_info,
PtrType*,
Tuple& tup)
{
if (!can_invoke(arg_types, tup)) return false;
typedef pseudo_tuple<Ts...> ttup_type;
ttup_type ttup;
size_t i = tup.size() - filtered_pattern::size;
size_t j = 0;
while (j < filtered_pattern::size)
{
ttup[j++] = const_cast<void*>(tup.at(i++));
}
// ensure const-correctness
typedef typename util::if_else<
std::is_const<Tuple>,
ttup_type const&,
util::wrapped<ttup_type&>
>::type
ttup_ref;
ttup_ref ttup_fwd = ttup;
return util::unchecked_apply_tuple<bool>(target, ttup_fwd);
}
};
template<class Pattern>
struct invoke_policy
: invoke_policy_impl<
get_wildcard_position<Pattern>(),
Pattern,
typename util::tl_filter_not_type<Pattern, anything>::type>
{
};
template<class Pattern, class Projection, class PartialFunction>
struct projection_partial_function_pair : std::pair<Projection, PartialFunction>
{
template<typename... Args>
projection_partial_function_pair(Args&&... args)
: std::pair<Projection, PartialFunction>(std::forward<Args>(args)...)
{
}
typedef Pattern pattern_type;
};
template<class Expr, class Guard, class Transformers, class Pattern>
struct get_case_
{
typedef typename util::get_callable_trait<Expr>::type ctrait;
typedef typename util::tl_filter_not_type<
Pattern,
anything
>::type
filtered_pattern;
typedef typename util::tl_pad_right<
Transformers,
filtered_pattern::size
>::type
padded_transformers;
typedef typename util::tl_map<
filtered_pattern,
std::add_const,
std::add_lvalue_reference
>::type
base_signature;
typedef typename util::tl_map_conditional<
typename util::tl_pad_left<
typename ctrait::arg_types,
filtered_pattern::size
>::type,
std::is_lvalue_reference,
false,
std::add_const,
std::add_lvalue_reference
>::type
padded_expr_args;
// override base signature with required argument types of Expr
// and result types of transformation
typedef typename util::tl_zip<
typename util::tl_map<
padded_transformers,
util::get_result_type,
util::rm_option,
std::add_lvalue_reference
>::type,
typename util::tl_zip<
padded_expr_args,
base_signature,
util::left_or_right
>::type,
util::left_or_right
>::type
partial_fun_signature;
// 'inherit' mutable references from partial_fun_signature
// for arguments without transformation
typedef typename util::tl_zip<
typename util::tl_zip<
padded_transformers,
partial_fun_signature,
util::if_not_left
>::type,
base_signature,
util::deduce_ref_type
>::type
projection_signature;
typedef typename projection_from_type_list<
padded_transformers,
projection_signature
>::type
type1;
typedef typename get_tpartial_function<
Expr,
Guard,
partial_fun_signature
>::type
type2;
typedef projection_partial_function_pair<Pattern, type1, type2> type;
};
template<bool IsComplete, class Expr, class Guard, class Transformers, class Pattern>
struct get_case
{
typedef typename get_case_<Expr, Guard, Transformers, Pattern>::type type;
};
template<class Expr, class Guard, class Transformers, class Pattern>
struct get_case<false, Expr, Guard, Transformers, Pattern>
{
typedef typename util::tl_pop_back<Pattern>::type lhs_pattern;
typedef typename util::tl_map<
typename util::get_arg_types<Expr>::types,
util::rm_ref
>::type
rhs_pattern;
typedef typename get_case_<
Expr,
Guard,
Transformers,
typename util::tl_concat<lhs_pattern, rhs_pattern>::type
>::type
type;
};
/*
template<class Expr>
struct get_case<true, Expr, value_guard<util::type_list<> >,
util::type_list<>, util::type_list<anything> >
{
typedef typename get_case_<
Expr,
value_guard<util::type_list<> >,
util::type_list<>,
util::type_list<anything>
>::type
type;
};
*/
template<typename First, typename Second>
struct pjf_same_pattern
: std::is_same<typename First::second::pattern_type,
typename Second::second::pattern_type>
{
};
// last invocation step; evaluates a {projection, tpartial_function} pair
template<typename Data>
struct invoke_helper3
{
Data const& data;
invoke_helper3(Data const& mdata) : data(mdata) { }
template<size_t Pos, typename T, typename... Args>
inline bool operator()(util::type_pair<std::integral_constant<size_t, Pos>, T>,
Args&&... args) const
{
auto const& target = get<Pos>(data);
return target.first(target.second, std::forward<Args>(args)...);
//return (get<Pos>(data))(args...);
}
};
template<class Data, class Token, class Pattern>
struct invoke_helper2
{
typedef Pattern pattern_type;
typedef typename util::tl_filter_not_type<pattern_type, anything>::type arg_types;
Data const& data;
invoke_helper2(Data const& mdata) : data(mdata) { }
template<typename... Args>
bool invoke(Args&&... args) const
{
typedef invoke_policy<Pattern> impl;
return impl::invoke(*this, std::forward<Args>(args)...);
}
// resolved argument list (called from invoke_policy)
template<typename... Args>
bool operator()(Args&&... args) const
{
//static_assert(false, "foo");
Token token;
invoke_helper3<Data> fun{data};
return util::static_foreach<0, Token::size>::eval_or(token, fun, std::forward<Args>(args)...);
}
};
// invokes a group of {projection, tpartial_function} pairs
template<typename Data>
struct invoke_helper
{
Data const& data;
std::uint64_t bitfield;
invoke_helper(Data const& mdata, std::uint64_t bits) : data(mdata), bitfield(bits) { }
// token: type_list<type_pair<integral_constant<size_t, X>,
// std::pair<projection, tpartial_function>>,
// ...>
// all {projection, tpartial_function} pairs have the same pattern
// thus, can be invoked from same data
template<class Token, typename... Args>
bool operator()(Token, Args&&... args)
{
typedef typename Token::head type_pair;
typedef typename type_pair::second leaf_pair;
if (bitfield & 0x01)
//if (*enabled++)
{
// next invocation step
invoke_helper2<Data,
Token,
typename leaf_pair::pattern_type> fun{data};
return fun.invoke(std::forward<Args>(args)...);
}
bitfield >>= 1;
//++enabled;
return false;
}
};
struct can_invoke_helper
{
std::uint64_t& bitfield;
size_t i;
can_invoke_helper(std::uint64_t& mbitfield) : bitfield(mbitfield), i(0) { }
template<class Token, typename... Args>
void operator()(Token, Args&&... args)
{
typedef typename Token::head type_pair;
typedef typename type_pair::second leaf_pair;
typedef invoke_policy<typename leaf_pair::pattern_type> impl;
if (impl::can_invoke(std::forward<Args>(args)...))
{
bitfield |= (0x01 << i);
}
++i;
}
};
template<typename T>
struct is_manipulator_case
{
static constexpr bool value = T::second_type::manipulates_args;
};
template<bool IsManipulator, typename T0, typename T1>
struct mexpr_fwd_
{
typedef T1 type;
};
template<typename T>
struct mexpr_fwd_<false, T const&, T>
{
typedef std::reference_wrapper<const T> type;
};
template<typename T>
struct mexpr_fwd_<true, T&, T>
{
typedef std::reference_wrapper<T> type;
};
template<bool IsManipulator, typename T>
struct mexpr_fwd
{
typedef typename mexpr_fwd_<
IsManipulator,
T,
typename detail::implicit_conversions<
typename util::rm_ref<T>::type
>::type
>::type
type;
};
} } // namespace cppa::detail
namespace cppa {
/**
* @brief A function that works on the projection of given data rather than
* on the data itself.
*/
template<class... Cases>
class match_expr
{
static_assert(sizeof...(Cases) < 64, "too many functions");
public:
typedef util::type_list<Cases...> cases_list;
typedef typename util::tl_group_by<
typename util::tl_zip_with_index<cases_list>::type,
detail::pjf_same_pattern
>::type
eval_order;
static constexpr bool has_manipulator =
util::tl_exists<cases_list, detail::is_manipulator_case>::value;
template<typename... Args>
match_expr(Args&&... args) : m_cases(std::forward<Args>(args)...)
{
init();
}
match_expr(match_expr&& other) : m_cases(std::move(other.m_cases))
{
init();
}
match_expr(match_expr const& other) : m_cases(other.m_cases)
{
init();
}
bool invoke(any_tuple const& tup)
{
return _invoke(tup);
}
bool invoke(any_tuple& tup)
{
return _invoke(tup);
}
bool invoke(any_tuple&& tup)
{
any_tuple tmp{tup};
return _invoke(tmp);
}
bool can_invoke(any_tuple const tup)
{
auto& type_token = *(tup.type_token());
eval_order token;
std::uint64_t tmp = 0;
detail::can_invoke_helper fun{tmp};
util::static_foreach<0, eval_order::size>
::_(token, fun, type_token, tup);
return tmp != 0;
}
bool operator()(any_tuple const& tup)
{
return _invoke(tup);
}
bool operator()(any_tuple& tup)
{
return _invoke(tup);
}
bool operator()(any_tuple&& tup)
{
any_tuple tmp{tup};
return _invoke(tmp);
}
template<typename... Args>
bool operator()(Args&&... args)
{
typedef detail::tdata<
typename detail::mexpr_fwd<has_manipulator, Args>::type...>
tuple_type;
// applies implicit conversions etc
tuple_type tup{std::forward<Args>(args)...};
auto& type_token = typeid(typename tuple_type::types);
auto enabled_begin = get_cache_entry(&type_token, tup);
typedef typename util::if_else_c<
has_manipulator,
tuple_type&,
util::wrapped<tuple_type const&>
>::type
ref_type;
typedef typename util::if_else_c<
has_manipulator,
void*,
util::wrapped<void const*>
>::type
ptr_type;
eval_order token;
detail::invoke_helper<decltype(m_cases)> fun{m_cases, enabled_begin};
return util::static_foreach<0, eval_order::size>
::eval_or(token,
fun,
type_token,
detail::statically_typed,
static_cast<ptr_type>(nullptr),
static_cast<ref_type>(tup));
}
template<class... OtherCases>
match_expr<Cases..., OtherCases...>
or_else(match_expr<OtherCases...> const& other) const
{
detail::tdata<ge_reference_wrapper<Cases>...,
ge_reference_wrapper<OtherCases>... > all_cases;
collect_tdata(all_cases, m_cases, other.cases());
return {all_cases};
}
inline detail::tdata<Cases...> const& cases() const
{
return m_cases;
}
struct pfun_impl : partial_function::impl
{
match_expr pfun;
template<typename Arg>
pfun_impl(Arg const& from) : pfun(from) { }
bool invoke(any_tuple& tup)
{
return pfun.invoke(tup);
}
bool invoke(any_tuple const& tup)
{
return pfun.invoke(tup);
}
bool defined_at(any_tuple const& tup)
{
return pfun.can_invoke(tup);
}
};
operator partial_function() const
{
return {partial_function::impl_ptr{new pfun_impl(*this)}};
}
private:
// structure: tdata< tdata<type_list<...>, ...>,
// tdata<type_list<...>, ...>,
// ...>
detail::tdata<Cases...> m_cases;
static constexpr size_t cache_size = 10;
//typedef std::array<bool, eval_order::size> cache_entry;
//typedef typename cache_entry::iterator cache_entry_iterator;
//typedef std::pair<std::type_info const*, cache_entry> cache_element;
// std::uint64_t is used as a bitmask to enable/disable groups
typedef std::pair<std::type_info const*, std::uint64_t> cache_element;
util::fixed_vector<cache_element, cache_size> m_cache;
// ring buffer like access to m_cache
size_t m_cache_begin;
size_t m_cache_end;
cache_element m_dummy;
static inline void advance_(size_t& i)
{
i = (i + 1) % cache_size;
}
inline size_t find_token_pos(std::type_info const* type_token)
{
for (size_t i = m_cache_begin ; i != m_cache_end; advance_(i))
{
if (m_cache[i].first == type_token) return i;
}
return m_cache_end;
}
template<class Tuple>
std::uint64_t get_cache_entry(std::type_info const* type_token,
Tuple const& value)
{
CPPA_REQUIRE(type_token != nullptr);
if (value.impl_type() == detail::dynamically_typed)
{
return m_dummy.second; // all groups enabled
}
size_t i = find_token_pos(type_token);
// if we didn't found a cache entry ...
if (i == m_cache_end)
{
// ... 'create' one (override oldest element in cache if full)
advance_(m_cache_end);
if (m_cache_end == m_cache_begin) advance_(m_cache_begin);
m_cache[i].first = type_token;
m_cache[i].second = 0;
eval_order token;
detail::can_invoke_helper fun{m_cache[i].second};
util::static_foreach<0, eval_order::size>
::_(token, fun, *type_token, value);
}
return m_cache[i].second;
}
void init()
{
m_dummy.second = std::numeric_limits<std::uint64_t>::max();
m_cache.resize(cache_size);
for (auto& entry : m_cache) { entry.first = nullptr; }
m_cache_begin = m_cache_end = 0;
}
template<typename AbstractTuple, typename NativeDataPtr>
bool _do_invoke(AbstractTuple& vals, NativeDataPtr ndp)
{
std::type_info const* type_token = vals.type_token();
auto bitfield = get_cache_entry(type_token, vals);
eval_order token;
detail::invoke_helper<decltype(m_cases)> fun{m_cases, bitfield};
return util::static_foreach<0, eval_order::size>
::eval_or(token,
fun,
*type_token,
vals.impl_type(),
ndp,
vals);
}
template<typename AnyTuple>
bool _invoke(AnyTuple& tup,
typename std::enable_if<
std::is_const<AnyTuple>::value == false
&& has_manipulator == true
>::type* = 0)
{
tup.force_detach();
auto& vals = *(tup.vals());
return _do_invoke(vals, vals.mutable_native_data());
}
template<typename AnyTuple>
bool _invoke(AnyTuple& tup,
typename std::enable_if<
std::is_const<AnyTuple>::value == false
&& has_manipulator == false
>::type* = 0)
{
return _invoke(static_cast<AnyTuple const&>(tup));
}
template<typename AnyTuple>
bool _invoke(AnyTuple& tup,
typename std::enable_if<
std::is_const<AnyTuple>::value == true
&& has_manipulator == false
>::type* = 0)
{
auto const& cvals = *(tup.cvals());
return _do_invoke(cvals, cvals.native_data());
}
template<typename AnyTuple>
bool _invoke(AnyTuple& tup,
typename std::enable_if<
std::is_const<AnyTuple>::value == true
&& has_manipulator == true
>::type* = 0)
{
any_tuple tup_copy{tup};
return _invoke(tup_copy);
}
};
template<class List>
struct match_expr_from_type_list;
template<typename... Args>
struct match_expr_from_type_list<util::type_list<Args...> >
{
typedef match_expr<Args...> type;
};
template<typename... Lhs, typename... Rhs>
inline match_expr<Lhs..., Rhs...> operator,(match_expr<Lhs...> const& lhs,
match_expr<Rhs...> const& rhs)
{
return lhs.or_else(rhs);
}
template<typename Arg0, typename... Args>
typename match_expr_from_type_list<
typename util::tl_concat<
typename Arg0::cases_list,
typename Args::cases_list...
>::type
>::type
mexpr_concat(Arg0 const& arg0, Args const&... args)
{
typename detail::tdata_from_type_list<
typename util::tl_map<
typename util::tl_concat<
typename Arg0::cases_list,
typename Args::cases_list...
>::type,
gref_wrapped
>::type
>::type
all_cases;
detail::collect_tdata(all_cases, arg0.cases(), args.cases()...);
return {all_cases};
}
template<typename Arg0, typename... Args>
partial_function mexpr_concat_convert(Arg0 const& arg0, Args const&... args)
{
typename detail::tdata_from_type_list<
typename util::tl_map<
typename util::tl_concat<
typename Arg0::cases_list,
typename Args::cases_list...
>::type,
gref_wrapped
>::type
>::type
all_cases;
typedef typename match_expr_from_type_list<
typename util::tl_concat<
typename Arg0::cases_list,
typename Args::cases_list...
>::type
>::type
combined_type;
typedef typename combined_type::pfun_impl impl_type;
detail::collect_tdata(all_cases, arg0.cases(), args.cases()...);
return {partial_function::impl_ptr{new impl_type(all_cases)}};
}
} // namespace cppa
#endif // MATCH_EXPR_HPP
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <chrono> #include <chrono>
#include <memory> #include <memory>
#include <type_traits>
#include "cppa/atom.hpp" #include "cppa/atom.hpp"
#include "cppa/pattern.hpp" #include "cppa/pattern.hpp"
...@@ -40,22 +41,62 @@ ...@@ -40,22 +41,62 @@
#include "cppa/behavior.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_expr.hpp"
#include "cppa/partial_function.hpp" #include "cppa/partial_function.hpp"
#include "cppa/util/duration.hpp" #include "cppa/util/duration.hpp"
#include "cppa/util/type_list.hpp" #include "cppa/util/type_list.hpp"
#include "cppa/util/enable_if.hpp"
#include "cppa/util/arg_match_t.hpp" #include "cppa/util/arg_match_t.hpp"
#include "cppa/util/callable_trait.hpp" #include "cppa/util/callable_trait.hpp"
#include "cppa/detail/boxed.hpp" #include "cppa/detail/boxed.hpp"
#include "cppa/detail/unboxed.hpp" #include "cppa/detail/unboxed.hpp"
#include "cppa/detail/invokable.hpp" #include "cppa/detail/invokable.hpp"
#include "cppa/detail/value_guard.hpp"
#include "cppa/detail/ref_counted_impl.hpp" #include "cppa/detail/ref_counted_impl.hpp"
#include "cppa/detail/implicit_conversions.hpp" #include "cppa/detail/implicit_conversions.hpp"
namespace cppa { namespace detail { namespace cppa { namespace detail {
template<bool IsFun, typename T>
struct add_ptr_to_fun_
{
typedef T* type;
};
template<typename T>
struct add_ptr_to_fun_<false, T>
{
typedef T type;
};
template<typename T>
struct add_ptr_to_fun : add_ptr_to_fun_<std::is_function<T>::value, T>
{
};
template<bool ToVoid, typename T>
struct to_void_impl
{
typedef util::void_type type;
};
template<typename T>
struct to_void_impl<false, T>
{
typedef typename add_ptr_to_fun<T>::type type;
};
template<typename T>
struct not_callable_to_void : to_void_impl<detail::is_boxed<T>::value || !util::is_callable<T>::value, T>
{
};
template<typename T>
struct boxed_and_callable_to_void : to_void_impl<detail::is_boxed<T>::value || util::is_callable<T>::value, T>
{
};
class behavior_rvalue_builder class behavior_rvalue_builder
{ {
...@@ -75,144 +116,106 @@ class behavior_rvalue_builder ...@@ -75,144 +116,106 @@ class behavior_rvalue_builder
}; };
template<typename... TypeList> struct rvalue_builder_args_ctor { };
class rvalue_builder
{
typedef util::arg_match_t arg_match_t; template<class Guard, class Transformers, class Pattern>
struct rvalue_builder
typedef util::type_list< {
typename detail::implicit_conversions<TypeList>::type...>
raw_types;
static constexpr bool is_complete = static constexpr bool is_complete =
!std::is_same<arg_match_t, typename raw_types::back>::value; !std::is_same<util::arg_match_t, typename Pattern::back>::value;
typedef typename util::if_else_c< typedef typename util::tl_apply<Transformers, tdata>::type fun_container;
is_complete == false,
typename util::tl_pop_back<raw_types>::type,
util::wrapped<raw_types> >::type
types;
static_assert(util::tl_find<types, arg_match_t>::value == -1, Guard m_guard;
"arg_match is allowed only as last parameter for on()"); fun_container m_funs;
typedef typename pattern_from_type_list<types>::type pattern_type; public:
typedef std::unique_ptr<value_matcher> vm_ptr;
vm_ptr m_vm; rvalue_builder() = default;
template<typename F> template<typename... Args>
partial_function cr_rvalue(F&& f, std::integral_constant<bool, true>) rvalue_builder(rvalue_builder_args_ctor, Args const&... args)
: m_guard(args...)
, m_funs(args...)
{ {
return get_invokable_impl<pattern_type>(std::forward<F>(f),
std::move(m_vm));
} }
template<typename F> rvalue_builder(Guard arg0, fun_container arg1)
partial_function cr_rvalue(F&& f, std::integral_constant<bool, false>) : m_guard(std::move(arg0)), m_funs(std::move(arg1))
{ {
using namespace ::cppa::util;
typedef typename get_callable_trait<F>::type ctrait;
typedef typename ctrait::arg_types raw_arg_types;
static_assert(raw_types::size > 0, "functor has no arguments");
typedef typename tl_map<raw_arg_types,rm_ref>::type arg_types;
typedef typename tl_concat<types,arg_types>::type full_types;
typedef typename pattern_from_type_list<full_types>::type epattern;
return get_invokable_impl<epattern>(std::forward<F>(f),
std::move(m_vm));
} }
public: template<typename NewGuard>
rvalue_builder<
//template<operator_id OP, typename F, typename S> guard_expr<
//rvalue_builder& when(guard_expr<OP, F, S> ge) logical_and_op,
template<typename Fun> guard_expr<exec_xfun_op, Guard, util::void_type>,
rvalue_builder& when(Fun&& fun) NewGuard>,
Transformers,
Pattern>
when(NewGuard ng,
typename std::enable_if<
std::is_same<NewGuard, NewGuard>::value
&& !std::is_same<Guard, value_guard< util::type_list<> >>::value
>::type* = 0 ) const
{ {
//TODO: static_assert return {(gcall(m_guard) && ng), std::move(m_funs)};
typedef typename util::rm_ref<Fun>::type fun_type;
if (m_vm)
{
struct impl1 : value_matcher
{
vm_ptr m_ptr;
fun_type m_fun;
impl1(vm_ptr&& ptr, Fun&& f)
: m_ptr(std::move(ptr)), m_fun(std::forward<Fun>(f))
{
}
bool operator()(any_tuple const& tup) const
{
if ((*m_ptr)(tup))
{
auto ttup = tuple_cast(tup, types{});
if (ttup)
{
return util::unchecked_apply_tuple<bool>(m_fun,
*ttup);
}
}
return false;
}
};
m_vm.reset(new impl1{std::move(m_vm), std::forward<Fun>(fun)});
}
else
{
struct impl2 : value_matcher
{
fun_type m_fun;
impl2(Fun&& f) : m_fun(std::forward<Fun>(f))
{
}
bool operator()(any_tuple const& tup) const
{
auto ttup = tuple_cast(tup, types{});
if (ttup)
{
return util::unchecked_apply_tuple<bool>(m_fun, *ttup);
}
return false;
}
};
m_vm.reset(new impl2{std::forward<Fun>(fun)});
}
return *this;
} }
template<typename... Args> template<typename NewGuard>
rvalue_builder(Args&&... args) rvalue_builder<NewGuard, Transformers, Pattern>
: m_vm(pattern_type::get_value_matcher(std::forward<Args>(args)...)) when(NewGuard ng,
typename std::enable_if<
std::is_same<NewGuard, NewGuard>::value
&& std::is_same<Guard, value_guard< util::type_list<> >>::value
>::type* = 0 ) const
{ {
return {std::move(ng), std::move(m_funs)};
} }
template<typename F> template<typename Expr>
partial_function operator>>(F&& f) match_expr<typename get_case<is_complete, Expr, Guard, Transformers, Pattern>::type>
operator>>(Expr expr) const
{ {
std::integral_constant<bool, is_complete> token; typedef typename get_case<
return cr_rvalue(std::forward<F>(f), token); is_complete,
Expr,
Guard,
Transformers,
Pattern
>::type
tpair;
return tpair{typename tpair::first_type{m_funs},
typename tpair::second_type{std::move(expr),
std::move(m_guard)}};
} }
}; };
template<> template<bool IsCallable, typename T>
class rvalue_builder<anything> struct pattern_type_
{ {
typedef util::get_callable_trait<T> ctrait;
typedef typename ctrait::arg_types args;
static_assert(args::size == 1, "only unary functions allowed");
typedef typename util::rm_ref<typename args::head>::type type;
};
typedef pattern<anything> pattern_type; template<typename T>
struct pattern_type_<false, T>
public: {
typedef typename implicit_conversions<
constexpr rvalue_builder() { } typename util::rm_ref<
typename detail::unboxed<T>::type
template<typename F> >::type
partial_function operator>>(F&& f) >::type
{ type;
return get_invokable_impl<pattern_type>(std::forward<F>(f)); };
}
template<typename T>
struct pattern_type : pattern_type_<util::is_callable<T>::value && !detail::is_boxed<T>::value, T>
{
}; };
class on_the_fly_rvalue_builder class on_the_fly_rvalue_builder
...@@ -224,16 +227,30 @@ class on_the_fly_rvalue_builder ...@@ -224,16 +227,30 @@ class on_the_fly_rvalue_builder
{ {
} }
template<typename F>
partial_function operator>>(F&& f) const template<typename Expr>
match_expr<
typename get_case<
false,
Expr,
value_guard< util::type_list<> >,
util::type_list<>,
util::type_list<>
>::type>
operator>>(Expr expr) const
{ {
using namespace ::cppa::util; typedef typename get_case<
typedef typename get_callable_trait<F>::type ctrait; false,
typedef typename ctrait::arg_types raw_types; Expr,
static_assert(raw_types::size > 0, "functor has no arguments"); value_guard< util::type_list<> >,
typedef typename tl_map<raw_types,rm_ref>::type types; util::type_list<>,
typedef typename pattern_from_type_list<types>::type pattern_type; util::type_list<>
return get_invokable_impl<pattern_type>(std::forward<F>(f)); >::type
result;
return result{typename result::first_type{},
typename result::second_type{
std::move(expr),
value_guard< util::type_list<> >{}}};
} }
}; };
...@@ -316,44 +333,59 @@ constexpr boxed_arg_match_t arg_match = boxed_arg_match_t(); ...@@ -316,44 +333,59 @@ constexpr boxed_arg_match_t arg_match = boxed_arg_match_t();
constexpr detail::on_the_fly_rvalue_builder on_arg_match; constexpr detail::on_the_fly_rvalue_builder on_arg_match;
template<typename Arg0, typename... Args> template<typename Arg0, typename... Args>
detail::rvalue_builder<typename detail::unboxed<typename util::rm_ref<Arg0>::type>::type, detail::rvalue_builder<
typename detail::unboxed<typename util::rm_ref<Args>::type>::type...> detail::value_guard<
on(Arg0&& arg0, Args&&... args) typename util::tl_trim<
typename util::tl_map<
util::type_list<Arg0, Args...>,
detail::boxed_and_callable_to_void,
detail::implicit_conversions
>::type
>::type
>,
typename util::tl_map<
util::type_list<Arg0, Args...>,
detail::not_callable_to_void
>::type,
util::type_list<typename detail::pattern_type<Arg0>::type,
typename detail::pattern_type<Args>::type...> >
on(Arg0 const& arg0, Args const&... args)
{ {
return {std::forward<Arg0>(arg0), std::forward<Args>(args)...}; return {detail::rvalue_builder_args_ctor{}, arg0, args...};
} }
template<typename... TypeList> template<typename... T>
detail::rvalue_builder<TypeList...> on() detail::rvalue_builder<detail::value_guard<util::type_list<> >,
util::type_list<>,
util::type_list<T...> >
on()
{ {
return { }; return {};
} }
template<atom_value A0, typename... Ts> template<atom_value A0, typename... Ts>
detail::rvalue_builder<atom_value, Ts...> on() decltype(on(A0, val<Ts>()...)) on()
{ {
return { A0 }; return on(A0, val<Ts>()...);
} }
template<atom_value A0, atom_value A1, typename... Ts> template<atom_value A0, atom_value A1, typename... Ts>
detail::rvalue_builder<atom_value, atom_value, Ts...> on() decltype(on(A0, A1, val<Ts>()...)) on()
{ {
return { A0, A1 }; return on(A0, A1, val<Ts>()...);
} }
template<atom_value A0, atom_value A1, atom_value A2, typename... Ts> template<atom_value A0, atom_value A1, atom_value A2, typename... Ts>
detail::rvalue_builder<atom_value, atom_value, atom_value, Ts...> on() decltype(on(A0, A1, A2, val<Ts>()...)) on()
{ {
return { A0, A1, A2 }; return on(A0, A1, A2, val<Ts>()...);
} }
template<atom_value A0, atom_value A1, template<atom_value A0, atom_value A1, atom_value A2, atom_value A3,
atom_value A2, atom_value A3,
typename... Ts> typename... Ts>
detail::rvalue_builder<atom_value, atom_value, atom_value, decltype(on(A0, A1, A2, A3, val<Ts>()...)) on()
atom_value, Ts...> on()
{ {
return { A0, A1, A2, A3 }; return on(A0, A1, A2, A3, val<Ts>()...);
} }
template<class Rep, class Period> template<class Rep, class Period>
...@@ -363,9 +395,9 @@ after(std::chrono::duration<Rep, Period> const& d) ...@@ -363,9 +395,9 @@ after(std::chrono::duration<Rep, Period> const& d)
return { util::duration(d) }; return { util::duration(d) };
} }
inline detail::rvalue_builder<anything> others() inline decltype(on<anything>()) others()
{ {
return { }; return on<anything>();
} }
#endif #endif
......
...@@ -55,55 +55,50 @@ class partial_function ...@@ -55,55 +55,50 @@ class partial_function
public: public:
typedef std::unique_ptr<detail::invokable> invokable_ptr; struct impl
{
partial_function() = default; virtual ~impl();
partial_function(partial_function&& other); virtual bool invoke(any_tuple&) = 0;
partial_function& operator=(partial_function&& other); virtual bool invoke(any_tuple const&) = 0;
virtual bool defined_at(any_tuple const&) = 0;
partial_function(invokable_ptr&& ptr); };
bool defined_at(any_tuple const& value); typedef std::unique_ptr<impl> impl_ptr;
bool operator()(any_tuple value); partial_function() = default;
partial_function(partial_function&&) = default;
partial_function& operator=(partial_function&&) = default;
detail::invokable const* definition_at(any_tuple value); partial_function(impl_ptr&& ptr);
template<class... Args> inline bool defined_at(any_tuple const& value)
partial_function& splice(partial_function&& arg0, Args&&... args)
{ {
m_funs.splice_after(m_funs.before_end(), std::move(arg0.m_funs)); return ((m_impl) && m_impl->defined_at(value));
arg0.m_cache.clear();
return splice(std::forward<Args>(args)...);
} }
private: inline bool operator()(any_tuple& value)
{
return ((m_impl) && m_impl->invoke(value));
}
// terminates recursion inline bool operator()(any_tuple const& value)
inline partial_function& splice()
{ {
m_cache.clear(); return ((m_impl) && m_impl->invoke(value));
return *this;
} }
typedef std::vector<detail::invokable*> cache_entry; inline bool operator()(any_tuple&& value)
typedef std::pair<void const*, cache_entry> cache_element; {
any_tuple cpy{std::move(value)};
return (*this)(cpy);
}
intrusive::singly_linked_list<detail::invokable> m_funs; private:
std::vector<cache_element> m_cache;
cache_element m_dummy; // binary search dummy
cache_entry& get_cache_entry(any_tuple const& value); impl_ptr m_impl;
}; };
inline partial_function operator,(partial_function&& lhs, //behavior operator,(partial_function&& lhs, behavior&& rhs);
partial_function&& rhs)
{
return std::move(lhs.splice(std::move(rhs)));
}
behavior operator,(partial_function&& lhs, behavior&& rhs);
} // namespace cppa } // namespace cppa
......
...@@ -39,8 +39,6 @@ ...@@ -39,8 +39,6 @@
#include "cppa/primitive_type.hpp" #include "cppa/primitive_type.hpp"
#include "cppa/util/pt_token.hpp" #include "cppa/util/pt_token.hpp"
#include "cppa/util/enable_if.hpp"
#include "cppa/util/disable_if.hpp"
#include "cppa/util/pt_dispatch.hpp" #include "cppa/util/pt_dispatch.hpp"
#include "cppa/util/is_primitive.hpp" #include "cppa/util/is_primitive.hpp"
...@@ -51,11 +49,11 @@ namespace cppa { namespace detail { ...@@ -51,11 +49,11 @@ namespace cppa { namespace detail {
template<primitive_type FT, class T, class V> template<primitive_type FT, class T, class V>
void ptv_set(primitive_type& lhs_type, T& lhs, V&& rhs, void ptv_set(primitive_type& lhs_type, T& lhs, V&& rhs,
typename util::disable_if<std::is_arithmetic<T>>::type* = 0); typename std::enable_if<!std::is_arithmetic<T>::value>::type* = 0);
template<primitive_type FT, class T, class V> template<primitive_type FT, class T, class V>
void ptv_set(primitive_type& lhs_type, T& lhs, V&& rhs, void ptv_set(primitive_type& lhs_type, T& lhs, V&& rhs,
typename util::enable_if<std::is_arithmetic<T>, int>::type* = 0); typename std::enable_if<std::is_arithmetic<T>::value, int>::type* = 0);
} } // namespace cppa::detail } } // namespace cppa::detail
...@@ -363,7 +361,7 @@ bool operator!=(primitive_variant const& lhs, primitive_variant const& rhs) ...@@ -363,7 +361,7 @@ bool operator!=(primitive_variant const& lhs, primitive_variant const& rhs)
} }
template<typename T> template<typename T>
typename util::enable_if<util::is_primitive<T>, bool>::type typename std::enable_if<util::is_primitive<T>::value, bool>::type
operator==(T const& lhs, primitive_variant const& rhs) operator==(T const& lhs, primitive_variant const& rhs)
{ {
static constexpr primitive_type ptype = detail::type_to_ptype<T>::ptype; static constexpr primitive_type ptype = detail::type_to_ptype<T>::ptype;
...@@ -372,21 +370,21 @@ operator==(T const& lhs, primitive_variant const& rhs) ...@@ -372,21 +370,21 @@ operator==(T const& lhs, primitive_variant const& rhs)
} }
template<typename T> template<typename T>
typename util::enable_if<util::is_primitive<T>, bool>::type typename std::enable_if<util::is_primitive<T>::value, bool>::type
operator==(primitive_variant const& lhs, T const& rhs) operator==(primitive_variant const& lhs, T const& rhs)
{ {
return (rhs == lhs); return (rhs == lhs);
} }
template<typename T> template<typename T>
typename util::enable_if<util::is_primitive<T>, bool>::type typename std::enable_if<util::is_primitive<T>::value, bool>::type
operator!=(primitive_variant const& lhs, T const& rhs) operator!=(primitive_variant const& lhs, T const& rhs)
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
template<typename T> template<typename T>
typename util::enable_if<util::is_primitive<T>, bool>::type typename std::enable_if<util::is_primitive<T>::value, bool>::type
operator!=(T const& lhs, primitive_variant const& rhs) operator!=(T const& lhs, primitive_variant const& rhs)
{ {
return !(lhs == rhs); return !(lhs == rhs);
...@@ -398,7 +396,7 @@ namespace cppa { namespace detail { ...@@ -398,7 +396,7 @@ namespace cppa { namespace detail {
template<primitive_type FT, class T, class V> template<primitive_type FT, class T, class V>
void ptv_set(primitive_type& lhs_type, T& lhs, V&& rhs, void ptv_set(primitive_type& lhs_type, T& lhs, V&& rhs,
typename util::disable_if<std::is_arithmetic<T>>::type*) typename std::enable_if<!std::is_arithmetic<T>::value>::type*)
{ {
if (FT == lhs_type) if (FT == lhs_type)
{ {
...@@ -413,7 +411,7 @@ void ptv_set(primitive_type& lhs_type, T& lhs, V&& rhs, ...@@ -413,7 +411,7 @@ void ptv_set(primitive_type& lhs_type, T& lhs, V&& rhs,
template<primitive_type FT, class T, class V> template<primitive_type FT, class T, class V>
void ptv_set(primitive_type& lhs_type, T& lhs, V&& rhs, void ptv_set(primitive_type& lhs_type, T& lhs, V&& rhs,
typename util::enable_if<std::is_arithmetic<T>, int>::type*) typename std::enable_if<std::is_arithmetic<T>::value, int>::type*)
{ {
// don't call a constructor for arithmetic types // don't call a constructor for arithmetic types
lhs = rhs; lhs = rhs;
......
...@@ -121,36 +121,26 @@ inline void receive(behavior& bhvr) { self->dequeue(bhvr); } ...@@ -121,36 +121,26 @@ inline void receive(behavior& bhvr) { self->dequeue(bhvr); }
inline void receive(partial_function& fun) { self->dequeue(fun); } inline void receive(partial_function& fun) { self->dequeue(fun); }
inline void receive(behavior&& arg0) template<typename Arg0, typename... Args>
void receive(Arg0&& arg0, Args&&... args)
{ {
behavior tmp{std::move(arg0)}; auto tmp = match_expr_concat(std::forward<Arg0>(arg0),
std::forward<Args>(args)...);
receive(tmp); receive(tmp);
} }
template<typename... Args>
void receive(partial_function&& arg0, Args&&... args)
{
typename detail::select_bhvr<Args...>::type tmp;
receive(tmp.splice(std::move(arg0), std::forward<Args>(args)...));
}
void receive_loop(behavior& rules); void receive_loop(behavior& rules);
void receive_loop(partial_function& rules); void receive_loop(partial_function& rules);
inline void receive_loop(behavior&& arg0) template<typename Arg0, typename... Args>
void receive_loop(Arg0&& arg0, Args&&... args)
{ {
behavior tmp{std::move(arg0)}; auto tmp = match_expr_concat(std::forward<Arg0>(arg0),
std::forward<Args>(args)...);
receive_loop(tmp); receive_loop(tmp);
} }
template<typename... Args>
void receive_loop(partial_function&& arg0, Args&&... args)
{
typename detail::select_bhvr<Args...>::type tmp;
receive_loop(tmp.splice(std::move(arg0), std::forward<Args>(args)...));
}
template<typename T> template<typename T>
detail::receive_for_helper<T> receive_for(T& begin, T const& end) detail::receive_for_helper<T> receive_for(T& begin, T const& end)
{ {
......
...@@ -31,9 +31,9 @@ ...@@ -31,9 +31,9 @@
#ifndef APPLY_TUPLE_HPP #ifndef APPLY_TUPLE_HPP
#define APPLY_TUPLE_HPP #define APPLY_TUPLE_HPP
#include <type_traits>
#include "cppa/get.hpp" #include "cppa/get.hpp"
#include "cppa/util/enable_if.hpp"
#include "cppa/util/disable_if.hpp"
#include "cppa/util/is_manipulator.hpp" #include "cppa/util/is_manipulator.hpp"
#include "cppa/util/callable_trait.hpp" #include "cppa/util/callable_trait.hpp"
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011, 2012 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation, either version 3 of the License *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef DISABLE_IF_HPP
#define DISABLE_IF_HPP
namespace cppa { namespace util {
template<bool Stmt, typename T = void>
struct disable_if_c { };
template<typename T>
struct disable_if_c<false, T>
{
typedef T type;
};
/**
* @ingroup MetaProgramming
* @brief SFINAE trick to disable a template function based on its
* template parameters.
*/
template<class Trait, typename T = void>
struct disable_if : disable_if_c<Trait::value, T>
{
};
} } // namespace cppa::util
#endif // DISABLE_IF_HPP
...@@ -31,9 +31,9 @@ ...@@ -31,9 +31,9 @@
#ifndef IS_FORWARD_ITERATOR_HPP #ifndef IS_FORWARD_ITERATOR_HPP
#define IS_FORWARD_ITERATOR_HPP #define IS_FORWARD_ITERATOR_HPP
#include <type_traits>
#include "cppa/util/rm_ref.hpp" #include "cppa/util/rm_ref.hpp"
#include "cppa/util/enable_if.hpp"
#include "cppa/util/disable_if.hpp"
namespace cppa { namespace util { namespace cppa { namespace util {
...@@ -52,11 +52,11 @@ class is_forward_iterator ...@@ -52,11 +52,11 @@ class is_forward_iterator
// check for 'C::value_type C::operator*()' returning a non-void type // check for 'C::value_type C::operator*()' returning a non-void type
typename rm_ref<decltype(*(*iter))>::type* = 0, typename rm_ref<decltype(*(*iter))>::type* = 0,
// check for 'C& C::operator++()' // check for 'C& C::operator++()'
typename enable_if<std::is_same<C&, decltype(++(*iter))>>::type* = 0, typename std::enable_if<std::is_same<C&, decltype(++(*iter))>::value>::type* = 0,
// check for 'bool C::operator==()' // check for 'bool C::operator==()'
typename enable_if<std::is_same<bool, decltype(*iter == *iter)>>::type* = 0, typename std::enable_if<std::is_same<bool, decltype(*iter == *iter)>::value>::type* = 0,
// check for 'bool C::operator!=()' // check for 'bool C::operator!=()'
typename enable_if<std::is_same<bool, decltype(*iter != *iter)>>::type* = 0 typename std::enable_if<std::is_same<bool, decltype(*iter != *iter)>::value>::type* = 0
) )
{ {
return true; return true;
......
...@@ -51,9 +51,9 @@ class is_iterable ...@@ -51,9 +51,9 @@ class is_iterable
( (
C const* cc, C const* cc,
// check for 'C::begin()' returning a forward iterator // check for 'C::begin()' returning a forward iterator
typename util::enable_if<util::is_forward_iterator<decltype(cc->begin())>>::type* = 0, typename std::enable_if<util::is_forward_iterator<decltype(cc->begin())>::value>::type* = 0,
// check for 'C::end()' returning the same kind of forward iterator // check for 'C::end()' returning the same kind of forward iterator
typename util::enable_if<std::is_same<decltype(cc->begin()), decltype(cc->end())>>::type* = 0 typename std::enable_if<std::is_same<decltype(cc->begin()), decltype(cc->end())>::value>::type* = 0
) )
{ {
return true; return true;
......
...@@ -895,9 +895,12 @@ struct tl_pad_left_impl<List, Size, Size, FillType> ...@@ -895,9 +895,12 @@ struct tl_pad_left_impl<List, Size, Size, FillType>
template<class List, size_t NewSize, typename FillType = void_type> template<class List, size_t NewSize, typename FillType = void_type>
struct tl_pad_left struct tl_pad_left
{ {
static_assert(NewSize >= List::size, "List too big"); //static_assert(NewSize >= List::size, "List too big");
typedef typename tl_pad_left_impl< typedef typename tl_pad_left_impl<
List, List::size, NewSize, FillType List,
List::size,
(List::size > NewSize) ? List::size : NewSize,
FillType
>::type >::type
type; type;
}; };
...@@ -992,6 +995,18 @@ struct tl_group_by ...@@ -992,6 +995,18 @@ struct tl_group_by
typedef typename tl_group_by_impl<List, type_list<>, Predicate>::type type; typedef typename tl_group_by_impl<List, type_list<>, Predicate>::type type;
}; };
/**
* @brief Applies the types of the list to @p VarArgTemplate.
*/
template<class List, template<typename...> class VarArgTemplate>
struct tl_apply;
template<typename... Ts, template<typename...> class VarArgTemplate>
struct tl_apply<type_list<Ts...>, VarArgTemplate>
{
typedef VarArgTemplate<Ts...> type;
};
/** /**
* @} * @}
*/ */
......
...@@ -21,7 +21,7 @@ void math_fun() ...@@ -21,7 +21,7 @@ void math_fun()
{ {
reply(atom("result"), a + b); reply(atom("result"), a + b);
}, },
on(atom("minus"), arg_match) >> [](int a, int b) on<atom("minus"), int, int>() >> [](int a, int b)
{ {
reply(atom("result"), a - b); reply(atom("result"), a - b);
}, },
......
...@@ -35,10 +35,9 @@ ...@@ -35,10 +35,9 @@
#include <stdexcept> #include <stdexcept>
#include <type_traits> #include <type_traits>
#include "cppa/util/enable_if.hpp"
#include "cppa/binary_deserializer.hpp" #include "cppa/binary_deserializer.hpp"
using cppa::util::enable_if; using std::enable_if;
namespace cppa { namespace cppa {
...@@ -57,14 +56,14 @@ inline void range_check(iterator begin, iterator end, size_t read_size) ...@@ -57,14 +56,14 @@ inline void range_check(iterator begin, iterator end, size_t read_size)
// @returns the next iterator position // @returns the next iterator position
template<typename T> template<typename T>
iterator read(iterator, iterator, T&, iterator read(iterator, iterator, T&,
typename enable_if< std::is_floating_point<T> >::type* = 0) typename enable_if<std::is_floating_point<T>::value>::type* = 0)
{ {
throw std::logic_error("read floating point not implemented yet"); throw std::logic_error("read floating point not implemented yet");
} }
template<typename T> template<typename T>
iterator read(iterator begin, iterator end, T& storage, iterator read(iterator begin, iterator end, T& storage,
typename enable_if< std::is_integral<T> >::type* = 0) typename enable_if<std::is_integral<T>::value>::type* = 0)
{ {
range_check(begin, end, sizeof(T)); range_check(begin, end, sizeof(T));
memcpy(&storage, begin, sizeof(T)); memcpy(&storage, begin, sizeof(T));
......
...@@ -33,11 +33,10 @@ ...@@ -33,11 +33,10 @@
#include <cstdint> #include <cstdint>
#include <type_traits> #include <type_traits>
#include "cppa/util/enable_if.hpp"
#include "cppa/primitive_variant.hpp" #include "cppa/primitive_variant.hpp"
#include "cppa/binary_serializer.hpp" #include "cppa/binary_serializer.hpp"
using cppa::util::enable_if; using std::enable_if;
namespace { namespace {
...@@ -75,7 +74,7 @@ class binary_writer ...@@ -75,7 +74,7 @@ class binary_writer
template<typename T> template<typename T>
void operator()(const T& value, void operator()(const T& value,
typename enable_if< std::is_integral<T> >::type* = 0) typename enable_if<std::is_integral<T>::value>::type* = 0)
{ {
m_serializer->acquire(sizeof(T)); m_serializer->acquire(sizeof(T));
write_int(m_serializer, value); write_int(m_serializer, value);
...@@ -83,7 +82,7 @@ class binary_writer ...@@ -83,7 +82,7 @@ class binary_writer
template<typename T> template<typename T>
void operator()(const T&, void operator()(const T&,
typename enable_if< std::is_floating_point<T> >::type* = 0) typename enable_if<std::is_floating_point<T>::value>::type* = 0)
{ {
throw std::logic_error("binary_serializer::write_floating_point " throw std::logic_error("binary_serializer::write_floating_point "
"not implemented yet"); "not implemented yet");
......
...@@ -37,101 +37,12 @@ ...@@ -37,101 +37,12 @@
namespace cppa { namespace cppa {
partial_function::partial_function(invokable_ptr&& ptr) partial_function::partial_function(impl_ptr&& ptr) : m_impl(std::move(ptr))
{ {
m_funs.push_back(ptr.release());
} }
partial_function::partial_function(partial_function&& other) partial_function::impl::~impl()
: m_funs(std::move(other.m_funs))
{ {
} }
partial_function& partial_function::operator=(partial_function&& other)
{
m_funs = std::move(other.m_funs);
m_cache.clear();
return *this;
}
auto partial_function::get_cache_entry(any_tuple const& value) -> cache_entry&
{
m_dummy.first = value.type_token();
auto end = m_cache.end();
// note: uses >= for comparison (not a "real" upper bound)
auto i = std::upper_bound(m_cache.begin(), end, m_dummy,
[](cache_element const& lhs,
cache_element const& rhs)
{
return lhs.first >= rhs.first;
});
// if we didn't found a cache entry ...
if (i == end || i->first != m_dummy.first)
{
// ... create one
cache_entry tmp;
if (value.impl_type() == detail::tuple_impl_info::statically_typed)
{
// use static type information for optimal caching
for (auto f = m_funs.begin(); f != m_funs.end(); ++f)
{
if (f->types_match(value)) tmp.push_back(f.ptr());
}
}
else
{
// "dummy" cache entry with all functions (dynamically typed tuple)
for (auto f = m_funs.begin(); f != m_funs.end(); ++f)
{
tmp.push_back(f.ptr());
}
}
// m_cache is always sorted,
// due to emplace(upper_bound, ...) insertions
i = m_cache.emplace(i, std::move(m_dummy.first), std::move(tmp));
}
return i->second;
}
bool partial_function::operator()(any_tuple value)
{
using detail::invokable;
auto& v = get_cache_entry(value);
if (value.impl_type() == detail::tuple_impl_info::statically_typed)
{
return std::any_of(v.begin(), v.end(),
[&](invokable* i) { return i->unsafe_invoke(value); });
}
else
{
return std::any_of(v.begin(), v.end(),
[&](invokable* i) { return i->invoke(value); });
}
}
detail::invokable const* partial_function::definition_at(any_tuple value)
{
using detail::invokable;
auto& v = get_cache_entry(value);
auto i = (value.impl_type() == detail::tuple_impl_info::statically_typed)
? std::find_if(v.begin(), v.end(),
[&](invokable* i) { return i->could_invoke(value);})
: std::find_if(v.begin(), v.end(),
[&](invokable* i) { return i->invoke(value); });
return (i != v.end()) ? *i : nullptr;
}
bool partial_function::defined_at(any_tuple const& value)
{
return definition_at(value) != nullptr;
}
behavior operator,(partial_function&& lhs, behavior&& rhs)
{
behavior bhvr{rhs.m_timeout, std::move(rhs.m_timeout_handler)};
bhvr.get_partial_function().splice(std::move(rhs.get_partial_function()),
std::move(lhs));
return bhvr;
}
} // namespace cppa } // namespace cppa
...@@ -39,14 +39,14 @@ namespace { ...@@ -39,14 +39,14 @@ namespace {
template<class T> template<class T>
void ptv_del(T&, void ptv_del(T&,
typename util::enable_if<std::is_arithmetic<T>, int>::type* = 0) typename std::enable_if<std::is_arithmetic<T>::value>::type* = 0)
{ {
// arithmetic types don't need destruction // arithmetic types don't need destruction
} }
template<class T> template<class T>
void ptv_del(T& what, void ptv_del(T& what,
typename util::disable_if< std::is_arithmetic<T> >::type* = 0) typename std::enable_if<!std::is_arithmetic<T>::value>::type* = 0)
{ {
what.~T(); what.~T();
} }
......
...@@ -123,6 +123,15 @@ void scheduler_helper::time_emitter(scheduler_helper::ptr_type m_self) ...@@ -123,6 +123,15 @@ void scheduler_helper::time_emitter(scheduler_helper::ptr_type m_self)
on<atom(":_DIE")>() >> [&]() on<atom(":_DIE")>() >> [&]()
{ {
done = true; done = true;
},
others() >> [&]()
{
# ifdef CPPA_DEBUG
std::cerr << "scheduler_helper::time_emitter: UNKNOWN MESSAGE: "
<< to_string(msg_ptr->msg)
<< std::endl;
# endif
msg_ptr.reset();
} }
); );
// loop // loop
......
...@@ -53,8 +53,6 @@ ...@@ -53,8 +53,6 @@
#include "cppa/util/duration.hpp" #include "cppa/util/duration.hpp"
#include "cppa/util/void_type.hpp" #include "cppa/util/void_type.hpp"
#include "cppa/util/enable_if.hpp"
#include "cppa/util/disable_if.hpp"
#include "cppa/detail/demangle.hpp" #include "cppa/detail/demangle.hpp"
#include "cppa/detail/object_array.hpp" #include "cppa/detail/object_array.hpp"
...@@ -639,8 +637,7 @@ class int_tinfo : public detail::default_uniform_type_info_impl<T> ...@@ -639,8 +637,7 @@ class int_tinfo : public detail::default_uniform_type_info_impl<T>
}; };
using std::is_integral; using std::is_integral;
using util::enable_if; using std::enable_if;
using util::disable_if;
class uniform_type_info_map_helper class uniform_type_info_map_helper
{ {
...@@ -664,7 +661,7 @@ class uniform_type_info_map_helper ...@@ -664,7 +661,7 @@ class uniform_type_info_map_helper
template<typename T> template<typename T>
static inline void insert(this_ptr d, static inline void insert(this_ptr d,
std::set<std::string> const& tnames, std::set<std::string> const& tnames,
typename enable_if<is_integral<T>>::type* = 0) typename enable_if<is_integral<T>::value>::type* = 0)
{ {
insert(d, new int_tinfo<T>, tnames); insert(d, new int_tinfo<T>, tnames);
} }
...@@ -672,7 +669,7 @@ class uniform_type_info_map_helper ...@@ -672,7 +669,7 @@ class uniform_type_info_map_helper
template<typename T> template<typename T>
static inline void insert(this_ptr d, static inline void insert(this_ptr d,
std::set<std::string> const& tnames, std::set<std::string> const& tnames,
typename disable_if<is_integral<T>>::type* = 0) typename enable_if<!is_integral<T>::value>::type* = 0)
{ {
insert(d, new default_uniform_type_info_impl<T>(), tnames); insert(d, new default_uniform_type_info_impl<T>(), tnames);
} }
......
...@@ -148,7 +148,7 @@ int main(int argc, char** argv) ...@@ -148,7 +148,7 @@ int main(int argc, char** argv)
auto args = get_kv_pairs(argc, argv); auto args = get_kv_pairs(argc, argv);
match_each(args) match_each(args)
( (
on("run", arg_match) >> [&](std::string const& what) on("run", val<std::string>) >> [&](std::string const& what)
{ {
if (what == "remote_actor") if (what == "remote_actor")
{ {
...@@ -156,7 +156,7 @@ int main(int argc, char** argv) ...@@ -156,7 +156,7 @@ int main(int argc, char** argv)
exit(0); exit(0);
} }
}, },
on("scheduler", arg_match) >> [](std::string const& sched) on("scheduler", val<std::string>) >> [](std::string const& sched)
{ {
if (sched == "thread_pool_scheduler") if (sched == "thread_pool_scheduler")
{ {
......
...@@ -8,19 +8,22 @@ ...@@ -8,19 +8,22 @@
#include <iostream> #include <iostream>
#include <type_traits> #include <type_traits>
#include "cppa/util/enable_if.hpp"
#include "cppa/util/disable_if.hpp"
template<typename T1, typename T2> template<typename T1, typename T2>
inline bool cppa_check_value_fun_eq(T1 const& value1, T2 const& value2, inline bool cppa_check_value_fun_eq(T1 const& value1, T2 const& value2,
typename cppa::util::disable_if_c<std::is_integral<T1>::value && std::is_integral<T2>::value>::type* = 0) typename std::enable_if<
!std::is_integral<T1>::value
|| !std::is_integral<T2>::value
>::type* = 0)
{ {
return value1 == value2; return value1 == value2;
} }
template<typename T1, typename T2> template<typename T1, typename T2>
inline bool cppa_check_value_fun_eq(T1 value1, T2 value2, inline bool cppa_check_value_fun_eq(T1 value1, T2 value2,
typename cppa::util::enable_if_c<std::is_integral<T1>::value && std::is_integral<T2>::value>::type* = 0) typename std::enable_if<
std::is_integral<T1>::value
&& std::is_integral<T2>::value
>::type* = 0)
{ {
return value1 == static_cast<T1>(value2); return value1 == static_cast<T1>(value2);
} }
......
...@@ -175,7 +175,7 @@ size_t test__match() ...@@ -175,7 +175,7 @@ size_t test__match()
vector<string> vec{"a", "b", "c"}; vector<string> vec{"a", "b", "c"};
match(vec) match(vec)
( (
on("a", "b", arg_match) >> [&](string& str) on("a", "b", val<string>) >> [&](string& str)
{ {
invoked = true; invoked = true;
str = "C"; str = "C";
...@@ -197,6 +197,7 @@ size_t test__match() ...@@ -197,6 +197,7 @@ size_t test__match()
CPPA_CHECK_EQUAL("A", vec.front()); CPPA_CHECK_EQUAL("A", vec.front());
invoked = false; invoked = false;
/*
match(vec) match(vec)
( (
others() >> [&](any_tuple& tup) others() >> [&](any_tuple& tup)
...@@ -214,7 +215,7 @@ size_t test__match() ...@@ -214,7 +215,7 @@ size_t test__match()
); );
if (!invoked) { CPPA_ERROR("match({\"a\", \"b\", \"c\"}) failed"); } if (!invoked) { CPPA_ERROR("match({\"a\", \"b\", \"c\"}) failed"); }
CPPA_CHECK_EQUAL(vec[1], "B"); CPPA_CHECK_EQUAL(vec[1], "B");
invoked = false; */
vector<string> vec2{"a=0", "b=1", "c=2"}; vector<string> vec2{"a=0", "b=1", "c=2"};
...@@ -226,34 +227,36 @@ size_t test__match() ...@@ -226,34 +227,36 @@ size_t test__match()
CPPA_CHECK_EQUAL(true, invoked); CPPA_CHECK_EQUAL(true, invoked);
invoked = false; invoked = false;
/*,
int pmatches = 0; int pmatches = 0;
using std::placeholders::_1; using std::placeholders::_1;
pmatch_each(vec2.begin(), vec2.end(), std::bind(split, _1, '=')) pmatch_each(vec2.begin(), vec2.end(), std::bind(split, _1, '='))
( (
on("a", arg_match) >> [&](string const& value) on("a", val<string>) >> [&](string const& value)
{ {
CPPA_CHECK_EQUAL("0", value); CPPA_CHECK_EQUAL("0", value);
CPPA_CHECK_EQUAL(0, pmatches); CPPA_CHECK_EQUAL(0, pmatches);
++pmatches; ++pmatches;
}, },
on("b", arg_match) >> [&](string const& value) on("b", val<string>) >> [&](string const& value)
{ {
CPPA_CHECK_EQUAL("1", value); CPPA_CHECK_EQUAL("1", value);
CPPA_CHECK_EQUAL(1, pmatches); CPPA_CHECK_EQUAL(1, pmatches);
++pmatches; ++pmatches;
}, },
on("c", arg_match) >> [&](string const& value) on("c", val<string>) >> [&](string const& value)
{ {
CPPA_CHECK_EQUAL("2", value); CPPA_CHECK_EQUAL("2", value);
CPPA_CHECK_EQUAL(2, pmatches); CPPA_CHECK_EQUAL(2, pmatches);
++pmatches; ++pmatches;
}, }
others() >> [](any_tuple const& value) others() >> [](any_tuple const& value)
{ {
cout << to_string(value) << endl; cout << to_string(value) << endl;
} }
); );
CPPA_CHECK_EQUAL(3, pmatches); CPPA_CHECK_EQUAL(3, pmatches);
*/
return CPPA_TEST_RESULT; return CPPA_TEST_RESULT;
} }
...@@ -14,8 +14,6 @@ ...@@ -14,8 +14,6 @@
#include "cppa/tuple_cast.hpp" #include "cppa/tuple_cast.hpp"
#include "cppa/partial_function.hpp" #include "cppa/partial_function.hpp"
#include "cppa/util/enable_if.hpp"
#include "cppa/util/disable_if.hpp"
#include "cppa/util/apply_tuple.hpp" #include "cppa/util/apply_tuple.hpp"
#include "cppa/util/is_primitive.hpp" #include "cppa/util/is_primitive.hpp"
#include "cppa/util/is_mutable_ref.hpp" #include "cppa/util/is_mutable_ref.hpp"
......
...@@ -41,8 +41,6 @@ ...@@ -41,8 +41,6 @@
#include "cppa/binary_deserializer.hpp" #include "cppa/binary_deserializer.hpp"
#include "cppa/util/pt_token.hpp" #include "cppa/util/pt_token.hpp"
#include "cppa/util/enable_if.hpp"
#include "cppa/util/disable_if.hpp"
#include "cppa/util/is_iterable.hpp" #include "cppa/util/is_iterable.hpp"
#include "cppa/util/is_primitive.hpp" #include "cppa/util/is_primitive.hpp"
#include "cppa/util/abstract_uniform_type_info.hpp" #include "cppa/util/abstract_uniform_type_info.hpp"
......
...@@ -330,6 +330,11 @@ size_t test__spawn() ...@@ -330,6 +330,11 @@ size_t test__spawn()
{ {
CPPA_TEST(test__spawn); CPPA_TEST(test__spawn);
CPPA_IF_VERBOSE(cout << "test send() ... " << std::flush);
send(self, 1, 2, 3);
receive(on(1, 2, 3) >> []() { });
CPPA_IF_VERBOSE(cout << "ok" << endl);
CPPA_IF_VERBOSE(cout << "test future_send() ... " << std::flush); CPPA_IF_VERBOSE(cout << "test future_send() ... " << std::flush);
future_send(self, std::chrono::seconds(1), 1, 2, 3); future_send(self, std::chrono::seconds(1), 1, 2, 3);
receive(on(1, 2, 3) >> []() { }); receive(on(1, 2, 3) >> []() { });
......
#include <list> #include <list>
#include <array> #include <array>
#include <string> #include <string>
#include <limits>
#include <cstdint>
#include <utility> #include <utility>
#include <iostream> #include <iostream>
#include <typeinfo> #include <typeinfo>
...@@ -38,1042 +40,11 @@ using std::endl; ...@@ -38,1042 +40,11 @@ using std::endl;
using namespace cppa; using namespace cppa;
using namespace cppa::detail; using namespace cppa::detail;
template<typename... T>
struct pseudo_tuple
{
typedef void* ptr_type;
typedef void const* const_ptr_type;
ptr_type data[sizeof...(T) > 0 ? sizeof...(T) : 1];
inline const_ptr_type at(size_t p) const
{
return data[p];
}
inline ptr_type mutable_at(size_t p)
{
return const_cast<ptr_type>(data[p]);
}
inline void*& operator[](size_t p)
{
return data[p];
}
};
template<class List>
struct pseudo_tuple_from_type_list;
template<typename... Ts>
struct pseudo_tuple_from_type_list<util::type_list<Ts...> >
{
typedef pseudo_tuple<Ts...> type;
};
template<size_t N, typename... Tn>
typename util::at<N, Tn...>::type const& get(pseudo_tuple<Tn...> const& tv)
{
static_assert(N < sizeof...(Tn), "N >= tv.size()");
return *reinterpret_cast<typename util::at<N, Tn...>::type const*>(tv.at(N));
}
template<size_t N, typename... Tn>
typename util::at<N, Tn...>::type& get_ref(pseudo_tuple<Tn...>& tv)
{
static_assert(N < sizeof...(Tn), "N >= tv.size()");
return *reinterpret_cast<typename util::at<N, Tn...>::type*>(tv.mutable_at(N));
}
// covers wildcard_position::multiple and wildcard_position::in_between
template<wildcard_position, class Pattern, class FilteredPattern>
struct invoke_policy_impl
{
typedef FilteredPattern filtered_pattern;
template<class Tuple>
static bool can_invoke(std::type_info const& type_token,
Tuple const& tup)
{
typedef typename match_impl_from_type_list<Tuple, Pattern>::type mimpl;
return type_token == typeid(filtered_pattern) || mimpl::_(tup);
}
template<class Target, typename PtrType, class Tuple>
static bool invoke(Target& target,
std::type_info const& type_token,
detail::tuple_impl_info,
PtrType*,
Tuple& tup)
{
typedef typename match_impl_from_type_list<
typename std::remove_const<Tuple>::type,
Pattern
>::type
mimpl;
util::fixed_vector<size_t, filtered_pattern::size> mv;
if (type_token == typeid(filtered_pattern) || mimpl::_(tup, mv))
{
typedef typename pseudo_tuple_from_type_list<filtered_pattern>::type
ttup_type;
ttup_type ttup;
// if we strip const here ...
for (size_t i = 0; i < filtered_pattern::size; ++i)
{
ttup[i] = const_cast<void*>(tup.at(mv[i]));
}
// ... we restore it here again
typedef typename util::if_else<
std::is_const<Tuple>,
ttup_type const&,
util::wrapped<ttup_type&>
>::type
ttup_ref;
ttup_ref ttup_fwd = ttup;
return util::unchecked_apply_tuple<bool>(target, ttup_fwd);
}
return false;
}
};
template<class Pattern, typename... Ts>
struct invoke_policy_impl<wildcard_position::nil,
Pattern, util::type_list<Ts...> >
{
typedef util::type_list<Ts...> filtered_pattern;
typedef detail::tdata<Ts...> native_data_type;
typedef typename detail::static_types_array<Ts...> arr_type;
template<class Target, class Tup>
static bool invoke(std::integral_constant<bool, false>, Target&, Tup&)
{
return false;
}
template<class Target, class Tup>
static bool invoke(std::integral_constant<bool, true>,
Target& target, Tup& tup)
{
return util::unchecked_apply_tuple<bool>(target, tup);
}
template<class Target, typename PtrType, class Tuple>
static bool invoke(Target& target,
std::type_info const&,
detail::tuple_impl_info,
PtrType*,
Tuple& tup,
typename util::disable_if<
std::is_same<typename std::remove_const<Tuple>::type,
detail::abstract_tuple>
>::type* = 0)
{
static constexpr bool can_apply =
util::tl_binary_forall<
typename util::tl_map<
typename Tuple::types,
util::purge_refs
>::type,
filtered_pattern,
std::is_same
>::value;
return invoke(std::integral_constant<bool, can_apply>{}, target, tup);
}
template<class Target, typename PtrType, typename Tuple>
static bool invoke(Target& target,
std::type_info const& arg_types,
detail::tuple_impl_info timpl,
PtrType* native_arg,
Tuple& tup,
typename util::enable_if<
std::is_same<typename std::remove_const<Tuple>::type,
detail::abstract_tuple>
>::type* = 0)
{
if (arg_types == typeid(filtered_pattern))
{
if (native_arg)
{
typedef typename util::if_else_c<
std::is_const<PtrType>::value,
native_data_type const*,
util::wrapped<native_data_type*>
>::type
cast_type;
auto arg = reinterpret_cast<cast_type>(native_arg);
return util::unchecked_apply_tuple<bool>(target, *arg);
}
// 'fall through'
}
else if (timpl == detail::dynamically_typed)
{
auto& arr = arr_type::arr;
if (tup.size() != filtered_pattern::size)
{
return false;
}
for (size_t i = 0; i < filtered_pattern::size; ++i)
{
if (arr[i] != tup.type_at(i))
{
return false;
}
}
// 'fall through'
}
else
{
return false;
}
typedef pseudo_tuple<Ts...> ttup_type;
ttup_type ttup;
// if we strip const here ...
for (size_t i = 0; i < sizeof...(Ts); ++i)
ttup[i] = const_cast<void*>(tup.at(i));
// ... we restore it here again
typedef typename util::if_else<
std::is_const<PtrType>,
ttup_type const&,
util::wrapped<ttup_type&>
>::type
ttup_ref;
ttup_ref ttup_fwd = ttup;
return util::unchecked_apply_tuple<bool>(target, ttup_fwd);
}
template<class Tuple>
static bool can_invoke(std::type_info const& arg_types, Tuple const&)
{
return arg_types == typeid(filtered_pattern);
}
};
template<>
struct invoke_policy_impl<wildcard_position::leading,
util::type_list<anything>,
util::type_list<> >
{
template<class Tuple>
static inline bool can_invoke(std::type_info const&,
Tuple const&)
{
return true;
}
template<class Target, typename... Args>
static bool invoke(Target& target, Args&&...)
{
return target();
}
};
template<class Pattern, typename... Ts>
struct invoke_policy_impl<wildcard_position::trailing,
Pattern, util::type_list<Ts...> >
{
typedef util::type_list<Ts...> filtered_pattern;
template<class Tuple>
static bool can_invoke(std::type_info const& arg_types,
Tuple const& tup)
{
if (arg_types == typeid(filtered_pattern))
{
return true;
}
typedef detail::static_types_array<Ts...> arr_type;
auto& arr = arr_type::arr;
if (tup.size() < filtered_pattern::size)
{
return false;
}
for (size_t i = 0; i < filtered_pattern::size; ++i)
{
if (arr[i] != tup.type_at(i))
{
return false;
}
}
return true;
}
template<class Target, typename PtrType, class Tuple>
static bool invoke(Target& target,
std::type_info const& arg_types,
detail::tuple_impl_info,
PtrType*,
Tuple& tup)
{
if (!can_invoke(arg_types, tup)) return false;
typedef pseudo_tuple<Ts...> ttup_type;
ttup_type ttup;
for (size_t i = 0; i < sizeof...(Ts); ++i)
ttup[i] = const_cast<void*>(tup.at(i));
// ensure const-correctness
typedef typename util::if_else<
std::is_const<Tuple>,
ttup_type const&,
util::wrapped<ttup_type&>
>::type
ttup_ref;
ttup_ref ttup_fwd = ttup;
return util::unchecked_apply_tuple<bool>(target, ttup_fwd);
}
};
template<class Pattern, typename... Ts>
struct invoke_policy_impl<wildcard_position::leading,
Pattern, util::type_list<Ts...> >
{
typedef util::type_list<Ts...> filtered_pattern;
template<class Tuple>
static bool can_invoke(std::type_info const& arg_types,
Tuple const& tup)
{
if (arg_types == typeid(filtered_pattern))
{
return true;
}
typedef detail::static_types_array<Ts...> arr_type;
auto& arr = arr_type::arr;
if (tup.size() < filtered_pattern::size)
{
return false;
}
size_t i = tup.size() - filtered_pattern::size;
size_t j = 0;
while (j < filtered_pattern::size)
{
if (arr[i++] != tup.type_at(j++))
{
return false;
}
}
return true;
}
template<class Target, typename PtrType, class Tuple>
static bool invoke(Target& target,
std::type_info const& arg_types,
detail::tuple_impl_info,
PtrType*,
Tuple& tup)
{
if (!can_invoke(arg_types, tup)) return false;
typedef pseudo_tuple<Ts...> ttup_type;
ttup_type ttup;
size_t i = tup.size() - filtered_pattern::size;
size_t j = 0;
while (j < filtered_pattern::size)
{
ttup[j++] = const_cast<void*>(tup.at(i++));
}
// ensure const-correctness
typedef typename util::if_else<
std::is_const<Tuple>,
ttup_type const&,
util::wrapped<ttup_type&>
>::type
ttup_ref;
ttup_ref ttup_fwd = ttup;
return util::unchecked_apply_tuple<bool>(target, ttup_fwd);
}
};
template<class Pattern>
struct invoke_policy
: invoke_policy_impl<
get_wildcard_position<Pattern>(),
Pattern,
typename util::tl_filter_not_type<Pattern, anything>::type>
{
};
template<class Pattern, class Projection, class PartialFunction>
struct projection_partial_function_pair : std::pair<Projection, PartialFunction>
{
template<typename... Args>
projection_partial_function_pair(Args&&... args)
: std::pair<Projection, PartialFunction>(std::forward<Args>(args)...)
{
}
typedef Pattern pattern_type;
};
template<class Expr, class Guard, class Transformers, class Pattern>
struct get_cfl
{
typedef typename util::get_callable_trait<Expr>::type ctrait;
typedef typename util::tl_filter_not_type<
Pattern,
anything
>::type
filtered_pattern;
typedef typename util::tl_pad_right<
Transformers,
filtered_pattern::size
>::type
padded_transformers;
typedef typename util::tl_map<
filtered_pattern,
std::add_const,
std::add_lvalue_reference
>::type
base_signature;
typedef typename util::tl_map_conditional<
typename util::tl_pad_left<
typename ctrait::arg_types,
filtered_pattern::size
>::type,
std::is_lvalue_reference,
false,
std::add_const,
std::add_lvalue_reference
>::type
padded_expr_args;
// override base signature with required argument types of Expr
// and result types of transformation
typedef typename util::tl_zip<
typename util::tl_map<
padded_transformers,
util::get_result_type,
util::rm_option,
std::add_lvalue_reference
>::type,
typename util::tl_zip<
padded_expr_args,
base_signature,
util::left_or_right
>::type,
util::left_or_right
>::type
partial_fun_signature;
// 'inherit' mutable references from partial_fun_signature
// for arguments without transformation
typedef typename util::tl_zip<
typename util::tl_zip<
padded_transformers,
partial_fun_signature,
util::if_not_left
>::type,
base_signature,
util::deduce_ref_type
>::type
projection_signature;
typedef typename projection_from_type_list<
padded_transformers,
projection_signature
>::type
type1;
typedef typename get_tpartial_function<
Expr,
Guard,
partial_fun_signature
>::type
type2;
typedef projection_partial_function_pair<Pattern, type1, type2> type;
};
template<typename First, typename Second>
struct pjf_same_pattern
: std::is_same<typename First::second::pattern_type,
typename Second::second::pattern_type>
{
};
// last invocation step; evaluates a {projection, tpartial_function} pair
template<typename Data>
struct invoke_helper3
{
Data const& data;
invoke_helper3(Data const& mdata) : data(mdata) { }
template<size_t Pos, typename T, typename... Args>
inline bool operator()(util::type_pair<std::integral_constant<size_t, Pos>, T>,
Args&&... args) const
{
auto const& target = get<Pos>(data);
return target.first(target.second, std::forward<Args>(args)...);
//return (get<Pos>(data))(args...);
}
};
template<class Data, class Token, class Pattern>
struct invoke_helper2
{
typedef Pattern pattern_type;
typedef typename util::tl_filter_not_type<pattern_type, anything>::type arg_types;
Data const& data;
invoke_helper2(Data const& mdata) : data(mdata) { }
template<typename... Args>
bool invoke(Args&&... args) const
{
typedef invoke_policy<Pattern> impl;
return impl::invoke(*this, std::forward<Args>(args)...);
}
// resolved argument list (called from invoke_policy)
template<typename... Args>
bool operator()(Args&&... args) const
{
//static_assert(false, "foo");
Token token;
invoke_helper3<Data> fun{data};
return util::static_foreach<0, Token::size>::eval_or(token, fun, std::forward<Args>(args)...);
}
};
// invokes a group of {projection, tpartial_function} pairs
template<typename Data, typename BoolIter>
struct invoke_helper
{
Data const& data;
BoolIter enabled;
invoke_helper(Data const& mdata, BoolIter biter) : data(mdata), enabled(biter) { }
// token: type_list<type_pair<integral_constant<size_t, X>,
// std::pair<projection, tpartial_function>>,
// ...>
// all {projection, tpartial_function} pairs have the same pattern
// thus, can be invoked from same data
template<class Token, typename... Args>
bool operator()(Token, Args&&... args)
{
typedef typename Token::head type_pair;
typedef typename type_pair::second leaf_pair;
if (*enabled++)
{
// next invocation step
invoke_helper2<Data,
Token,
typename leaf_pair::pattern_type> fun{data};
return fun.invoke(std::forward<Args>(args)...);
}
//++enabled;
return false;
}
};
template<typename BoolArray>
struct can_invoke_helper
{
BoolArray& data;
size_t i;
can_invoke_helper(BoolArray& mdata) : data(mdata), i(0) { }
template<class Token, typename... Args>
void operator()(Token, Args&&... args)
{
typedef typename Token::head type_pair;
typedef typename type_pair::second leaf_pair;
typedef invoke_policy<typename leaf_pair::pattern_type> impl;
data[i++] = impl::can_invoke(std::forward<Args>(args)...);
}
};
template<typename T>
struct is_manipulator_leaf
{
static constexpr bool value = T::second_type::manipulates_args;
};
template<bool IsManipulator, typename T0, typename T1>
struct pj_fwd_
{
typedef T1 type;
};
template<typename T>
struct pj_fwd_<false, T const&, T>
{
typedef std::reference_wrapper<const T> type;
};
template<typename T>
struct pj_fwd_<true, T&, T>
{
typedef std::reference_wrapper<T> type;
};
template<bool IsManipulator, typename T>
struct pj_fwd
{
typedef typename pj_fwd_<
IsManipulator,
T,
typename detail::implicit_conversions<
typename util::rm_ref<T>::type
>::type
>::type
type;
};
/**
* @brief A function that works on the projection of given data rather than
* on the data itself.
*/
template<class... Leaves>
class projected_fun
{
public:
typedef util::type_list<Leaves...> leaves_list;
typedef typename util::tl_zip_with_index<leaves_list>::type zipped_list;
typedef typename util::tl_group_by<zipped_list, pjf_same_pattern>::type
eval_order;
static constexpr bool has_manipulator =
util::tl_exists<leaves_list, is_manipulator_leaf>::value;
template<typename... Args>
projected_fun(Args&&... args) : m_leaves(std::forward<Args>(args)...)
{
init();
}
projected_fun(projected_fun&& other) : m_leaves(std::move(other.m_leaves))
{
init();
}
projected_fun(projected_fun const& other) : m_leaves(other.m_leaves)
{
init();
}
bool invoke(any_tuple const& tup)
{
return _invoke(tup);
}
bool invoke(any_tuple& tup)
{
return _invoke(tup);
}
bool invoke(any_tuple&& tup)
{
any_tuple tmp{tup};
return invoke(tmp);
}
template<typename... Args>
bool can_invoke(Args&&... args)
{
typedef detail::tdata<typename pj_fwd<has_manipulator, Args>::type...>
tuple_type;
// applies implicit conversions etc
tuple_type tup{std::forward<Args>(args)...};
auto& type_token = typeid(typename tuple_type::types);
eval_order token;
cache_entry tmp;
can_invoke_helper<cache_entry> fun{tmp};
util::static_foreach<0, eval_order::size>
::_(token, fun, type_token, tup);
return std::any_of(tmp.begin(), tmp.end(), [](bool value) { return value; });
}
template<typename... Args>
bool operator()(Args&&... args)
{
typedef detail::tdata<typename pj_fwd<has_manipulator, Args>::type...>
tuple_type;
// applies implicit conversions etc
tuple_type tup{std::forward<Args>(args)...};
auto& type_token = typeid(typename tuple_type::types);
auto enabled_begin = get_cache_entry(&type_token, tup);
typedef typename util::if_else_c<
has_manipulator,
tuple_type&,
util::wrapped<tuple_type const&>
>::type
ref_type;
typedef typename util::if_else_c<
has_manipulator,
void*,
util::wrapped<void const*>
>::type
ptr_type;
eval_order token;
invoke_helper<decltype(m_leaves), decltype(enabled_begin)> fun{m_leaves, enabled_begin};
return util::static_foreach<0, eval_order::size>
::eval_or(token,
fun,
type_token,
detail::statically_typed,
static_cast<ptr_type>(nullptr),
static_cast<ref_type>(tup));
}
template<class... Rhs>
projected_fun<Leaves..., Rhs...>
or_else(projected_fun<Rhs...> const& other) const
{
detail::tdata<ge_reference_wrapper<Leaves>...,
ge_reference_wrapper<Rhs>... > all_leaves;
collect_tdata(all_leaves, m_leaves, other.leaves());
return {all_leaves};
}
inline detail::tdata<Leaves...> const& leaves() const
{
return m_leaves;
}
private:
// structure: tdata< tdata<type_list<...>, ...>,
// tdata<type_list<...>, ...>,
// ...>
detail::tdata<Leaves...> m_leaves;
static constexpr size_t cache_size = 10;
typedef std::array<bool, eval_order::size> cache_entry;
typedef typename cache_entry::iterator cache_entry_iterator;
typedef std::pair<std::type_info const*, cache_entry> cache_element;
util::fixed_vector<cache_element, cache_size> m_cache;
// ring buffer like access to m_cache
size_t m_cache_begin;
size_t m_cache_end;
cache_element m_dummy;
static inline void advance_(size_t& i)
{
i = (i + 1) % cache_size;
}
inline size_t find_token_pos(std::type_info const* type_token)
{
for (size_t i = m_cache_begin ; i != m_cache_end; advance_(i))
{
if (m_cache[i].first == type_token) return i;
}
return m_cache_end;
}
template<class Tuple>
cache_entry_iterator get_cache_entry(std::type_info const* type_token,
Tuple const& value)
{
CPPA_REQUIRE(type_token != nullptr);
if (value.impl_type() == detail::dynamically_typed)
{
return m_dummy.second.begin();
}
size_t i = find_token_pos(type_token);
// if we didn't found a cache entry ...
if (i == m_cache_end)
{
// ... 'create' one
advance_(m_cache_end);
if (m_cache_end == m_cache_begin) advance_(m_cache_begin);
m_cache[i].first = type_token;
eval_order token;
can_invoke_helper<cache_entry> fun{m_cache[i].second};
util::static_foreach<0, eval_order::size>
::_(token, fun, *type_token, value);
}
return m_cache[i].second.begin();
}
void init()
{
m_dummy.second.fill(true);
m_cache.resize(cache_size);
for(size_t i = 0; i < cache_size; ++i) m_cache[i].first = nullptr;
m_cache_begin = m_cache_end = 0;
}
template<typename AbstractTuple, typename NativeDataPtr>
bool _do_invoke(AbstractTuple& vals, NativeDataPtr ndp)
{
std::type_info const* type_token = vals.type_token();
auto enabled_begin = get_cache_entry(type_token, vals);
eval_order token;
invoke_helper<decltype(m_leaves), decltype(enabled_begin)> fun{m_leaves, enabled_begin};
return util::static_foreach<0, eval_order::size>
::eval_or(token,
fun,
*type_token,
vals.impl_type(),
ndp,
vals);
}
template<typename AnyTuple>
bool _invoke(AnyTuple& tup,
typename util::enable_if_c<
std::is_const<AnyTuple>::value == false
&& has_manipulator == true
>::type* = 0)
{
tup.force_detach();
auto& vals = *(tup.vals());
return _do_invoke(vals, vals.mutable_native_data());
}
template<typename AnyTuple>
bool _invoke(AnyTuple& tup,
typename util::enable_if_c<
std::is_const<AnyTuple>::value == false
&& has_manipulator == false
>::type* = 0)
{
return _invoke(static_cast<AnyTuple const&>(tup));
}
template<typename AnyTuple>
bool _invoke(AnyTuple& tup,
typename util::enable_if_c<
std::is_const<AnyTuple>::value == true
&& has_manipulator == false
>::type* = 0)
{
auto const& cvals = *(tup.cvals());
return _do_invoke(cvals, cvals.native_data());
}
template<typename AnyTuple>
bool _invoke(AnyTuple& tup,
typename util::enable_if_c<
std::is_const<AnyTuple>::value == true
&& has_manipulator == true
>::type* = 0)
{
any_tuple tup_copy{tup};
return _invoke(tup_copy);
}
};
template<class List>
struct projected_fun_from_type_list;
template<typename... Args>
struct projected_fun_from_type_list<util::type_list<Args...> >
{
typedef projected_fun<Args...> type;
};
template<typename... Lhs, typename... Rhs>
projected_fun<Lhs..., Rhs...> operator,(projected_fun<Lhs...> const& lhs,
projected_fun<Rhs...> const& rhs)
{
return lhs.or_else(rhs);
}
template<typename Arg0, typename... Args>
typename projected_fun_from_type_list<
typename util::tl_concat<
typename Arg0::leaves_list,
typename Args::leaves_list...
>::type
>::type
pj_concat(Arg0 const& arg0, Args const&... args)
{
typename detail::tdata_from_type_list<
typename util::tl_map<
typename util::tl_concat<
typename Arg0::leaves_list,
typename Args::leaves_list...
>::type,
gref_wrapped
>::type
>::type
all_leaves;
collect_tdata(all_leaves, arg0.leaves(), args.leaves()...);
return {all_leaves};
}
#define VERBOSE(LineOfCode) cout << #LineOfCode << " = " << (LineOfCode) << endl #define VERBOSE(LineOfCode) cout << #LineOfCode << " = " << (LineOfCode) << endl
struct cf_builder_from_args { };
template<class Guard, class Transformers, class Pattern>
struct cf_builder
{
typedef typename detail::tdata_from_type_list<Transformers>::type
fun_container;
Guard m_guard;
typename detail::tdata_from_type_list<Transformers>::type m_funs;
public:
cf_builder() = default;
template<typename... Args>
cf_builder(cf_builder_from_args const&, Args const&... args)
: m_guard(args...)
, m_funs(args...)
{
}
cf_builder(Guard& mg, fun_container const& funs)
: m_guard(std::move(mg)), m_funs(funs)
{
}
cf_builder(Guard const& mg, fun_container const& funs)
: m_guard(mg), m_funs(funs)
{
}
template<typename NewGuard>
cf_builder<
guard_expr<
logical_and_op,
guard_expr<exec_xfun_op, Guard, util::void_type>,
NewGuard>,
Transformers,
Pattern>
when(NewGuard ng,
typename util::disable_if_c<
std::is_same<NewGuard, NewGuard>::value
&& std::is_same<Guard, value_guard< util::type_list<> >>::value
>::type* = 0 ) const
{
return {(gcall(m_guard) && ng), m_funs};
}
template<typename NewGuard>
cf_builder<NewGuard, Transformers, Pattern>
when(NewGuard ng,
typename util::enable_if_c<
std::is_same<NewGuard, NewGuard>::value
&& std::is_same<Guard, value_guard< util::type_list<> >>::value
>::type* = 0 ) const
{
return {ng, m_funs};
}
template<typename Expr>
projected_fun<typename get_cfl<Expr, Guard, Transformers, Pattern>::type>
operator>>(Expr expr) const
{
typedef typename get_cfl<Expr, Guard, Transformers, Pattern>::type tpair;
return tpair{typename tpair::first_type{m_funs},
typename tpair::second_type{std::move(expr), m_guard}};
}
};
template<bool IsFun, typename T>
struct add_ptr_to_fun_
{
typedef T* type;
};
template<typename T>
struct add_ptr_to_fun_<false, T>
{
typedef T type;
};
template<typename T>
struct add_ptr_to_fun : add_ptr_to_fun_<std::is_function<T>::value, T>
{
};
template<bool ToVoid, typename T>
struct to_void_impl
{
typedef util::void_type type;
};
template<typename T>
struct to_void_impl<false, T>
{
typedef typename add_ptr_to_fun<T>::type type;
};
template<typename T>
struct not_callable_to_void : to_void_impl<detail::is_boxed<T>::value || !util::is_callable<T>::value, T>
{
};
template<typename T>
struct boxed_and_callable_to_void : to_void_impl<detail::is_boxed<T>::value || util::is_callable<T>::value, T>
{
};
template<bool IsCallable, typename T>
struct pattern_type_
{
typedef util::get_callable_trait<T> ctrait;
typedef typename ctrait::arg_types args;
static_assert(args::size == 1, "only unary functions allowed");
typedef typename util::rm_ref<typename args::head>::type type;
};
template<typename T>
struct pattern_type_<false, T>
{
typedef typename util::rm_ref<typename detail::unboxed<T>::type>::type type;
};
template<typename T>
struct pattern_type : pattern_type_<util::is_callable<T>::value && !detail::is_boxed<T>::value, T>
{
};
template<typename... T>
cf_builder<value_guard<util::type_list<> >,
util::type_list<>,
util::type_list<T...> >
_on()
{
return {};
}
template<typename Arg0, typename... Args>
cf_builder<
value_guard<
typename util::tl_trim<
typename util::tl_map<
util::type_list<Arg0, Args...>,
boxed_and_callable_to_void
>::type
>::type
>,
typename util::tl_map<
util::type_list<Arg0, Args...>,
not_callable_to_void
>::type,
util::type_list<typename pattern_type<Arg0>::type,
typename pattern_type<Args>::type...> >
_on(Arg0 const& arg0, Args const&... args)
{
return {cf_builder_from_args{}, arg0, args...};
}
std::string int2str(int i) std::string int2str(int i)
{ {
return std::to_string(i); return std::to_string(i);
...@@ -1153,14 +124,14 @@ size_t test__tuple() ...@@ -1153,14 +124,14 @@ size_t test__tuple()
std::string invoked; std::string invoked;
auto f00 = _on<int, int>() >> [&]() { invoked = "f00"; }; auto f00 = on<int, int>() >> [&]() { invoked = "f00"; };
CPPA_CHECK_INVOKED(f00, (42, 42)); CPPA_CHECK_INVOKED(f00, (42, 42));
auto f01 = _on<int, int>().when(_x1 == 42) >> [&]() { invoked = "f01"; }; auto f01 = on<int, int>().when(_x1 == 42) >> [&]() { invoked = "f01"; };
CPPA_CHECK_INVOKED(f01, (42, 42)); CPPA_CHECK_INVOKED(f01, (42, 42));
CPPA_CHECK_NOT_INVOKED(f01, (1, 2)); CPPA_CHECK_NOT_INVOKED(f01, (1, 2));
auto f02 = _on<int, int>().when(_x1 == 42 && _x2 * 2 == _x1) >> [&]() { invoked = "f02"; }; auto f02 = on<int, int>().when(_x1 == 42 && _x2 * 2 == _x1) >> [&]() { invoked = "f02"; };
CPPA_CHECK_NOT_INVOKED(f02, (0, 0)); CPPA_CHECK_NOT_INVOKED(f02, (0, 0));
CPPA_CHECK_NOT_INVOKED(f02, (42, 42)); CPPA_CHECK_NOT_INVOKED(f02, (42, 42));
CPPA_CHECK_NOT_INVOKED(f02, (2, 1)); CPPA_CHECK_NOT_INVOKED(f02, (2, 1));
...@@ -1170,11 +141,11 @@ size_t test__tuple() ...@@ -1170,11 +141,11 @@ size_t test__tuple()
CPPA_CHECK_EQUAL("f02", invoked); CPPA_CHECK_EQUAL("f02", invoked);
invoked = ""; invoked = "";
auto f03 = _on(42, val<int>) >> [&](int const& a, int&) { invoked = "f03"; CPPA_CHECK_EQUAL(42, a); }; auto f03 = on(42, val<int>) >> [&](int const& a, int&) { invoked = "f03"; CPPA_CHECK_EQUAL(42, a); };
CPPA_CHECK_NOT_INVOKED(f03, (0, 0)); CPPA_CHECK_NOT_INVOKED(f03, (0, 0));
CPPA_CHECK_INVOKED(f03, (42, 42)); CPPA_CHECK_INVOKED(f03, (42, 42));
auto f04 = _on(42, int2str).when(_x2 == "42") >> [&](std::string& str) auto f04 = on(42, int2str).when(_x2 == "42") >> [&](std::string& str)
{ {
CPPA_CHECK_EQUAL("42", str); CPPA_CHECK_EQUAL("42", str);
invoked = "f04"; invoked = "f04";
...@@ -1185,17 +156,17 @@ size_t test__tuple() ...@@ -1185,17 +156,17 @@ size_t test__tuple()
CPPA_CHECK_NOT_INVOKED(f04, (42, 0)); CPPA_CHECK_NOT_INVOKED(f04, (42, 0));
CPPA_CHECK_INVOKED(f04, (42, 42)); CPPA_CHECK_INVOKED(f04, (42, 42));
auto f05 = _on(str2int).when(_x1 % 2 == 0) >> [&]() { invoked = "f05"; }; auto f05 = on(str2int).when(_x1 % 2 == 0) >> [&]() { invoked = "f05"; };
CPPA_CHECK_NOT_INVOKED(f05, ("1")); CPPA_CHECK_NOT_INVOKED(f05, ("1"));
CPPA_CHECK_INVOKED(f05, ("2")); CPPA_CHECK_INVOKED(f05, ("2"));
auto f06 = _on(42, str2int).when(_x2 % 2 == 0) >> [&]() { invoked = "f06"; }; auto f06 = on(42, str2int).when(_x2 % 2 == 0) >> [&]() { invoked = "f06"; };
CPPA_CHECK_NOT_INVOKED(f06, (0, "0")); CPPA_CHECK_NOT_INVOKED(f06, (0, "0"));
CPPA_CHECK_NOT_INVOKED(f06, (42, "1")); CPPA_CHECK_NOT_INVOKED(f06, (42, "1"));
CPPA_CHECK_INVOKED(f06, (42, "2")); CPPA_CHECK_INVOKED(f06, (42, "2"));
int f07_val = 1; int f07_val = 1;
auto f07 = _on<int>().when(_x1 == gref(f07_val)) >> [&]() { invoked = "f07"; }; auto f07 = on<int>().when(_x1 == gref(f07_val)) >> [&]() { invoked = "f07"; };
CPPA_CHECK_NOT_INVOKED(f07, (0)); CPPA_CHECK_NOT_INVOKED(f07, (0));
CPPA_CHECK_INVOKED(f07, (1)); CPPA_CHECK_INVOKED(f07, (1));
CPPA_CHECK_NOT_INVOKED(f07, (2)); CPPA_CHECK_NOT_INVOKED(f07, (2));
...@@ -1206,7 +177,7 @@ size_t test__tuple() ...@@ -1206,7 +177,7 @@ size_t test__tuple()
CPPA_CHECK(f07.invoke(make_cow_tuple(2))); CPPA_CHECK(f07.invoke(make_cow_tuple(2)));
int f08_val = 666; int f08_val = 666;
auto f08 = _on<int>() >> [&](int& mref) { mref = 8; invoked = "f08"; }; auto f08 = on<int>() >> [&](int& mref) { mref = 8; invoked = "f08"; };
CPPA_CHECK_INVOKED(f08, (f08_val)); CPPA_CHECK_INVOKED(f08, (f08_val));
CPPA_CHECK_EQUAL(8, f08_val); CPPA_CHECK_EQUAL(8, f08_val);
any_tuple f08_any_val = make_cow_tuple(666); any_tuple f08_any_val = make_cow_tuple(666);
...@@ -1214,7 +185,7 @@ size_t test__tuple() ...@@ -1214,7 +185,7 @@ size_t test__tuple()
CPPA_CHECK_EQUAL(8, f08_any_val.get_as<int>(0)); CPPA_CHECK_EQUAL(8, f08_any_val.get_as<int>(0));
int f09_val = 666; int f09_val = 666;
auto f09 = _on(str2int, val<int>) >> [&](int& mref) { mref = 9; invoked = "f09"; }; auto f09 = on(str2int, val<int>) >> [&](int& mref) { mref = 9; invoked = "f09"; };
CPPA_CHECK_NOT_INVOKED(f09, ("hello lambda", f09_val)); CPPA_CHECK_NOT_INVOKED(f09, ("hello lambda", f09_val));
CPPA_CHECK_INVOKED(f09, ("0", f09_val)); CPPA_CHECK_INVOKED(f09, ("0", f09_val));
CPPA_CHECK_EQUAL(9, f09_val); CPPA_CHECK_EQUAL(9, f09_val);
...@@ -1233,9 +204,9 @@ size_t test__tuple() ...@@ -1233,9 +204,9 @@ size_t test__tuple()
auto f10 = auto f10 =
( (
_on<int>().when(_x1 < 10) >> [&]() { invoked = "f10.0"; }, on<int>().when(_x1 < 10) >> [&]() { invoked = "f10.0"; },
_on<int>() >> [&]() { invoked = "f10.1"; }, on<int>() >> [&]() { invoked = "f10.1"; },
_on<std::string, anything>() >> [&](std::string&) { invoked = "f10.2"; } on<std::string, anything>() >> [&](std::string&) { invoked = "f10.2"; }
); );
CPPA_CHECK(f10(9)); CPPA_CHECK(f10(9));
...@@ -1252,19 +223,19 @@ size_t test__tuple() ...@@ -1252,19 +223,19 @@ size_t test__tuple()
//CPPA_CHECK(f10(static_cast<std::string const&>(foobar), "b", "c")); //CPPA_CHECK(f10(static_cast<std::string const&>(foobar), "b", "c"));
int f11_fun = 0; int f11_fun = 0;
auto f11 = pj_concat auto f11 =
( (
_on<int>().when(_x1 == 1) >> [&]() { f11_fun = 1; }, on<int>().when(_x1 == 1) >> [&]() { f11_fun = 1; },
_on<int>().when(_x1 == 2) >> [&]() { f11_fun = 2; }, on<int>().when(_x1 == 2) >> [&]() { f11_fun = 2; },
_on<int>().when(_x1 == 3) >> [&]() { f11_fun = 3; }, on<int>().when(_x1 == 3) >> [&]() { f11_fun = 3; },
_on<int>().when(_x1 == 4) >> [&]() { f11_fun = 4; }, on<int>().when(_x1 == 4) >> [&]() { f11_fun = 4; },
_on<int>().when(_x1 == 5) >> [&]() { f11_fun = 5; }, on<int>().when(_x1 == 5) >> [&]() { f11_fun = 5; },
_on<int>().when(_x1 == 6) >> [&]() { f11_fun = 6; }, on<int>().when(_x1 == 6) >> [&]() { f11_fun = 6; },
_on<int>().when(_x1 == 7) >> [&]() { f11_fun = 7; }, on<int>().when(_x1 == 7) >> [&]() { f11_fun = 7; },
_on<int>().when(_x1 == 8) >> [&]() { f11_fun = 8; }, on<int>().when(_x1 == 8) >> [&]() { f11_fun = 8; },
_on<int>().when(_x1 >= 9) >> [&]() { f11_fun = 9; }, on<int>().when(_x1 >= 9) >> [&]() { f11_fun = 9; },
_on(str2int) >> [&]() { f11_fun = 10; }, on(str2int) >> [&]() { f11_fun = 10; },
_on<std::string>() >> [&]() { f11_fun = 11; } on<std::string>() >> [&]() { f11_fun = 11; }
); );
CPPA_CHECK(f11(1)); CPPA_CHECK(f11(1));
...@@ -1280,9 +251,9 @@ size_t test__tuple() ...@@ -1280,9 +251,9 @@ size_t test__tuple()
CPPA_CHECK(f11("10")); CPPA_CHECK(f11("10"));
CPPA_CHECK_EQUAL(10, f11_fun); CPPA_CHECK_EQUAL(10, f11_fun);
auto f12 = pj_concat auto f12 =
( (
_on<int, anything, int>().when(_x1 < _x2) >> [&](int a, int b) on<int, anything, int>().when(_x1 < _x2) >> [&](int a, int b)
{ {
CPPA_CHECK_EQUAL(1, a); CPPA_CHECK_EQUAL(1, a);
CPPA_CHECK_EQUAL(5, b); CPPA_CHECK_EQUAL(5, b);
...@@ -1292,9 +263,9 @@ size_t test__tuple() ...@@ -1292,9 +263,9 @@ size_t test__tuple()
CPPA_CHECK_INVOKED(f12, (1, 2, 3, 4, 5)); CPPA_CHECK_INVOKED(f12, (1, 2, 3, 4, 5));
int f13_fun = 0; int f13_fun = 0;
auto f13 = pj_concat auto f13 =
( (
_on<int, anything, std::string, anything, int>().when(_x1 < _x3 && _x2.starts_with("-")) >> [&](int a, std::string const& str, int b) on<int, anything, std::string, anything, int>().when(_x1 < _x3 && _x2.starts_with("-")) >> [&](int a, std::string const& str, int b)
{ {
CPPA_CHECK_EQUAL("-h", str); CPPA_CHECK_EQUAL("-h", str);
CPPA_CHECK_EQUAL(1, a); CPPA_CHECK_EQUAL(1, a);
...@@ -1302,7 +273,7 @@ size_t test__tuple() ...@@ -1302,7 +273,7 @@ size_t test__tuple()
f13_fun = 1; f13_fun = 1;
invoked = "f13"; invoked = "f13";
}, },
_on<anything, std::string, anything, int, anything, float, anything>() >> [&](std::string const& str, int a, float b) on<anything, std::string, anything, int, anything, float, anything>() >> [&](std::string const& str, int a, float b)
{ {
CPPA_CHECK_EQUAL("h", str); CPPA_CHECK_EQUAL("h", str);
CPPA_CHECK_EQUAL(12, a); CPPA_CHECK_EQUAL(12, a);
...@@ -1310,7 +281,7 @@ size_t test__tuple() ...@@ -1310,7 +281,7 @@ size_t test__tuple()
f13_fun = 2; f13_fun = 2;
invoked = "f13"; invoked = "f13";
}, },
_on<float, anything, float>().when(_x1 * 2 == _x2) >> [&](float a, float b) on<float, anything, float>().when(_x1 * 2 == _x2) >> [&](float a, float b)
{ {
CPPA_CHECK_EQUAL(1.f, a); CPPA_CHECK_EQUAL(1.f, a);
CPPA_CHECK_EQUAL(2.f, b); CPPA_CHECK_EQUAL(2.f, b);
...@@ -1339,10 +310,10 @@ size_t test__tuple() ...@@ -1339,10 +310,10 @@ size_t test__tuple()
auto new_pf = auto new_pf =
( (
_on(42) >> []() { }, on(42) >> []() { },
_on(std::string("abc")) >> []() { }, on(std::string("abc")) >> []() { },
_on<int, int>() >> []() { }, on<int, int>() >> []() { },
_on<anything>() >> []() { } on<anything>() >> []() { }
); );
any_tuple testee[] = { any_tuple testee[] = {
...@@ -1462,10 +433,10 @@ size_t test__tuple() ...@@ -1462,10 +433,10 @@ size_t test__tuple()
{ {
auto tmp = auto tmp =
( (
_on(42) >> []() { }, on(42) >> []() { },
_on(std::string("abc")) >> []() { }, on(std::string("abc")) >> []() { },
_on<int, int>() >> []() { }, on<int, int>() >> []() { },
_on<anything>() >> []() { } on<anything>() >> []() { }
); );
for (auto& x : testee) { tmp(x); } for (auto& x : testee) { tmp(x); }
} }
...@@ -1490,13 +461,13 @@ size_t test__tuple() ...@@ -1490,13 +461,13 @@ size_t test__tuple()
VERBOSE(f05(42, std::string("42"))); VERBOSE(f05(42, std::string("42")));
VERBOSE(f05(42, std::string("hello world!"))); VERBOSE(f05(42, std::string("hello world!")));
auto f06 = f04.or_else(_on<int, int>().when(_x2 > _x1) >> []() { }); auto f06 = f04.or_else(on<int, int>().when(_x2 > _x1) >> []() { });
VERBOSE(f06(42, 42)); VERBOSE(f06(42, 42));
VERBOSE(f06(1, 2)); VERBOSE(f06(1, 2));
*/ */
/* /*
auto f06 = _on<anything, int>() >> []() { }; auto f06 = on<anything, int>() >> []() { };
VERBOSE(f06(1)); VERBOSE(f06(1));
VERBOSE(f06(1.f, 2)); VERBOSE(f06(1.f, 2));
......
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