Commit 704aa400 authored by Dominik Charousset's avatar Dominik Charousset

maintenance

parent 7ae2965f
......@@ -61,3 +61,4 @@ examples/announce_example_5
examples/hello_world_example
examples/math_actor_example
examples/dining_philosophers
examples/dancing_kirby
......@@ -31,6 +31,8 @@
#ifndef ANY_TUPLE_HPP
#define ANY_TUPLE_HPP
#include <iostream>
#include "cppa/tuple.hpp"
#include "cppa/config.hpp"
#include "cppa/cow_ptr.hpp"
......@@ -136,7 +138,7 @@ class any_tuple
}
template<typename T>
inline T& get_mutable_as(size_t p)
inline T& get_as_mutable(size_t p)
{
CPPA_REQUIRE(*(type_at(p)) == typeid(T));
return *reinterpret_cast<T*>(mutable_at(p));
......@@ -146,14 +148,16 @@ class any_tuple
inline const_iterator end() const { return m_vals->end(); }
cow_ptr<detail::abstract_tuple> const& vals() const;
inline cow_ptr<detail::abstract_tuple>& vals() { return m_vals; }
inline cow_ptr<detail::abstract_tuple> const& vals() const { return m_vals; }
inline cow_ptr<detail::abstract_tuple> const& cvals() const { return m_vals; }
inline void const* type_token() const
inline std::type_info const* type_token() const
{
return m_vals->type_token();
}
inline std::type_info const* impl_type() const
inline detail::tuple_impl_info impl_type() const
{
return m_vals->impl_type();
}
......@@ -235,7 +239,7 @@ class any_tuple
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)));
return new detail::container_tuple_view<T>(new ctype(std::forward<T>(value)), true);
}
};
......
......@@ -32,6 +32,7 @@
#define ABSTRACT_TUPLE_HPP
#include <iterator>
#include <typeinfo>
#include "cppa/config.hpp"
#include "cppa/ref_counted.hpp"
......@@ -42,11 +43,21 @@
namespace cppa { namespace detail {
struct abstract_tuple : ref_counted
enum tuple_impl_info
{
statically_typed,
dynamically_typed
};
class abstract_tuple : public ref_counted
{
tuple_impl_info m_impl_type;
public:
abstract_tuple() = default;
abstract_tuple(abstract_tuple const&);
inline abstract_tuple(tuple_impl_info tii) : m_impl_type(tii) { }
abstract_tuple(abstract_tuple const& other);
// mutators
virtual void* mutable_at(size_t pos) = 0;
......@@ -57,12 +68,16 @@ struct abstract_tuple : ref_counted
virtual void const* at(size_t pos) const = 0;
virtual uniform_type_info const* type_at(size_t pos) const = 0;
// identifies the type of the implementation, this is NOT the
// typeid of the implementation class
virtual std::type_info const* impl_type() const = 0;
// Identifies the type of the implementation.
// A statically typed tuple implementation can use some optimizations,
// e.g., "impl_type() == statically_typed" implies that type_token()
// identifies all possible instances of a given tuple implementation
inline tuple_impl_info impl_type() const { return m_impl_type; }
// uniquely identifies this category (element types) of messages
virtual void const* type_token() const = 0;
// override this member function only if impl_type() == statically_typed
// (default returns &typeid(void))
virtual std::type_info const* type_token() const;
bool equals(abstract_tuple const& other) const;
......@@ -151,8 +166,10 @@ struct abstract_tuple : ref_counted
};
inline const_iterator begin() const { return {this}; }
inline const_iterator cbegin() const { return {this}; }
inline const_iterator end() const { return {this, size()}; }
inline const_iterator cend() const { return {this, size()}; }
};
......
......@@ -31,6 +31,8 @@
#ifndef CONTAINER_TUPLE_VIEW_HPP
#define CONTAINER_TUPLE_VIEW_HPP
#include <iostream>
#include "cppa/detail/tuple_vals.hpp"
#include "cppa/detail/object_array.hpp"
#include "cppa/detail/abstract_tuple.hpp"
......@@ -42,11 +44,14 @@ template<class Container>
class container_tuple_view : public abstract_tuple
{
typedef abstract_tuple super;
public:
typedef typename Container::value_type value_type;
container_tuple_view(Container* c, bool take_ownership = false) : m_ptr(c)
container_tuple_view(Container* c, bool take_ownership = false)
: super(tuple_impl_info::dynamically_typed), m_ptr(c)
{
CPPA_REQUIRE(c != nullptr);
if (!take_ownership) m_ptr.get_deleter().disable();
......@@ -78,22 +83,11 @@ class container_tuple_view : public abstract_tuple
return &(*i);
}
uniform_type_info const* type_at(size_t pos) const
uniform_type_info const* type_at(size_t) const
{
CPPA_REQUIRE(pos < size());
return static_types_array<value_type>::arr[0];
}
void const* type_token() const
{
return &(typeid(Container));
}
std::type_info const* impl_type() const
{
return &(typeid(detail::object_array));
}
private:
std::unique_ptr<Container, disablable_delete<Container> > m_ptr;
......
......@@ -53,6 +53,8 @@ template<typename... ElementTypes>
class decorated_tuple : public abstract_tuple
{
typedef abstract_tuple super;
static_assert(sizeof...(ElementTypes) > 0,
"decorated_tuple is not allowed to be empty");
......@@ -102,14 +104,9 @@ class decorated_tuple : public abstract_tuple
return m_decorated->type_at(m_mapping[pos]);
}
void const* type_token() const
{
return detail::static_type_list<ElementTypes...>::list;
}
std::type_info const* impl_type() const
std::type_info const* type_token() const
{
return detail::static_type_list<ElementTypes...>::list;
return static_type_list<ElementTypes...>::list;
}
private:
......@@ -118,7 +115,8 @@ class decorated_tuple : public abstract_tuple
vector_type m_mapping;
decorated_tuple(cow_pointer_type d, vector_type const& v)
: m_decorated(std::move(d)), m_mapping(v)
: super(tuple_impl_info::statically_typed)
, m_decorated(std::move(d)), m_mapping(v)
{
# ifdef CPPA_DEBUG
cow_pointer_type const& ptr = m_decorated; // prevent detaching
......@@ -129,7 +127,7 @@ class decorated_tuple : public abstract_tuple
}
decorated_tuple(cow_pointer_type d, size_t offset)
: m_decorated(std::move(d))
: super(tuple_impl_info::statically_typed), m_decorated(std::move(d))
{
# ifdef CPPA_DEBUG
cow_pointer_type const& ptr = m_decorated; // prevent detaching
......
......@@ -40,14 +40,14 @@ struct empty_tuple : abstract_tuple
using abstract_tuple::const_iterator;
empty_tuple();
size_t size() const;
void* mutable_at(size_t);
abstract_tuple* copy() const;
void const* at(size_t) const;
bool equals(abstract_tuple const& other) const;
uniform_type_info const* type_at(size_t) const;
std::type_info const* impl_type() const;
void const* type_token() const;
std::type_info const* type_token() const;
};
......
......@@ -47,9 +47,6 @@
#include "cppa/detail/matches.hpp"
#include "cppa/detail/intermediate.hpp"
// forward declaration
namespace cppa { class any_tuple; class partial_function; }
namespace cppa { namespace detail {
class invokable
......@@ -65,207 +62,306 @@ class invokable
inline invokable() : next(nullptr) { }
virtual ~invokable();
virtual bool invoke(any_tuple const&) const;
// Suppress type checking.
virtual bool unsafe_invoke(any_tuple const& value) const;
// Checks whether the types of @p value match the pattern.
virtual bool types_match(any_tuple const& value) const;
// Checks whether this invokable could be invoked with @p value.
virtual bool could_invoke(any_tuple const& value) const;
// Type checking.
virtual bool invoke(any_tuple& value) const;
// Suppress type checking.
virtual bool unsafe_invoke(any_tuple& value) const;
// Prepare this invokable.
virtual intermediate* get_intermediate(any_tuple const& value);
virtual intermediate* get_intermediate(any_tuple& value);
// Prepare this invokable and suppress type checking.
virtual intermediate* get_unsafe_intermediate(any_tuple const& value);
virtual intermediate* get_unsafe_intermediate(any_tuple& value);
};
template<class Tuple, class Pattern>
struct abstract_invokable : public invokable
/*
* @tparam Fun Function or functor
* @tparam FunArgs Type list of functor parameters *without* any qualifiers
*/
template<typename Fun, class FunArgs, class TupleTypes>
struct iimpl : intermediate
{
Pattern m_pattern;
abstract_invokable() { }
template<typename... Args>
abstract_invokable(Args&&... args) : m_pattern(std::forward<Args>(args)...)
typedef Fun functor_type;
typedef typename tuple_from_type_list<TupleTypes>::type tuple_type;
functor_type m_fun;
tuple_type m_default_args;
tuple_type m_args;
template<typename F> iimpl(F&& fun) : m_fun(std::forward<F>(fun)) { }
void invoke()
{
util::apply_tuple(m_fun, m_args);
// "forget" arguments after invocation
m_args = m_default_args;
}
bool types_match(any_tuple const& value) const
inline intermediate* prepare(option<tuple_type>&& tup)
{
return matches_types(value, m_pattern);
}
bool could_invoke(any_tuple const& value) const
{
return matches(value, m_pattern);
if (tup)
{
m_args = std::move(*tup);
return this;
}
return nullptr;
}
};
template<bool CheckValues, size_t NumArgs, typename Fun, class Tuple, class Pattern>
class invokable_impl : public abstract_invokable<Tuple, Pattern>
{
typedef abstract_invokable<Tuple, Pattern> super;
template<typename T>
inline bool invoke_impl(option<T>&& tup) const
inline bool operator()(option<tuple_type>&& tup) const
{
if (tup)
{
util::apply_tuple(m_iimpl.m_fun, *tup);
util::apply_tuple(m_fun, *tup);
return true;
}
return false;
}
};
template<typename T>
inline intermediate* get_intermediate_impl(option<T>&& tup)
template<typename Fun, class TupleTypes>
struct iimpl<Fun, util::type_list<>, TupleTypes> : intermediate
{
typedef Fun functor_type;
functor_type m_fun;
template<typename F> iimpl(F&& fun) : m_fun(std::forward<F>(fun)) { }
void invoke() { m_fun(); }
inline intermediate* prepare(bool result) // result passed by policy
{
if (tup)
{
m_iimpl.m_args = std::move(*tup);
return &m_iimpl;
}
return nullptr;
return result ? this : nullptr;
}
inline bool operator()(bool result) const // result passed by policy
{
if (result) m_fun();
return result;
}
};
protected:
struct iimpl : intermediate
template<typename Fun, class TupleTypes>
struct iimpl<Fun, util::type_list<any_tuple>, TupleTypes> : intermediate
{
typedef Fun functor_type;
functor_type m_fun;
any_tuple m_arg;
template<typename F> iimpl(F&& fun) : m_fun(std::forward<F>(fun)) { }
void invoke() { m_fun(m_arg); m_arg = any_tuple{}; }
inline intermediate* prepare(any_tuple arg)
{
m_arg = std::move(arg);
return this;
}
inline bool operator()(any_tuple arg) const
{
Fun m_fun;
Tuple m_args;
template<typename F> iimpl(F&& fun) : m_fun(std::forward<F>(fun)) { }
void invoke() { util::apply_tuple(m_fun, m_args); }
m_fun(arg);
return true;
}
m_iimpl;
};
public:
enum mapping_policy
{
do_not_map,
map_to_bool,
map_to_option
};
template<typename F, typename... Args>
invokable_impl(F&& fun, Args&&... args)
: super(std::forward<Args>(args)...), m_iimpl(std::forward<F>(fun))
template<mapping_policy, class Pattern>
struct pattern_policy
{
Pattern m_pattern;
template<typename... Args>
pattern_policy(Args&&... args) : m_pattern(std::forward<Args>(args)...) { }
bool types_match(any_tuple const& value) const
{
return matches_types(value, m_pattern);
}
bool invoke(any_tuple const& value) const
bool could_invoke(any_tuple const& value) const
{
return invoke_impl(tuple_cast(value, this->m_pattern));
return matches(value, m_pattern);
}
bool unsafe_invoke(any_tuple const& value) const
any_tuple map(any_tuple& value) const
{
return invoke_impl(unsafe_tuple_cast(value, this->m_pattern));
return std::move(value);
}
intermediate* get_intermediate(any_tuple const& value)
any_tuple map_unsafe(any_tuple& value) const
{
return get_intermediate_impl(tuple_cast(value, this->m_pattern));
return std::move(value);
}
};
intermediate* get_unsafe_intermediate(any_tuple const& value)
template<class Pattern>
struct pattern_policy<map_to_option, Pattern>
{
Pattern m_pattern;
template<typename... Args>
pattern_policy(Args&&... args) : m_pattern(std::forward<Args>(args)...) { }
bool types_match(any_tuple const& value) const
{
return get_intermediate_impl(unsafe_tuple_cast(value, this->m_pattern));
return matches_types(value, m_pattern);
}
bool could_invoke(any_tuple const& value) const
{
return matches(value, m_pattern);
}
auto map(any_tuple& value) const
-> decltype(moving_tuple_cast(value, m_pattern))
{
auto result = moving_tuple_cast(value, m_pattern);
return result;
}
auto map_unsafe(any_tuple& value) const
-> decltype(unsafe_tuple_cast(value, m_pattern))
{
return unsafe_tuple_cast(value, m_pattern);
}
};
template<class Pattern>
struct pattern_policy<map_to_bool, Pattern>
{
Pattern m_pattern;
template<typename... Args>
pattern_policy(Args&&... args) : m_pattern(std::forward<Args>(args)...) { }
bool types_match(any_tuple const& value) const
{
return matches_types(value, m_pattern);
}
bool could_invoke(any_tuple const& value) const
{
return matches(value, m_pattern);
}
bool map(any_tuple& value) const
{
return could_invoke(value);
}
bool map_unsafe(any_tuple& value) const
{
return could_invoke(value);
}
};
template<size_t NumArgs, typename Fun, class Tuple, class Pattern>
struct invokable_impl<false, NumArgs, Fun, Tuple, Pattern> : public invokable_impl<true, NumArgs, Fun, Tuple, Pattern>
struct dummy_policy
{
typedef invokable_impl<true, NumArgs, Fun, Tuple, Pattern> super;
template<typename F>
invokable_impl(F&& fun) : super(std::forward<F>(fun))
inline bool types_match(any_tuple const&) const
{
return true;
}
bool unsafe_invoke(any_tuple const& value) const
inline bool could_invoke(any_tuple const&) const
{
auto tup = forced_tuple_cast(value, this->m_pattern);
util::apply_tuple((this->m_iimpl).m_fun, tup);
return true;
}
intermediate* get_unsafe_intermediate(any_tuple const& value)
inline any_tuple map(any_tuple& value) const
{
return std::move(value);
}
inline any_tuple map_unsafe(any_tuple& value) const
{
(this->m_iimpl).m_args = forced_tuple_cast(value, this->m_pattern);
return &(this->m_iimpl);
return std::move(value);
}
};
template<typename Fun, class Tuple, class Pattern>
class invokable_impl<true, 0, Fun, Tuple, Pattern> : public abstract_invokable<Tuple, Pattern>
template<class IntermediateImpl, class Policy>
struct invokable_impl : public invokable
{
typedef abstract_invokable<Tuple, Pattern> super;
IntermediateImpl m_ii;
Policy m_policy;
template<typename... P>
inline bool unsafe_vmatch(any_tuple const& t, pattern<P...> const& p) const
template<typename Arg0, typename... Args>
invokable_impl(Arg0&& arg0, Args&&... args)
: m_ii(std::forward<Arg0>(arg0))
, m_policy(std::forward<Args>(args)...)
{
return matcher<pattern<P...>::wildcard_pos, P...>::vmatch(t, p);
}
protected:
struct iimpl : intermediate
bool invoke(any_tuple& value) const
{
Fun m_fun;
template<typename F> iimpl(F&& fun) : m_fun(std::forward<F>(fun)) { }
void invoke() { m_fun(); }
inline bool operator()() const { m_fun(); return true; }
return m_ii(m_policy.map(value));
}
m_iimpl;
public:
template<typename F, typename... Args>
invokable_impl(F&& fun, Args&&... args)
: super(std::forward<Args>(args)...), m_iimpl(std::forward<F>(fun))
bool unsafe_invoke(any_tuple& value) const
{
return m_ii(m_policy.map_unsafe(value));
}
bool invoke(any_tuple const& value) const
bool types_match(any_tuple const& value) const
{
return matches(value, this->m_pattern) ? m_iimpl() : false;
return m_policy.types_match(value);
}
bool unsafe_invoke(any_tuple const& value) const
bool could_invoke(any_tuple const& value) const
{
return unsafe_vmatch(value, this->m_pattern) ? m_iimpl() : false;
return m_policy.could_invoke(value);
}
intermediate* get_intermediate(any_tuple const& value)
intermediate* get_intermediate(any_tuple& value)
{
return matches(value, this->m_pattern) ? &m_iimpl : nullptr;
return m_ii.prepare(m_policy.map(value));
}
intermediate* get_unsafe_intermediate(any_tuple const& value)
intermediate* get_unsafe_intermediate(any_tuple& value)
{
return unsafe_vmatch(value, this->m_pattern) ? &m_iimpl : nullptr;
return m_ii.prepare(m_policy.map_unsafe(value));
}
};
template<typename Fun, class Tuple, class Pattern>
struct invokable_impl<false, 0, Fun, Tuple, Pattern> : public invokable_impl<true, 0, Fun, Tuple, Pattern>
template<class ArgTypes>
constexpr mapping_policy get_mapping_policy()
{
typedef invokable_impl<true, 0, Fun, Tuple, Pattern> super;
template<typename... Args>
invokable_impl(Args&&... args) : super(std::forward<Args>(args)...) { }
bool unsafe_invoke(any_tuple const&) const
{
return (this->m_iimpl)();
}
intermediate* get_unsafe_intermediate(any_tuple const&)
{
return &(this->m_iimpl);
}
return (ArgTypes::size == 0)
? map_to_bool
: (( std::is_same<typename ArgTypes::head, any_tuple>::value
&& ArgTypes::size == 1)
? do_not_map
: map_to_option);
}
template<class Container>
struct filtered;
template<typename... Ts>
struct filtered<util::type_list<Ts...> >
{
typedef typename util::tl_filter_not<util::type_list<Ts...>, is_anything>::type
types;
};
template<typename... Ts>
struct filtered<pattern<Ts...> >
{
typedef typename filtered<util::type_list<Ts...>>::types types;
};
template<typename Fun, class Pattern>
struct select_invokable_impl
{
typedef typename util::get_arg_types<Fun>::types arg_types;
typedef typename Pattern::filtered_types filtered_types;
typedef typename tuple_from_type_list<filtered_types>::type tuple_type;
typedef invokable_impl<true, arg_types::size, Fun, tuple_type, Pattern> type1;
typedef invokable_impl<false, arg_types::size, Fun, tuple_type, Pattern> type2;
typedef typename util::get_arg_types<Fun>::types qualified_arg_types;
typedef typename util::tl_apply<qualified_arg_types, util::rm_ref>::type
arg_types;
static constexpr mapping_policy mp = get_mapping_policy<arg_types>();
typedef invokable_impl<iimpl<Fun, arg_types, typename filtered<Pattern>::types>,
pattern_policy<mp, Pattern> > type;
};
template<typename Fun>
struct select_invokable_impl<Fun, pattern<anything> >
{
typedef typename util::get_arg_types<Fun>::types qualified_arg_types;
typedef typename util::tl_apply<qualified_arg_types, util::rm_ref>::type
arg_types;
typedef typename util::rm_ref<typename arg_types::head>::type arg0;
static_assert(arg_types::size < 2, "functor has too many arguments");
static_assert( arg_types::size == 0
|| std::is_same<any_tuple, arg0>::value,
"bad signature");
typedef invokable_impl<iimpl<Fun, arg_types, util::type_list<> >,
dummy_policy> type;
};
template<class Pattern, typename Fun, typename Data>
std::unique_ptr<invokable> get_invokable_impl(Fun&& fun, Data&& dt)
{
typedef typename select_invokable_impl<Fun, Pattern>::type1 result;
typedef typename select_invokable_impl<Fun, Pattern>::type result;
return std::unique_ptr<invokable>(
new result(std::forward<Fun>(fun), std::forward<Data>(dt)));
}
......@@ -273,7 +369,7 @@ std::unique_ptr<invokable> get_invokable_impl(Fun&& fun, Data&& dt)
template<class Pattern, typename Fun>
std::unique_ptr<invokable> get_invokable_impl(Fun&& fun)
{
typedef typename select_invokable_impl<Fun, Pattern>::type2 result;
typedef typename select_invokable_impl<Fun, typename Pattern::types>::type result;
return std::unique_ptr<invokable>(new result(std::forward<Fun>(fun)));
}
......
......@@ -46,18 +46,14 @@ 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)
if (tup.impl_type() == tuple_impl_info::statically_typed)
{
return true;
// statically typed tuples return &typeid(type_list<T...>)
// as type token
return typeid(util::type_list<T...>) == *(tup.type_token());
}
// always use a full dynamic match for object arrays
else if (*impl == typeid(detail::object_array)
&& tup.size() == sizeof...(T))
// always use a full dynamic match for dynamic typed tuples
else if (tup.size() == sizeof...(T))
{
auto& tarr = detail::static_types_array<T...>::arr;
return std::equal(tup.begin(), tup.end(), tarr.begin(),
......@@ -479,6 +475,24 @@ bool matches(any_tuple const& tup, pattern<Ts...> const& pn,
mv);
}
// support for type_list based matching
template<typename... Ts>
inline bool matches(any_tuple const& tup, util::type_list<Ts...> const&)
{
return matches<Ts...>(tup);
}
template<typename... Ts>
inline bool matches(any_tuple const& tup, util::type_list<Ts...> const&,
util::fixed_vector<
size_t,
util::tl_count_not<
util::type_list<Ts...>,
is_anything>::value>& mv)
{
return matches<Ts...>(mv);
}
/*
* @brief Returns true if this tuple matches the pattern <tt>{Ts...}</tt>
* (does not match for values).
......@@ -489,6 +503,12 @@ inline bool matches_types(any_tuple const& tup, pattern<Ts...> const&)
return matches<Ts...>(tup);
}
template<typename... Ts>
inline bool matches_types(any_tuple const& tup, util::type_list<Ts...> const&)
{
return matches<Ts...>(tup);
}
} } // namespace cppa::detail
#endif // MATCHES_HPP
......@@ -42,13 +42,13 @@ namespace cppa { namespace detail {
class object_array : public abstract_tuple
{
std::vector<object> m_elements;
typedef abstract_tuple super;
public:
using abstract_tuple::const_iterator;
object_array() = default;
object_array();
object_array(object_array&&) = default;
object_array(object_array const&) = default;
......@@ -68,9 +68,9 @@ class object_array : public abstract_tuple
uniform_type_info const* type_at(size_t pos) const;
void const* type_token() const;
private:
std::type_info const* impl_type() const;
std::vector<object> m_elements;
};
......
......@@ -61,19 +61,21 @@ 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;
static inline option<Result> safe(any_tuple const& tup)
static inline option<Result> safe(any_tuple& tup)
{
mapping_vector mv;
if (matches<T...>(tup, mv)) return {Result::from(tup.vals(), mv)};
if (matches<T...>(tup, mv)) return {Result::from(std::move(tup.vals()),
mv)};
return {};
}
static inline option<Result> safe(any_tuple const& tup, pattern<T...> const& p)
static inline option<Result> safe(any_tuple& tup, pattern<T...> const& p)
{
mapping_vector mv;
if (matches(tup, p, mv)) return {Result::from(tup.vals(), mv)};
if (matches(tup, p, mv)) return {Result::from(std::move(tup.vals()),
mv)};
return {};
}
static inline option<Result> unsafe(any_tuple const& tup, pattern<T...> const& p)
static inline option<Result> unsafe(any_tuple& tup, pattern<T...> const& p)
{
mapping_vector mv;
if (WP == wildcard_position::in_between)
......@@ -87,16 +89,17 @@ struct tuple_cast_impl
// second range
begin = mv.begin() + first_wc;
std::iota(begin, mv.end(), tup.size() - (size - first_wc));
return {Result::from(tup.vals(), mv)};
return {Result::from(std::move(tup.vals()), mv)};
}
}
else
{
if (matches(tup, p, mv)) return {Result::from(tup.vals(), mv)};
if (matches(tup, p, mv)) return {Result::from(std::move(tup.vals()),
mv)};
}
return {};
}
static inline Result force(any_tuple const& tup, pattern<T...> const& p)
static inline Result force(any_tuple& tup, pattern<T...> const& p)
{
mapping_vector mv;
if (WP == wildcard_position::in_between)
......@@ -108,12 +111,12 @@ struct tuple_cast_impl
// second range
begin = mv.begin() + first_wc;
std::iota(begin, mv.end(), tup.size() - (size - first_wc));
return {Result::from(tup.vals(), mv)};
return {Result::from(std::move(tup.vals()), mv)};
}
else
{
matches(tup, p, mv);
return {Result::from(tup.vals(), mv)};
matches(tup, p, mv);
return {Result::from(std::move(tup.vals()), mv)};
}
}
};
......@@ -121,28 +124,31 @@ struct tuple_cast_impl
template<class Result, typename... T>
struct tuple_cast_impl<wildcard_position::nil, Result, T...>
{
static inline option<Result> safe(any_tuple const& tup)
static inline option<Result> safe(any_tuple& tup)
{
if (matches<T...>(tup)) return {Result::from(tup.vals())};
if (matches<T...>(tup)) return {Result::from(std::move(tup.vals()))};
return {};
}
static inline option<Result> safe(any_tuple const& tup, pattern<T...> const& p)
static inline option<Result> safe(any_tuple& tup, pattern<T...> const& p)
{
if (matches(tup, p)) return {Result::from(tup.vals())};
if (matches(tup, p))
{
return {Result::from(std::move(tup.vals()))};
}
return {};
}
static inline option<Result> unsafe(any_tuple const& tup, pattern<T...> const& p)
static inline option<Result> unsafe(any_tuple& tup, pattern<T...> const& p)
{
if ( p.has_values() == false
|| matcher<wildcard_position::nil, T...>::vmatch(tup, p))
{
return {Result::from(tup.vals())};
return {Result::from(std::move(tup.vals()))};
}
return {};
}
static inline Result force(any_tuple const& tup, pattern<T...> const&)
static inline Result force(any_tuple& tup, pattern<T...> const&)
{
return {Result::from(tup.vals())};
return {Result::from(std::move(tup.vals()))};
}
};
......@@ -150,37 +156,37 @@ template<class Result, typename... T>
struct tuple_cast_impl<wildcard_position::trailing, Result, T...>
: tuple_cast_impl<wildcard_position::nil, Result, T...>
{
static inline option<Result> unsafe(any_tuple const& tup, pattern<T...> const& p)
static inline option<Result> unsafe(any_tuple& tup, pattern<T...> const& p)
{
if ( p.has_values() == false
|| matcher<wildcard_position::trailing, T...>::vmatch(tup, p))
{
return {Result::from(tup.vals())};
return {Result::from(std::move(tup.vals()))};
}
return {};
}
static inline Result force(any_tuple const& tup, pattern<T...> const&)
static inline Result force(any_tuple& tup, pattern<T...> const&)
{
return {Result::from(tup.vals())};
return {Result::from(std::move(tup.vals()))};
}
};
template<class Result, typename... T>
struct tuple_cast_impl<wildcard_position::leading, Result, T...>
{
static inline option<Result> safe(any_tuple const& tup)
static inline option<Result> safe(any_tuple& tup)
{
size_t o = tup.size() - (sizeof...(T) - 1);
if (matches<T...>(tup)) return {Result::offset_subtuple(tup.vals(), o)};
return {};
}
static inline option<Result> safe(any_tuple const& tup, pattern<T...> const& p)
static inline option<Result> safe(any_tuple& tup, pattern<T...> const& p)
{
size_t o = tup.size() - (sizeof...(T) - 1);
if (matches(tup, p)) return {Result::offset_subtuple(tup.vals(), o)};
return {};
}
static inline option<Result> unsafe(any_tuple const& tup, pattern<T...> const& p)
static inline option<Result> unsafe(any_tuple& tup, pattern<T...> const& p)
{
if ( p.has_values() == false
|| matcher<wildcard_position::leading, T...>::vmatch(tup, p))
......@@ -190,7 +196,7 @@ struct tuple_cast_impl<wildcard_position::leading, Result, T...>
}
return {};
}
static inline Result force(any_tuple const& tup, pattern<T...> const&)
static inline Result force(any_tuple& tup, pattern<T...> const&)
{
size_t o = tup.size() - (sizeof...(T) - 1);
return Result::offset_subtuple(tup.vals(), o);
......
......@@ -59,11 +59,14 @@ class tuple_vals : public abstract_tuple
typedef types_array<ElementTypes...> element_types;
tuple_vals() : m_data() { }
tuple_vals() : super(tuple_impl_info::statically_typed), m_data() { }
tuple_vals(tuple_vals const& other) : super(), m_data(other.m_data) { }
tuple_vals(tuple_vals const&) = default;
tuple_vals(ElementTypes const&... args) : m_data(args...) { }
tuple_vals(ElementTypes const&... args)
: super(tuple_impl_info::statically_typed), m_data(args...)
{
}
inline data_type& data()
{
......@@ -114,12 +117,7 @@ class tuple_vals : public abstract_tuple
return abstract_tuple::equals(other);
}
void const* type_token() const
{
return detail::static_type_list<ElementTypes...>::list;
}
std::type_info const* impl_type() const
std::type_info const* type_token() const
{
return detail::static_type_list<ElementTypes...>::list;
}
......
......@@ -57,6 +57,8 @@ class tuple_view : public abstract_tuple
static_assert(sizeof...(ElementTypes) > 0,
"tuple_vals is not allowed to be empty");
typedef abstract_tuple super;
public:
typedef tdata<ElementTypes*...> data_type;
......@@ -69,7 +71,10 @@ class tuple_view : public abstract_tuple
/**
* @warning @p tuple_view does @b NOT takes ownership for given pointers
*/
tuple_view(ElementTypes*... args) : m_data(args...) { }
tuple_view(ElementTypes*... args)
: super(tuple_impl_info::statically_typed), m_data(args...)
{
}
inline data_type& data()
{
......@@ -112,12 +117,7 @@ class tuple_view : public abstract_tuple
return m_types[pos];
}
void const* type_token() const
{
return detail::static_type_list<ElementTypes...>::list;
}
std::type_info const* impl_type() const
std::type_info const* type_token() const
{
return detail::static_type_list<ElementTypes...>::list;
}
......
......@@ -38,23 +38,29 @@ namespace cppa { namespace detail {
struct match_helper
{
match_helper(match_helper const&) = delete;
match_helper& operator=(match_helper const&) = delete;
any_tuple tup;
match_helper(any_tuple t) : tup(std::move(t)) { }
match_helper(any_tuple&& t) : tup(std::move(t)) { }
match_helper(match_helper&&) = default;
template<class... Args>
void operator()(partial_function&& pf, Args&&... args)
{
partial_function tmp;
tmp.splice(std::move(pf), std::forward<Args>(args)...);
tmp(tup);
tmp(std::move(tup));
}
};
template<typename Iterator>
struct match_each_helper
{
match_each_helper(match_each_helper const&) = delete;
match_each_helper& operator=(match_each_helper const&) = delete;
Iterator i;
Iterator e;
match_each_helper(Iterator first, Iterator last) : i(first), e(last) { }
match_each_helper(match_each_helper&&) = default;
template<typename... Args>
void operator()(partial_function&& arg0, Args&&... args)
{
......@@ -70,11 +76,17 @@ struct match_each_helper
template<typename Iterator, typename Projection>
struct pmatch_each_helper
{
pmatch_each_helper(pmatch_each_helper const&) = delete;
pmatch_each_helper& operator=(pmatch_each_helper const&) = delete;
Iterator i;
Iterator e;
Projection p;
pmatch_each_helper(pmatch_each_helper&&) = default;
template<typename PJ>
pmatch_each_helper(Iterator first, Iterator last, PJ&& proj) : i(first), e(last), p(std::forward<PJ>(proj)) { }
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)
{
......@@ -91,6 +103,11 @@ struct pmatch_each_helper
namespace cppa {
//inline detail::match_helper match(any_tuple t)
//{
// return std::move(t);
//}
/**
* @brief Match expression.
*/
......
......@@ -65,11 +65,11 @@ class partial_function
bool defined_at(any_tuple const& value);
void operator()(any_tuple const& value);
void operator()(any_tuple value);
detail::invokable const* definition_at(any_tuple const& value);
detail::invokable const* definition_at(any_tuple value);
detail::intermediate* get_intermediate(any_tuple const& value);
detail::intermediate* get_intermediate(any_tuple value);
template<class... Args>
partial_function& splice(partial_function&& arg0, Args&&... args)
......
......@@ -43,7 +43,7 @@ std::string to_string_impl(void const* what, uniform_type_info const* utype);
} // namespace detail
/**
* @brief Serializes a value to a string.
* @brief Serializes a value to a string representation.
* @param what A value of an announced type.
* @returns A string representation of @p what.
*/
......
......@@ -121,19 +121,19 @@ class tuple
inline static tuple from(cow_ptr_type ptr)
{
return {priv_ctor(), std::move(ptr)};
return {priv_ctor{}, std::move(ptr)};
}
inline static tuple from(cow_ptr_type ptr,
util::fixed_vector<size_t, num_elements> const& mv)
{
return {priv_ctor(), decorated_type::create(std::move(ptr), mv)};
return {priv_ctor{}, decorated_type::create(std::move(ptr), mv)};
}
inline static tuple offset_subtuple(cow_ptr_type ptr, size_t offset)
{
CPPA_REQUIRE(offset > 0);
return {priv_ctor(), decorated_type::create(std::move(ptr), offset)};
return {priv_ctor{}, decorated_type::create(std::move(ptr), offset)};
}
/**
......
......@@ -42,10 +42,11 @@
namespace cppa {
/**
* @brief Tries to cast @p tup to {@link tuple tuple<T...>}.
* @brief Tries to cast @p tup to {@link tuple tuple<T...>}; moves content
* of @p tup on success.
*/
template<typename... T>
auto tuple_cast(any_tuple const& tup, pattern<T...> const& p)
auto moving_tuple_cast(any_tuple& tup, pattern<T...> const& p)
-> option<
typename tuple_from_type_list<
typename pattern<T...>::filtered_types
......@@ -59,28 +60,70 @@ auto tuple_cast(any_tuple const& tup, pattern<T...> const& p)
}
/**
* @brief Tries to cast @p tup to {@link tuple tuple<T...>}.
* @brief Tries to cast @p tup to {@link tuple tuple<T...>}; moves content
* of @p tup on success.
*/
template<typename... T>
auto tuple_cast(any_tuple const& tup)
auto moving_tuple_cast(any_tuple& tup)
-> option<
typename tuple_from_type_list<
typename util::tl_filter_not<util::type_list<T...>,
is_anything>::type
>::type>
{
typedef decltype(tuple_cast<T...>(tup)) result_type;
typedef decltype(moving_tuple_cast<T...>(tup)) result_type;
typedef typename result_type::value_type tuple_type;
static constexpr auto impl =
get_wildcard_position<util::type_list<T...>>();
return detail::tuple_cast_impl<impl, tuple_type, T...>::safe(tup);
}
template<typename... T>
auto moving_tuple_cast(any_tuple& tup, util::type_list<T...> const&)
-> decltype(moving_tuple_cast<T...>(tup))
{
return moving_tuple_cast<T...>(tup);
}
/**
* @brief Tries to cast @p tup to {@link tuple tuple<T...>}.
*/
template<typename... T>
auto tuple_cast(any_tuple tup, pattern<T...> const& p)
-> option<
typename tuple_from_type_list<
typename pattern<T...>::filtered_types
>::type>
{
return moving_tuple_cast(tup, p);
}
/**
* @brief Tries to cast @p tup to {@link tuple tuple<T...>}.
*/
template<typename... T>
auto tuple_cast(any_tuple tup)
-> option<
typename tuple_from_type_list<
typename util::tl_filter_not<util::type_list<T...>,
is_anything>::type
>::type>
{
return moving_tuple_cast<T...>(tup);
}
template<typename... T>
auto tuple_cast(any_tuple tup, util::type_list<T...> const&)
-> decltype(tuple_cast<T...>(tup))
{
return moving_tuple_cast<T...>(tup);
}
/////////////////////////// for in-library use only! ///////////////////////////
// cast using a pattern; does not perform type checking
// (moving) cast using a pattern; does not perform type checking
template<typename... T>
auto unsafe_tuple_cast(any_tuple const& tup, pattern<T...> const& p)
auto unsafe_tuple_cast(any_tuple& tup, pattern<T...> const& p)
-> option<
typename tuple_from_type_list<
typename pattern<T...>::filtered_types
......@@ -93,9 +136,16 @@ auto unsafe_tuple_cast(any_tuple const& tup, pattern<T...> const& p)
return detail::tuple_cast_impl<impl, tuple_type, T...>::unsafe(tup, p);
}
template<typename... T>
auto unsafe_tuple_cast(any_tuple& tup, util::type_list<T...> const&)
-> decltype(tuple_cast<T...>(tup))
{
return tuple_cast<T...>(tup);
}
// cast using a pattern; does neither perform type checking nor checks values
template<typename... T>
auto forced_tuple_cast(any_tuple const& tup, pattern<T...> const& p)
auto forced_tuple_cast(any_tuple& tup, pattern<T...> const& p)
-> typename tuple_from_type_list<
typename pattern<T...>::filtered_types
>::type
......
......@@ -118,7 +118,7 @@ int main(int, char**)
int i = 0;
receive_while([&]() { return ++i <= 2; })
(
on<bar>() >> [](const bar& val)
on<bar>() >> [](bar const& val)
{
cout << "bar(foo("
<< val.f.a() << ","
......@@ -126,12 +126,11 @@ int main(int, char**)
<< val.i << ")"
<< endl;
},
on<baz>() >> []()
on<baz>() >> [](baz const& val)
{
// prints: @<> ( { baz ( foo ( 1, 2 ), bar ( foo ( 3, 4 ), 5 ) ) } )
cout << to_string(self->last_dequeued()) << endl;
// prints: baz ( foo ( 1, 2 ), bar ( foo ( 3, 4 ), 5 ) )
cout << to_string(val) << endl;
}
);
return 0;
}
......
......@@ -39,6 +39,15 @@ bool abstract_tuple::equals(const abstract_tuple &other) const
&& std::equal(begin(), end(), other.begin(), detail::full_eq_v3));
}
abstract_tuple::abstract_tuple(abstract_tuple const&) : ref_counted() { }
abstract_tuple::abstract_tuple(abstract_tuple const& other)
: ref_counted()
, m_impl_type(other.m_impl_type)
{
}
std::type_info const* abstract_tuple::type_token() const
{
return &typeid(void);
}
} } // namespace cppa::detail
......@@ -34,51 +34,6 @@
namespace {
/*
struct offset_decorator : cppa::detail::abstract_tuple
{
typedef cppa::cow_ptr<cppa::detail::abstract_tuple> ptr_type;
offset_decorator(ptr_type const& decorated, size_t offset)
: m_offset(offset)
, m_decorated(decorated)
{
}
void* mutable_at(size_t pos)
{
return m_decorated->mutable_at(pos + m_offset);
}
size_t size() const
{
return m_decorated->size() - m_offset;
}
abstract_tuple* copy() const
{
return new offset_decorator(m_decorated, m_offset);
}
const void* at(size_t pos) const
{
return m_decorated->at(pos + m_offset);
}
const cppa::uniform_type_info* type_at(size_t pos) const
{
return m_decorated->type_at(pos + m_offset);
}
private:
size_t m_offset;
ptr_type m_decorated;
};
*/
inline cppa::detail::empty_tuple* s_empty_tuple()
{
return cppa::detail::singleton_manager::get_empty_tuple();
......@@ -131,11 +86,6 @@ const uniform_type_info* any_tuple::type_at(size_t p) const
return m_vals->type_at(p);
}
const cow_ptr<detail::abstract_tuple>& any_tuple::vals() const
{
return m_vals;
}
bool any_tuple::equals(any_tuple const& other) const
{
return m_vals->equals(*other.vals());
......
......@@ -33,6 +33,10 @@
namespace cppa { namespace detail {
empty_tuple::empty_tuple() : abstract_tuple(tuple_impl_info::statically_typed)
{
}
size_t empty_tuple::size() const
{
return 0;
......@@ -63,14 +67,9 @@ bool empty_tuple::equals(const abstract_tuple& other) const
return other.size() == 0;
}
void const* empty_tuple::type_token() const
{
return &typeid(empty_tuple);
}
std::type_info const* empty_tuple::impl_type() const
std::type_info const* empty_tuple::type_token() const
{
return &typeid(empty_tuple);
return &typeid(util::type_list<>);
}
} } // namespace cppa::detail
......@@ -36,16 +36,16 @@ invokable::~invokable()
{
}
bool invokable::invoke(any_tuple const&) const { return false; }
bool invokable::invoke(any_tuple&) const { return false; }
bool invokable::unsafe_invoke(any_tuple const&) const { return false; }
bool invokable::unsafe_invoke(any_tuple&) const { return false; }
bool invokable::types_match(any_tuple const&) const { return false; }
bool invokable::could_invoke(any_tuple const&) const { return false; }
intermediate* invokable::get_intermediate(any_tuple const&) { return 0; }
intermediate* invokable::get_intermediate(any_tuple&) { return 0; }
intermediate* invokable::get_unsafe_intermediate(any_tuple const&) { return 0; }
intermediate* invokable::get_unsafe_intermediate(any_tuple&) { return 0; }
} } // namespace cppa::detail
......@@ -32,6 +32,10 @@
namespace cppa { namespace detail {
object_array::object_array() : super(tuple_impl_info::dynamically_typed)
{
}
void object_array::push_back(object const& what)
{
m_elements.push_back(what);
......@@ -67,14 +71,4 @@ uniform_type_info const* object_array::type_at(size_t pos) const
return m_elements[pos].type();
}
void const* object_array::type_token() const
{
return &typeid(object_array);
}
std::type_info const* object_array::impl_type() const
{
return &typeid(object_array);
}
} } // namespace cppa::detail
......@@ -28,6 +28,8 @@
\******************************************************************************/
#include "cppa/to_string.hpp"
#include "cppa/config.hpp"
#include "cppa/behavior.hpp"
#include "cppa/partial_function.hpp"
......@@ -66,11 +68,23 @@ auto partial_function::get_cache_entry(any_tuple const& value) -> cache_entry&
// if we didn't found a cache entry ...
if (i == end || i->first != m_dummy.first)
{
// ... create one (store all invokables with matching types)
// ... create one
cache_entry tmp;
for (auto f = m_funs.begin(); f != m_funs.end(); ++f)
if (value.impl_type() == detail::tuple_impl_info::statically_typed)
{
// use static type information for optimal caching
for (auto f = m_funs.begin(); f != m_funs.end(); ++f)
{
if (f->types_match(value)) tmp.push_back(f.ptr());
}
}
else
{
if (f->types_match(value)) tmp.push_back(f.ptr());
// "dummy" cache entry with all functions (dynamically typed tuple)
for (auto f = m_funs.begin(); f != m_funs.end(); ++f)
{
tmp.push_back(f.ptr());
}
}
// m_cache is always sorted,
// due to emplace(upper_bound, ...) insertions
......@@ -79,20 +93,31 @@ auto partial_function::get_cache_entry(any_tuple const& value) -> cache_entry&
return i->second;
}
void partial_function::operator()(any_tuple const& value)
void partial_function::operator()(any_tuple value)
{
using detail::invokable;
auto& v = get_cache_entry(value);
(void) std::any_of(
v.begin(), v.end(),
[&](detail::invokable* i) { return i->unsafe_invoke(value); });
if (value.impl_type() == detail::tuple_impl_info::statically_typed)
{
std::any_of(v.begin(), v.end(),
[&](invokable* i) { return i->unsafe_invoke(value); });
}
else
{
std::any_of(v.begin(), v.end(),
[&](invokable* i) { return i->invoke(value); });
}
}
detail::invokable const* partial_function::definition_at(any_tuple const& value)
detail::invokable const* partial_function::definition_at(any_tuple value)
{
using detail::invokable;
auto& v = get_cache_entry(value);
auto i = std::find_if(
v.begin(), v.end(),
[&](detail::invokable* i) { return i->could_invoke(value); });
auto i = (value.impl_type() == detail::tuple_impl_info::statically_typed)
? std::find_if(v.begin(), v.end(),
[&](invokable* i) { return i->could_invoke(value);})
: std::find_if(v.begin(), v.end(),
[&](invokable* i) { return i->invoke(value); });
return (i != v.end()) ? *i : nullptr;
}
......@@ -101,15 +126,20 @@ bool partial_function::defined_at(any_tuple const& value)
return definition_at(value) != nullptr;
}
detail::intermediate* partial_function::get_intermediate(any_tuple const& value)
detail::intermediate* partial_function::get_intermediate(any_tuple value)
{
detail::intermediate* result = nullptr;
for (auto& i : get_cache_entry(value))
if (value.impl_type() == detail::tuple_impl_info::statically_typed)
{
if ((result = i->get_unsafe_intermediate(value)) != nullptr)
{
return result;
}
for (auto& i : get_cache_entry(value))
if ((result = i->get_unsafe_intermediate(value)) != nullptr)
return result;
}
else
{
for (auto& i : get_cache_entry(value))
if ((result = i->get_intermediate(value)) != nullptr)
return result;
}
return nullptr;
}
......
......@@ -65,6 +65,15 @@ using std::endl;
using namespace cppa;
std::vector<std::string> split(std::string const& str, char delim)
{
std::vector<std::string> result;
std::stringstream strs{str};
std::string tmp;
while (std::getline(strs, tmp, delim)) result.push_back(tmp);
return result;
}
void print_node_id()
{
auto pinfo = cppa::process_information::get();
......@@ -78,15 +87,6 @@ void print_node_id()
<< endl;
}
std::vector<std::string> split(std::string const& str, char delim)
{
std::vector<std::string> result;
std::stringstream strs{str};
std::string tmp;
while (std::getline(strs, tmp, delim)) result.push_back(tmp);
return result;
}
std::vector<string_pair> get_kv_pairs(int argc, char** argv, int begin = 1)
{
std::vector<string_pair> result;
......@@ -121,16 +121,6 @@ void usage(char const* argv0)
int main(int argc, char** argv)
{
/*
std::string abc = "abc";
cout << "is_iterable<string> = " << cppa::util::is_iterable<std::string>::value << endl;
match(abc)
(
on("abc") >> []()
{
cout << "ABC" << endl;
}
);
match_each(argv + 1, argv + argc)
(
on_arg_match >> [](std::string const& str)
......@@ -145,11 +135,15 @@ int main(int argc, char** argv)
{
cout << "key = \"" << key << "\", value = \"" << value << "\""
<< endl;
},
others() >> [](any_tuple const& oops)
{
cout << "not a key value pair: " << to_string(oops) << endl;
}
);
return 0;
*/
//*/
auto args = get_kv_pairs(argc, argv);
match_each(args)
......
......@@ -4,6 +4,7 @@
#include <vector>
#include <string>
#include <cstddef>
#include <sstream>
#include <iostream>
#include <type_traits>
......@@ -110,6 +111,8 @@ size_t test__intrusive_containers();
void test__queue_performance();
std::vector<std::string> split(std::string const& str, char delim);
using std::cout;
using std::endl;
using std::cerr;
......
#include <functional>
#include "test.hpp"
#include "cppa/on.hpp"
#include "cppa/match.hpp"
#include "cppa/announce.hpp"
#include "cppa/to_string.hpp"
using namespace cppa;
using std::vector;
using std::string;
size_t test__match()
{
CPPA_TEST(test__match);
bool invoked = false;
match("abc")
(
on("abc") >> [&]()
{
invoked = true;
}
);
if (!invoked) { CPPA_ERROR("match(\"abc\") failed"); }
invoked = false;
vector<string> vec{"a", "b", "c"};
match(vec)
(
on("a", "b", arg_match) >> [&](string& str)
{
invoked = true;
str = "C";
}
);
if (!invoked) { CPPA_ERROR("match({\"a\", \"b\", \"c\"}) failed"); }
CPPA_CHECK_EQUAL("C", vec.back());
invoked = false;
match_each(vec)
(
on("a") >> [&](string& str)
{
invoked = true;
str = "A";
}
);
if (!invoked) { CPPA_ERROR("match_each({\"a\", \"b\", \"C\"}) failed"); }
CPPA_CHECK_EQUAL("A", vec.front());
invoked = false;
match(vec)
(
others() >> [&](any_tuple& tup)
{
if (detail::matches<string, string, string>(tup))
{
tup.get_as_mutable<string>(1) = "B";
}
else
{
CPPA_ERROR("matches<string, string, string>(tup) == false");
}
invoked = true;
}
);
if (!invoked) { CPPA_ERROR("match({\"a\", \"b\", \"c\"}) failed"); }
CPPA_CHECK_EQUAL(vec[1], "B");
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(true, invoked);
invoked = false;
int pmatches = 0;
using std::placeholders::_1;
pmatch_each(vec2.begin(), vec2.end(), std::bind(split, _1, '='))
(
on("a", arg_match) >> [&](string const& value)
{
CPPA_CHECK_EQUAL("0", value);
CPPA_CHECK_EQUAL(0, pmatches);
++pmatches;
},
on("b", arg_match) >> [&](string const& value)
{
CPPA_CHECK_EQUAL("1", value);
CPPA_CHECK_EQUAL(1, pmatches);
++pmatches;
},
on("c", arg_match) >> [&](string const& value)
{
CPPA_CHECK_EQUAL("2", value);
CPPA_CHECK_EQUAL(2, pmatches);
++pmatches;
},
others() >> [](any_tuple const& value)
{
cout << to_string(value) << endl;
}
);
CPPA_CHECK_EQUAL(3, pmatches);
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