Commit cdd9aa4d authored by Dominik Charousset's avatar Dominik Charousset

improved pattern matching

parent 68086d89
......@@ -40,6 +40,7 @@ libcppa_la_SOURCES = \
src/object.cpp \
src/object_array.cpp \
src/partial_function.cpp \
src/pattern.cpp \
src/post_office.cpp \
src/post_office_msg.cpp \
src/primitive_variant.cpp \
......@@ -191,6 +192,7 @@ 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,3 +258,5 @@ cppa/detail/tuple_view.hpp
cppa/detail/container_tuple_view.hpp
cppa/detail/matches.hpp
unit_testing/test__match.cpp
src/pattern.cpp
cppa/util/guard.hpp
......@@ -31,8 +31,6 @@
#ifndef ANY_TUPLE_HPP
#define ANY_TUPLE_HPP
#include <iostream>
#include "cppa/cow_tuple.hpp"
#include "cppa/config.hpp"
#include "cppa/cow_ptr.hpp"
......@@ -183,7 +181,7 @@ class any_tuple
static constexpr bool can_optimize =
std::is_same<converted, vtype>::value
&& std::is_reference<T>::value
&& !std::is_const<T>::value;
&& !std::is_const<typename std::remove_reference<T>::type>::value;
std::integral_constant<bool, can_optimize> token;
return any_tuple{simple_view(std::forward<T>(value), token)};
}
......
......@@ -31,6 +31,9 @@
#ifndef UNBOXED_HPP
#define UNBOXED_HPP
#include <memory>
#include "cppa/util/guard.hpp"
#include "cppa/util/wrapped.hpp"
namespace cppa { namespace detail {
......@@ -65,6 +68,12 @@ struct unboxed<util::wrapped<T> (*)()>
typedef typename util::wrapped<T>::type type;
};
template<typename T>
struct unboxed<std::unique_ptr<util::guard<T>>>
{
typedef T type;
};
} } // namespace cppa::detail
#endif // UNBOXED_HPP
......@@ -81,7 +81,7 @@ class uniform_type_info_map
// maps uniform names to uniform type informations
uti_map m_by_uname;
// maps sizeof(-integer_type-) to { raw-names-set, uniform-names-set }
// maps sizeof(-integer_type-) to { signed-names-set, unsigned-names-set }
int_map m_ints;
};
......
......@@ -73,6 +73,26 @@ struct match_each_helper
}
};
template<class Container>
struct copying_match_each_helper
{
copying_match_each_helper(copying_match_each_helper const&) = delete;
copying_match_each_helper& operator=(copying_match_each_helper const&) = delete;
Container vec;
copying_match_each_helper(Container tmp) : vec(std::move(tmp)) { }
copying_match_each_helper(copying_match_each_helper&&) = default;
template<typename... Args>
void operator()(partial_function&& arg0, Args&&... args)
{
partial_function tmp;
tmp.splice(std::move(arg0), std::forward<Args>(args)...);
for (auto& i : vec)
{
tmp(any_tuple::view(i));
}
}
};
template<typename Iterator, typename Projection>
struct pmatch_each_helper
{
......@@ -112,9 +132,9 @@ inline detail::match_helper match(any_tuple t)
* @brief Match expression.
*/
template<typename T>
detail::match_helper match(T& what)
detail::match_helper match(T&& what)
{
return any_tuple::view(what);
return any_tuple::view(std::forward<T>(what));
}
/**
......@@ -127,6 +147,16 @@ auto match_each(Container& what)
return {std::begin(what), std::end(what)};
}
template<typename T>
auto match_each(std::initializer_list<T> list)
-> detail::copying_match_each_helper<std::vector<typename detail::strip_and_convert<T>::type>>
{
std::vector<typename detail::strip_and_convert<T>::type> vec;
vec.reserve(list.size());
for (auto& i : list) vec.emplace_back(std::move(i));
return vec;
}
template<typename InputIterator>
auto match_each(InputIterator first, InputIterator last)
-> detail::match_each_helper<InputIterator>
......
......@@ -260,11 +260,11 @@ constexpr boxed_arg_match_t arg_match = boxed_arg_match_t();
constexpr detail::on_the_fly_rvalue_builder on_arg_match;
template<typename Arg0, typename... Args>
detail::rvalue_builder<typename detail::unboxed<Arg0>::type,
typename detail::unboxed<Args>::type...>
on(Arg0 const& arg0, Args const&... args)
detail::rvalue_builder<typename detail::unboxed<typename util::rm_ref<Arg0>::type>::type,
typename detail::unboxed<typename util::rm_ref<Args>::type>::type...>
on(Arg0&& arg0, Args&&... args)
{
return { arg0, args... };
return {std::forward<Arg0>(arg0), std::forward<Args>(args)...};
}
template<typename... TypeList>
......
......@@ -45,6 +45,7 @@
#include "cppa/type_value_pair.hpp"
#include "cppa/uniform_type_info.hpp"
#include "cppa/util/guard.hpp"
#include "cppa/util/tbind.hpp"
#include "cppa/util/type_list.hpp"
#include "cppa/util/arg_match_t.hpp"
......@@ -106,6 +107,11 @@ struct cmp_helper
return what == tup.get_as<T>(i++);
}
template<typename T>
inline bool operator()(std::unique_ptr<util::guard<T> > const& g)
{
return (*g)(tup.get_as<T>(i++));
}
template<typename T>
inline bool operator()(util::wrapped<T> const&)
{
++i;
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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_HPP
#define GUARD_HPP
namespace cppa { namespace util {
template<typename T>
struct guard
{
virtual ~guard() { }
virtual bool operator()(T const&) const = 0;
};
} } // namespace cppa::util
#endif // GUARD_HPP
......@@ -46,6 +46,9 @@ struct rm_ref<T const&> { typedef T type; };
template<typename T>
struct rm_ref<T&> { typedef T type; };
template<typename T>
struct rm_ref<const T> { typedef T type; };
template<>
struct rm_ref<void> { };
......
......@@ -135,11 +135,4 @@ void demonitor(actor_ptr& whom)
if (whom) whom->detach(mtoken);
}
value_matcher::~value_matcher() { }
bool dummy_matcher::operator()(any_tuple const&)
{
return true;
}
} // namespace cppa
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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/>. *
\******************************************************************************/
#include "cppa/pattern.hpp"
namespace cppa {
value_matcher::~value_matcher() { }
bool dummy_matcher::operator()(any_tuple const&)
{
return true;
}
} // namespace cppa
......@@ -264,5 +264,4 @@ std::string to_uniform_name(const std::type_info& tinfo)
return to_uniform_name(demangle(tinfo.name()));
}
} } // namespace cppa::detail
......@@ -112,14 +112,14 @@ typedef std::set<std::string> string_set;
template<typename Int>
void push(std::map<int, std::pair<string_set, string_set>>& ints,
std::integral_constant<bool, true>)
std::integral_constant<bool, true>) // signed version
{
ints[sizeof(Int)].first.insert(raw_name<Int>());
}
template<typename Int>
void push(std::map<int, std::pair<string_set, string_set>>& ints,
std::integral_constant<bool, false>)
std::integral_constant<bool, false>) // unsigned version
{
ints[sizeof(Int)].second.insert(raw_name<Int>());
}
......@@ -625,25 +625,19 @@ class int_tinfo : public detail::default_uniform_type_info_impl<T>
public:
bool equals(const std::type_info& tinfo) const
bool equals(std::type_info const& tinfo) const
{
// TODO: string comparsion sucks & is slow; find a nicer solution
auto map_iter = uti_map().int_names().find(sizeof(T));
const string_set& st = is_signed<T>::value ? map_iter->second.first
string_set const& st = is_signed<T>::value ? map_iter->second.first
: map_iter->second.second;
auto end = st.end();
for (auto i = st.begin(); i != end; ++i)
{
if ((*i) == raw_name(tinfo)) return true;
}
return false;
auto x = raw_name(tinfo);
return std::any_of(st.begin(), st.end(),
[&](std::string const& y) { return x == y; });
}
};
//} } } // namespace cppa::detail::<anonymous>
//namespace cppa { namespace detail {
using std::is_integral;
using util::enable_if;
using util::disable_if;
......@@ -655,14 +649,12 @@ class uniform_type_info_map_helper
typedef uniform_type_info_map* this_ptr;
static void insert(this_ptr d, uniform_type_info* uti,
const std::set<std::string>& tnames)
static void insert(this_ptr d,
uniform_type_info* uti,
std::set<std::string> const& tnames)
{
if (tnames.empty())
{
throw std::logic_error("tnames.empty()");
}
for (const std::string& tname : tnames)
CPPA_REQUIRE(tnames.empty() == false);
for (std::string const& tname : tnames)
{
d->m_by_rname.insert(std::make_pair(tname, uti));
}
......@@ -671,16 +663,15 @@ class uniform_type_info_map_helper
template<typename T>
static inline void insert(this_ptr d,
const std::set<std::string>& tnames,
std::set<std::string> const& tnames,
typename enable_if<is_integral<T>>::type* = 0)
{
//insert(new default_uniform_type_info_impl<T>(), tnames);
insert(d, new int_tinfo<T>, tnames);
}
template<typename T>
static inline void insert(this_ptr d,
const std::set<std::string>& tnames,
std::set<std::string> const& tnames,
typename disable_if<is_integral<T>>::type* = 0)
{
insert(d, new default_uniform_type_info_impl<T>(), tnames);
......@@ -689,7 +680,7 @@ class uniform_type_info_map_helper
template<typename T>
static inline void insert(this_ptr d)
{
insert<T>(d, { std::string(raw_name<T>()) });
insert<T>(d, {std::string(raw_name<T>())});
}
static void init(this_ptr d)
......@@ -707,6 +698,8 @@ class uniform_type_info_map_helper
insert(d, new addr_msg_tinfo, {raw_name<detail::addressed_message>() });
insert(d, new void_type_tinfo, { raw_name<void_type>() });
insert<float>(d);
insert<double>(d);
/*
if (sizeof(double) == sizeof(long double))
{
std::string dbl = raw_name<double>();
......@@ -718,6 +711,7 @@ class uniform_type_info_map_helper
insert<double>(d);
insert<long double>(d);
}
*/
// first: signed
// second: unsigned
push<char,
......
......@@ -11,94 +11,106 @@ using namespace cppa;
using std::vector;
using std::string;
template<typename T>
std::function<bool (T const&)> is_any_of(std::vector<T> vec)
{
return [=](T const& value)
{
return std::any_of(vec.begin(), vec.end(),
[&](T const& v) { return value == v; });
};
}
#define CPPA_GUARD_IMPL(GuardOperator) \
struct impl : util::guard<T> \
{ \
T m_val; \
impl(T&& val) : m_val(std::move(val)) { } \
bool operator()(T const& other) const { return other < m_val; } \
}; return std::unique_ptr<util::guard<T>>{new impl{std::move(value)}}
template<typename T>
std::function<bool (T const&)> is_none_of(std::vector<T> vec)
struct pattern_placeholder
{
return [=](T const& value)
{
return std::none_of(vec.begin(), vec.end(),
[&](T const& v) { return value == v; });
};
}
constexpr pattern_placeholder() { }
struct placeholder
{
constexpr placeholder() { }
template<typename T>
std::function<bool (T const&)> operator<(T const& value) const
std::unique_ptr<util::guard<T>> operator<(T value) const
{
return [=](T const& other) { return other < value; };
CPPA_GUARD_IMPL(<);
}
template<typename T>
std::function<bool (T const&)> operator<=(T const& value) const
std::unique_ptr<util::guard<T>> operator<=(T value) const
{
return [=](T const& other) { return other <= value; };
CPPA_GUARD_IMPL(<=);
}
template<typename T>
std::function<bool (T const&)> operator>(T const& value) const
std::unique_ptr<util::guard<T>> operator>(T value) const
{
return [=](T const& other) { return other > value; };
CPPA_GUARD_IMPL(>);
}
template<typename T>
std::function<bool (T const&)> operator>=(T const& value) const
std::unique_ptr<util::guard<T>> operator>=(T value) const
{
return [=](T const& other) { return other >= value; };
CPPA_GUARD_IMPL(>=);
}
template<typename T>
std::function<bool (T const&)> operator==(T const& value) const
T operator==(T value) const
{
return [=](T const& other) { return other == value; };
return value;
}
template<typename T>
std::function<bool (T const&)> operator!=(T const& value) const
std::unique_ptr<util::guard<T>> operator!=(T value) const
{
return [=](T const& other) { return other != value; };
CPPA_GUARD_IMPL(!=);
}
template<typename T>
std::function<bool (T const&)> any_of(std::vector<T> vec) const
std::unique_ptr<util::guard<T>> any_of(std::vector<T> vec) const
{
return [=](T const& value)
cout << "guard<vector<" << detail::demangle(typeid(T).name()) << ">>" << endl;
typedef std::vector<T> vector_type;
struct impl : util::guard<T>
{
return std::any_of(vec.begin(), vec.end(),
[&](T const& v) { return value == v; });
vector_type m_vec;
impl(vector_type&& v) : m_vec(std::move(v)) { }
bool operator()(T const& value) const
{
cout << "guard<vector<" << detail::demangle(typeid(T).name()) << ">>::operator()(" << value << ")" << endl;
return std::any_of(m_vec.begin(), m_vec.end(),
[&](T const& val) { return val == value; });
}
};
return std::unique_ptr<util::guard<T>>{new impl{std::move(vec)}};
}
template<typename T>
std::function<bool (typename detail::implicit_conversions<T>::type const&)>
std::unique_ptr<util::guard<typename detail::strip_and_convert<T>::type>>
any_of(std::initializer_list<T> list) const
{
typedef typename detail::implicit_conversions<T>::type ctype;
vector<ctype> vec;
typedef typename detail::strip_and_convert<T>::type sc_type;
std::vector<sc_type> vec;
vec.reserve(list.size());
for (auto& i : list) vec.emplace_back(i);
//vec.insert(vec.begin(), list.begin(), list.end());
return [vec](ctype const& value)
{
return std::any_of(vec.begin(), vec.end(),
[&](ctype const& v) { return value == v; });
};
return this->any_of(std::move(vec));
}
template<typename T>
std::function<bool (T const&)> none_of(std::vector<T> vec) const
std::unique_ptr<util::guard<typename detail::strip_and_convert<T>::type>>
starts_with(T substr) const
{
return [=](T const& value)
typedef typename detail::strip_and_convert<T>::type str_type;
struct impl : util::guard<str_type>
{
return std::none_of(vec.begin(), vec.end(),
[&](T const& v) { return value == v; });
str_type m_str;
impl(str_type str) : m_str(std::move(str)) { }
bool operator()(str_type const& str) const
{
return m_str.size() <= str.size()
&& std::equal(m_str.begin(), m_str.end(), str.begin());
}
};
return std::unique_ptr<util::guard<str_type>>{new impl{std::move(substr)}};
}
};
static constexpr placeholder _x;
static constexpr pattern_placeholder _x;
template<typename... Args>
void _on(Args&&...)
......@@ -109,6 +121,7 @@ size_t test__match()
{
CPPA_TEST(test__match);
/*
auto xfun = _x.any_of<int>({1, 2, 3});
cout << "xfun(4) = " << xfun(4) << endl;
cout << "xfun(2) = " << xfun(2) << endl;
......@@ -126,6 +139,7 @@ size_t test__match()
auto hfun = _x.any_of({"-h", "--help"});
cout << "hfun(-h) = " << hfun("-h") << endl;
cout << "hfun(-r) = " << hfun("-r") << endl;
*/
bool invoked = false;
match("abc")
......@@ -138,6 +152,39 @@ size_t test__match()
if (!invoked) { CPPA_ERROR("match(\"abc\") failed"); }
invoked = false;
match_each({"-h", "-wtf"})
(
on(_x.any_of({"-h", "--help"})) >> []()
{
cout << "AWESOME!!!" << endl;
},
on(_x.starts_with("-")) >> [](std::string const& str)
{
match_each(str.begin() + 1, str.end())
(
on<char>() >> [](char c)
//on(_x.any_of({'w', 't', 'f'})) >> [](char c)
{
cout << c;
},
others() >> [](any_tuple const& tup)
{
cout << "oops: " << to_string(tup) << endl;
}
);
cout << endl;
}
);
match(5)
(
on(_x < 6) >> [](int i)
{
cout << i << " < 6 !!! :)" << endl;
}
);
vector<string> vec{"a", "b", "c"};
match(vec)
(
......
......@@ -190,6 +190,37 @@ size_t test__pattern()
);
CPPA_CHECK_EQUAL(true, invoked);
pattern<char, short, int, long> p12;
pattern<char, short, int, long> p13{char(0), short(1), int(2), long(3)};
any_tuple t4 = make_cow_tuple(char(0), short(1), int(2), long(3));
CPPA_CHECK((detail::matches(t4, p12)));
CPPA_CHECK(p12._matches_values(t4));
CPPA_CHECK((detail::matches(t4, p13)));
CPPA_CHECK(p13._matches_values(t4));
invoked = false;
match('a')
(
on<char>() >> [&](char c)
{
invoked = true;
CPPA_CHECK_EQUAL('a', c);
}
);
CPPA_CHECK_EQUAL(true, invoked);
invoked = false;
const char muhaha = 'a';
match(muhaha)
(
on<char>() >> [&](char c)
{
invoked = true;
CPPA_CHECK_EQUAL('a', c);
}
);
CPPA_CHECK_EQUAL(true, invoked);
/*
CPPA_CHECK(p0(x));
CPPA_CHECK(p1(x));
......
......@@ -89,11 +89,6 @@ size_t test__uniform_type()
"@channel", // cppa::channel_ptr
"cppa::util::duration"
};
if (sizeof(double) != sizeof(long double))
{
// long double is only present if it's not an alias for double
expected.insert("long double");
}
// holds the type names we see at runtime
std::set<std::string> found;
// fetch all available type names
......
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