Commit ece82dbb authored by Joseph Noir's avatar Joseph Noir

Merge branch 'unstable' of github.com:Neverlord/libcppa into unstable

parents 6aa1cd24 f580a1ef
......@@ -46,20 +46,29 @@
namespace cppa { namespace detail {
struct match_helper {
class match_helper {
match_helper(const match_helper&) = delete;
match_helper& operator=(const match_helper&) = delete;
any_tuple tup;
match_helper(any_tuple t) : tup(std::move(t)) { }
public:
match_helper(match_helper&&) = default;
inline match_helper(any_tuple t) : tup(std::move(t)) { }
template<typename... Ts>
bool operator()(Ts&&... args) {
auto operator()(Ts&&... args)
-> decltype(match_expr_collect(std::forward<Ts>(args)...)(any_tuple{})) {
static_assert(sizeof...(Ts) > 0, "at least one argument required");
auto tmp = match_expr_convert(std::forward<Ts>(args)...);
static_assert(std::is_same<partial_function, decltype(tmp)>::value,
"match statement contains timeout");
auto tmp = match_expr_collect(std::forward<Ts>(args)...);
return tmp(tup);
}
private:
any_tuple tup;
};
struct identity_fun {
......@@ -72,22 +81,25 @@ struct identity_fun {
template<typename Iterator, typename Projection = identity_fun>
class match_each_helper {
match_each_helper(const match_each_helper&) = delete;
match_each_helper& operator=(const match_each_helper&) = delete;
public:
match_each_helper(match_each_helper&&) = default;
match_each_helper(const match_each_helper&) = delete;
match_each_helper& operator=(const match_each_helper&) = delete;
match_each_helper(Iterator first, Iterator last) : i(first), e(last) { }
match_each_helper(Iterator first, Iterator last, Projection proj)
: i(first), e(last), p(proj) { }
match_each_helper(Iterator first, Iterator last, Projection proj = Projection{})
: i(std::move(first)), e(std::move(last)), p(std::move(proj)) { }
template<typename... Ts>
void operator()(Ts&&... args) {
Iterator operator()(Ts&&... args) {
static_assert(sizeof...(Ts) > 0, "at least one argument required");
auto expr = match_expr_collect(std::forward<Ts>(args)...);
for (; i != e; ++i) {
expr(p(*i));
auto res = expr(p(*i));
if (!res) return i;
}
return e;
}
private:
......@@ -103,17 +115,20 @@ struct advance_once {
inline void operator()(T& what) { ++what; }
};
template<class Iterator, class Predicate,
template<class Iterator,
class Predicate,
class Advance = advance_once,
class Projection = identity_fun>
class match_for_helper {
match_for_helper(const match_for_helper&) = delete;
match_for_helper& operator=(const match_for_helper&) = delete;
public:
match_for_helper(match_for_helper&&) = default;
match_for_helper(const match_for_helper&) = delete;
match_for_helper& operator=(const match_for_helper&) = delete;
match_for_helper(Iterator first, Predicate p, Advance a = Advance(), Projection pj = Projection())
match_for_helper(Iterator first, Predicate p, Advance a = Advance{}, Projection pj = Projection{})
: i(first), adv(a), pred(p), proj(pj) { }
template<typename... Ts>
......@@ -142,36 +157,20 @@ size_t run_case(std::vector<T>& vec,
const InputIterator& end,
Case& target);
template<size_t N, size_t Size>
struct unwind_and_call {
typedef unwind_and_call<N+1, Size> next;
template<class Target, typename T, typename... Unwinded>
static inline bool _(Target& target, bool& skipped, std::vector<T>& vec, Unwinded&&... args) {
return next::_(target, skipped, vec, std::forward<Unwinded>(args)..., vec[N]);
}
template<size_t Pos, size_t Max>
struct unwind_pos_token { };
template<typename T, typename InputIterator, class MatchExpr>
static inline bool _(std::vector<T>& vec, InputIterator& pos, InputIterator end, MatchExpr& ex) {
bool skipped = false;
if (run_case(vec, skipped, pos, end, get<N>(ex.cases())) == 0) {
return (skipped) ? false : next::_(vec, pos, end, ex);
}
return true;
}
};
template<size_t Size>
struct unwind_and_call<Size, Size> {
template<size_t Pos, size_t Max>
constexpr unwind_pos_token<Pos+1, Max> next(unwind_pos_token<Pos, Max>) {
return {};
}
template<typename T>
static inline bool eval_res(const optional<T>& res, bool&) {
template<typename T>
static inline bool eval_res(const optional<T>& res, bool&) {
return static_cast<bool>(res);
}
}
static inline bool eval_res(const optional<match_hint>& res, bool& skipped) {
static inline bool eval_res(const optional<match_hint>& res, bool& skipped) {
if (res) {
if (*res == match_hint::skip) {
skipped = true;
......@@ -180,21 +179,58 @@ struct unwind_and_call<Size, Size> {
return true;
}
return false;
}
}
template<class Target, typename T, typename... Unwinded>
static inline bool _(Target& target, bool& skipped, std::vector<T>&, Unwinded&&... args) {
return eval_res(target.first(target.second, std::forward<Unwinded>(args)...), skipped);
}
template<size_t Max, class Target, typename T, typename... Ts>
bool unwind_and_call(unwind_pos_token<Max, Max>,
Target& target,
bool& skipped,
std::vector<T>&,
Ts&&... args) {
return eval_res(target.first(target.second, std::forward<Ts>(args)...),
skipped);
}
template<typename T, typename... Ts>
static inline bool _(std::vector<T>&, Ts&&...) { return false; }
template<size_t Max, typename T, typename InputIterator, class MatchExpr>
bool unwind_and_call(unwind_pos_token<Max, Max>,
std::vector<T>&,
InputIterator&,
InputIterator,
MatchExpr&) {
return false;
}
};
template<size_t Pos, size_t Max, class Target, typename T, typename... Ts>
bool unwind_and_call(unwind_pos_token<Pos, Max> pt,
Target& target,
bool& skipped,
std::vector<T>& vec,
Ts&&... args) {
return unwind_and_call(next(pt),
target,
skipped,
vec,
std::forward<Ts>(args)...,
vec[Pos]);
}
template<size_t Pos, size_t Max, typename T, typename InputIterator, class MatchExpr>
bool unwind_and_call(unwind_pos_token<Pos, Max> pt,
std::vector<T>& vec,
InputIterator& pos,
InputIterator end,
MatchExpr& ex) {
bool skipped = false;
if (run_case(vec, skipped, pos, end, get<Pos>(ex.cases())) == 0) {
return (skipped) ? false : unwind_and_call(next(pt), vec, pos, end, ex);
}
return true;
}
template<class Case, typename T>
inline bool run_case_impl(Case& target, std::vector<T>& vec, bool& skipped) {
return unwind_and_call<0, util::tl_size<typename Case::pattern_type>::value>::_(target, skipped, vec);
unwind_pos_token<0, util::tl_size<typename Case::pattern_type>::value> pt;
return unwind_and_call(pt, target, skipped, vec);
}
// Case is a projection_partial_function_pair
......@@ -212,7 +248,7 @@ size_t run_case(std::vector<T>& vec,
"empty match expressions are not allowed in stream matching");
static_assert(util::tl_forall<plain_args, util::tbind<std::is_same, T>::template type>::value,
"match_stream<T>: at least one callback argument "
" is not of type T");
"is not of type T");
while (vec.size() < num_args) {
if (pos == end) {
return 0;
......@@ -244,9 +280,10 @@ class stream_matcher {
template<typename... Ts>
bool operator()(Ts&&... args) {
auto expr = match_expr_collect(std::forward<Ts>(args)...);
typedef decltype(expr) expr_type;
typedef decltype(expr) et;
unwind_pos_token<0, util::tl_size<typename et::cases_list>::value> pt;
while (m_pos != m_end) {
if (!unwind_and_call<0, util::tl_size<typename expr_type::cases_list>::value>::_(m_cache, m_pos, m_end, expr)) {
if (!unwind_and_call(pt, m_cache, m_pos, m_end, expr)) {
return false;
}
}
......@@ -285,7 +322,8 @@ detail::match_helper match(T&& what) {
/**
* @brief Splits @p str using @p delim and match the resulting strings.
*/
detail::match_helper match_split(const std::string& str, char delim, bool keep_empties = false);
detail::match_helper
match_split(const std::string& str, char delim, bool keep_empties = false);
/**
* @brief Starts a match expression that matches each element in
......@@ -295,8 +333,8 @@ detail::match_helper match_split(const std::string& str, char delim, bool keep_e
* @returns A helper object providing <tt>operator(...)</tt>.
*/
template<typename InputIterator>
auto match_each(InputIterator first, InputIterator last)
-> detail::match_each_helper<InputIterator> {
detail::match_each_helper<InputIterator>
match_each(InputIterator first, InputIterator last) {
return {first, last};
}
......@@ -309,39 +347,40 @@ auto match_each(InputIterator first, InputIterator last)
* @returns A helper object providing <tt>operator(...)</tt>.
*/
template<typename InputIterator, typename Projection>
auto match_each(InputIterator first, InputIterator last, Projection proj)
-> detail::match_each_helper<InputIterator, Projection> {
detail::match_each_helper<InputIterator, Projection>
match_each(InputIterator first, InputIterator last, Projection proj) {
return {first, last, std::move(proj)};
}
template<typename InputIterator, typename Predicate>
auto match_for(InputIterator first, Predicate pred)
-> detail::match_for_helper<InputIterator, Predicate> {
detail::match_for_helper<InputIterator, Predicate>
match_for(InputIterator first, Predicate pred) {
return {first, std::move(pred)};
}
template<typename InputIterator, typename Predicate, typename Advance>
auto match_for(InputIterator first, Predicate pred, Advance adv)
-> detail::match_for_helper<InputIterator, Predicate, Advance> {
detail::match_for_helper<InputIterator, Predicate, Advance>
match_for(InputIterator first, Predicate pred, Advance adv) {
return {first, std::move(pred), std::move(adv)};
}
template<class InputIterator, class Predicate, class Advance, class Projection>
auto match_for(InputIterator first, Predicate pred, Advance adv, Projection pj)
-> detail::match_for_helper<InputIterator, Predicate, Advance, Projection>{
detail::match_for_helper<InputIterator, Predicate, Advance, Projection>
match_for(InputIterator first, Predicate pred, Advance adv, Projection pj) {
return {first, std::move(pred), std::move(adv), std::move(pj)};
}
template<typename T>
detail::stream_matcher<T, std::istream_iterator<T> > match_stream(std::istream& stream) {
detail::stream_matcher<T, std::istream_iterator<T>>
match_stream(std::istream& stream) {
std::istream_iterator<T> first(stream);
std::istream_iterator<T> last; // 'end of stream' iterator
return {first, last};
}
template<typename T, typename InputIterator>
detail::stream_matcher<T, InputIterator> match_stream(InputIterator first,
InputIterator last ) {
detail::stream_matcher<T, InputIterator>
match_stream(InputIterator first, InputIterator last) {
return {first, last};
}
......
......@@ -31,6 +31,7 @@
#ifndef OPTIONAL_VARIANT_HPP
#define OPTIONAL_VARIANT_HPP
#include <iosfwd>
#include <stdexcept>
#include <type_traits>
......@@ -196,12 +197,12 @@ class optional_variant {
}
template<typename Visitor>
auto apply(const Visitor& visitor) const -> decltype(visitor(none_t{})) {
auto apply(Visitor& visitor) const -> decltype(visitor(none_t{})) {
return do_apply(*this, visitor);
}
template<typename Visitor>
auto apply(const Visitor& visitor) -> decltype(visitor(none_t{})) {
auto apply(Visitor& visitor) -> decltype(visitor(none_t{})) {
return do_apply(*this, visitor);
}
......@@ -241,7 +242,7 @@ class optional_variant {
}
template<typename Self, typename Visitor>
static auto do_apply(Self& from, const Visitor& visitor) -> decltype(visitor(none_t{})) {
static auto do_apply(Self& from, Visitor& visitor) -> decltype(visitor(none_t{})) {
switch (from.m_type) {
default: throw std::runtime_error("invalid type found");
case -1: return visitor(none_t{});
......@@ -259,7 +260,8 @@ class optional_variant {
}
inline void destroy_data() {
apply(detail::optional_variant_data_destructor{});
detail::optional_variant_data_destructor f;
apply(f);
}
template<typename U>
......@@ -325,6 +327,14 @@ T& get_ref(optional_variant<Us...>& value) {
return value.get(token);
}
/**
* @relates optional_variant
*/
template<typename Visitor, typename... Ts>
auto apply_visitor(Visitor& visitor, const optional_variant<Ts...>& data) -> decltype(visitor(none_t{})) {
return data.apply(visitor);
}
/**
* @relates optional_variant
*/
......@@ -333,6 +343,14 @@ auto apply_visitor(const Visitor& visitor, const optional_variant<Ts...>& data)
return data.apply(visitor);
}
/**
* @relates optional_variant
*/
template<typename Visitor, typename... Ts>
auto apply_visitor(Visitor& visitor, optional_variant<Ts...>& data) -> decltype(visitor(none_t{})) {
return data.apply(visitor);
}
/**
* @relates optional_variant
*/
......@@ -349,6 +367,59 @@ struct optional_variant_from_type_list<util::type_list<Ts...>> {
typedef optional_variant<Ts...> type;
};
namespace detail {
template<typename T>
struct optional_variant_cmp_helper {
const T& lhs;
optional_variant_cmp_helper(const T& value) : lhs{value} { }
// variant is comparable
template<typename U>
typename std::enable_if<util::is_comparable<T, U>::value, bool>::type
operator()(const U& rhs) const { return lhs == rhs; }
// variant is not comparable
template<typename U>
typename std::enable_if<!util::is_comparable<T, U>::value, bool>::type
operator()(const U&) const { return false; }
// variant is void
bool operator()() const { return false; }
};
} // namespace detail
/**
* @relates optional_variant
*/
template<typename T, typename... Ts>
bool operator==(const T& lhs, const optional_variant<Ts...>& rhs) {
return apply_visitor(detail::optional_variant_cmp_helper<T>{lhs}, rhs);
}
/**
* @relates optional_variant
*/
template<typename T, typename... Ts>
bool operator==(const optional_variant<Ts...>& lhs, const T& rhs) {
return rhs == lhs;
}
namespace detail {
struct optional_variant_ostream_helper {
std::ostream& lhs;
inline optional_variant_ostream_helper(std::ostream& os) : lhs(os) { }
template<typename T>
std::ostream& operator()(const T& value) const { return lhs << value; }
inline std::ostream& operator()(const none_t&) const { return lhs; }
inline std::ostream& operator()() const { return lhs; }
};
} // namespace detail
/**
* @relates optional_variant
*/
template<typename T0, typename... Ts>
std::ostream& operator<<(std::ostream& lhs, const optional_variant<T0, Ts...>& rhs) {
return apply_visitor(detail::optional_variant_ostream_helper{lhs}, rhs);
}
} // namespace cppa
#endif // OPTIONAL_VARIANT_HPP
......@@ -11,188 +11,80 @@
using namespace std;
using namespace cppa;
using namespace std::placeholders;
using namespace cppa::placeholders;
bool is_even(int i) { return i % 2 == 0; }
/*
*
* projection:
*
* on(_x.rsplit("--(.*)=(.*)")) >> [](std::vector<std::string> matched_groups)
*
*/
struct dummy {
inline operator actor_ptr() const { return nullptr; }
inline actor_ptr as_facade() const { return nullptr; }
};
inline dummy operator|(const dummy&, const dummy&) { return {}; }
template<typename T>
dummy operator|(const dummy& lhs, const T&) {
return lhs;
}
template<typename T>
dummy operator|(const T&, const dummy& rhs) {
return rhs;
bool vec_sorted(const std::vector<int>& vec) {
return std::is_sorted(vec.begin(), vec.end());
}
dummy slice(int,int) { return {}; }
dummy prepend(atom_value) { return {}; }
dummy consume(atom_value) { return {}; }
dummy split(int) { return {}; }
dummy join(int) { return {}; }
void example() {
// {}: tuple
// []: list
// 'a': atom 'a' == atom("a")
// x => y: replies to x with y
{
// for starters: get the internally used user-ID from a key-value store
// and get the user role, e.g., "admin", from the user database
// {'get', key} => {user_id, [tags]}
actor_ptr kvstore;
// {'info', user_id} => {name, address, phone, role}
actor_ptr userinfo;
// {username} => {role}
auto query = kvstore | slice(0,0) | prepend(atom("info")) | userinfo | slice(3,3);
// check whether Dirty Harry has admin access
sync_send(query, atom("get"), "Dirty Harry").then(
on("admin") >> [] {
// grant access
},
others() >> [] {
// deny access (well, no one denies Dirty Harry access anyways)
}
);
// creates a new actor providing the interface {username} => {role}
actor_ptr roles = query.as_facade();
}
{
// we have an actor representing a database for orders and we want
// to have the net price of all orders from Dirty Harry
// {'orders', user_id} => {[order_id]}
// {'price', order_id} => {net_price}
actor_ptr orders;
// {'prices', user_id} => {[net_price]}
auto query = consume(atom("prices"))
| prepend(atom("orders"))
| orders
| prepend(atom("price"))
| split(1)
| orders
| join(0);
sync_send(query, atom("prices"), "Dirty Harry").then(
[](const vector<float>& prices) {
cout << "Dirty Harry has ordered products "
<< "with a total net price of $"
<< accumulate(prices.begin(), prices.end(), 0)
<< endl;
}
);
vector<string> kvp_split(const string& str) {
auto pos = str.find('=');
if (pos != string::npos && pos == str.rfind('=')) {
return vector<string>{str.substr(0, pos), str.substr(pos+1)};
}
return {};
}
template<typename T>
struct type_token { typedef T type; };
template<typename... Ts>
struct variant;
template<typename T>
struct variant<T> {
T& get(type_token<T>) { return m_value; }
T m_value;
};
template<typename T0, typename T1>
struct variant<T0, T1> {
public:
T0& get(type_token<T0>) { return m_v0; }
T1& get(type_token<T1>) { return m_v1; }
variant() : m_type{0}, m_v0{} { }
~variant() {
switch (m_type) {
case 0: m_v0.~T0(); break;
case 1: m_v1.~T1(); break;
}
}
private:
size_t m_type;
optional<int> toint(const string& str) {
char* endptr = nullptr;
int result = static_cast<int>(strtol(str.c_str(), &endptr, 10));
if (endptr != nullptr && *endptr == '\0') return result;
return none;
}
union { T0 m_v0; T1 m_v1; };
template<size_t Pos, size_t Max>
struct index_token { };
};
template<size_t Max>
void foobar(index_token<Max, Max>) { }
template<typename T, typename... Ts>
T& get(variant<Ts...>& v) {
return v.get(type_token<T>{});
template<size_t Pos, size_t Max>
void foobar(index_token<Pos, Max>) {
cout << "foobar<" << Pos << "," << Max << ">" << endl;
foobar(index_token<Pos+1, Max>{});
}
int main() {
CPPA_TEST(test_match);
using namespace std::placeholders;
using namespace cppa::placeholders;
variant<int, double> rofl;
get<int>(rofl) = 42;
cout << "rofl = " << get<int>(rofl) << endl;
/* test guard evaluation */ {
// ascending values
auto ascending = [](int a, int b, int c) -> bool {
return a < b && b < c;
};
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 expr0_b = gcall(ascending, _x1, std::ref(ival0), _x2);
CPPA_CHECK(ge_invoke(expr0_b, 1, 3));
++ival0;
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));
// user-defined expressions using '+', '<', '%'
auto expr1 = _x1 + _x2;
auto expr2 = _x1 + _x2 < _x3;
auto expr3 = _x1 % _x2 == 0;
CPPA_CHECK_EQUAL((ge_invoke(expr1, 2, 3)), 5);
//CPPA_CHECK(ge_invoke(expr2, 1, 2, 4));
CPPA_CHECK(expr2(1, 2, 4));
CPPA_CHECK_EQUAL((ge_invoke(expr1, std::string{"1"}, std::string{"2"})), "12");
CPPA_CHECK(expr3(100, 2));
// user-defined expressions using '||'
auto expr4 = _x1 == "-h" || _x1 == "--help";
CPPA_CHECK(ge_invoke(expr4, string("-h")));
CPPA_CHECK(ge_invoke(expr4, string("--help")));
CPPA_CHECK(!ge_invoke(expr4, string("-g")));
}
/* guard expressions on containers */ {
auto expr5 = _x1.starts_with("--");
CPPA_CHECK(ge_invoke(expr5, string("--help")));
CPPA_CHECK(!ge_invoke(expr5, string("-help")));
// container search (x in y)
vector<string> vec1{"hello", "world"};
auto expr6 = _x1.in(vec1);
CPPA_CHECK(ge_invoke(expr6, string("hello")));
......@@ -205,7 +97,25 @@ int main() {
vec1.emplace_back("hello world");
CPPA_CHECK(!ge_invoke(expr6, string("hello world")));
CPPA_CHECK(ge_invoke(expr7, string("hello world")));
// container search (x in y) for initializer lists
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")));
// container search (x not in y)
auto expr12 = _x1.not_in({"hello", "world"});
CPPA_CHECK(ge_invoke(expr12, string("foo")));
CPPA_CHECK(!ge_invoke(expr12, string("hello")));
// user-defined function to evaluate whether container is sorted
std::vector<int> expr21_vec_a{1, 2, 3};
std::vector<int> expr21_vec_b{1, 0, 2};
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")));
}
/* user-defined expressions */ {
int ival = 5;
auto expr8 = _x1 == ival;
auto expr9 = _x1 == std::ref(ival);
......@@ -214,29 +124,18 @@ int main() {
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")));
// user-defined expressions w/ wide range of operators
auto expr13 = _x1 * _x2 < _x3 - _x4;
CPPA_CHECK(ge_invoke(expr13, 1, 1, 4, 2));
auto expr14 = _x1 + _x2;
static_assert(std::is_same<decltype(ge_invoke(expr14, 1, 2)), int>::value,
"wrong return type");
CPPA_CHECK_EQUAL((ge_invoke(expr14, 2, 3)), 5);
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((ge_invoke(expr15, 7, 10, 25)), 42);
// user-defined operations on containers such as 'size' and 'front'
std::string expr16_str;// = "expr16";
auto expr16_a = _x1.size();
auto expr16_b = _x1.front() == 'e';
......@@ -247,13 +146,13 @@ int main() {
CPPA_CHECK_EQUAL((ge_invoke(expr16_a, expr16_str)), expr16_str.size());
expr16_str.front() = '_';
CPPA_CHECK_EQUAL((ge_invoke(expr16_b, expr16_str)), false);
}
/* user-defined expressions using 'gref' */ {
int expr17_value = 42;
auto expr17 = gref(expr17_value) == 42;
CPPA_CHECK_EQUAL(ge_invoke(expr17), true);
expr17_value = 0;
CPPA_CHECK_EQUAL(ge_invoke(expr17), false);
int expr18_value = 42;
auto expr18_a = gref(expr18_value) == 42;
CPPA_CHECK_EQUAL(ge_invoke(expr18_a), true);
......@@ -263,105 +162,65 @@ int main() {
auto expr18_c = std::ref(expr18_value) == _x1;
CPPA_CHECK_EQUAL((ge_invoke(expr18_b, 0)), true);
CPPA_CHECK_EQUAL((ge_invoke(expr18_c, 0)), true);
bool invoked = false;
auto kvp_split1 = [](const string& str) -> vector<string> {
auto pos = str.find('=');
if (pos != string::npos && pos == str.rfind('=')) {
return vector<string>{str.substr(0, pos), str.substr(pos+1)};
bool enable_case1 = true;
auto expr19 = (
on<anything>().when(gref(enable_case1) == false) >> [] { return 1; },
on<anything>() >> [] { return 2; }
);
any_tuple expr19_tup = make_cow_tuple("hello guard!");
CPPA_CHECK_EQUAL(expr19(expr19_tup), 2);
partial_function expr20 = expr19;
enable_case1 = false;
CPPA_CHECK_EQUAL(expr20(expr19_tup), 1);
}
return {};
};
match("value=42") (
on(kvp_split1).when(_x1.not_empty()) >> [&](const vector<string>& vec) {
/* test 'match' function */ {
auto res0 = match(5) (
on_arg_match.when(_x1 < 6) >> [&](int i) {
CPPA_CHECK_EQUAL(i, 5);
}
);
CPPA_CHECK(res0);
auto res1 = match("value=42") (
on(kvp_split).when(_x1.not_empty()) >> [&](const vector<string>& vec) {
CPPA_CHECK_EQUAL("value", vec[0]);
CPPA_CHECK_EQUAL("42", vec[1]);
invoked = true;
}
);
CPPA_CHECK(invoked);
invoked = false;
auto toint = [](const string& str) -> optional<int> {
char* endptr = nullptr;
int result = static_cast<int>(strtol(str.c_str(), &endptr, 10));
if (endptr != nullptr && *endptr == '\0') {
return result;
}
return none;
};
match("42") (
CPPA_CHECK(res1);
auto res2 = match("42") (
on(toint) >> [&](int i) {
CPPA_CHECK_EQUAL(42, i);
invoked = true;
}
);
CPPA_CHECK(invoked);
invoked = false;
match("abc") (
on<string>().when(_x1 == "abc") >> [&]() {
invoked = true;
}
);
if (!invoked) { CPPA_FAILURE("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;
}
CPPA_CHECK(res2);
auto res3 = match("abc") (
on<string>().when(_x1 == "abc") >> [&] { }
);
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 = [](const std::vector<int>& 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}) (
CPPA_CHECK(res3);
CPPA_CHECK(res3.is<void>());
// match vectors
auto res4 = match(std::vector<int>{1, 2, 3}) (
on<int, int, int>().when( _x1 + _x2 + _x3 == 6
&& _x2(is_even)
&& _x3 % 2 == 1) >> [&]() {
invoked = true;
&& _x3 % 2 == 1 ) >> [&] { }
);
CPPA_CHECK(res4);
vector<string> vec{"a", "b", "c"};
auto res5 = match(vec) (
on("a", "b", val<string>) >> [](string&) -> string {
return "C";
}
);
if (!invoked) { CPPA_FAILURE("match({1, 2, 3}) failed"); }
invoked = false;
CPPA_CHECK_EQUAL(res5, "C");
}
/* test 'match_each' */ {
string sum;
vector<string> sum_args = { "-h", "--version", "-wtf" };
match_each(begin(sum_args), end(sum_args)) (
on<string>().when(_x1.in({"-h", "--help"})) >> [&](string s) {
auto iter1 = match_each(begin(sum_args), end(sum_args)) (
on<string>().when(_x1.in({"-h", "--help"})) >> [&](const string& s) {
sum += s;
},
on<string>().when(_x1 == "-v" || _x1 == "--version") >> [&](string s) {
on<string>().when(_x1 == "-v" || _x1 == "--version") >> [&](const string& s) {
sum += s;
},
on<string>().when(_x1.starts_with("-")) >> [&](const string& str) {
......@@ -372,71 +231,28 @@ int main() {
on<char>() >> CPPA_FAILURE_CB("guard didn't match"),
others() >> CPPA_FAILURE_CB("unexpected match")
);
},
others() >> CPPA_FAILURE_CB("unexpected match")
);
CPPA_CHECK_EQUAL(sum, "-h--versionwtf");
match(5) (
on<int>().when(_x1 < 6) >> [&](int i) {
CPPA_CHECK_EQUAL(i, 5);
invoked = true;
}
);
CPPA_CHECK(invoked);
invoked = false;
vector<string> vec{"a", "b", "c"};
match(vec) (
on("a", "b", val<string>) >> [&](string& str) {
invoked = true;
str = "C";
}
CPPA_CHECK(iter1 == end(sum_args));
CPPA_CHECK_EQUAL(sum, "-h--versionwtf");
auto iter2 = match_each(begin(sum_args), end(sum_args)) (
on("-h") >> [] { }
);
if (!invoked) { CPPA_FAILURE("match({\"a\", \"b\", \"c\"}) failed"); }
CPPA_CHECK_EQUAL(vec.back(), "C");
invoked = false;
match_each(begin(vec), end(vec)) (
on("a") >> [&](string& str) {
invoked = true;
str = "A";
CPPA_CHECK(iter2 == (begin(sum_args) + 1));
}
);
if (!invoked) { CPPA_FAILURE("match_each({\"a\", \"b\", \"C\"}) failed"); }
CPPA_CHECK_EQUAL(vec.front(), "A");
invoked = false;
vector<string> vec2{"a=0", "b=1", "c=2"};
auto c2 = split(vec2.back(), '=');
match(c2) (
on("c", "2") >> [&]() { invoked = true; }
);
CPPA_CHECK_EQUAL(invoked, true);
invoked = false;
// let's get the awesomeness started
/* test match_stream */ {
bool success = false;
istringstream iss("hello world");
success = match_stream<string>(iss) (
on("hello", "world") >> CPPA_CHECKPOINT_CB()
);
CPPA_CHECK_EQUAL(success, true);
auto extract_name = [](const string& kvp) -> optional<string> {
auto vec = split(kvp, '=');
if (vec.size() == 2) {
if (vec.front() == "--name") {
return vec.back();
}
}
if (vec.size() == 2 && vec.front() == "--name") return vec.back();
return none;
};
const char* svec[] = {"-n", "foo", "--name=bar", "-p", "2"};
success = match_stream<string>(begin(svec), end(svec)) (
(on("-n", arg_match) || on(extract_name)) >> [](const string& name) -> bool {
CPPA_CHECK(name == "foo" || name == "bar");
......@@ -456,41 +272,16 @@ int main() {
}
);
CPPA_CHECK_EQUAL(success, true);
CPPA_PRINT("check combined partial function matching");
std::string last_invoked_fun;
# define check(pf, tup, str) { \
last_invoked_fun = ""; \
pf(tup); \
CPPA_CHECK_EQUAL(last_invoked_fun, str); \
}
partial_function pf0 = (
on<int, int>() >> [&] { last_invoked_fun = "<int, int>@1"; },
on<float>() >> [&] { last_invoked_fun = "<float>@2"; }
);
auto pf1 = pf0.or_else(
on<int, int>() >> [&] { last_invoked_fun = "<int, int>@3"; },
on<string>() >> [&] { last_invoked_fun = "<string>@4"; }
);
check(pf0, make_any_tuple(1, 2), "<int, int>@1");
check(pf1, make_any_tuple(1, 2), "<int, int>@1");
check(pf0, make_any_tuple("hi"), "");
check(pf1, make_any_tuple("hi"), "<string>@4");
CPPA_PRINT("check match expressions with boolean return value");
// utility macro to identify invoked functors
std::string last_invoked_fun;
# define bhvr_check(pf, tup, expected_result, str) { \
last_invoked_fun = ""; \
CPPA_CHECK_EQUAL(pf(tup), expected_result); \
CPPA_CHECK_EQUAL(last_invoked_fun, str); \
}
behavior bhvr1 = (
/* test if match hints are evaluated properly */ {
behavior bhvr1 {
on<int>() >> [&](int i) -> match_hint {
last_invoked_fun = "<int>@1";
return (i == 42) ? match_hint::skip : match_hint::handle;
......@@ -504,26 +295,55 @@ int main() {
others() >> [&] {
last_invoked_fun = "<*>@4";
}
);
};
bhvr_check(bhvr1, make_any_tuple(42), false, "<int>@1");
bhvr_check(bhvr1, make_any_tuple(24), true, "<int>@1");
bhvr_check(bhvr1, make_any_tuple(2.f), true, "<float>@2");
bhvr_check(bhvr1, make_any_tuple(""), true, "<*>@4");
}
/* test or_else concatenation */ {
partial_function pf0 {
on<int, int>() >> [&] { last_invoked_fun = "<int, int>@1"; },
on<float>() >> [&] { last_invoked_fun = "<float>@2"; }
};
auto pf1 = pf0.or_else (
on<int, int>() >> [&] { last_invoked_fun = "<int, int>@3"; },
on<string>() >> [&] { last_invoked_fun = "<string>@4"; }
);
bhvr_check(pf0, make_any_tuple(1, 2), true, "<int, int>@1");
bhvr_check(pf1, make_any_tuple(1, 2), true, "<int, int>@1");
bhvr_check(pf0, make_any_tuple("hi"), false, "");
bhvr_check(pf1, make_any_tuple("hi"), true, "<string>@4");
partial_function pf11 {
on_arg_match >> [&](int) { last_invoked_fun = "<int>@1"; }
};
partial_function pf12 {
on_arg_match >> [&](int) { last_invoked_fun = "<int>@2"; },
on_arg_match >> [&](float) { last_invoked_fun = "<float>@2"; }
};
auto pf13 = pf11.or_else(pf12);
bhvr_check(pf13, make_any_tuple(42), true, "<int>@1");
bhvr_check(pf13, make_any_tuple(42.24f), true, "<float>@2");
}
/* check result of pattern matching */ {
auto res = match(make_any_tuple(42, 4.2f)) (
on(42, arg_match) >> [](double d) {
return d;
},
on(42, arg_match) >> [](float f) {
return f;
}
);
CPPA_CHECK(res && res.is<float>() && get<float>(res) == 4.2f);
auto res2 = match(make_any_tuple(23, 4.2f)) (
on(42, arg_match) >> [](double d) {
return d;
},
on(42, arg_match) >> [](float f) {
return f;
}
);
CPPA_CHECK(!res2);
}
return CPPA_TEST_RESULT();
}
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