Commit 58318857 authored by neverlord's avatar neverlord

match() and match_each()

parent a7c57cea
......@@ -74,7 +74,6 @@ nobase_library_include_HEADERS = \
cppa/actor_proxy.hpp \
cppa/announce.hpp \
cppa/any_tuple.hpp \
cppa/any_tuple_view.hpp \
cppa/anything.hpp \
cppa/atom.hpp \
cppa/attachable.hpp \
......@@ -96,6 +95,7 @@ nobase_library_include_HEADERS = \
cppa/detail/boxed.hpp \
cppa/detail/buffer.hpp \
cppa/detail/channel.hpp \
cppa/detail/container_tuple_view.hpp \
cppa/detail/converted_thread_context.hpp \
cppa/detail/decorated_tuple.hpp \
cppa/detail/default_uniform_type_info_impl.hpp \
......@@ -111,6 +111,7 @@ nobase_library_include_HEADERS = \
cppa/detail/list_member.hpp \
cppa/detail/mailman.hpp \
cppa/detail/map_member.hpp \
cppa/detail/matches.hpp \
cppa/detail/mock_scheduler.hpp \
cppa/detail/native_socket.hpp \
cppa/detail/network_manager.hpp \
......@@ -132,6 +133,7 @@ nobase_library_include_HEADERS = \
cppa/detail/to_uniform_name.hpp \
cppa/detail/tuple_cast_impl.hpp \
cppa/detail/tuple_vals.hpp \
cppa/detail/tuple_view.hpp \
cppa/detail/type_to_ptype.hpp \
cppa/detail/types_array.hpp \
cppa/detail/unboxed.hpp \
......@@ -172,7 +174,6 @@ nobase_library_include_HEADERS = \
cppa/to_string.hpp \
cppa/tuple.hpp \
cppa/tuple_cast.hpp \
cppa/tuple_view.hpp \
cppa/type_value_pair.hpp \
cppa/uniform_type_info.hpp \
cppa/util/abstract_uniform_type_info.hpp \
......
......@@ -11,7 +11,6 @@ src/uniform_type_info.cpp
cppa/config.hpp
unit_testing/test__tuple.cpp
cppa/detail/abstract_tuple.hpp
cppa/tuple_view.hpp
cppa/detail/tuple_vals.hpp
cppa/detail/decorated_tuple.hpp
cppa/cow_ptr.hpp
......@@ -234,7 +233,6 @@ cppa/tuple_cast.hpp
cppa/util/is_mutable_ref.hpp
cppa/util/is_manipulator.hpp
cppa/util/apply_tuple.hpp
cppa/any_tuple_view.hpp
benchmarks/Matching.scala
benchmarks/matching.cpp
benchmarks/matching.erl
......@@ -256,3 +254,7 @@ cppa/intrusive/forward_iterator.hpp
unit_testing/test__intrusive_containers.cpp
examples/dancing_kirby.cpp
cppa/util/is_comparable.hpp
cppa/detail/tuple_view.hpp
cppa/detail/container_tuple_view.hpp
cppa/detail/matches.hpp
unit_testing/test__match.cpp
......@@ -34,7 +34,16 @@
#include "cppa/tuple.hpp"
#include "cppa/config.hpp"
#include "cppa/cow_ptr.hpp"
#include "cppa/util/rm_ref.hpp"
#include "cppa/util/enable_if.hpp"
#include "cppa/util/disable_if.hpp"
#include "cppa/util/is_iterable.hpp"
#include "cppa/detail/tuple_view.hpp"
#include "cppa/detail/abstract_tuple.hpp"
#include "cppa/detail/container_tuple_view.hpp"
#include "cppa/detail/implicit_conversions.hpp"
namespace cppa {
......@@ -149,19 +158,99 @@ class any_tuple
return m_vals->impl_type();
}
template<typename T>
static inline any_tuple view(T&& value,
typename util::enable_if<util::is_iterable<typename util::rm_ref<T>::type> >::type* = 0)
{
static constexpr bool can_optimize = std::is_reference<T>::value
&& !std::is_const<T>::value;
std::integral_constant<bool, can_optimize> token;
return any_tuple{container_view(std::forward<T>(value), token)};
}
template<typename T>
static inline any_tuple view(T&& value,
typename util::disable_if<util::is_iterable<typename util::rm_ref<T>::type> >::type* = 0)
{
typedef typename util::rm_ref<T>::type vtype;
typedef typename detail::implicit_conversions<vtype>::type converted;
static_assert(util::is_legal_tuple_type<converted>::value,
"T is not a valid tuple type");
static constexpr bool can_optimize =
std::is_same<converted, vtype>::value
&& std::is_reference<T>::value
&& !std::is_const<T>::value;
std::integral_constant<bool, can_optimize> token;
return any_tuple{simple_view(std::forward<T>(value), token)};
}
private:
cow_ptr<detail::abstract_tuple> m_vals;
explicit any_tuple(cow_ptr<detail::abstract_tuple> const& vals);
typedef detail::abstract_tuple* tup_ptr;
template<typename T>
static inline tup_ptr simple_view(T& value,
std::integral_constant<bool, true>)
{
return new detail::tuple_view<T>(&value);
}
template<typename First, typename Second>
static inline tup_ptr simple_view(std::pair<First, Second>& p,
std::integral_constant<bool, true>)
{
return new detail::tuple_view<First, Second>(&p.first, &p.second);
}
template<typename T>
static inline tup_ptr simple_view(T&& value,
std::integral_constant<bool, false>)
{
typedef typename util::rm_ref<T>::type vtype;
typedef typename detail::implicit_conversions<vtype>::type converted;
return new detail::tuple_vals<converted>(std::forward<T>(value));
}
template<typename First, typename Second>
static inline any_tuple view(std::pair<First, Second> p,
std::integral_constant<bool, false>)
{
return new detail::tuple_vals<First, Second>(std::move(p.first),
std::move(p.second));
}
template<typename T>
static inline detail::abstract_tuple* container_view(T& value,
std::integral_constant<bool, true>)
{
return new detail::container_tuple_view<T>(&value);
}
template<typename T>
static inline detail::abstract_tuple* container_view(T&& value,
std::integral_constant<bool, false>)
{
typedef typename util::rm_ref<T>::type ctype;
return new detail::container_tuple_view<T>(new ctype(std::forward<T>(value)));
}
};
/**
* @relates any_tuple
*/
inline bool operator==(any_tuple const& lhs, any_tuple const& rhs)
{
return lhs.equals(rhs);
}
/**
* @relates any_tuple
*/
inline bool operator!=(any_tuple const& lhs, any_tuple const& rhs)
{
return !(lhs == rhs);
......
......@@ -28,132 +28,78 @@
\******************************************************************************/
#ifndef ANY_TUPLE_VIEW_HPP
#define ANY_TUPLE_VIEW_HPP
#ifndef CONTAINER_TUPLE_VIEW_HPP
#define CONTAINER_TUPLE_VIEW_HPP
#include <set>
#include <list>
#include <vector>
#include <utility>
#include <iterator>
#include <algorithm>
#include "cppa/tuple.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/tuple_view.hpp"
#include "cppa/uniform_type_info.hpp"
#include "cppa/util/enable_if.hpp"
#include "cppa/util/is_primitive.hpp"
#include "cppa/detail/types_array.hpp"
#include "cppa/detail/tuple_vals.hpp"
#include "cppa/detail/object_array.hpp"
#include "cppa/detail/abstract_tuple.hpp"
#include "cppa/detail/disablable_delete.hpp"
namespace cppa {
namespace cppa { namespace detail {
class any_tuple_view
template<class Container>
class container_tuple_view : public abstract_tuple
{
typedef std::vector<type_value_pair> vector_type;
public:
vector_type m_values;
typedef typename Container::value_type value_type;
template<typename T>
void from_list(T const& list)
container_tuple_view(Container* c, bool take_ownership = false) : m_ptr(c)
{
auto& arr = detail::static_types_array<typename T::value_type>::arr;
for (auto i = list.begin(); i != list.end(); ++i)
{
m_values.push_back(std::make_pair(arr[0], &(*i)));
}
CPPA_REQUIRE(c != nullptr);
if (!take_ownership) m_ptr.get_deleter().disable();
}
public:
class const_iterator;
friend class const_iterator;
any_tuple_view(any_tuple_view&&) = default;
any_tuple_view(any_tuple_view const&) = default;
any_tuple_view& operator=(any_tuple_view&&) = default;
any_tuple_view& operator=(any_tuple_view const&) = default;
any_tuple_view(any_tuple& tup)
{
if (tup.size() > 0)
size_t size() const
{
// force tuple to detach
tup.mutable_at(0);
std::back_insert_iterator<vector_type> back_iter{m_values};
std::copy(tup.begin(), tup.end(), back_iter);
}
return m_ptr->size();
}
template<typename... T>
any_tuple_view(tuple_view<T...> const& tup)
abstract_tuple* copy() const
{
for (size_t i = 0; i < tup.size(); ++i)
{
m_values.push_back(std::make_pair(tup.type_at(i), tup.at(i)));
}
return new container_tuple_view{new Container(*m_ptr), true};
}
template<typename F, typename S>
any_tuple_view(std::pair<F, S> const& pair)
void const* at(size_t pos) const
{
auto& arr = detail::static_types_array<F, S>::arr;
m_values.push_back(std::make_pair(arr[0], &pair.first));
m_values.push_back(std::make_pair(arr[1], &pair.second));
CPPA_REQUIRE(pos < size());
auto i = m_ptr->begin();
std::advance(i, pos);
return &(*i);
}
template<typename T>
any_tuple_view(std::set<T>& vec) { from_list(vec); }
template<typename T>
any_tuple_view(std::list<T>& vec) { from_list(vec); }
template<typename T>
any_tuple_view(std::vector<T>& vec) { from_list(vec); }
template<typename T>
any_tuple_view(T& val,
typename util::enable_if<util::is_primitive<T> >::type* = 0)
void* mutable_at(size_t pos)
{
auto& arr = detail::static_types_array<T>::arr;
m_values.push_back(std::make_pair(arr[0], &val));
CPPA_REQUIRE(pos < size());
auto i = m_ptr->begin();
std::advance(i, pos);
return &(*i);
}
inline vector_type const& vals() const { return m_values; }
inline size_t size() const { return m_values.size(); }
inline void const* at(size_t p) const { return m_values[p].second; }
void* mutable_at(size_t p) { return const_cast<void*>(m_values[p].second); }
inline uniform_type_info const* type_at(size_t p) const
uniform_type_info const* type_at(size_t pos) const
{
return m_values[p].first;
CPPA_REQUIRE(pos < size());
return static_types_array<value_type>::arr[0];
}
inline bool empty() const { return m_values.empty(); }
template<typename T>
inline T const& get_as(size_t p) const
void const* type_token() const
{
return *reinterpret_cast<T const*>(at(p));
return &(typeid(Container));
}
inline std::type_info const& impl_type() const
std::type_info const* impl_type() const
{
// this is a lie, but the pattern matching implementation
// needs to do a full runtime check of each element
return typeid(detail::object_array);
return &(typeid(detail::object_array));
}
private:
std::unique_ptr<Container, disablable_delete<Container> > m_ptr;
};
} // namespace cppa
} } // namespace cppa::detail
#endif // ANY_TUPLE_VIEW_HPP
#endif // CONTAINER_TUPLE_VIEW_HPP
......@@ -36,7 +36,6 @@
#include <cstddef>
#include <cstdint>
#include "cppa/match.hpp"
#include "cppa/pattern.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/tuple_cast.hpp"
......@@ -45,6 +44,7 @@
#include "cppa/util/fixed_vector.hpp"
#include "cppa/util/callable_trait.hpp"
#include "cppa/detail/matches.hpp"
#include "cppa/detail/intermediate.hpp"
// forward declaration
......@@ -90,11 +90,11 @@ struct abstract_invokable : public invokable
}
bool types_match(any_tuple const& value) const
{
return match_types(value, m_pattern);
return matches_types(value, m_pattern);
}
bool could_invoke(any_tuple const& value) const
{
return match(value, m_pattern);
return matches(value, m_pattern);
}
};
......@@ -218,9 +218,9 @@ class invokable_impl<true, 0, Fun, Tuple, Pattern> : public abstract_invokable<T
: super(std::forward<Args>(args)...), m_iimpl(std::forward<F>(fun))
{
}
bool invoke(any_tuple const& data) const
bool invoke(any_tuple const& value) const
{
return match(data, this->m_pattern) ? m_iimpl() : false;
return matches(value, this->m_pattern) ? m_iimpl() : false;
}
bool unsafe_invoke(any_tuple const& value) const
{
......@@ -228,7 +228,7 @@ class invokable_impl<true, 0, Fun, Tuple, Pattern> : public abstract_invokable<T
}
intermediate* get_intermediate(any_tuple const& value)
{
return match(value, this->m_pattern) ? &m_iimpl : nullptr;
return matches(value, this->m_pattern) ? &m_iimpl : nullptr;
}
intermediate* get_unsafe_intermediate(any_tuple const& value)
{
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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 MATCHES_HPP
#define MATCHES_HPP
#include "cppa/pattern.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/util/type_list.hpp"
namespace cppa { namespace detail {
template<wildcard_position, typename...>
struct matcher;
template<typename... T>
struct matcher<wildcard_position::nil, T...>
{
static inline bool tmatch(any_tuple const& tup)
{
// match implementation type if possible
auto impl = tup.impl_type();
// the impl_type of both decorated_tuple and tuple_vals
// is &typeid(type_list<T...>)
auto tinf = detail::static_type_list<T...>::list;
if (impl == tinf || *impl == *tinf)
{
return true;
}
// always use a full dynamic match for object arrays
else if (*impl == typeid(detail::object_array)
&& tup.size() == sizeof...(T))
{
auto& tarr = detail::static_types_array<T...>::arr;
return std::equal(tup.begin(), tup.end(), tarr.begin(),
detail::types_only_eq);
}
return false;
}
static inline bool tmatch(any_tuple const& tup,
util::fixed_vector<size_t, sizeof...(T)>& mv)
{
if (tmatch(tup))
{
mv.resize(sizeof...(T));
std::iota(mv.begin(), mv.end(), 0);
return true;
}
return false;
}
static inline bool vmatch(any_tuple const& tup, pattern<T...> const& ptrn)
{
CPPA_REQUIRE(tup.size() == sizeof...(T));
return std::equal(ptrn.begin(), ptrn.vend(), tup.begin(),
detail::values_only_eq_v2);
}
};
template<typename... T>
struct matcher<wildcard_position::trailing, T...>
{
static constexpr size_t size = sizeof...(T) - 1;
static inline bool tmatch(any_tuple const& tup)
{
if (tup.size() >= size)
{
auto& tarr = static_types_array<T...>::arr;
auto begin = tup.begin();
return std::equal(begin, begin + size, tarr.begin(),
detail::types_only_eq);
}
return false;
}
static inline bool tmatch(any_tuple const& tup,
util::fixed_vector<size_t, size>& mv)
{
if (tmatch(tup))
{
mv.resize(size);
std::iota(mv.begin(), mv.end(), 0);
return true;
}
return false;
}
static inline bool vmatch(any_tuple const& tup, pattern<T...> const& ptrn)
{
return std::equal(ptrn.begin(), ptrn.vend(), tup.begin(),
detail::values_only_eq_v2);
}
};
template<>
struct matcher<wildcard_position::leading, anything>
{
static inline bool tmatch(any_tuple const&)
{
return true;
}
static inline bool tmatch(any_tuple const&, util::fixed_vector<size_t, 0>&)
{
return true;
}
static inline bool vmatch(any_tuple const&, pattern<anything> const&)
{
return true;
}
};
template<typename... T>
struct matcher<wildcard_position::leading, T...>
{
static constexpr size_t size = sizeof...(T) - 1;
static inline bool tmatch(any_tuple const& tup)
{
auto tup_size = tup.size();
if (tup_size >= size)
{
auto& tarr = static_types_array<T...>::arr;
auto begin = tup.begin();
begin += (tup_size - size);
return std::equal(begin, tup.end(),
(tarr.begin() + 1), // skip 'anything'
detail::types_only_eq);
}
return false;
}
static inline bool tmatch(any_tuple const& tup,
util::fixed_vector<size_t, size>& mv)
{
if (tmatch(tup))
{
mv.resize(size);
std::iota(mv.begin(), mv.end(), tup.size() - size);
return true;
}
return false;
}
static inline bool vmatch(any_tuple const& tup, pattern<T...> const& ptrn)
{
auto tbegin = tup.begin();
// skip unmatched elements
tbegin += (tup.size() - size);
// skip leading wildcard ++(ptr.begin())
return std::equal(++(ptrn.begin()), ptrn.vend(), tbegin,
detail::values_only_eq_v2);
}
};
template<typename... T>
struct matcher<wildcard_position::in_between, T...>
{
static constexpr int signed_wc_pos =
util::tl_find<util::type_list<T...>, anything>::value;
static constexpr size_t size = sizeof...(T);
static constexpr size_t wc_pos = static_cast<size_t>(signed_wc_pos);
static_assert( signed_wc_pos != -1
&& signed_wc_pos != 0
&& signed_wc_pos != (sizeof...(T) - 1),
"illegal wildcard position");
static inline bool tmatch(any_tuple const& tup)
{
auto tup_size = tup.size();
if (tup_size >= size)
{
auto& tarr = static_types_array<T...>::arr;
// first range [0, X1)
auto begin = tup.begin();
auto end = begin + wc_pos;
if (std::equal(begin, end, tarr.begin(), detail::types_only_eq))
{
// second range [X2, N)
begin = end = tup.end();
begin -= (size - (wc_pos + 1));
auto arr_begin = tarr.begin() + (wc_pos + 1);
return std::equal(begin, end, arr_begin, detail::types_only_eq);
}
}
return false;
}
static inline bool tmatch(any_tuple const& tup,
util::fixed_vector<size_t, size - 1>& mv)
{
if (tmatch(tup))
{
// first range
mv.resize(size - 1);
auto begin = mv.begin();
std::iota(begin, begin + wc_pos, 0);
// second range
begin = mv.begin() + wc_pos;
std::iota(begin, mv.end(), tup.size() - (size - (wc_pos + 1)));
return true;
}
return false;
}
static inline bool vmatch(any_tuple const& tup, pattern<T...> const& ptrn)
{
// first range
auto tbegin = tup.begin();
auto tend = tbegin + wc_pos;
if (std::equal(tbegin, tend, ptrn.begin(), detail::values_only_eq))
{
// second range
tbegin = tend = tup.end();
tbegin -= (size - (wc_pos + 1));
auto pbegin = ptrn.begin();
pbegin += (wc_pos + 1);
return std::equal(tbegin, tend, pbegin, detail::values_only_eq);
}
return false;
}
};
template<typename... T>
struct matcher<wildcard_position::multiple, T...>
{
static constexpr size_t wc_count =
util::tl_count<util::type_list<T...>, is_anything>::value;
static_assert(sizeof...(T) > wc_count, "only wildcards given");
template<class TupleIter, class PatternIter,
class Push, class Commit, class Rollback>
static bool match(TupleIter tbegin, TupleIter tend,
PatternIter pbegin, PatternIter pend,
Push&& push, Commit&& commit, Rollback&& rollback)
{
while (!(pbegin == pend && tbegin == tend))
{
if (pbegin == pend)
{
// reached end of pattern while some values remain unmatched
return false;
}
else if (pbegin.type() == nullptr) // nullptr == wildcard (anything)
{
// perform submatching
++pbegin;
// always true at the end of the pattern
if (pbegin == pend) return true;
// safe current mapping as fallback
commit();
// iterate over tuple values until we found a match
for (; tbegin != tend; ++tbegin)
{
if (match(tbegin, tend, pbegin, pend,
push, commit, rollback))
{
return true;
}
// restore mapping to fallback (delete invalid mappings)
rollback();
}
return false; // no submatch found
}
// compare types
else if (tbegin.type() == pbegin.type()) push(tbegin);
// no match
else return false;
// next iteration
++tbegin;
++pbegin;
}
return true; // pbegin == pend && tbegin == tend
}
static inline bool tmatch(any_tuple const& tup)
{
auto& tarr = static_types_array<T...>::arr;
if (tup.size() >= (sizeof...(T) - wc_count))
{
return match(tup.begin(), tup.end(), tarr.begin(), tarr.end(),
[](any_tuple::const_iterator const&) { },
[]() { },
[]() { });
}
return false;
}
template<class MappingVector>
static inline bool tmatch(any_tuple const& tup, MappingVector& mv)
{
auto& tarr = static_types_array<T...>::arr;
if (tup.size() >= (sizeof...(T) - wc_count))
{
size_t commited_size = 0;
return match(tup.begin(), tup.end(), tarr.begin(), tarr.end(),
[&](any_tuple::const_iterator const& iter)
{
mv.push_back(iter.position());
},
[&]() { commited_size = mv.size(); },
[&]() { mv.resize(commited_size); });
}
return false;
}
static inline bool vmatch(any_tuple const& tup,
pattern<T...> const& ptrn,
typename pattern<T...>::mapping_vector const& mv)
{
auto i = mv.begin();
for (auto j = ptrn.begin(); j != ptrn.end(); ++j)
{
if (j.type() != nullptr)
{
if ( j.value() != nullptr
&& j.type()->equals(tup.at(*i), j.value()) == false)
{
return false;
}
++i;
}
}
}
};
// implementation for zero or one wildcards
template<wildcard_position PC, typename... Ts>
struct match_impl
{
static inline bool _(any_tuple const& tup)
{
return detail::matcher<PC, Ts...>::tmatch(tup);
}
template<size_t Size>
static inline bool _(any_tuple const& tup,
util::fixed_vector<size_t, Size>& mv)
{
return detail::matcher<PC, Ts...>::tmatch(tup, mv);
}
static inline bool _(any_tuple const& tup,
pattern<Ts...> const& p)
{
return detail::matcher<PC, Ts...>::tmatch(tup)
&& ( p.has_values() == false
|| detail::matcher<PC, Ts...>::vmatch(tup, p));
}
static inline bool _(any_tuple const& tup,
pattern<Ts...> const& p,
typename pattern<Ts...>::mapping_vector& mv)
{
return detail::matcher<PC, Ts...>::tmatch(tup, mv)
&& ( p.has_values() == false
|| detail::matcher<PC, Ts...>::vmatch(tup, p));
}
};
// implementation for multiple wildcards
template<typename... Ts>
struct match_impl<wildcard_position::multiple, Ts...>
{
static constexpr auto PC = wildcard_position::multiple;
static inline bool _(any_tuple const& tup)
{
return detail::matcher<PC, Ts...>::tmatch(tup);
}
template<size_t Size>
static inline bool _(any_tuple const& tup,
util::fixed_vector<size_t, Size>& mv)
{
return detail::matcher<PC, Ts...>::tmatch(tup, mv);
}
static inline bool _(any_tuple const& tup, pattern<Ts...> const& p)
{
if (p.has_values())
{
typename pattern<Ts...>::mapping_vector mv;
return detail::matcher<PC, Ts...>::tmatch(tup, mv)
&& detail::matcher<PC, Ts...>::vmatch(tup, p, mv);
}
return detail::matcher<PC, Ts...>::tmatch(tup);
}
static inline bool _(any_tuple const& tup, pattern<Ts...> const& p,
typename pattern<Ts...>::mapping_vector& mv)
{
if (p.has_values())
{
typename pattern<Ts...>::mapping_vector mv;
return detail::matcher<PC, Ts...>::tmatch(tup, mv)
&& detail::matcher<PC, Ts...>::vmatch(tup, p, mv);
}
return detail::matcher<PC, Ts...>::tmatch(tup, mv);
}
};
/*
* @brief Returns true if this tuple matches the pattern <tt>{Ts...}</tt>.
*/
template<typename... Ts>
bool matches(any_tuple const& tup)
{
typedef util::type_list<Ts...> tl;
return detail::match_impl<get_wildcard_position<tl>(), Ts...>::_(tup);
}
/*
* @brief Returns true if this tuple matches the pattern <tt>{Ts...}</tt>.
*/
template<typename... Ts>
bool matches(any_tuple const& tup,
util::fixed_vector<
size_t,
util::tl_count_not<
util::type_list<Ts...>,
is_anything>::value>& mv)
{
typedef util::type_list<Ts...> tl;
return detail::match_impl<get_wildcard_position<tl>(), Ts...>::_(tup, mv);
}
/*
* @brief Returns true if this tuple matches @p pn.
*/
template<typename... Ts>
bool matches(any_tuple const& tup, pattern<Ts...> const& pn)
{
typedef util::type_list<Ts...> tl;
return detail::match_impl<get_wildcard_position<tl>(), Ts...>::_(tup, pn);
}
/*
* @brief Returns true if this tuple matches @p pn.
*/
template<typename... Ts>
bool matches(any_tuple const& tup, pattern<Ts...> const& pn,
typename pattern<Ts...>::mapping_vector& mv)
{
typedef util::type_list<Ts...> tl;
return detail::match_impl<get_wildcard_position<tl>(), Ts...>::_(tup,
pn,
mv);
}
/*
* @brief Returns true if this tuple matches the pattern <tt>{Ts...}</tt>
* (does not match for values).
*/
template<typename... Ts>
inline bool matches_types(any_tuple const& tup, pattern<Ts...> const&)
{
return matches<Ts...>(tup);
}
} } // namespace cppa::detail
#endif // MATCHES_HPP
......@@ -50,6 +50,18 @@ uniform_type_info const* uniform_typeid(std::type_info const&);
namespace cppa { namespace detail {
template<typename T>
inline void* ptr_to(T& what) { return &what; }
template<typename T>
inline void const* ptr_to(T const& what) { return &what; }
template<typename T>
inline void* ptr_to(T* what) { return what; }
template<typename T>
inline void const* ptr_to(T const* what) { return what; }
/*
* "enhanced std::tuple"
*/
......@@ -153,7 +165,7 @@ struct tdata<Head, Tail...> : tdata<Tail...>
inline void const* at(size_t p) const
{
return (p == 0) ? &head : super::at(p-1);
return (p == 0) ? ptr_to(head) : super::at(p-1);
}
inline uniform_type_info const* type_at(size_t p) const
......@@ -215,7 +227,7 @@ struct tdata<option<Head>, Tail...> : tdata<Tail...>
inline void const* at(size_t p) const
{
return (p == 0) ? &head : super::at(p-1);
return (p == 0) ? ptr_to(head) : super::at(p-1);
}
inline uniform_type_info const* type_at(size_t p) const
......
......@@ -31,10 +31,11 @@
#ifndef TUPLE_CAST_IMPL_HPP
#define TUPLE_CAST_IMPL_HPP
#include "cppa/match.hpp"
#include "cppa/pattern.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/type_value_pair.hpp"
#include "cppa/detail/matches.hpp"
#include "cppa/detail/tuple_vals.hpp"
#include "cppa/detail/types_array.hpp"
#include "cppa/detail/object_array.hpp"
......@@ -60,22 +61,19 @@ struct tuple_cast_impl
static constexpr size_t first_wc =
static_cast<size_t>(util::tl_find<util::type_list<T...>, anything>::value);
typedef util::fixed_vector<size_t, size> mapping_vector;
template<class Tuple>
static inline option<Result> safe(Tuple const& tup)
static inline option<Result> safe(any_tuple const& tup)
{
mapping_vector mv;
if (match<T...>(tup, mv)) return {Result::from(tup.vals(), mv)};
if (matches<T...>(tup, mv)) return {Result::from(tup.vals(), mv)};
return {};
}
template<class Tuple>
static inline option<Result> safe(Tuple const& tup, pattern<T...> const& p)
static inline option<Result> safe(any_tuple const& tup, pattern<T...> const& p)
{
mapping_vector mv;
if (match(tup, p, mv)) return {Result::from(tup.vals(), mv)};
if (matches(tup, p, mv)) return {Result::from(tup.vals(), mv)};
return {};
}
template<class Tuple>
static inline option<Result> unsafe(Tuple const& tup, pattern<T...> const& p)
static inline option<Result> unsafe(any_tuple const& tup, pattern<T...> const& p)
{
mapping_vector mv;
if (WP == wildcard_position::in_between)
......@@ -94,12 +92,11 @@ struct tuple_cast_impl
}
else
{
if (match(tup, p, mv)) return {Result::from(tup.vals(), mv)};
if (matches(tup, p, mv)) return {Result::from(tup.vals(), mv)};
}
return {};
}
template<class Tuple>
static inline Result force(Tuple const& tup, pattern<T...> const& p)
static inline Result force(any_tuple const& tup, pattern<T...> const& p)
{
mapping_vector mv;
if (WP == wildcard_position::in_between)
......@@ -115,7 +112,7 @@ struct tuple_cast_impl
}
else
{
match(tup, p, mv);
matches(tup, p, mv);
return {Result::from(tup.vals(), mv)};
}
}
......@@ -124,20 +121,17 @@ struct tuple_cast_impl
template<class Result, typename... T>
struct tuple_cast_impl<wildcard_position::nil, Result, T...>
{
template<class Tuple>
static inline option<Result> safe(Tuple const& tup)
static inline option<Result> safe(any_tuple const& tup)
{
if (match<T...>(tup)) return {Result::from(tup.vals())};
if (matches<T...>(tup)) return {Result::from(tup.vals())};
return {};
}
template<class Tuple>
static inline option<Result> safe(Tuple const& tup, pattern<T...> const& p)
static inline option<Result> safe(any_tuple const& tup, pattern<T...> const& p)
{
if (match(tup, p)) return {Result::from(tup.vals())};
if (matches(tup, p)) return {Result::from(tup.vals())};
return {};
}
template<class Tuple>
static inline option<Result> unsafe(Tuple const& tup, pattern<T...> const& p)
static inline option<Result> unsafe(any_tuple const& tup, pattern<T...> const& p)
{
if ( p.has_values() == false
|| matcher<wildcard_position::nil, T...>::vmatch(tup, p))
......@@ -146,8 +140,7 @@ struct tuple_cast_impl<wildcard_position::nil, Result, T...>
}
return {};
}
template<class Tuple>
static inline Result force(Tuple const& tup, pattern<T...> const&)
static inline Result force(any_tuple const& tup, pattern<T...> const&)
{
return {Result::from(tup.vals())};
}
......@@ -157,8 +150,7 @@ template<class Result, typename... T>
struct tuple_cast_impl<wildcard_position::trailing, Result, T...>
: tuple_cast_impl<wildcard_position::nil, Result, T...>
{
template<class Tuple>
static inline option<Result> unsafe(Tuple const& tup, pattern<T...> const& p)
static inline option<Result> unsafe(any_tuple const& tup, pattern<T...> const& p)
{
if ( p.has_values() == false
|| matcher<wildcard_position::trailing, T...>::vmatch(tup, p))
......@@ -167,8 +159,7 @@ struct tuple_cast_impl<wildcard_position::trailing, Result, T...>
}
return {};
}
template<class Tuple>
static inline Result force(Tuple const& tup, pattern<T...> const&)
static inline Result force(any_tuple const& tup, pattern<T...> const&)
{
return {Result::from(tup.vals())};
}
......@@ -177,22 +168,19 @@ struct tuple_cast_impl<wildcard_position::trailing, Result, T...>
template<class Result, typename... T>
struct tuple_cast_impl<wildcard_position::leading, Result, T...>
{
template<class Tuple>
static inline option<Result> safe(Tuple const& tup)
static inline option<Result> safe(any_tuple const& tup)
{
size_t o = tup.size() - (sizeof...(T) - 1);
if (match<T...>(tup)) return {Result::offset_subtuple(tup.vals(), o)};
if (matches<T...>(tup)) return {Result::offset_subtuple(tup.vals(), o)};
return {};
}
template<class Tuple>
static inline option<Result> safe(Tuple const& tup, pattern<T...> const& p)
static inline option<Result> safe(any_tuple const& tup, pattern<T...> const& p)
{
size_t o = tup.size() - (sizeof...(T) - 1);
if (match(tup, p)) return {Result::offset_subtuple(tup.vals(), o)};
if (matches(tup, p)) return {Result::offset_subtuple(tup.vals(), o)};
return {};
}
template<class Tuple>
static inline option<Result> unsafe(Tuple const& tup, pattern<T...> const& p)
static inline option<Result> unsafe(any_tuple const& tup, pattern<T...> const& p)
{
if ( p.has_values() == false
|| matcher<wildcard_position::leading, T...>::vmatch(tup, p))
......@@ -202,8 +190,7 @@ struct tuple_cast_impl<wildcard_position::leading, Result, T...>
}
return {};
}
template<class Tuple>
static inline Result force(Tuple const& tup, pattern<T...> const&)
static inline Result force(any_tuple const& tup, pattern<T...> const&)
{
size_t o = tup.size() - (sizeof...(T) - 1);
return Result::offset_subtuple(tup.vals(), o);
......
......@@ -53,22 +53,23 @@ class tuple_vals : public abstract_tuple
typedef abstract_tuple super;
public:
typedef tdata<ElementTypes...> data_type;
typedef types_array<ElementTypes...> element_types;
data_type m_data;
static types_array<ElementTypes...> m_types;
public:
tuple_vals() : m_data() { }
tuple_vals(tuple_vals const& other) : super(), m_data(other.m_data) { }
tuple_vals(ElementTypes const&... args) : m_data(args...) { }
inline data_type& data()
{
return m_data;
}
inline data_type const& data() const
{
return m_data;
......@@ -92,6 +93,7 @@ class tuple_vals : public abstract_tuple
void* mutable_at(size_t pos)
{
CPPA_REQUIRE(pos < size());
return const_cast<void*>(at(pos));
}
......@@ -122,6 +124,12 @@ class tuple_vals : public abstract_tuple
return detail::static_type_list<ElementTypes...>::list;
}
private:
data_type m_data;
static types_array<ElementTypes...> m_types;
};
template<typename... ElementTypes>
......
......@@ -31,156 +31,108 @@
#ifndef TUPLE_VIEW_HPP
#define TUPLE_VIEW_HPP
#include <vector>
#include <cstring>
#include "cppa/util/static_foreach.hpp"
#include "cppa/get.hpp"
#include "cppa/tuple.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/detail/tuple_vals.hpp"
#include "cppa/detail/abstract_tuple.hpp"
#include "cppa/util/at.hpp"
#include "cppa/util/type_list.hpp"
#include "cppa/util/fixed_vector.hpp"
#include "cppa/util/compare_tuples.hpp"
namespace cppa { namespace detail {
#include "cppa/detail/decorated_tuple.hpp"
namespace cppa {
template<size_t N, typename... Types>
typename util::at<N, Types...>::type& get_ref(tuple_view<Types...>& t);
struct tuple_view_copy_helper
{
size_t pos;
abstract_tuple* target;
tuple_view_copy_helper(abstract_tuple* trgt) : pos(0), target(trgt) { }
template<typename T>
void operator()(T const* value)
{
*(reinterpret_cast<T*>(target->mutable_at(pos++))) = *value;
}
};
/**
* @brief Describes a view of an fixed-length tuple.
*/
template<typename... ElementTypes>
class tuple_view
class tuple_view : public abstract_tuple
{
template<size_t N, typename... Types>
friend typename util::at<N, Types...>::type& get_ref(tuple_view<Types...>&);
static_assert(sizeof...(ElementTypes) > 0,
"tuple_vals is not allowed to be empty");
void* m_data[sizeof...(ElementTypes)];
public:
tuple_view() { }
typedef tdata<ElementTypes*...> data_type;
public:
typedef types_array<ElementTypes...> element_types;
static constexpr size_t num_elements = sizeof...(ElementTypes);
tuple_view() = delete;
tuple_view(tuple_view const&) = delete;
typedef util::type_list<ElementTypes...> types;
/**
* @warning @p tuple_view does @b NOT takes ownership for given pointers
*/
tuple_view(ElementTypes*... args) : m_data(args...) { }
static tuple_view from(std::vector<type_value_pair> const& vec)
inline data_type& data()
{
tuple_view result;
size_t j = 0;
for (type_value_pair const& tvp : vec)
{
result.m_data[j++] = const_cast<void*>(tvp.second);
}
return std::move(result);
return m_data;
}
static tuple_view from(std::vector<type_value_pair> const& vec,
util::fixed_vector<size_t, sizeof...(ElementTypes)> const& mv)
{
tuple_view result;
for (size_t i = 0; i < sizeof...(ElementTypes); ++i)
inline data_type const& data() const
{
result.m_data[i] = const_cast<void*>(vec[mv[i]].second);
return m_data;
}
return std::move(result);
size_t size() const
{
return sizeof...(ElementTypes);
}
tuple_view& operator=(tuple_view const& other)
abstract_tuple* copy() const
{
memcpy(m_data, other.m_data, num_elements * sizeof(void*));
return *this;
auto result = new tuple_vals<ElementTypes...>;
tuple_view_copy_helper f{result};
util::static_foreach<0, sizeof...(ElementTypes)>::_(m_data, f);
return result;
}
tuple_view(tuple_view const& other)
void const* at(size_t pos) const
{
memcpy(m_data, other.m_data, num_elements * sizeof(void*));
CPPA_REQUIRE(pos < size());
return m_data.at(pos);
}
inline size_t size() const
void* mutable_at(size_t pos)
{
return sizeof...(ElementTypes);
CPPA_REQUIRE(pos < size());
return const_cast<void*>(at(pos));
}
inline void const* at(size_t p) const { return m_data[p]; }
uniform_type_info const* type_at(size_t pos) const
{
CPPA_REQUIRE(pos < size());
return m_types[pos];
}
inline void* mutable_at(size_t p) { return m_data[p]; }
void const* type_token() const
{
return detail::static_type_list<ElementTypes...>::list;
}
};
std::type_info const* impl_type() const
{
return detail::static_type_list<ElementTypes...>::list;
}
template<size_t N, typename... Types>
const typename util::at<N, Types...>::type& get(tuple_view<Types...> const& t)
{
static_assert(N < sizeof...(Types), "N >= t.size()");
typedef typename util::at<N, Types...>::type result_t;
return *reinterpret_cast<result_t const*>(t.at(N));
}
private:
template<size_t N, typename... Types>
typename util::at<N, Types...>::type& get_ref(tuple_view<Types...>& t)
{
static_assert(N < sizeof...(Types), "N >= t.size()");
typedef typename util::at<N, Types...>::type result_t;
return *reinterpret_cast<result_t*>(t.mutable_at(N));
}
data_type m_data;
template<typename TypeList>
struct tuple_view_from_type_list;
static types_array<ElementTypes...> m_types;
template<typename... Types>
struct tuple_view_from_type_list<util::type_list<Types...>>
{
typedef tuple_view<Types...> type;
};
template<typename... LhsTypes, typename... RhsTypes>
inline bool operator==(tuple_view<LhsTypes...> const& lhs,
tuple_view<RhsTypes...> const& rhs)
{
return util::compare_tuples(lhs, rhs);
}
template<typename... LhsTypes, typename... RhsTypes>
inline bool operator==(tuple<LhsTypes...> const& lhs,
tuple_view<RhsTypes...> const& rhs)
{
return util::compare_tuples(lhs, rhs);
}
template<typename... LhsTypes, typename... RhsTypes>
inline bool operator==(tuple_view<LhsTypes...> const& lhs,
tuple<RhsTypes...> const& rhs)
{
return util::compare_tuples(lhs, rhs);
}
template<typename... LhsTypes, typename... RhsTypes>
inline bool operator!=(tuple_view<LhsTypes...> const& lhs,
tuple_view<RhsTypes...> const& rhs)
{
return !(lhs == rhs);
}
template<typename... LhsTypes, typename... RhsTypes>
inline bool operator!=(tuple<LhsTypes...> const& lhs,
tuple_view<RhsTypes...> const& rhs)
{
return !(lhs == rhs);
}
template<typename... LhsTypes, typename... RhsTypes>
inline bool operator!=(tuple_view<LhsTypes...> const& lhs,
tuple<RhsTypes...> const& rhs)
{
return !(lhs == rhs);
}
template<typename... ElementTypes>
types_array<ElementTypes...> tuple_view<ElementTypes...>::m_types;
} // namespace cppa
} } // namespace cppa::detail
#endif // TUPLE_VIEW_HPP
......@@ -44,9 +44,6 @@ namespace detail { template<typename...> class tdata; }
// forward declaration of tuple
template<typename...> class tuple;
// forward declaration of tuple_view
template<typename...> class tuple_view;
// forward declaration of get(detail::tdata<...> const&)
template<size_t N, typename... Tn>
const typename util::at<N, Tn...>::type& get(detail::tdata<Tn...> const&);
......@@ -55,10 +52,6 @@ const typename util::at<N, Tn...>::type& get(detail::tdata<Tn...> const&);
template<size_t N, typename... Tn>
const typename util::at<N, Tn...>::type& get(tuple<Tn...> const&);
// forward declarations of get(tuple_view<...> const&)
template<size_t N, typename... Tn>
const typename util::at<N, Tn...>::type& get(tuple_view<Tn...> const&);
// forward declarations of get_ref(detail::tdata<...>&)
template<size_t N, typename... Tn>
typename util::at<N, Tn...>::type& get_ref(detail::tdata<Tn...>&);
......@@ -67,10 +60,6 @@ typename util::at<N, Tn...>::type& get_ref(detail::tdata<Tn...>&);
template<size_t N, typename... Tn>
typename util::at<N, Tn...>::type& get_ref(tuple<Tn...>&);
// forward declarations of get_ref(tuple_view<...>&)
template<size_t N, typename... Tn>
typename util::at<N, Tn...>::type& get_ref(tuple_view<Tn...>&);
} // namespace cppa
#endif // GET_HPP
......@@ -28,498 +28,102 @@
\******************************************************************************/
#ifndef MATCHES_HPP
#define MATCHES_HPP
#ifndef MATCH_HPP
#define MATCH_HPP
#include <type_traits>
#include "cppa/pattern.hpp"
#include "cppa/anything.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/partial_function.hpp"
#include "cppa/util/type_list.hpp"
#include "cppa/detail/tuple_vals.hpp"
#include "cppa/detail/types_array.hpp"
#include "cppa/detail/object_array.hpp"
#include "cppa/detail/decorated_tuple.hpp"
namespace cppa {
namespace detail {
typedef std::integral_constant<wildcard_position,
wildcard_position::nil>
no_wildcard;
} // namespace detail
namespace detail {
template<wildcard_position, typename...> struct matcher;
} // namespace detail
template<wildcard_position PC, typename... Ts>
struct match_impl;
/**
*
*/
template<typename... Ts>
inline bool match(any_tuple const& tup)
{
typedef util::type_list<Ts...> tl;
return match_impl<get_wildcard_position<tl>(), Ts...>::_(tup);
}
/**
*
*/
template<typename... Ts>
inline bool match(any_tuple const& tup,
util::fixed_vector<
size_t,
util::tl_count_not<
util::type_list<Ts...>,
is_anything>::value>& mv)
{
typedef util::type_list<Ts...> tl;
return match_impl<get_wildcard_position<tl>(), Ts...>::_(tup, mv);
}
namespace cppa { namespace detail {
/**
*
*/
template<typename... Ts>
inline bool match(any_tuple const& tup, pattern<Ts...> const& ptrn)
struct match_helper
{
typedef util::type_list<Ts...> tl;
return match_impl<get_wildcard_position<tl>(), Ts...>::_(tup, ptrn);
}
/**
*
*/
template<typename... Ts>
inline bool match(any_tuple const& tup,
pattern<Ts...> const& ptrn,
typename pattern<Ts...>::mapping_vector& mv)
{
typedef util::type_list<Ts...> tl;
return match_impl<get_wildcard_position<tl>(), Ts...>::_(tup,
ptrn,
mv);
}
/**
* @brief Matches types only (ignores all values of given pattern).
*/
template<typename... Ts>
inline bool match_types(any_tuple const& tup, pattern<Ts...> const&)
{
typedef util::type_list<Ts...> tl;
return match_impl<get_wildcard_position<tl>(), Ts...>::_(tup);
}
// implementation for zero or one wildcards
template<wildcard_position PC, typename... Ts>
struct match_impl
{
static inline bool _(any_tuple const& tup)
{
return detail::matcher<PC, Ts...>::tmatch(tup);
}
template<size_t Size>
static inline bool _(any_tuple const& tup,
util::fixed_vector<size_t, Size>& mv)
any_tuple tup;
match_helper(any_tuple t) : tup(std::move(t)) { }
template<class... Args>
void operator()(partial_function&& pf, Args&&... args)
{
return detail::matcher<PC, Ts...>::tmatch(tup, mv);
}
static inline bool _(any_tuple const& tup,
pattern<Ts...> const& p)
{
return detail::matcher<PC, Ts...>::tmatch(tup)
&& ( p.has_values() == false
|| detail::matcher<PC, Ts...>::vmatch(tup, p));
}
static inline bool _(any_tuple const& tup,
pattern<Ts...> const& p,
typename pattern<Ts...>::mapping_vector& mv)
{
return detail::matcher<PC, Ts...>::tmatch(tup, mv)
&& ( p.has_values() == false
|| detail::matcher<PC, Ts...>::vmatch(tup, p));
partial_function tmp;
tmp.splice(std::move(pf), std::forward<Args>(args)...);
tmp(tup);
}
};
// implementation for multiple wildcards
template<typename... Ts>
struct match_impl<wildcard_position::multiple, Ts...>
template<typename Iterator>
struct match_each_helper
{
static constexpr auto PC = wildcard_position::multiple;
static inline bool _(any_tuple const& tup)
Iterator i;
Iterator e;
match_each_helper(Iterator first, Iterator last) : i(first), e(last) { }
template<typename... Args>
void operator()(partial_function&& arg0, Args&&... args)
{
return detail::matcher<PC, Ts...>::tmatch(tup);
}
template<size_t Size>
static inline bool _(any_tuple const& tup,
util::fixed_vector<size_t, Size>& mv)
partial_function tmp;
tmp.splice(std::move(arg0), std::forward<Args>(args)...);
for (; i != e; ++i)
{
return detail::matcher<PC, Ts...>::tmatch(tup, mv);
tmp(any_tuple::view(*i));
}
static inline bool _(any_tuple const& tup, pattern<Ts...> const& p)
{
if (p.has_values())
{
typename pattern<Ts...>::mapping_vector mv;
return detail::matcher<PC, Ts...>::tmatch(tup, mv)
&& detail::matcher<PC, Ts...>::vmatch(tup, p, mv);
}
return detail::matcher<PC, Ts...>::tmatch(tup);
}
static inline bool _(any_tuple const& tup, pattern<Ts...> const& p,
typename pattern<Ts...>::mapping_vector& mv)
{
if (p.has_values())
{
typename pattern<Ts...>::mapping_vector mv;
return detail::matcher<PC, Ts...>::tmatch(tup, mv)
&& detail::matcher<PC, Ts...>::vmatch(tup, p, mv);
}
return detail::matcher<PC, Ts...>::tmatch(tup, mv);
}
};
/******************************************************************************\
** implementation details **
\******************************************************************************/
namespace detail {
template<typename... T>
struct matcher<wildcard_position::nil, T...>
template<typename Iterator, typename Projection>
struct pmatch_each_helper
{
static inline bool tmatch(any_tuple const& tup)
{
// match implementation type if possible
auto impl = tup.impl_type();
// the impl_type of both decorated_tuple and tuple_vals
// is &typeid(type_list<T...>)
auto tinf = detail::static_type_list<T...>::list;
if (impl == tinf || *impl == *tinf)
{
return true;
}
// always use a full dynamic match for object arrays
else if (*impl == typeid(detail::object_array)
&& tup.size() == sizeof...(T))
Iterator i;
Iterator e;
Projection p;
template<typename PJ>
pmatch_each_helper(Iterator first, Iterator last, PJ&& proj) : i(first), e(last), p(std::forward<PJ>(proj)) { }
template<typename... Args>
void operator()(partial_function&& arg0, Args&&... args)
{
auto& tarr = detail::static_types_array<T...>::arr;
return std::equal(tup.begin(), tup.end(), tarr.begin(),
detail::types_only_eq);
}
return false;
}
static inline bool tmatch(any_tuple const& tup,
util::fixed_vector<size_t, sizeof...(T)>& mv)
partial_function tmp;
tmp.splice(std::move(arg0), std::forward<Args>(args)...);
for (; i != e; ++i)
{
if (tmatch(tup))
{
mv.resize(sizeof...(T));
std::iota(mv.begin(), mv.end(), 0);
return true;
tmp(any_tuple::view(p(*i)));
}
return false;
}
static inline bool vmatch(any_tuple const& tup, pattern<T...> const& ptrn)
{
CPPA_REQUIRE(tup.size() == sizeof...(T));
return std::equal(ptrn.begin(), ptrn.vend(), tup.begin(),
detail::values_only_eq_v2);
}
};
template<typename... T>
struct matcher<wildcard_position::trailing, T...>
{
static constexpr size_t size = sizeof...(T) - 1;
} } // namespace cppa::detail
static inline bool tmatch(any_tuple const& tup)
{
if (tup.size() >= size)
{
auto& tarr = static_types_array<T...>::arr;
auto begin = tup.begin();
return std::equal(begin, begin + size, tarr.begin(),
detail::types_only_eq);
}
return false;
}
static inline bool tmatch(any_tuple const& tup,
util::fixed_vector<size_t, size>& mv)
{
if (tmatch(tup))
{
mv.resize(size);
std::iota(mv.begin(), mv.end(), 0);
return true;
}
return false;
}
static inline bool vmatch(any_tuple const& tup, pattern<T...> const& ptrn)
{
return std::equal(ptrn.begin(), ptrn.vend(), tup.begin(),
detail::values_only_eq_v2);
}
};
namespace cppa {
template<>
struct matcher<wildcard_position::leading, anything>
/**
* @brief Match expression.
*/
template<typename T>
detail::match_helper match(T& what)
{
static inline bool tmatch(any_tuple const&)
{
return true;
}
static inline bool tmatch(any_tuple const&, util::fixed_vector<size_t, 0>&)
{
return true;
}
static inline bool vmatch(any_tuple const&, pattern<anything> const&)
{
return true;
}
};
return any_tuple::view(what);
}
template<typename... T>
struct matcher<wildcard_position::leading, T...>
/**
* @brief Match expression that matches against all elements of @p what.
*/
template<class Container>
auto match_each(Container& what)
-> detail::match_each_helper<decltype(std::begin(what))>
{
static constexpr size_t size = sizeof...(T) - 1;
static inline bool tmatch(any_tuple const& tup)
{
auto tup_size = tup.size();
if (tup_size >= size)
{
auto& tarr = static_types_array<T...>::arr;
auto begin = tup.begin();
begin += (tup_size - size);
return std::equal(begin, tup.end(),
(tarr.begin() + 1), // skip 'anything'
detail::types_only_eq);
}
return false;
}
static inline bool tmatch(any_tuple const& tup,
util::fixed_vector<size_t, size>& mv)
{
if (tmatch(tup))
{
mv.resize(size);
std::iota(mv.begin(), mv.end(), tup.size() - size);
return true;
}
return false;
}
static inline bool vmatch(any_tuple const& tup, pattern<T...> const& ptrn)
{
auto tbegin = tup.begin();
// skip unmatched elements
tbegin += (tup.size() - size);
// skip leading wildcard ++(ptr.begin())
return std::equal(++(ptrn.begin()), ptrn.vend(), tbegin,
detail::values_only_eq_v2);
}
};
return {std::begin(what), std::end(what)};
}
template<typename... T>
struct matcher<wildcard_position::in_between, T...>
template<typename InputIterator>
auto match_each(InputIterator first, InputIterator last)
-> detail::match_each_helper<InputIterator>
{
static constexpr int signed_wc_pos =
util::tl_find<util::type_list<T...>, anything>::value;
static constexpr size_t size = sizeof...(T);
static constexpr size_t wc_pos = static_cast<size_t>(signed_wc_pos);
static_assert( signed_wc_pos != -1
&& signed_wc_pos != 0
&& signed_wc_pos != (sizeof...(T) - 1),
"illegal wildcard position");
static inline bool tmatch(any_tuple const& tup)
{
auto tup_size = tup.size();
if (tup_size >= size)
{
auto& tarr = static_types_array<T...>::arr;
// first range [0, X1)
auto begin = tup.begin();
auto end = begin + wc_pos;
if (std::equal(begin, end, tarr.begin(), detail::types_only_eq))
{
// second range [X2, N)
begin = end = tup.end();
begin -= (size - (wc_pos + 1));
auto arr_begin = tarr.begin() + (wc_pos + 1);
return std::equal(begin, end, arr_begin, detail::types_only_eq);
}
}
return false;
}
static inline bool tmatch(any_tuple const& tup,
util::fixed_vector<size_t, size - 1>& mv)
{
if (tmatch(tup))
{
// first range
mv.resize(size - 1);
auto begin = mv.begin();
std::iota(begin, begin + wc_pos, 0);
// second range
begin = mv.begin() + wc_pos;
std::iota(begin, mv.end(), tup.size() - (size - (wc_pos + 1)));
return true;
}
return false;
}
static inline bool vmatch(any_tuple const& tup, pattern<T...> const& ptrn)
{
// first range
auto tbegin = tup.begin();
auto tend = tbegin + wc_pos;
if (std::equal(tbegin, tend, ptrn.begin(), detail::values_only_eq))
{
// second range
tbegin = tend = tup.end();
tbegin -= (size - (wc_pos + 1));
auto pbegin = ptrn.begin();
pbegin += (wc_pos + 1);
return std::equal(tbegin, tend, pbegin, detail::values_only_eq);
}
return false;
}
};
return {first, last};
}
template<typename... T>
struct matcher<wildcard_position::multiple, T...>
template<typename InputIterator, typename Projection>
auto pmatch_each(InputIterator first, InputIterator last, Projection&& proj)
-> detail::pmatch_each_helper<InputIterator, typename util::rm_ref<Projection>::type>
{
static constexpr size_t wc_count =
util::tl_count<util::type_list<T...>, is_anything>::value;
static_assert(sizeof...(T) > wc_count, "only wildcards given");
template<class TupleIter, class PatternIter,
class Push, class Commit, class Rollback>
static bool match(TupleIter tbegin, TupleIter tend,
PatternIter pbegin, PatternIter pend,
Push&& push, Commit&& commit, Rollback&& rollback)
{
while (!(pbegin == pend && tbegin == tend))
{
if (pbegin == pend)
{
// reached end of pattern while some values remain unmatched
return false;
}
else if (pbegin.type() == nullptr) // nullptr == wildcard (anything)
{
// perform submatching
++pbegin;
// always true at the end of the pattern
if (pbegin == pend) return true;
// safe current mapping as fallback
commit();
// iterate over tuple values until we found a match
for (; tbegin != tend; ++tbegin)
{
if (match(tbegin, tend, pbegin, pend,
push, commit, rollback))
{
return true;
}
// restore mapping to fallback (delete invalid mappings)
rollback();
}
return false; // no submatch found
}
// compare types
else if (tbegin.type() == pbegin.type()) push(tbegin);
// no match
else return false;
// next iteration
++tbegin;
++pbegin;
}
return true; // pbegin == pend && tbegin == tend
}
static inline bool tmatch(any_tuple const& tup)
{
auto& tarr = static_types_array<T...>::arr;
if (tup.size() >= (sizeof...(T) - wc_count))
{
return match(tup.begin(), tup.end(), tarr.begin(), tarr.end(),
[](any_tuple::const_iterator const&) { },
[]() { },
[]() { });
}
return false;
}
template<class MappingVector>
static inline bool tmatch(any_tuple const& tup, MappingVector& mv)
{
auto& tarr = static_types_array<T...>::arr;
if (tup.size() >= (sizeof...(T) - wc_count))
{
size_t commited_size = 0;
return match(tup.begin(), tup.end(), tarr.begin(), tarr.end(),
[&](any_tuple::const_iterator const& iter)
{
mv.push_back(iter.position());
},
[&]() { commited_size = mv.size(); },
[&]() { mv.resize(commited_size); });
}
return false;
}
static inline bool vmatch(any_tuple const& tup,
pattern<T...> const& ptrn,
typename pattern<T...>::mapping_vector const& mv)
{
auto i = mv.begin();
for (auto j = ptrn.begin(); j != ptrn.end(); ++j)
{
if (j.type() != nullptr)
{
if ( j.value() != nullptr
&& j.type()->equals(tup.at(*i), j.value()) == false)
{
return false;
}
++i;
}
}
}
};
} // namespace detail
return {first, last, std::forward<Projection>(proj)};
}
} // namespace cppa
#endif // MATCHES_HPP
#endif // MATCH_HPP
......@@ -38,8 +38,6 @@
#include "cppa/option.hpp"
#include "cppa/anything.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/tuple_view.hpp"
#include "cppa/type_value_pair.hpp"
#include "cppa/uniform_type_info.hpp"
......
......@@ -33,15 +33,17 @@
#include <type_traits>
#include "cppa/match.hpp"
#include "cppa/option.hpp"
#include "cppa/pattern.hpp"
#include "cppa/detail/matches.hpp"
#include "cppa/detail/tuple_cast_impl.hpp"
namespace cppa {
// cast using a pattern
/**
* @brief Tries to cast @p tup to {@link tuple tuple<T...>}.
*/
template<typename... T>
auto tuple_cast(any_tuple const& tup, pattern<T...> const& p)
-> option<
......@@ -56,7 +58,9 @@ auto tuple_cast(any_tuple const& tup, pattern<T...> const& p)
return detail::tuple_cast_impl<impl, tuple_type, T...>::safe(tup, p);
}
// cast using types
/**
* @brief Tries to cast @p tup to {@link tuple tuple<T...>}.
*/
template<typename... T>
auto tuple_cast(any_tuple const& tup)
-> option<
......
......@@ -105,12 +105,18 @@ class type_value_pair_const_iterator
};
/**
* @relates type_value_pair_const_iterator
*/
inline bool operator==(type_value_pair_const_iterator const& lhs,
type_value_pair_const_iterator const& rhs)
{
return lhs.base() == rhs.base();
}
/**
* @relates type_value_pair_const_iterator
*/
inline bool operator!=(type_value_pair_const_iterator const& lhs,
type_value_pair_const_iterator const& rhs)
{
......
......@@ -263,12 +263,18 @@ class uniform_type_info
};
/**
* @relates uniform_type_info
*/
template<typename T>
inline uniform_type_info const* uniform_typeid()
{
return uniform_typeid(typeid(T));
}
/**
* @relates uniform_type_info
*/
inline bool operator==(uniform_type_info const& lhs,
uniform_type_info const& rhs)
{
......@@ -277,27 +283,42 @@ inline bool operator==(uniform_type_info const& lhs,
return &lhs == &rhs;
}
/**
* @relates uniform_type_info
*/
inline bool operator!=(uniform_type_info const& lhs,
uniform_type_info const& rhs)
{
return !(lhs == rhs);
}
/**
* @relates uniform_type_info
*/
inline bool operator==(uniform_type_info const& lhs, std::type_info const& rhs)
{
return lhs.equals(rhs);
}
/**
* @relates uniform_type_info
*/
inline bool operator!=(uniform_type_info const& lhs, std::type_info const& rhs)
{
return !(lhs.equals(rhs));
}
/**
* @relates uniform_type_info
*/
inline bool operator==(std::type_info const& lhs, uniform_type_info const& rhs)
{
return rhs.equals(lhs);
}
/**
* @relates uniform_type_info
*/
inline bool operator!=(std::type_info const& lhs, uniform_type_info const& rhs)
{
return !(rhs.equals(lhs));
......
......@@ -31,6 +31,8 @@
#ifndef STATIC_FOREACH_HPP
#define STATIC_FOREACH_HPP
#include "cppa/get.hpp"
namespace cppa { namespace util {
/**
......
......@@ -32,8 +32,8 @@
#include <algorithm>
#include "cppa/self.hpp"
#include "cppa/match.hpp"
#include "cppa/exception.hpp"
#include "cppa/detail/matches.hpp"
#include "cppa/detail/invokable.hpp"
#include "cppa/detail/intermediate.hpp"
#include "cppa/detail/converted_thread_context.hpp"
......@@ -111,7 +111,7 @@ void converted_thread_context::dequeue(behavior& rules) /*override*/
converted_thread_context::throw_on_exit_result
converted_thread_context::throw_on_exit(any_tuple const& msg)
{
if (match(msg, m_exit_msg_pattern))
if (matches(msg, m_exit_msg_pattern))
{
auto reason = msg.get_as<std::uint32_t>(1);
if (reason != exit_reason::normal)
......
......@@ -15,6 +15,7 @@ unit_tests_SOURCES = main.cpp \
test__queue_performance.cpp \
test__remote_actor.cpp \
test__ripemd_160.cpp \
test__match.cpp \
test__serialization.cpp \
test__spawn.cpp \
test__tuple.cpp \
......
......@@ -16,6 +16,7 @@
#include "cppa/cppa.hpp"
#include "cppa/tuple.hpp"
#include "cppa/match.hpp"
#include "cppa/config.hpp"
#include "cppa/anything.hpp"
#include "cppa/detail/demangle.hpp"
......@@ -86,10 +87,9 @@ std::vector<std::string> split(std::string const& str, char delim)
return result;
}
std::map<std::string, std::string>
get_kv_pairs(int argc, char** argv, int begin = 1)
std::vector<string_pair> get_kv_pairs(int argc, char** argv, int begin = 1)
{
std::map<std::string, std::string> result;
std::vector<string_pair> result;
for (int i = begin; i < argc; ++i)
{
auto vec = split(argv[i], '=');
......@@ -97,75 +97,62 @@ get_kv_pairs(int argc, char** argv, int begin = 1)
{
cerr << "\"" << argv[i] << "\" is not a key-value pair" << endl;
}
else if (result.insert(std::make_pair(vec[0], vec[1])).second == false)
else if (std::any_of(result.begin(), result.end(),
[&](string_pair const& p) { return p.first == vec[0]; }))
{
cerr << "key \"" << vec[0] << "\" is already defined" << endl;
exit(1);
}
else
{
result.emplace_back(vec[0], vec[1]);
}
}
return result;
}
template<typename Iterator, class Container, typename Key>
inline bool found_key(Iterator& i, Container& cont, Key&& key)
{
return (i = cont.find(std::forward<Key>(key))) != cont.end();
}
template<typename F, typename S>
any_tuple to_tuple(std::pair<F, S> const& p)
void usage(char const* argv0)
{
return make_tuple(p.first, p.second);
cout << "usage: " << split(argv0, '/').back() << " "
<< "[run=remote_actor] "
<< "[scheduler=(thread_pool_scheduler|mock_scheduler)]"
<< endl;
}
struct match_helper
int main(int argc, char** argv)
{
any_tuple tup;
template<class... Args>
void operator()(partial_function&& pf, Args&&... args)
/*
std::string abc = "abc";
cout << "is_iterable<string> = " << cppa::util::is_iterable<std::string>::value << endl;
match(abc)
(
on("abc") >> []()
{
partial_function tmp;
tmp.splice(std::move(pf), std::forward<Args>(args)...);
tmp(tup);
cout << "ABC" << endl;
}
};
template<typename F, typename S>
match_helper match(std::pair<F, S> const& what)
{
return {to_tuple(what)};
}
);
template<class Container>
struct match_each_helper
{
Container const& args;
template<typename... Args>
void operator()(partial_function&& pf, Args&&... args)
{
partial_function tmp;
tmp.splice(std::move(pf), std::forward<Args>(args)...);
for (auto& arg : args)
match_each(argv + 1, argv + argc)
(
on_arg_match >> [](std::string const& str)
{
tmp(to_tuple(arg));
}
cout << "matched \"" << str << "\"" << endl;
}
};
);
void usage(char const* argv0)
{
cout << "usage: " << split(argv0, '/').back() << " "
<< "[run=remote_actor] "
<< "[scheduler=(thread_pool_scheduler|mock_scheduler)]"
pmatch_each(argv + 1, argv + argc, [](char const* cstr) { return split(cstr, '='); })
(
on_arg_match >> [](std::string const& key, std::string const& value)
{
cout << "key = \"" << key << "\", value = \"" << value << "\""
<< endl;
}
}
);
return 0;
*/
int main(int argc, char** argv)
{
auto args = get_kv_pairs(argc, argv);
for (auto& kvp : args)
{
match(kvp)
match_each(args)
(
on("run", arg_match) >> [&](std::string const& what)
{
......@@ -194,7 +181,6 @@ int main(int argc, char** argv)
}
}
);
}
//print_node_id();
std::cout << std::boolalpha;
size_t errors = 0;
......@@ -203,6 +189,7 @@ int main(int argc, char** argv)
RUN_TEST(test__intrusive_containers);
RUN_TEST(test__uniform_type);
RUN_TEST(test__pattern);
RUN_TEST(test__match);
RUN_TEST(test__intrusive_ptr);
RUN_TEST(test__type_list);
RUN_TEST(test__fixed_vector);
......
#ifndef TEST_HPP
#define TEST_HPP
#include <map>
#include <vector>
#include <string>
#include <cstddef>
#include <iostream>
......@@ -88,14 +88,17 @@ std::cerr << err_msg << std::endl; \
#define CPPA_CHECK_NOT_EQUAL(lhs_loc, rhs_loc) CPPA_CHECK(((lhs_loc) != (rhs_loc)))
typedef std::pair<std::string, std::string> string_pair;
size_t test__yield_interface();
size_t test__remote_actor(const char* app_path, bool is_client,
const std::map<std::string, std::string>& args);
size_t test__remote_actor(char const* app_path, bool is_client,
std::vector<string_pair> const& args);
size_t test__ripemd_160();
size_t test__uniform_type();
size_t test__type_list();
size_t test__atom();
size_t test__tuple();
size_t test__match();
size_t test__spawn();
size_t test__pattern();
size_t test__intrusive_ptr();
......
#include "test.hpp"
#include "cppa/match.hpp"
size_t test__match()
{
CPPA_TEST(test__match);
return CPPA_TEST_RESULT;
}
......@@ -16,9 +16,10 @@ using namespace cppa;
namespace {
void client_part(std::map<std::string, std::string> const& args)
void client_part(std::vector<string_pair> const& args)
{
auto i = args.find("port");
auto i = std::find_if(args.begin(), args.end(),
[](string_pair const& p) { return p.first == "port"; });
if (i == args.end())
{
throw std::runtime_error("no port specified");
......@@ -34,7 +35,7 @@ void client_part(std::map<std::string, std::string> const& args)
} // namespace <anonymous>
size_t test__remote_actor(char const* app_path, bool is_client,
std::map<std::string, std::string> const& args)
std::vector<string_pair> const& args)
{
if (is_client)
{
......
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