Commit 00f15911 authored by neverlord's avatar neverlord

guard expressions

parent 3652f62e
......@@ -151,6 +151,7 @@ nobase_library_include_HEADERS = \
cppa/fsm_actor.hpp \
cppa/get.hpp \
cppa/group.hpp \
cppa/guard_expr.hpp \
cppa/intrusive/forward_iterator.hpp \
cppa/intrusive/single_reader_queue.hpp \
cppa/intrusive/singly_linked_list.hpp \
......@@ -192,7 +193,6 @@ nobase_library_include_HEADERS = \
cppa/util/enable_if.hpp \
cppa/util/fiber.hpp \
cppa/util/fixed_vector.hpp \
cppa/util/guard.hpp \
cppa/util/if_else.hpp \
cppa/util/is_array_of.hpp \
cppa/util/is_builtin.hpp \
......
......@@ -258,5 +258,5 @@ cppa/detail/tuple_view.hpp
cppa/detail/container_tuple_view.hpp
cppa/detail/matches.hpp
unit_testing/test__match.cpp
cppa/guard_expr.hpp
src/pattern.cpp
cppa/util/guard.hpp
......@@ -163,7 +163,7 @@ enum mapping_policy
map_to_option
};
template<mapping_policy, class Pattern>
template<mapping_policy, class Pattern> // do_not_map
struct pattern_policy
{
Pattern m_pattern;
......
......@@ -267,9 +267,9 @@ template<typename T>
struct tdata_from_type_list;
template<typename... T>
struct tdata_from_type_list<cppa::util::type_list<T...>>
struct tdata_from_type_list<util::type_list<T...>>
{
typedef cppa::detail::tdata<T...> type;
typedef tdata<T...> type;
};
} } // 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 GUARD_EXPR_HPP
#define GUARD_EXPR_HPP
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
#include <type_traits>
#include "cppa/util/at.hpp"
#include "cppa/detail/tdata.hpp"
namespace cppa {
enum operator_id
{
// arithmetic operators
addition_op, subtraction_op, multiplication_op, division_op, modulo_op,
// comparison operators
less_op, less_eq_op, greater_op, greater_eq_op, equal_op, not_equal_op,
// logical operators
logical_and_op, logical_or_op,
// pseudo operators for function invocation
exec_fun1_op, exec_fun2_op, exec_fun3_op,
// pseudo operator to store function parameters
dummy_op
};
// {operator, lhs, rhs} expression
template<operator_id OP, typename First, typename Second>
struct guard_expr
{
typedef First first_type;
typedef Second second_type;
std::pair<First, Second> m_args;
//guard_expr() = default;
template<typename T0, typename T1>
guard_expr(T0&& a0, T1&& a1)
: m_args(std::forward<T0>(a0), std::forward<T1>(a1))
{
}
// {operator, {operator, a0, a1}, a2}
template<typename T0, typename T1, typename T2>
guard_expr(T0&& a0, T1&& a1, T2&& a2)
: m_args(First{std::forward<T0>(a0), std::forward<T1>(a1)},
std::forward<T2>(a2))
{
}
// {operator, {operator, a0, a1}, {operator, a2, a3}}
template<typename T0, typename T1, typename T2, typename T3>
guard_expr(T0&& a0, T1&& a1, T2&& a2, T3&& a3)
: m_args(First{std::forward<T0>(a0), std::forward<T1>(a1)},
Second{std::forward<T2>(a2), std::forward<T3>(a3)})
{
}
guard_expr(guard_expr const&) = default;
guard_expr(guard_expr&& other) : m_args(std::move(other.m_args)) { }
};
#define CPPA_FORALL_OPS(SubMacro) \
SubMacro (addition_op, +) SubMacro (subtraction_op, -) \
SubMacro (multiplication_op, *) SubMacro (division_op, /) \
SubMacro (modulo_op, %) SubMacro (less_op, <) \
SubMacro (less_eq_op, <=) SubMacro (greater_op, >) \
SubMacro (greater_eq_op, >=) SubMacro (equal_op, ==) \
SubMacro (not_equal_op, !=)
// bind utility for placeholders
template<typename Fun, typename T1>
struct gbind1
{
typedef guard_expr<exec_fun1_op, Fun, T1> result;
};
template<typename Fun, typename T1, typename T2>
struct gbind2
{
typedef guard_expr<exec_fun2_op, guard_expr<dummy_op, Fun, T1>, T2> result;
};
template<typename Fun, typename T1, typename T2, typename T3>
struct gbind3
{
typedef guard_expr<exec_fun3_op, guard_expr<dummy_op, Fun, T1>,
guard_expr<dummy_op, T2, T3> >
result;
};
/**
* @brief Call wrapper for guard placeholders and lazy evaluation.
*/
template<typename Fun, typename T1>
typename gbind1<Fun, T1>::result gbind(Fun fun, T1 t1)
{
return {fun, t1};
}
/**
* @brief Call wrapper for guard placeholders and lazy evaluation.
*/
template<typename Fun, typename T1, typename T2>
typename gbind2<Fun, T1, T2>::result gbind(Fun fun, T1 t1, T2 t2)
{
return {fun, t1, t2};
}
/**
* @brief Call wrapper for guard placeholders and lazy evaluation.
*/
template<typename Fun, typename T1, typename T2, typename T3>
typename gbind3<Fun, T1, T2, T3>::result gbind(Fun fun, T1 t1, T2 t2, T3 t3)
{
return {fun, t1, t2, t3};
}
struct ge_search_container
{
bool sc;
ge_search_container(bool should_contain) : sc(should_contain) { }
template<class C>
bool operator()(C const& haystack,
typename C::value_type const& needle) const
{
typedef typename C::value_type vtype;
if (sc)
return std::any_of(haystack.begin(), haystack.end(),
[&](vtype const& val) { return needle == val; });
return std::none_of(haystack.begin(), haystack.end(),
[&](vtype const& val) { return needle == val; });
}
template<class C>
bool operator()(std::reference_wrapper<C> const& haystack_ref,
typename C::value_type const& needle) const
{
return (*this)(haystack_ref.get(), needle);
}
};
/**
* @brief A placeholder for guard expression.
*/
template<int X>
struct guard_placeholder
{
constexpr guard_placeholder() { }
/**
* @brief Convenient way to call <tt>gbind(fun, guard_placeholder)</tt>.
*/
template<typename Fun>
typename gbind1<Fun, guard_placeholder>::result operator()(Fun fun) const
{
return gbind(fun, *this);
}
// utility function for starts_with()
static bool u8_starts_with(std::string const& lhs, std::string const& rhs)
{
return std::equal(rhs.begin(), rhs.end(), lhs.begin());
}
/**
* @brief Evaluates to true if unbound argument starts with @p str.
*/
typename gbind2<decltype(&guard_placeholder::u8_starts_with),
guard_placeholder,
std::string
>::result
starts_with(std::string str) const
{
return gbind(&guard_placeholder::u8_starts_with, *this, str);
}
/**
* @brief Evaluates to true if unbound argument
* is contained in @p container.
*/
template<class C>
typename gbind2<ge_search_container, C, guard_placeholder>::result
in(C container) const
{
return gbind(ge_search_container{true}, container, *this);
}
/**
* @brief Evaluates to true if unbound argument
* is contained in @p container.
*/
template<class C>
typename gbind2<ge_search_container,
std::reference_wrapper<C>,
guard_placeholder
>::result
in(std::reference_wrapper<C> container) const
{
return gbind(ge_search_container{true}, container, *this);
}
/**
* @brief Evaluates to true if unbound argument
* is contained in @p list.
*/
template<typename T>
typename gbind2<ge_search_container,
std::vector<typename detail::strip_and_convert<T>::type>,
guard_placeholder
>::result
in(std::initializer_list<T> list) const
{
std::vector<typename detail::strip_and_convert<T>::type> vec;
for (auto& i : list) vec.emplace_back(i);
return in(vec);
}
/**
* @brief Evaluates to true if unbound argument
* is not contained in @p container.
*/
template<class C>
typename gbind2<ge_search_container, C, guard_placeholder>::result
not_in(C container) const
{
return gbind(ge_search_container{false}, container, *this);
}
/**
* @brief Evaluates to true if unbound argument
* is not contained in @p container.
*/
template<class C>
typename gbind2<ge_search_container,
std::reference_wrapper<C>,
guard_placeholder
>::result
not_in(std::reference_wrapper<C> container) const
{
return gbind(ge_search_container{false}, container, *this);
}
/**
* @brief Evaluates to true if unbound argument
* is not contained in @p list.
*/
template<typename T>
typename gbind2<ge_search_container,
std::vector<typename detail::strip_and_convert<T>::type>,
guard_placeholder
>::result
not_in(std::initializer_list<T> list) const
{
std::vector<typename detail::strip_and_convert<T>::type> vec;
for (auto& i : list) vec.emplace_back(i);
return not_in(vec);
}
};
// result type computation
template<typename T, class Tuple>
struct ge_unbound
{
typedef T type;
};
// unbound type of placeholder
template<int X, typename... Ts>
struct ge_unbound<guard_placeholder<X>, detail::tdata<Ts...> >
{
static_assert(X < sizeof...(Ts),
"Cannot unbind placeholder (too few arguments)");
typedef typename std::remove_pointer<typename util::at<X, Ts...>::type>::type type;
};
// operators, operators, operators
#define CPPA_GUARD_PLACEHOLDER_OPERATOR(EnumValue, Operator) \
template<int Pos1, int Pos2> \
guard_expr< EnumValue , guard_placeholder<Pos1>, guard_placeholder<Pos2>> \
operator Operator (guard_placeholder<Pos1> p1, guard_placeholder<Pos2> p2) \
{ return {p1, p2}; } \
template<int Pos, typename T> \
guard_expr< EnumValue , guard_placeholder<Pos>, \
typename detail::strip_and_convert<T>::type > \
operator Operator (guard_placeholder<Pos> gp, T value) \
{ return {std::move(gp), std::move(value)}; } \
template<typename T, int Pos> \
guard_expr< EnumValue , \
typename detail::strip_and_convert<T>::type, \
guard_placeholder<Pos> > \
operator Operator (T value, guard_placeholder<Pos> gp) \
{ return {std::move(value), std::move(gp)}; }
CPPA_FORALL_OPS(CPPA_GUARD_PLACEHOLDER_OPERATOR)
#define CPPA_GUARD_EXPR_OPERATOR(EnumValue, Operator) \
template<operator_id OP, typename F, typename S, typename T> \
guard_expr< EnumValue , guard_expr<OP, F, S>, \
typename detail::strip_and_convert<T>::type> \
operator Operator (guard_expr<OP, F, S> lhs, T rhs) \
{ return {lhs, rhs}; } \
template<typename T, operator_id OP, typename F, typename S> \
guard_expr< EnumValue , typename detail::strip_and_convert<T>::type, \
guard_expr<OP, F, S>> \
operator Operator (T lhs, guard_expr<OP, F, S> rhs) \
{ return {lhs, rhs}; } \
template<operator_id OP, typename F, typename S, int X> \
guard_expr< EnumValue , guard_expr<OP, F, S>, guard_placeholder<X> > \
operator Operator (guard_expr<OP, F, S> lhs, guard_placeholder<X> rhs) \
{ return {lhs, rhs}; } \
template<int X, operator_id OP, typename F, typename S> \
guard_expr< EnumValue , guard_placeholder<X>, guard_expr<OP, F, S>> \
operator Operator (guard_placeholder<X> lhs, guard_expr<OP, F, S> rhs) \
{ return {lhs, rhs}; } \
template<operator_id OP1, typename F1, typename S1, \
operator_id OP2, typename F2, typename S2> \
guard_expr< EnumValue , guard_expr<OP1, F1, S1>, guard_expr<OP2, F2, S2>> \
operator Operator (guard_expr<OP1,F1,S1> lhs, guard_expr<OP2,F2,S2> rhs) \
{ return {lhs, rhs}; }
CPPA_FORALL_OPS(CPPA_GUARD_EXPR_OPERATOR)
template<operator_id OP>
struct ge_eval_op;
#define CPPA_EVAL_OP_IMPL(EnumValue, Operator) \
template<> struct ge_eval_op< EnumValue > { \
template<typename T1, typename T2> \
static inline auto _(T1 const& lhs, T2 const& rhs) \
-> decltype(lhs Operator rhs) { return lhs Operator rhs; } \
};
CPPA_FORALL_OPS(CPPA_EVAL_OP_IMPL)
CPPA_EVAL_OP_IMPL(logical_and_op, &&)
CPPA_EVAL_OP_IMPL(logical_or_op, ||)
template<typename T, class Tuple>
struct ge_result_
{
typedef typename ge_unbound<T, Tuple>::type type;
};
template<operator_id OP, typename First, typename Second, class Tuple>
struct ge_result_<guard_expr<OP, First, Second>, Tuple>
{
typedef typename ge_result_<First, Tuple>::type lhs_type;
typedef typename ge_result_<Second, Tuple>::type rhs_type;
typedef decltype(
ge_eval_op<OP>::_(*static_cast<lhs_type const*>(nullptr),
*static_cast<rhs_type const*>(nullptr))) type;
};
template<typename First, typename Second, class Tuple>
struct ge_result_<guard_expr<exec_fun1_op, First, Second>, Tuple>
{
typedef First type0;
typedef typename ge_unbound<Second, Tuple>::type type1;
typedef decltype(
(*static_cast<type0 const*>(nullptr))(
*static_cast<type1 const*>(nullptr)
)) type;
};
template<typename First, typename Second, class Tuple>
struct ge_result_<guard_expr<exec_fun2_op, First, Second>, Tuple>
{
typedef typename First::first_type type0;
typedef typename ge_unbound<typename First::second_type, Tuple>::type type1;
typedef typename ge_unbound<Second, Tuple>::type type2;
typedef decltype(
(*static_cast<type0 const*>(nullptr))(
*static_cast<type1 const*>(nullptr),
*static_cast<type2 const*>(nullptr)
)) type;
};
template<typename First, typename Second, class Tuple>
struct ge_result_<guard_expr<exec_fun3_op, First, Second>, Tuple>
{
typedef typename First::first_type type0;
typedef typename ge_unbound<typename First::second_type,Tuple>::type type1;
typedef typename ge_unbound<typename Second::first_type,Tuple>::type type2;
typedef typename ge_unbound<typename Second::second_type,Tuple>::type type3;
typedef decltype(
(*static_cast<type0 const*>(nullptr))(
*static_cast<type1 const*>(nullptr),
*static_cast<type2 const*>(nullptr),
*static_cast<type3 const*>(nullptr)
)) type;
};
/*
#define CPPA_G_RESULT_TYPE_SPECIALIZATION(EnumValue, Operator) \
template<typename First, typename Second, class Tuple> \
struct ge_result_< guard_expr< EnumValue , First, Second>, Tuple> \
{ \
typedef typename ge_result_<First, Tuple>::type lhs_type; \
typedef typename ge_result_<Second, Tuple>::type rhs_type; \
typedef decltype(*static_cast<lhs_type const*>(nullptr) \
Operator \
*static_cast<rhs_type const*>(nullptr)) type; \
};
CPPA_G_RESULT_TYPE_SPECIALIZATION(addition_op, +)
CPPA_G_RESULT_TYPE_SPECIALIZATION(subtraction_op, -)
CPPA_G_RESULT_TYPE_SPECIALIZATION(multiplication_op, *)
CPPA_G_RESULT_TYPE_SPECIALIZATION(division_op, /)
CPPA_G_RESULT_TYPE_SPECIALIZATION(modulo_op, %)
*/
template<operator_id OP, typename First, typename Second, class Tuple>
struct ge_result
{
typedef typename ge_result_<guard_expr<OP, First, Second>, Tuple>::type
type;
};
template<operator_id OP1, typename F1, typename S1,
operator_id OP2, typename F2, typename S2>
guard_expr<logical_and_op, guard_expr<OP1, F1, S1>, guard_expr<OP2, F2, S2>>
operator&&(guard_expr<OP1, F1, S1> lhs,
guard_expr<OP2, F2, S2> rhs)
{
return {lhs, rhs};
}
template<operator_id OP1, typename F1, typename S1,
operator_id OP2, typename F2, typename S2>
guard_expr<logical_or_op, guard_expr<OP1, F1, S1>, guard_expr<OP2, F2, S2>>
operator||(guard_expr<OP1, F1, S1> lhs,
guard_expr<OP2, F2, S2> rhs)
{
return {lhs, rhs};
}
// evaluation of guard_expr
template<class Tuple, typename T>
inline T const& ge_resolve(Tuple const&, T const& value)
{
return value;
}
template<class Tuple, int X>
inline auto ge_resolve(Tuple const& tup, guard_placeholder<X>)
-> decltype(*get<X>(tup))
{
return *get<X>(tup);
}
template<class Tuple, operator_id OP, typename First, typename Second>
auto ge_resolve(Tuple const& tup, guard_expr<OP, First, Second> const& ge)
-> typename ge_result<OP, First, Second, Tuple>::type;
template<operator_id OP, class Tuple, typename First, typename Second>
struct ge_eval_
{
static inline typename ge_result<OP, First, Second, Tuple>::type
_(Tuple const& tup, First const& lhs, Second const& rhs)
{
return ge_eval_op<OP>::_(ge_resolve(tup, lhs), ge_resolve(tup, rhs));
}
};
template<class Tuple, typename First, typename Second>
struct ge_eval_<logical_and_op, Tuple, First, Second>
{
static inline bool _(Tuple const& tup, First const& lhs, Second const& rhs)
{
// emulate short-circuit evaluation
if (ge_resolve(tup, lhs)) return ge_resolve(tup, rhs);
return false;
}
};
template<class Tuple, typename First, typename Second>
struct ge_eval_<logical_or_op, Tuple, First, Second>
{
static inline bool _(Tuple const& tup, First const& lhs, Second const& rhs)
{
// emulate short-circuit evaluation
if (ge_resolve(tup, lhs)) return true;
return ge_resolve(tup, rhs);
}
};
template<class Tuple, typename First, typename Second>
struct ge_eval_<exec_fun1_op, Tuple, First, Second>
{
static inline auto _(Tuple const& tup, First const& fun, Second const& arg0)
-> decltype(fun(ge_resolve(tup, arg0)))
{
return fun(ge_resolve(tup, arg0));
}
};
template<class Tuple, typename First, typename Second>
struct ge_eval_<exec_fun2_op, Tuple, First, Second>
{
static inline auto _(Tuple const& tup, First const& lhs, Second const& rhs)
-> decltype(lhs.m_args.first(ge_resolve(tup, lhs.m_args.second),
ge_resolve(tup, rhs)))
{
return lhs.m_args.first(ge_resolve(tup, lhs.m_args.second),
ge_resolve(tup, rhs));
}
};
template<class Tuple, typename First, typename Second>
struct ge_eval_<exec_fun3_op, Tuple, First, Second>
{
static inline auto _(Tuple const& tup, First const& lhs, Second const& rhs)
-> decltype(lhs.m_args.first(ge_resolve(tup, lhs.m_args.second),
ge_resolve(tup, rhs.m_args.first),
ge_resolve(tup, rhs.m_args.second)))
{
return lhs.m_args.first(ge_resolve(tup, lhs.m_args.second),
ge_resolve(tup, rhs.m_args.first),
ge_resolve(tup, rhs.m_args.second));
}
};
template<operator_id OP, class Tuple, typename First, typename Second>
inline typename ge_result<OP, First, Second, Tuple>::type
ge_eval(Tuple const& tup, First const& lhs, Second const& rhs)
{
return ge_eval_<OP, Tuple, First, Second>::_(tup, lhs, rhs);
}
template<class Tuple, operator_id OP, typename First, typename Second>
auto ge_resolve(Tuple const& tup, guard_expr<OP, First, Second> const& ge)
-> typename ge_result<OP, First, Second, Tuple>::type
{
return ge_eval<OP>(tup, ge.m_args.first, ge.m_args.second);
}
template<operator_id OP, typename First, typename Second, typename... Args>
auto ge_invoke_step2(guard_expr<OP, First, Second> const& ge,
detail::tdata<Args...> const& tup)
-> typename ge_result<OP, First, Second, detail::tdata<Args...>>::type
{
return ge_eval<OP>(tup, ge.m_args.first, ge.m_args.second);
}
template<operator_id OP, typename First, typename Second, typename... Args>
auto ge_invoke(guard_expr<OP, First, Second> const& ge,
Args const&... args)
-> typename ge_result<OP, First, Second, detail::tdata<Args*...>>::type
{
detail::tdata<Args const*...> tup{&args...};
return ge_invoke_step2(ge, tup);
}
template<class GuardExpr>
struct ge_invoke_helper
{
GuardExpr const& ge;
ge_invoke_helper(GuardExpr const& arg) : ge(arg) { }
template<typename... Args>
bool operator()(Args&&... args)
{
return ge_invoke(ge, std::forward<Args>(args)...);
}
};
template<typename TupleTypes, operator_id OP, typename First, typename Second>
typename ge_result<
OP, First, Second,
typename detail::tdata_from_type_list<
typename util::tl_filter_not<TupleTypes, is_anything>::type
>::type
>::type
ge_invoke_any(guard_expr<OP, First, Second> const& ge,
any_tuple const& tup)
{
typedef typename ge_result<
OP, First, Second,
typename detail::tdata_from_type_list<
typename util::tl_filter_not<TupleTypes, is_anything>::type
>::type
>::type
result_type;
using namespace util;
typename if_else<
std::is_same<typename TupleTypes::back, anything>,
TupleTypes,
wrapped<typename tl_push_back<TupleTypes, anything>::type>
>::type
cast_token;
auto x = tuple_cast(tup, cast_token);
CPPA_REQUIRE(static_cast<bool>(x) == true);
ge_invoke_helper<guard_expr<OP, First, Second> > f{ge};
return util::unchecked_apply_tuple<result_type>(f, *x);
}
// finally ...
namespace placeholders { namespace {
constexpr guard_placeholder<0> _x1;
constexpr guard_placeholder<1> _x2;
constexpr guard_placeholder<2> _x3;
constexpr guard_placeholder<3> _x4;
constexpr guard_placeholder<4> _x5;
constexpr guard_placeholder<5> _x6;
constexpr guard_placeholder<6> _x7;
constexpr guard_placeholder<7> _x8;
constexpr guard_placeholder<8> _x9;
} } // namespace placeholders::<anonymous>
} // namespace cppa
#endif // GUARD_EXPR_HPP
......@@ -39,6 +39,7 @@
#include "cppa/anything.hpp"
#include "cppa/behavior.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/guard_expr.hpp"
#include "cppa/partial_function.hpp"
#include "cppa/util/duration.hpp"
......@@ -98,7 +99,9 @@ class rvalue_builder
typedef typename pattern_from_type_list<types>::type pattern_type;
std::unique_ptr<value_matcher> m_vm;
typedef std::unique_ptr<value_matcher> vm_ptr;
vm_ptr m_vm;
template<typename F>
partial_function cr_rvalue(F&& f, std::integral_constant<bool, true>)
......@@ -123,6 +126,30 @@ class rvalue_builder
public:
template<operator_id OP, typename F, typename S>
rvalue_builder& when(guard_expr<OP, F, S> ge)
{
typedef guard_expr<OP, F, S> gtype;
struct vm_impl : value_matcher
{
vm_ptr m_ptr;
gtype m_ge;
vm_impl(vm_ptr&& ptr, gtype&& g) : m_ptr(std::move(ptr)), m_ge(std::move(g)) { }
bool operator()(any_tuple const& tup) const
{
static_assert(std::is_same<decltype(ge_invoke_any<types>(m_ge, tup)), bool>::value,
"guard expression does not return a boolean");
if ((*m_ptr)(tup))
{
return ge_invoke_any<types>(m_ge, tup);
}
return false;
}
};
m_vm.reset(new vm_impl(std::move(m_vm), std::move(ge)));
return *this;
}
template<typename... Args>
rvalue_builder(Args&&... args)
: m_vm(pattern_type::get_value_matcher(std::forward<Args>(args)...))
......
......@@ -82,8 +82,7 @@ struct apply_tuple_util<Result, IsManipulator, 1, 0>
};
template<typename F, template<typename...> class Tuple, typename... T>
auto apply_tuple(F&& fun, Tuple<T...>& tup)
-> typename get_result_type<F>::type
typename get_result_type<F>::type apply_tuple(F&& fun, Tuple<T...>& tup)
{
typedef typename get_result_type<F>::type result_type;
typedef typename get_arg_types<F>::types fun_args;
......@@ -98,8 +97,7 @@ auto apply_tuple(F&& fun, Tuple<T...>& tup)
}
template<typename F, template<typename...> class Tuple, typename... T>
auto apply_tuple(F&& fun, Tuple<T...> const& tup)
-> typename get_result_type<F>::type
typename get_result_type<F>::type apply_tuple(F&& fun, Tuple<T...> const& tup)
{
typedef typename get_result_type<F>::type result_type;
typedef typename get_arg_types<F>::types fun_args;
......@@ -113,16 +111,24 @@ auto apply_tuple(F&& fun, Tuple<T...> const& tup)
::apply(std::forward<F>(fun), tup);
}
template<typename Result, typename F, template<typename...> class Tuple, typename... T>
Result unchecked_apply_tuple(F&& fun, Tuple<T...>& tup)
template<typename Result, size_t From, size_t To,
typename F, template<typename...> class Tuple, typename... T>
Result unchecked_apply_tuple_in_range(F&& fun, Tuple<T...> const& tup)
{
static constexpr size_t tup_size = sizeof...(T);
static constexpr size_t from = 0;
static constexpr size_t to = tup_size - 1;
return apply_tuple_util<Result, false, from, to>
return apply_tuple_util<Result, false, From, To>
::apply(std::forward<F>(fun), tup);
}
// applies all values of @p tup to @p fun
// does not evaluate result type of functor
template<typename Result, typename F,
template<typename...> class Tuple, typename... T>
Result unchecked_apply_tuple(F&& fun, Tuple<T...> const& tup)
{
return unchecked_apply_tuple_in_range<Result, 0, sizeof...(T) - 1>
(std::forward<F>(fun), tup);
}
} } // namespace cppa::util
#endif // APPLY_TUPLE_HPP
......@@ -314,6 +314,20 @@ struct tl_concat<type_list<ListATypes...>, type_list<ListBTypes...> >
typedef type_list<ListATypes..., ListBTypes...> type;
};
// list list::push_back(list, type)
template<typename List, typename What>
struct tl_push_back;
/**
* @brief Appends @p What to given list.
*/
template<typename... ListTypes, typename What>
struct tl_push_back<type_list<ListTypes...>, What>
{
typedef type_list<ListTypes..., What> type;
};
// list list::appy(trait)
template<typename List, template<typename> class Trait>
......
......@@ -5,398 +5,110 @@
#include "cppa/match.hpp"
#include "cppa/announce.hpp"
#include "cppa/to_string.hpp"
#include "cppa/guard_expr.hpp"
using namespace cppa;
using std::vector;
using std::string;
enum operator_id
{
addition_op,
subtraction_op,
multiplication_op,
division_op,
modulo_op,
less_op,
less_eq_op,
greater_op,
greater_eq_op,
equal_op,
not_equal_op,
exec_fun_op,
logical_and_op,
logical_or_op
};
#define CPPA_DISPATCH_OP(EnumValue, Operator) \
template<typename T1, typename T2> \
inline auto eval_op(std::integral_constant<operator_id, EnumValue >, \
T1 const& lhs, T2 const& rhs) const \
-> decltype(lhs Operator rhs) { return lhs Operator rhs; }
template<operator_id, typename First, typename Second>
struct guard_expr;
template<int X>
struct guard_placeholder
{
constexpr guard_placeholder() { }
template<typename Fun>
guard_expr<exec_fun_op, guard_placeholder, Fun> operator()(Fun f) const
{
return {*this, std::move(f)};
}
};
template<operator_id OP, typename First, typename Second>
struct guard_expr;
template<typename... Ts, typename T>
T const& fetch(detail::tdata<Ts...> const&, T const& value)
{
return value;
}
template<typename... Ts, int X>
auto fetch(detail::tdata<Ts...> const& tup, guard_placeholder<X>)
-> decltype(*get<X>(tup))
{
return *get<X>(tup);
}
template<typename... Ts, operator_id OP, typename First, typename Second>
auto fetch(detail::tdata<Ts...> const& tup,
guard_expr<OP, First, Second> const& ge)
-> decltype(ge.eval(tup));
template<class Tuple, operator_id OP, typename First, typename Second>
auto eval_guard_expr(std::integral_constant<operator_id, OP> token,
Tuple const& tup,
First const& lhs,
Second const& rhs)
-> decltype(eval_op(token, fetch(tup, lhs), fetch(tup, rhs)))
{
return eval_op(token, fetch(tup, lhs), fetch(tup, rhs));
}
template<class Tuple, typename First, typename Second>
bool eval_guard_expr(std::integral_constant<operator_id, logical_and_op>,
Tuple const& tup,
First const& lhs,
Second const& rhs)
{
// emulate short-circuit evaluation
if (fetch(tup, lhs)) return fetch(tup, rhs);
return false;
}
template<class Tuple, typename First, typename Second>
bool eval_guard_expr(std::integral_constant<operator_id, logical_or_op>,
Tuple const& tup,
First const& lhs,
Second const& rhs)
{
// emulate short-circuit evaluation
if (fetch(tup, lhs)) return true;
return fetch(tup, rhs);
}
template<typename T, class Tuple>
struct compute_
{
typedef T type;
};
template<int X, typename... Ts>
struct compute_<guard_placeholder<X>, detail::tdata<Ts...> >
{
typedef typename std::remove_pointer<typename util::at<X, Ts...>::type>::type type;
};
template<operator_id OP, typename First, typename Second, class Tuple>
struct compute_result_type
{
typedef bool type;
};
template<typename First, typename Second, class Tuple>
struct compute_result_type<addition_op, First, Second, Tuple>
{
typedef typename compute_<First, Tuple>::type lhs_type;
typedef typename compute_<Second, Tuple>::type rhs_type;
typedef decltype(lhs_type() + rhs_type()) type;
};
template<operator_id OP, typename First, typename Second>
struct guard_expr
{
std::pair<First, Second> m_args;
template<typename F, typename S>
guard_expr(F&& f, S&& s) : m_args(std::forward<F>(f), std::forward<S>(s)) { }
guard_expr() = default;
guard_expr(guard_expr&& other) : m_args(std::move(other.m_args)) { }
guard_expr(guard_expr const&) = default;
template<typename... Args>
auto eval(detail::tdata<Args...> const& tup) const
-> typename compute_result_type<OP, First, Second, detail::tdata<Args...>>::type
{
std::integral_constant<operator_id, OP> token;
return eval_guard_expr(token, tup, m_args.first, m_args.second);
}
template<typename... Args>
auto operator()(Args const&... args) const
-> typename compute_result_type<OP, First, Second, detail::tdata<Args...>>::type
{
detail::tdata<Args const*...> tup{&args...};
return eval(tup);
}
};
template<typename... Ts, operator_id OP, typename First, typename Second>
auto fetch(detail::tdata<Ts...> const& tup,
guard_expr<OP, First, Second> const& ge)
-> decltype(ge.eval(tup))
{
return ge.eval(tup);
}
static constexpr guard_placeholder<0> _x1;
static constexpr guard_placeholder<1> _x2;
static constexpr guard_placeholder<2> _x3;
static constexpr guard_placeholder<3> _x4;
static constexpr guard_placeholder<4> _x5;
static constexpr guard_placeholder<5> _x6;
static constexpr guard_placeholder<6> _x7;
static constexpr guard_placeholder<7> _x8;
static constexpr guard_placeholder<8> _x9;
#define GUARD_PLACEHOLDER_OPERATOR(EnumValue, Operator) \
template<int Pos1, int Pos2> \
guard_expr< EnumValue , guard_placeholder<Pos1>, guard_placeholder<Pos2>> \
operator Operator (guard_placeholder<Pos1>, guard_placeholder<Pos2>) \
{ return {}; } \
template<int Pos, typename T> \
guard_expr< EnumValue , guard_placeholder<Pos>, \
typename detail::strip_and_convert<T>::type > \
operator Operator (guard_placeholder<Pos> gp, T value) \
{ return {std::move(gp), std::move(value)}; } \
template<typename T, int Pos> \
guard_expr< EnumValue , \
typename detail::strip_and_convert<T>::type, \
guard_placeholder<Pos> > \
operator Operator (T value, guard_placeholder<Pos> gp) \
{ return {std::move(value), std::move(gp)}; }
GUARD_PLACEHOLDER_OPERATOR(addition_op, +)
GUARD_PLACEHOLDER_OPERATOR(subtraction_op, -)
GUARD_PLACEHOLDER_OPERATOR(multiplication_op, *)
GUARD_PLACEHOLDER_OPERATOR(division_op, /)
GUARD_PLACEHOLDER_OPERATOR(modulo_op, %)
GUARD_PLACEHOLDER_OPERATOR(less_op, <)
GUARD_PLACEHOLDER_OPERATOR(less_eq_op, <=)
GUARD_PLACEHOLDER_OPERATOR(greater_op, >=)
GUARD_PLACEHOLDER_OPERATOR(greater_eq_op, >=)
GUARD_PLACEHOLDER_OPERATOR(equal_op, ==)
GUARD_PLACEHOLDER_OPERATOR(not_equal_op, !=)
template<operator_id OP1, typename F1, typename S1,
operator_id OP2, typename F2, typename S2>
guard_expr<logical_and_op, guard_expr<OP1, F1, S1>, guard_expr<OP2, F2, S2>>
operator&&(guard_expr<OP1, F1, S1> lhs,
guard_expr<OP2, F2, S2> rhs)
{
return {std::move(lhs), std::move(rhs)};
}
template<operator_id OP1, typename F1, typename S1,
operator_id OP2, typename F2, typename S2>
guard_expr<logical_or_op, guard_expr<OP1, F1, S1>, guard_expr<OP2, F2, S2>>
operator||(guard_expr<OP1, F1, S1> lhs,
guard_expr<OP2, F2, S2> rhs)
{
return {std::move(lhs), std::move(rhs)};
}
template<operator_id OP, typename F, typename S, typename T>
guard_expr<equal_op, guard_expr<OP, F, S>, T>
operator==(guard_expr<OP, F, S> lhs,
T rhs)
{
return {std::move(lhs), std::move(rhs)};
}
template<typename TupleTypes, class Fun>
bool eval_(any_tuple const& tup,
Fun const& fun)
{
typename util::tl_concat<TupleTypes, util::type_list<anything>>::type
cast_token;
auto x = tuple_cast(tup, cast_token);
CPPA_REQUIRE(static_cast<bool>(x) == true);
return util::unchecked_apply_tuple<bool>(fun, *x);
}
template<class GuardExpr, class TupleTypes>
struct guard_expr_value_matcher : value_matcher
{
GuardExpr m_expr;
guard_expr_value_matcher(GuardExpr&& ge) : m_expr(std::move(ge)) { }
bool operator()(any_tuple const& tup) const
{
typename util::tl_concat<TupleTypes, util::type_list<anything>>::type
cast_token;
auto x = tuple_cast(tup, cast_token);
CPPA_REQUIRE(static_cast<bool>(x) == true);
return util::unchecked_apply_tuple<bool>(m_expr, *x);
}
};
bool is_even(int i) { return i % 2 == 0; }
struct foobaz
{
template<typename... Args>
bool operator()(Args const&... args)
{
detail::tdata<Args const*...> tup{&args...};
cout << "0: " << fetch(tup, _x1) << endl;
return true;
}
};
template<operator_id OP, typename First, typename Second>
value_matcher* when(guard_expr<OP, First, Second> ge)
{
return nullptr;
}
std::string to_string(operator_id op)
{
switch (op)
{
case addition_op: return "+";
case less_op: return "<";
case less_eq_op: return "<=";
case greater_op: return ">";
case greater_eq_op: return ">=";
case equal_op: return "==";
case not_equal_op: return "!=";
case logical_and_op: return "&&";
case logical_or_op: return "||";
default: return "???";
}
}
/*
template<typename T>
std::string to_string(T const& value)
{
std::ostringstream oss;
oss << value;
return oss.str();
}
*/
template<int X>
std::string to_string(guard_placeholder<X>)
{
return "_x" + std::to_string(X+1);
}
template<typename... Ts, operator_id OP, typename First, typename Second>
std::string to_string(guard_expr<OP, First, Second> const& ge)
{
std::string result;
result += "(";
result += to_string(ge.m_args.first);
result += to_string(OP);
result += to_string(ge.m_args.second);
result += ")";
return result;
}
/*
*
* projection:
*
* on(_x.rsplit("--(.*)=(.*)")) >> [](std::vector<std::string> matched_groups) { }
* on(_x.rsplit("--(.*)=(.*)")) >> [](std::vector<std::string> matched_groups)
*
*/
bool ascending(int a, int b, int c)
{
return a < b && b < c;
}
size_t test__match()
{
CPPA_TEST(test__match);
using namespace std::placeholders;
using namespace cppa::placeholders;
foobaz fb;
fb(1);
auto expr0 = gbind(ascending, _x1, _x2, _x3);
CPPA_CHECK(ge_invoke(expr0, 1, 2, 3));
CPPA_CHECK(!ge_invoke(expr0, 3, 2, 1));
typedef util::type_list<int, int, int, int> ttypes;
any_tuple testee = make_cow_tuple(10, 20, 30, 40);
cout << "testee[0] < testee[1] = "
<< eval_<ttypes>(testee, _x1 < _x2)
<< " ---- > "
<< eval_<ttypes>(testee, _x1 < _x2 && _x2 < 50 && _x3 < _x4 && _x4 == 40)
<< " ---- > "
<< eval_<ttypes>(testee, 5 < _x1)
<< "; is_even(10): "
<< eval_<ttypes>(testee, _x1(is_even))
<< "; _x1 + _x2 < _x3: "
<< eval_<ttypes>(testee, _x1 + _x2 < _x3)
<< endl;
auto crazy_shit1 = _x1 < _x2 && _x2 < 50 && _x3 < _x4 && _x4 == 40;
auto crazy_shit2 = _x1 < _x2 && (_x2 < 50 && _x3 < _x4 && _x4 == 40);
cout << to_string(crazy_shit1) << endl;
cout << to_string(crazy_shit2) << endl;
int ival0 = 2;
auto expr01 = gbind(ascending, _x1, std::ref(ival0), _x2);
CPPA_CHECK(ge_invoke(expr01, 1, 3));
++ival0;
CPPA_CHECK(!ge_invoke(expr01, 1, 3));
auto expr1 = _x1 + _x2;
auto expr2 = _x1 + _x2 < _x3;
auto expr3 = _x1 % _x2 == 0;
CPPA_CHECK_EQUAL(5, (expr1(2, 3)));
CPPA_CHECK_EQUAL("12", (expr1(std::string{"1"}, std::string{"2"})));
CPPA_CHECK_EQUAL("((_x1+_x2)<_x3)", to_string(expr2));
CPPA_CHECK((expr3(100, 2)));
CPPA_CHECK_EQUAL(5, (ge_invoke(expr1, 2, 3)));
CPPA_CHECK(ge_invoke(expr2, 1, 2, 4));
CPPA_CHECK_EQUAL("12", (ge_invoke(expr1, std::string{"1"}, std::string{"2"})));
CPPA_CHECK((ge_invoke(expr3, 100, 2)));
auto expr4 = _x1 == "-h" || _x1 == "--help";
CPPA_CHECK(expr4(std::string("-h")));
CPPA_CHECK(expr4(std::string("--help")));
CPPA_CHECK(!expr4(std::string("-g")));
exit(0);
/*
auto xfun = _x.any_of<int>({1, 2, 3});
cout << "xfun(4) = " << xfun(4) << endl;
cout << "xfun(2) = " << xfun(2) << endl;
auto lfun = _x < 5;
cout << "lfun(4) = " << lfun(4) << endl;
cout << "lfun(6) = " << lfun(6) << endl;
cout << "sizeof(std::function<bool (int const&)>) = "
<< sizeof(std::function<bool (int const&)>)
<< endl;
_on(_x.any_of({"-h", "--help"}), _x == 5);
auto hfun = _x.any_of({"-h", "--help"});
cout << "hfun(-h) = " << hfun("-h") << endl;
cout << "hfun(-r) = " << hfun("-r") << endl;
*/
CPPA_CHECK(ge_invoke(expr4, string("-h")));
CPPA_CHECK(ge_invoke(expr4, string("--help")));
CPPA_CHECK(!ge_invoke(expr4, string("-g")));
auto expr5 = _x1.starts_with("--");
CPPA_CHECK(ge_invoke(expr5, string("--help")));
CPPA_CHECK(!ge_invoke(expr5, string("-help")));
vector<string> vec1{"hello", "world"};
auto expr6 = _x1.in(vec1);
CPPA_CHECK(ge_invoke(expr6, string("hello")));
CPPA_CHECK(ge_invoke(expr6, string("world")));
CPPA_CHECK(!ge_invoke(expr6, string("hello world")));
auto expr7 = _x1.in(std::ref(vec1));
CPPA_CHECK(ge_invoke(expr7, string("hello")));
CPPA_CHECK(ge_invoke(expr7, string("world")));
CPPA_CHECK(!ge_invoke(expr7, string("hello world")));
vec1.emplace_back("hello world");
CPPA_CHECK(!ge_invoke(expr6, string("hello world")));
CPPA_CHECK(ge_invoke(expr7, string("hello world")));
int ival = 5;
auto expr8 = _x1 == ival;
auto expr9 = _x1 == std::ref(ival);
CPPA_CHECK(ge_invoke(expr8, 5));
CPPA_CHECK(ge_invoke(expr9, 5));
ival = 10;
CPPA_CHECK(!ge_invoke(expr9, 5));
CPPA_CHECK(ge_invoke(expr9, 10));
auto expr11 = _x1.in({"one", "two"});
CPPA_CHECK(ge_invoke(expr11, string("one")));
CPPA_CHECK(ge_invoke(expr11, string("two")));
CPPA_CHECK(!ge_invoke(expr11, string("three")));
auto expr12 = _x1 * _x2 < _x3 - _x4;
CPPA_CHECK(ge_invoke(expr12, 1, 1, 4, 2));
auto expr13 = _x1.not_in({"hello", "world"});
CPPA_CHECK(ge_invoke(expr13, string("foo")));
CPPA_CHECK(!ge_invoke(expr13, string("hello")));
auto expr14 = _x1 + _x2;
static_assert(std::is_same<decltype(ge_invoke(expr14, 1, 2)), int>::value,
"wrong return type");
CPPA_CHECK_EQUAL(5, (ge_invoke(expr14, 2, 3)));
auto expr15 = _x1 + _x2 + _x3;
static_assert(std::is_same<decltype(ge_invoke(expr15,1,2,3)), int>::value,
"wrong return type");
CPPA_CHECK_EQUAL(42, (ge_invoke(expr15, 7, 10, 25)));
bool invoked = false;
match("abc")
(
on("abc") >> [&]()
on<string>().when(_x1 == "abc") >> [&]()
{
invoked = true;
}
......@@ -404,37 +116,60 @@ size_t test__match()
if (!invoked) { CPPA_ERROR("match(\"abc\") failed"); }
invoked = false;
match_each({"-h", "-wtf"})
match(std::vector<int>{1, 2, 3})
(
on(_x.any_of({"-h", "--help"})) >> []()
on<int, int, int>().when( _x1 + _x2 + _x3 == 6
&& _x2(is_even)
&& _x3 % 2 == 1) >> [&]()
{
cout << "AWESOME!!!" << endl;
invoked = true;
}
);
if (!invoked) { CPPA_ERROR("match({1, 2, 3}) failed"); }
invoked = false;
string sum;
match_each({"-h", "--version", "-wtf"})
(
on<string>().when(_x1.in({"-h", "--help"})) >> [&](string s)
{
sum += s;
},
on(_x.starts_with("-")) >> [](std::string const& str)
on<string>().when(_x1 == "-v" || _x1 == "--version") >> [&](string s)
{
sum += s;
},
on<string>().when(_x1.starts_with("-")) >> [&](string const& str)
{
match_each(str.begin() + 1, str.end())
(
on<char>() >> [](char c)
//on(_x.any_of({'w', 't', 'f'})) >> [](char c)
on<char>().when(_x1.in({'w', 't', 'f'})) >> [&](char c)
{
cout << c;
sum += c;
},
others() >> [](any_tuple const& tup)
others() >> [&]()
{
cout << "oops: " << to_string(tup) << endl;
CPPA_ERROR("unexpected match");
}
);
cout << endl;
},
others() >> [&]()
{
CPPA_ERROR("unexpected match");
}
);
CPPA_CHECK_EQUAL("-h--versionwtf", sum);
match(5)
(
on(_x < 6) >> [](int i)
on<int>().when(_x1 < 6) >> [&](int i)
{
cout << i << " < 6 !!! :)" << endl;
CPPA_CHECK_EQUAL(5, i);
invoked = true;
}
);
CPPA_CHECK(invoked);
invoked = false;
vector<string> vec{"a", "b", "c"};
match(vec)
......
......@@ -23,7 +23,7 @@ using std::endl;
using namespace cppa;
// GCC 4.7 supports non-static member initialization
#if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 7)
#if 0 //(__GNUC__ >= 4) && (__GNUC_MINOR__ >= 7)
struct event_testee : public fsm_actor<event_testee>
{
......
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