Commit 1c883a73 authored by neverlord's avatar neverlord

improved guard expressions

parent cf13709e
......@@ -171,8 +171,12 @@ class projection<util::type_list<> >
template<class PartialFun>
bool operator()(PartialFun& fun) const
{
fun();
return true;
if (fun.defined_at())
{
fun();
return true;
}
return false;
}
};
......
......@@ -38,8 +38,10 @@
#include <type_traits>
#include "cppa/config.hpp"
#include "cppa/option.hpp"
#include "cppa/util/at.hpp"
#include "cppa/util/rm_ref.hpp"
#include "cppa/util/void_type.hpp"
#include "cppa/util/apply_tuple.hpp"
......@@ -113,6 +115,63 @@ struct guard_expr
SubMacro (not_equal_op, !=)
template<typename T>
struct ge_mutable_reference_wrapper
{
T* value;
ge_mutable_reference_wrapper() : value(nullptr) { }
ge_mutable_reference_wrapper(T&&) = delete;
ge_mutable_reference_wrapper(T& vref) : value(&vref) { }
ge_mutable_reference_wrapper(ge_mutable_reference_wrapper const&) = default;
ge_mutable_reference_wrapper& operator=(T& vref)
{
value = &vref;
return *this;
}
ge_mutable_reference_wrapper& operator=(ge_mutable_reference_wrapper const&) = default;
T& get() const { CPPA_REQUIRE(value != 0); return *value; }
operator T& () const { CPPA_REQUIRE(value != 0); return *value; }
};
template<typename T>
struct ge_reference_wrapper
{
T const* value;
ge_reference_wrapper(T&&) = delete;
ge_reference_wrapper() : value(nullptr) { }
ge_reference_wrapper(T const& val_ref) : value(&val_ref) { }
ge_reference_wrapper(ge_reference_wrapper const&) = default;
ge_reference_wrapper& operator=(T const& vref)
{
value = &vref;
return *this;
}
ge_reference_wrapper& operator=(ge_reference_wrapper const&) = default;
T const& get() const { CPPA_REQUIRE(value != 0); return *value; }
operator T const& () const { CPPA_REQUIRE(value != 0); return *value; }
};
// support use of gref(BooleanVariable) as receive loop 'guard'
template<>
struct ge_reference_wrapper<bool>
{
bool const* value;
ge_reference_wrapper(bool&&) = delete;
ge_reference_wrapper(bool const& val_ref) : value(&val_ref) { }
ge_reference_wrapper(ge_reference_wrapper const&) = default;
ge_reference_wrapper& operator=(ge_reference_wrapper const&) = default;
bool const& get() const { CPPA_REQUIRE(value != 0); return *value; }
operator bool const& () const { CPPA_REQUIRE(value != 0); return *value; }
bool operator()() const { CPPA_REQUIRE(value != 0); return *value; }
};
/**
* @brief Create a reference wrapper similar to std::reference_wrapper<const T>
* that could be used in guard expressions or to enforce lazy evaluation.
*/
template<typename T>
ge_reference_wrapper<T> gref(T const& value) { return {value}; }
// bind utility for placeholders
template<typename Fun, typename T1>
......@@ -176,6 +235,7 @@ 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
......@@ -187,12 +247,55 @@ struct ge_search_container
return std::none_of(haystack.begin(), haystack.end(),
[&](vtype const& val) { return needle == val; });
}
};
struct ge_get_size
{
template<class C>
bool operator()(std::reference_wrapper<C> const& haystack_ref,
typename C::value_type const& needle) const
inline auto operator()(C const& what) const -> decltype(what.size())
{
return what.size();
}
};
struct ge_is_empty
{
bool expected;
ge_is_empty(bool expected_value) : expected(expected_value) { }
template<class C>
inline bool operator()(C const& what) const
{
return what.empty() == expected;
}
};
struct ge_get_front
{
template<class C>
inline auto operator()(C const& what,
typename std::enable_if<
std::is_reference<
decltype(what.front())
>::value
>::type* = 0) const
-> option<
std::reference_wrapper<
const typename util::rm_ref<decltype(what.front())>::type> >
{
if (what.empty() == false) return {what.front()};
return {};
}
template<class C>
inline auto operator()(C const& what,
typename std::enable_if<
std::is_reference<
decltype(what.front())
>::value == false
>::type* = 0) const
-> option<decltype(what.front())>
{
return (*this)(haystack_ref.get(), needle);
if (what.empty() == false) return {what.front()};
return {};
}
};
......@@ -220,16 +323,42 @@ struct guard_placeholder
return std::equal(rhs.begin(), rhs.end(), lhs.begin());
}
/**
* @brief Evaluates to the size of a container.
*/
typename gcall1<ge_get_size, guard_placeholder>::result size() const
{
return gcall(ge_get_size{}, *this);
}
typename gcall1<ge_is_empty, guard_placeholder>::result empty() const
{
return gcall(ge_is_empty{true}, *this);
}
typename gcall1<ge_is_empty, guard_placeholder>::result not_empty() const
{
return gcall(ge_is_empty{false}, *this);
}
/**
* @brief Evaluates to the first element of a container if it's not empty.
*/
typename gcall1<ge_get_front, guard_placeholder>::result front() const
{
return gcall(ge_get_front{}, *this);
}
/**
* @brief Evaluates to true if unbound argument starts with @p str.
*/
typename gcall2<decltype(&guard_placeholder::u8_starts_with),
guard_placeholder,
std::string
guard_placeholder,
std::string
>::result
starts_with(std::string str) const
{
return gcall(&guard_placeholder::u8_starts_with, *this, str);
return gcall(&guard_placeholder::u8_starts_with, *this, std::move(str));
}
/**
......@@ -240,21 +369,7 @@ struct guard_placeholder
typename gcall2<ge_search_container, C, guard_placeholder>::result
in(C container) const
{
return gcall(ge_search_container{true}, container, *this);
}
/**
* @brief Evaluates to true if unbound argument
* is contained in @p container.
*/
template<class C>
typename gcall2<ge_search_container,
std::reference_wrapper<C>,
guard_placeholder
>::result
in(std::reference_wrapper<C> container) const
{
return gcall(ge_search_container{true}, container, *this);
return gcall(ge_search_container{true}, std::move(container), *this);
}
/**
......@@ -270,7 +385,7 @@ struct guard_placeholder
{
std::vector<typename detail::strip_and_convert<T>::type> vec;
for (auto& i : list) vec.emplace_back(i);
return in(vec);
return in(std::move(vec));
}
/**
......@@ -281,21 +396,7 @@ struct guard_placeholder
typename gcall2<ge_search_container, C, guard_placeholder>::result
not_in(C container) const
{
return gcall(ge_search_container{false}, container, *this);
}
/**
* @brief Evaluates to true if unbound argument
* is not contained in @p container.
*/
template<class C>
typename gcall2<ge_search_container,
std::reference_wrapper<C>,
guard_placeholder
>::result
not_in(std::reference_wrapper<C> container) const
{
return gcall(ge_search_container{false}, container, *this);
return gcall(ge_search_container{false}, std::move(container), *this);
}
/**
......@@ -316,85 +417,31 @@ struct guard_placeholder
};
template<typename T>
struct ge_mutable_reference_wrapper
{
T* value;
ge_mutable_reference_wrapper() : value(nullptr) { }
ge_mutable_reference_wrapper(T&&) = delete;
ge_mutable_reference_wrapper(T& vref) : value(&vref) { }
ge_mutable_reference_wrapper(ge_mutable_reference_wrapper const&) = default;
ge_mutable_reference_wrapper& operator=(T& vref)
{
value = &vref;
return *this;
}
ge_mutable_reference_wrapper& operator=(ge_mutable_reference_wrapper const&) = default;
T& get() const { CPPA_REQUIRE(value != 0); return *value; }
operator T& () const { CPPA_REQUIRE(value != 0); return *value; }
};
template<typename T>
struct ge_reference_wrapper
{
T const* value;
ge_reference_wrapper(T&&) = delete;
ge_reference_wrapper() : value(nullptr) { }
ge_reference_wrapper(T const& val_ref) : value(&val_ref) { }
ge_reference_wrapper(ge_reference_wrapper const&) = default;
ge_reference_wrapper& operator=(T const& vref)
{
value = &vref;
return *this;
}
ge_reference_wrapper& operator=(ge_reference_wrapper const&) = default;
T const& get() const { CPPA_REQUIRE(value != 0); return *value; }
operator T const& () const { CPPA_REQUIRE(value != 0); return *value; }
};
// support use of gref(BooleanVariable) as receive loop 'guard'
template<>
struct ge_reference_wrapper<bool>
{
bool const* value;
ge_reference_wrapper(bool&&) = delete;
ge_reference_wrapper(bool const& val_ref) : value(&val_ref) { }
ge_reference_wrapper(ge_reference_wrapper const&) = default;
ge_reference_wrapper& operator=(ge_reference_wrapper const&) = default;
bool get() const { CPPA_REQUIRE(value != 0); return *value; }
operator bool () const { CPPA_REQUIRE(value != 0); return *value; }
bool operator()() const { CPPA_REQUIRE(value != 0); return *value; }
};
/**
* @brief Create a reference wrapper similar to std::reference_wrapper<const T>
* that could be used in guard expressions or to enforce lazy evaluation.
*/
template<typename T>
ge_reference_wrapper<T> gref(T const& value) { return {value}; }
// result type computation
template<typename T, class Tuple>
struct ge_unbound { typedef T type; };
// result type computation
template<typename T, class Tuple>
struct ge_unbound<ge_reference_wrapper<T>, Tuple> { typedef T type; };
template<typename T, class Tuple>
struct ge_unbound
{
typedef T type;
};
struct ge_unbound<std::reference_wrapper<T>, Tuple> { typedef T type; };
template<typename T, class Tuple>
struct ge_unbound<ge_reference_wrapper<T>, Tuple>
{
typedef T type;
};
struct ge_unbound<std::reference_wrapper<const T>, Tuple> { typedef T type; };
// unbound type of placeholder
template<int X, typename... Ts>
struct ge_unbound<guard_placeholder<X>, detail::tdata<std::reference_wrapper<Ts>...> >
struct ge_unbound<guard_placeholder<X>, detail::tdata<Ts...> >
{
static_assert(X < sizeof...(Ts),
"Cannot unbind placeholder (too few arguments)");
typedef typename util::at<X, Ts...>::type type;
typedef typename ge_unbound<
typename util::at<X, Ts...>::type,
detail::tdata<std::reference_wrapper<Ts>...>
>::type
type;
};
// operators, operators, operators
......@@ -552,6 +599,18 @@ inline T const& ge_resolve(Tuple const&, T const& value)
return value;
}
template<class Tuple, typename T>
inline T const& ge_resolve(Tuple const&, std::reference_wrapper<T> const& value)
{
return value.get();
}
template<class Tuple, typename T>
inline T const& ge_resolve(Tuple const&, std::reference_wrapper<const T> const& value)
{
return value.get();
}
template<class Tuple, typename T>
inline T const& ge_resolve(Tuple const&, ge_reference_wrapper<T> const& value)
{
......
......@@ -220,45 +220,45 @@ class option
};
/** @relates option */
template<typename T>
bool operator==(option<T> const& lhs, option<T> const& rhs)
template<typename T, typename U>
bool operator==(option<T> const& lhs, option<U> const& rhs)
{
if ((lhs) && (rhs)) return *lhs == *rhs;
return false;
}
/** @relates option */
template<typename T>
bool operator==(option<T> const& lhs, T const& rhs)
template<typename T, typename U>
bool operator==(option<T> const& lhs, U const& rhs)
{
if (lhs) return *lhs == rhs;
return false;
}
/** @relates option */
template<typename T>
bool operator==(T const& lhs, option<T> const& rhs)
template<typename T, typename U>
bool operator==(T const& lhs, option<U> const& rhs)
{
return rhs == lhs;
}
/** @relates option */
template<typename T>
bool operator!=(option<T> const& lhs, option<T> const& rhs)
template<typename T, typename U>
bool operator!=(option<T> const& lhs, option<U> const& rhs)
{
return !(lhs == rhs);
}
/** @relates option */
template<typename T>
bool operator!=(option<T> const& lhs, T const& rhs)
template<typename T, typename U>
bool operator!=(option<T> const& lhs, U const& rhs)
{
return !(lhs == rhs);
}
/** @relates option */
template<typename T>
bool operator!=(T const& lhs, option<T> const& rhs)
template<typename T, typename U>
bool operator!=(T const& lhs, option<U> const& rhs)
{
return !(lhs == rhs);
}
......
#include <functional>
#include "test.hpp"
#include "cppa/cppa.hpp"
#include "cppa/on.hpp"
#include "cppa/match.hpp"
#include "cppa/announce.hpp"
......@@ -34,15 +35,19 @@ size_t test__match()
using namespace std::placeholders;
using namespace cppa::placeholders;
auto expr0 = gcall(ascending, _x1, _x2, _x3);
CPPA_CHECK(ge_invoke(expr0, 1, 2, 3));
CPPA_CHECK(!ge_invoke(expr0, 3, 2, 1));
auto expr0_a = gcall(ascending, _x1, _x2, _x3);
CPPA_CHECK(ge_invoke(expr0_a, 1, 2, 3));
CPPA_CHECK(!ge_invoke(expr0_a, 3, 2, 1));
int ival0 = 2;
auto expr01 = gcall(ascending, _x1, std::ref(ival0), _x2);
CPPA_CHECK(ge_invoke(expr01, 1, 3));
auto expr0_b = gcall(ascending, _x1, std::ref(ival0), _x2);
CPPA_CHECK(ge_invoke(expr0_b, 1, 3));
++ival0;
CPPA_CHECK(!ge_invoke(expr01, 1, 3));
CPPA_CHECK(!ge_invoke(expr0_b, 1, 3));
auto expr0_c = gcall(ascending, 10, _x1, 30);
CPPA_CHECK(!ge_invoke(expr0_c, 10));
CPPA_CHECK(ge_invoke(expr0_c, 11));
auto expr1 = _x1 + _x2;
auto expr2 = _x1 + _x2 < _x3;
......@@ -106,6 +111,34 @@ size_t test__match()
"wrong return type");
CPPA_CHECK_EQUAL(42, (ge_invoke(expr15, 7, 10, 25)));
std::string expr16_str;// = "expr16";
auto expr16_a = _x1.size();
auto expr16_b = _x1.front() == 'e';
CPPA_CHECK_EQUAL(false, ge_invoke(expr16_b, expr16_str));
CPPA_CHECK_EQUAL(0, ge_invoke(expr16_a, expr16_str));
expr16_str = "expr16";
CPPA_CHECK_EQUAL(true, ge_invoke(expr16_b, expr16_str));
CPPA_CHECK_EQUAL(expr16_str.size(), ge_invoke(expr16_a, expr16_str));
expr16_str.front() = '_';
CPPA_CHECK_EQUAL(false, ge_invoke(expr16_b, expr16_str));
int expr17_value = 42;
auto expr17 = gref(expr17_value) == 42;
CPPA_CHECK_EQUAL(true, ge_invoke(expr17));
expr17_value = 0;
CPPA_CHECK_EQUAL(false, ge_invoke(expr17));
int expr18_value = 42;
auto expr18_a = gref(expr18_value) == 42;
CPPA_CHECK_EQUAL(true, ge_invoke(expr18_a));
expr18_value = 0;
CPPA_CHECK_EQUAL(false, ge_invoke(expr18_a));
auto expr18_b = gref(expr18_value) == _x1;
auto expr18_c = std::ref(expr18_value) == _x1;
CPPA_CHECK_EQUAL(true, ge_invoke(expr18_b, 0));
CPPA_CHECK_EQUAL(true, ge_invoke(expr18_c, 0));
bool invoked = false;
match("abc")
(
......@@ -117,6 +150,46 @@ size_t test__match()
if (!invoked) { CPPA_ERROR("match(\"abc\") failed"); }
invoked = false;
bool disable_case1 = true;
bool case1_invoked = false;
bool case2_invoked = false;
auto expr19 =
(
on<anything>().when(gref(disable_case1) == false) >> [&]()
{
case1_invoked = true;
},
on<anything>() >> [&]()
{
case2_invoked = true;
}
);
any_tuple expr19_tup = make_cow_tuple("hello guard!");
expr19(expr19_tup);
CPPA_CHECK(!case1_invoked);
CPPA_CHECK(case2_invoked);
partial_function expr20 = expr19;
case1_invoked = false;
case2_invoked = false;
disable_case1 = false;
expr20(expr19_tup);
CPPA_CHECK(case1_invoked);
CPPA_CHECK(!case2_invoked);
std::vector<int> expr21_vec_a{1, 2, 3};
std::vector<int> expr21_vec_b{1, 0, 2};
auto vec_sorted = [](std::vector<int> const& vec)
{
return std::is_sorted(vec.begin(), vec.end());
};
auto expr21 = gcall(vec_sorted, _x1);
CPPA_CHECK(ge_invoke(expr21, expr21_vec_a));
CPPA_CHECK(!ge_invoke(expr21, expr21_vec_b));
auto expr22 = _x1.empty() && _x2.not_empty();
CPPA_CHECK(ge_invoke(expr22, std::string(""), std::string("abc")));
match(std::vector<int>{1, 2, 3})
(
on<int, int, int>().when( _x1 + _x2 + _x3 == 6
......
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