Commit 30bdfb6a authored by neverlord's avatar neverlord

pattern matching

parent 1620a761
......@@ -176,6 +176,7 @@ nobase_library_include_HEADERS = \
cppa/tuple_cast.hpp \
cppa/type_value_pair.hpp \
cppa/uniform_type_info.hpp \
cppa/util/a_matches_b.hpp \
cppa/util/abstract_uniform_type_info.hpp \
cppa/util/apply_tuple.hpp \
cppa/util/arg_match_t.hpp \
......
......@@ -258,3 +258,4 @@ cppa/detail/matches.hpp
unit_testing/test__match.cpp
cppa/guard_expr.hpp
src/pattern.cpp
cppa/util/a_matches_b.hpp
......@@ -68,6 +68,10 @@ class abstract_tuple : public ref_counted
virtual void const* at(size_t pos) const = 0;
virtual uniform_type_info const* type_at(size_t pos) const = 0;
// returns either tdata<...> object or nullptr (default) if tuple
// is not a 'native' implementation
virtual void const* native_data() const;
// 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()
......
......@@ -39,6 +39,8 @@
#include "cppa/util/at.hpp"
#include "cppa/util/wrapped.hpp"
#include "cppa/util/type_list.hpp"
#include "cppa/util/enable_if.hpp"
#include "cppa/util/disable_if.hpp"
#include "cppa/util/arg_match_t.hpp"
#include "cppa/detail/abstract_tuple.hpp"
......@@ -75,6 +77,13 @@ struct tdata<>
util::void_type head;
typedef util::void_type head_type;
typedef tdata<> tail_type;
typedef util::void_type back_type;
typedef util::type_list<> types;
static constexpr size_t tdata_size = 0;
constexpr tdata() { }
inline tdata(tdata&&) { }
......@@ -84,15 +93,9 @@ struct tdata<>
// swallow "arg_match" silently
constexpr tdata(util::wrapped<util::arg_match_t> const&) { }
tdata<>& tail()
{
throw std::out_of_range("");
}
tdata<>& tail() { return *this; }
tdata<> const& tail() const
{
throw std::out_of_range("");
}
tdata<> const& tail() const { return *this; }
inline void const* at(size_t) const
{
......@@ -119,8 +122,22 @@ struct tdata<Head, Tail...> : tdata<Tail...>
typedef tdata<Tail...> super;
typedef util::type_list<Head, Tail...> types;
Head head;
static constexpr size_t tdata_size = (sizeof...(Tail) + 1);
typedef Head head_type;
typedef tdata<Tail...> tail_type;
typedef typename util::if_else_c<
(sizeof...(Tail) > 0),
typename tdata<Tail...>::back_type,
util::wrapped<Head>
>::type
back_type;
inline tdata() : super(), head() { }
//tdata(Head const& v0, Tail const&... vals) : super(vals...), head(v0) { }
......@@ -141,11 +158,51 @@ struct tdata<Head, Tail...> : tdata<Tail...>
}
// allow (partial) initialization from a different tdata
// with traling extra arguments to initialize additional arguments
template<typename... Y>
tdata(tdata<Y...> const& other) : super(other.tail()), head(other.head)
{
}
template<typename... Y>
tdata(tdata<Y...>&& other)
: super(std::move(other.tail())), head(std::move(other.head))
{
}
template<typename... Y>
tdata(tdata<Y...> const& other) : super(other.tail()), head(other.head) { }
tdata(Head const& arg, tdata<Y...> const& other)
: super(other), head(arg)
{
}
template<typename... Y>
tdata(tdata<Y...>&& other) : super(std::move(other.tail())), head(std::move(other.head)) { }
tdata(tdata<Head> const& arg, tdata<Y...> const& other)
: super(other), head(arg.head)
{
}
template<typename ExtraArg, typename Y0, typename Y1, typename... Y>
tdata(tdata<Y0, Y1, Y...> const& other, ExtraArg const& arg)
: super(other.tail(), arg), head(other.head)
{
}
template<typename ExtraArg, typename Y0>
tdata(tdata<Y0> const& other, ExtraArg const& arg,
typename util::enable_if_c< std::is_same<ExtraArg, ExtraArg>::value
&& (sizeof...(Tail) > 0)>::type* = 0)
: super(arg), head(other.head)
{
}
template<typename ExtraArg, typename Y0>
tdata(tdata<Y0> const& other, ExtraArg const& arg,
typename util::enable_if_c< std::is_same<ExtraArg, ExtraArg>::value
&& (sizeof...(Tail) == 0)>::type* = 0)
: super(), head(other.head, arg)
{
}
// allow initialization with a function pointer or reference
// returning a wrapped<Head>
......@@ -183,75 +240,42 @@ struct tdata<Head, Tail...> : tdata<Tail...>
return (p == 0) ? uniform_typeid(typeid(Head)) : super::type_at(p-1);
}
};
template<typename Head, typename... Tail>
struct tdata<option<Head>, Tail...> : tdata<Tail...>
{
typedef tdata<Tail...> super;
option<Head> head;
typedef option<Head> opt_type;
inline tdata() : super(), head() { }
template<typename... Args>
tdata(Head const& v0, Args const&... vals) : super(vals...), head(v0) { }
template<typename... Args>
tdata(Head&& v0, Args const&... vals) : super(vals...), head(std::move(v0)) { }
template<typename... Args>
tdata(util::wrapped<Head> const&, Args const&... vals) : super(vals...) { }
tdata(tdata<>&&) : super(), head() { }
tdata(tdata<> const&) : super(), head() { }
// allow (partial) initialization from a different tdata
template<typename... Y>
tdata(tdata<Y...> const& other) : super(other.tail()), head(other.head) { }
template<typename... Y>
tdata(tdata<Y...>&& other) : super(std::move(other.tail())), head(std::move(other.head)) { }
// allow initialization with a function pointer or reference
// returning a wrapped<Head>
template<typename...Args>
tdata(util::wrapped<Head>(*)(), Args const&... vals)
: super(vals...), head()
Head& _back(std::integral_constant<size_t, 0>)
{
return head;
}
template<typename Arg0, typename... Args>
inline void set(Arg0&& arg0, Args&&... args)
template<size_t Pos>
back_type& _back(std::integral_constant<size_t, Pos>)
{
head = std::forward<Arg0>(arg0);
super::set(std::forward<Args>(args)...);
std::integral_constant<size_t, Pos - 1> token;
return super::_back(token);
}
template<typename... Y>
tdata& operator=(tdata<Y...> const& other)
back_type& back()
{
tdata_set(*this, other);
return *this;
std::integral_constant<size_t, sizeof...(Tail)> token;
return _back(token);
}
// upcast
inline tdata<Tail...>& tail() { return *this; }
inline tdata<Tail...> const& tail() const { return *this; }
inline void const* at(size_t p) const
Head const& _back(std::integral_constant<size_t, 0>) const
{
return (p == 0) ? ptr_to(head) : super::at(p-1);
return head;
}
inline uniform_type_info const* type_at(size_t p) const
template<size_t Pos>
back_type const& _back(std::integral_constant<size_t, Pos>) const
{
return (p == 0) ? uniform_typeid(typeid(Head)) : super::type_at(p-1);
std::integral_constant<size_t, Pos - 1> token;
return super::_back(token);
}
back_type const& back() const
{
std::integral_constant<size_t, sizeof...(Tail)> token;
return _back(token);
}
};
template<typename... X>
......
......@@ -68,6 +68,11 @@ class tuple_vals : public abstract_tuple
{
}
void const* native_data() const
{
return &m_data;
}
inline data_type& data()
{
return m_data;
......
......@@ -306,6 +306,7 @@ struct ge_reference_wrapper
{
T const* value;
ge_reference_wrapper(T&&) = delete;
ge_reference_wrapper() : value(nullptr) { }
ge_reference_wrapper(T const& val_ref) : value(&val_ref) { }
ge_reference_wrapper(ge_reference_wrapper const&) = default;
ge_reference_wrapper& operator=(ge_reference_wrapper const&) = default;
......
......@@ -115,6 +115,32 @@ struct get_result_type
typedef typename trait_type::result_type type;
};
template<typename T>
struct is_callable
{
template<typename C>
static bool _fun(C*, typename callable_trait<C>::result_type* = nullptr)
{
return true;
}
template<typename C>
static bool _fun(C*, typename callable_trait<decltype(&C::operator())>::result_type* = nullptr)
{
return true;
}
static void _fun(void*) { }
typedef decltype(_fun(static_cast<T*>(nullptr))) result_type;
public:
static constexpr bool value = std::is_same<bool, result_type>::value;
};
} } // namespace cppa::util
#endif // CPPA_UTIL_CALLABLE_TRAIT
......@@ -35,49 +35,46 @@
namespace cppa { namespace util {
template<size_t Begin, size_t End, bool BeginGreaterEnd>
template<bool BeginLessEnd, size_t Begin, size_t End>
struct static_foreach_impl
{
template<typename Container, typename Fun>
static inline void _(Container const& c, Fun& f)
template<typename Container, typename Fun, typename... Args>
static inline void _(Container const& c, Fun& f, Args const&... args)
{
f(get<Begin>(c));
static_foreach_impl<Begin+1, End, (Begin+1 > End)>::_(c, f);
f(get<Begin>(c), args...);
static_foreach_impl<(Begin+1 < End), Begin+1, End>::_(c, f, args...);
}
template<typename Container, typename Fun>
static inline bool eval(Container const& c, Fun& f)
template<typename Container, typename Fun, typename... Args>
static inline void _ref(Container& c, Fun& f, Args const&... args)
{
return f(get<Begin>(c))
&& static_foreach_impl<Begin+1, End, (Begin+1 > End)>::eval(c, f);
f(get_ref<Begin>(c), args...);
static_foreach_impl<(Begin+1 < End), Begin+1, End>::_ref(c, f, args...);
}
template<typename Container, typename Fun>
static inline bool eval_or(Container const& c, Fun& f)
template<typename Container, typename Fun, typename... Args>
static inline bool eval(Container const& c, Fun& f, Args const&... args)
{
return f(get<Begin>(c))
|| static_foreach_impl<Begin+1, End, (Begin+1 > End)>::eval_or(c, f);
return f(get<Begin>(c), args...)
&& static_foreach_impl<(Begin+1 < End), Begin+1, End>::eval(c, f, args...);
}
template<typename Container, typename Fun, typename... Args>
static inline bool eval_or(Container const& c, Fun& f, Args const&... args)
{
return f(get<Begin>(c), args...)
|| static_foreach_impl<(Begin+1 < End), Begin+1, End>::eval_or(c, f, args...);
}
};
template<size_t X>
struct static_foreach_impl<X, X, false>
{
template<typename Container, typename Fun>
static inline void _(Container const&, Fun&) { }
template<typename Container, typename Fun>
static inline bool eval(Container const&, Fun&) { return true; }
template<typename Container, typename Fun>
static inline bool eval_or(Container const&, Fun&) { return true; }
};
template<size_t X, size_t Y>
struct static_foreach_impl<X, Y, true>
struct static_foreach_impl<false, X, Y>
{
template<typename Container, typename Fun>
static inline void _(Container const&, Fun&) { }
template<typename Container, typename Fun>
static inline bool eval(Container const&, Fun&) { return true; }
template<typename Container, typename Fun>
static inline bool eval_or(Container const&, Fun&) { return true; }
template<typename... Args>
static inline void _(Args const&...) { }
template<typename... Args>
static inline void _ref(Args const&...) { }
template<typename... Args>
static inline bool eval(Args const&...) { return true; }
template<typename... Args>
static inline bool eval_or(Args const&...) { return false; }
};
/**
......@@ -85,7 +82,7 @@ struct static_foreach_impl<X, Y, true>
* @brief A for loop that can be used with tuples.
*/
template<size_t Begin, size_t End>
struct static_foreach : static_foreach_impl<Begin, End, (Begin > End)>
struct static_foreach : static_foreach_impl<(Begin < End), Begin, End>
{
};
......
......@@ -32,7 +32,9 @@
#define LIBCPPA_UTIL_TYPE_LIST_HPP
#include <typeinfo>
#include <type_traits>
#include "cppa/util/tbind.hpp"
#include "cppa/util/if_else.hpp"
#include "cppa/util/type_pair.hpp"
#include "cppa/util/void_type.hpp"
......@@ -87,6 +89,18 @@ struct type_list<Head, Tail...>
};
template<typename T>
struct is_type_list
{
static constexpr bool value = false;
};
template<typename... Ts>
struct is_type_list<type_list<Ts...> >
{
static constexpr bool value = true;
};
// static list list::zip(list, list)
template<class ListA, class ListB>
......@@ -109,6 +123,37 @@ struct tl_zip<type_list<LhsElements...>, type_list<RhsElements...> >
"Lists have different size");
};
// static list list::zip_with_index(list)
template<bool Done, class List, size_t Pos, size_t...>
struct tl_zip_with_index_impl;
template<class List, size_t Pos, size_t... Range>
struct tl_zip_with_index_impl<false, List, Pos, Range...>
: tl_zip_with_index_impl<List::size == (Pos + 1), List, (Pos + 1), Range..., Pos>
{
};
template<typename... Ts, size_t Pos, size_t... Range>
struct tl_zip_with_index_impl<true, type_list<Ts...>, Pos, Range...>
{
typedef type_list<type_pair<std::integral_constant<size_t, Range>, Ts>...>
type;
};
template<class List>
struct tl_zip_with_index
{
typedef typename tl_zip_with_index_impl<false, List, 0>::type type;
};
template<>
struct tl_zip_with_index<type_list<> >
{
typedef type_list<> type;
};
// list list::reverse()
template<class From, typename... Elements>
......@@ -141,39 +186,47 @@ struct tl_reverse
* @brief Finds the first element of type @p What beginning at
* index @p Pos.
*/
template<class List, typename What, int Pos = 0>
template<class List, template<typename> class Predicate, int Pos = 0>
struct tl_find_impl;
template<typename What, int Pos>
struct tl_find_impl<type_list<>, What, Pos>
template<template<typename> class Predicate, int Pos>
struct tl_find_impl<type_list<>, Predicate, Pos>
{
static constexpr int value = -1;
typedef type_list<> rest_list;
};
template<typename What, int Pos, typename... Tail>
struct tl_find_impl<type_list<What, Tail...>, What, Pos>
template<template<typename> class Predicate, int Pos,
typename Head, typename... Tail>
struct tl_find_impl<type_list<Head, Tail...>, Predicate, Pos>
{
static constexpr int value = Pos;
typedef type_list<Tail...> rest_list;
static constexpr int value =
Predicate<Head>::value
? Pos
: tl_find_impl<type_list<Tail...>, Predicate, Pos+1>::value;
};
template<typename What, int Pos, typename Head, typename... Tail>
struct tl_find_impl<type_list<Head, Tail...>, What, Pos>
/**
* @brief Finds the first element of type @p What beginning at
* index @p Pos.
*/
template<class List, typename What, int Pos = 0>
struct tl_find
{
static constexpr int value = tl_find_impl<type_list<Tail...>, What, Pos+1>::value;
typedef typename tl_find_impl<type_list<Tail...>, What, Pos+1>::rest_list rest_list;
static constexpr int value =
tl_find_impl<List,
tbind<std::is_same, What>::template type,
Pos
>::value;
};
/**
* @brief Finds the first element of type @p What beginning at
* @brief Finds the first element satisfying @p Predicate beginning at
* index @p Pos.
*/
template<class List, class What, int Pos = 0>
struct tl_find
template<class List, template<typename> class Predicate, int Pos = 0>
struct tl_find_if
{
static constexpr int value = tl_find_impl<List, What, Pos>::value;
typedef typename tl_find_impl<List, What, Pos>::rest_list rest_list;
static constexpr int value = tl_find_impl<List, Predicate, Pos>::value;
};
// list list::first_n(size_t)
......@@ -453,18 +506,192 @@ struct tl_filter<type_list<T...>, Predicate>
};
/**
* @brief Create a new list containing all elements which
* @brief Creates a new list containing all elements which
* do not satisfy @p Predicate.
*/
template<class List, template<typename> class Predicate>
struct tl_filter_not;
template<template<typename> class Predicate>
struct tl_filter_not<type_list<>, Predicate>
{
typedef type_list<> type;
};
template<template<typename> class Predicate, typename... T>
struct tl_filter_not<type_list<T...>, Predicate>
{
typedef typename tl_filter_impl<type_list<T...>, !Predicate<T>::value...>::type type;
};
/**
* @brief Creates a new list containing all elements which
* are not equal to @p Type.
*/
template<class List, class Type>
struct tl_filter_type;
template<class Type, typename... T>
struct tl_filter_type<type_list<T...>, Type>
{
typedef typename tl_filter_impl<type_list<T...>, std::is_same<T, Type>::value...>::type type;
};
// list list::distinct(list)
/**
* @brief Creates a new list from @p List without any duplicate elements.
*/
template<class List>
struct tl_distinct;
template<>
struct tl_distinct<type_list<> > { typedef type_list<> type; };
template<typename Head, typename... Tail>
struct tl_distinct<type_list<Head, Tail...> >
{
typedef typename tl_concat<
type_list<Head>,
typename tl_distinct<
typename tl_filter_type<type_list<Tail...>, Head>::type
>::type
>::type
type;
};
// list list::resize(list, size, fill_type)
template<class List, bool OldSizeLessNewSize,
size_t OldSize, size_t NewSize, typename FillType>
struct tl_resize_impl;
template<class List, size_t OldSize, size_t NewSize, typename FillType>
struct tl_resize_impl<List, false, OldSize, NewSize, FillType>
{
typedef typename tl_first_n<List, NewSize>::type type;
};
template<class List, size_t Size, typename FillType>
struct tl_resize_impl<List, false, Size, Size, FillType>
{
typedef List type;
};
template<class List, size_t OldSize, size_t NewSize, typename FillType>
struct tl_resize_impl<List, true, OldSize, NewSize, FillType>
{
typedef typename tl_resize_impl<
typename tl_push_back<List, FillType>::type,
(OldSize + 1) < NewSize,
OldSize + 1,
NewSize,
FillType
>::type
type;
};
/**
* @brief Resizes the list to contain @p NewSize elements and uses
* @p FillType to initialize the new elements with.
*/
template<class List, size_t NewSize, typename FillType>
struct tl_resize
{
typedef typename tl_resize_impl<
List, (List::size < NewSize), List::size, NewSize, FillType
>::type
type;
};
template<class List>
struct tl_is_zipped
{
static constexpr bool value = tl_forall<List, is_type_pair>::value;
};
/**
* @brief Removes trailing @p What elements from the end.
*/
template<class List, typename What>
struct tl_trim
{
typedef typename util::if_else<
std::is_same<typename List::back, What>,
typename tl_trim<typename tl_pop_back<List>::type, What>::type,
util::wrapped<List>
>::type
type;
};
template<typename What>
struct tl_trim<type_list<>, What>
{
typedef type_list<> type;
};
// list list::group_by(list, predicate)
template<bool Append, typename What, class Where>
struct tl_group_by_impl_step;
template<typename What, typename... Ts>
struct tl_group_by_impl_step<true, What, type_list<Ts...> >
{
typedef type_list<type_list<Ts..., What> > type;
};
template<typename What, class List>
struct tl_group_by_impl_step<false, What, List>
{
typedef type_list<List, type_list<What> > type;
};
template<class In, class Out, template<typename, typename> class Predicate>
struct tl_group_by_impl
{
typedef typename Out::back last_group;
typedef typename tl_group_by_impl_step<
Predicate<typename In::head, typename last_group::back>::value,
typename In::head,
last_group
>::type
suffix;
typedef typename tl_pop_back<Out>::type prefix;
typedef typename tl_concat<prefix, suffix>::type new_out;
typedef typename tl_group_by_impl<
typename In::tail,
new_out,
Predicate
>::type
type;
};
template<template<typename, typename> class Predicate, typename Head, typename... Tail>
struct tl_group_by_impl<type_list<Head, Tail...>, type_list<>, Predicate>
{
typedef typename tl_group_by_impl<
type_list<Tail...>,
type_list<type_list<Head> >,
Predicate
>::type
type;
};
template<class Out, template<typename, typename> class Predicate>
struct tl_group_by_impl<type_list<>, Out, Predicate>
{
typedef Out type;
};
template<class List, template<typename, typename> class Predicate>
struct tl_group_by
{
typedef typename tl_group_by_impl<List, type_list<>, Predicate>::type type;
};
/**
* @}
*/
......
......@@ -44,6 +44,18 @@ struct type_pair
typedef Second second;
};
template<class What>
struct is_type_pair
{
static constexpr bool value = false;
};
template<typename First, typename Second>
struct is_type_pair<type_pair<First, Second> >
{
static constexpr bool value = true;
};
} } // namespace cppa::util
#endif // TYPE_PAIR_HPP
......@@ -40,6 +40,14 @@ struct void_type
{
typedef void_type head;
typedef type_list<> tail;
constexpr void_type() { }
constexpr void_type(void_type const&) { }
void_type& operator=(void_type const&) = default;
// anything could be used to initialize a void...
template<typename Arg0, typename... Args>
void_type(Arg0&&, Args&&...) { }
};
inline bool operator==(void_type const&, void_type const&) { return true; }
......
......@@ -50,4 +50,9 @@ std::type_info const* abstract_tuple::type_token() const
return &typeid(void);
}
void const* abstract_tuple::native_data() const
{
return nullptr;
}
} } // namespace cppa::detail
This diff is collapsed.
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