Commit 30bdfb6a authored by neverlord's avatar neverlord

pattern matching

parent 1620a761
...@@ -176,6 +176,7 @@ nobase_library_include_HEADERS = \ ...@@ -176,6 +176,7 @@ nobase_library_include_HEADERS = \
cppa/tuple_cast.hpp \ cppa/tuple_cast.hpp \
cppa/type_value_pair.hpp \ cppa/type_value_pair.hpp \
cppa/uniform_type_info.hpp \ cppa/uniform_type_info.hpp \
cppa/util/a_matches_b.hpp \
cppa/util/abstract_uniform_type_info.hpp \ cppa/util/abstract_uniform_type_info.hpp \
cppa/util/apply_tuple.hpp \ cppa/util/apply_tuple.hpp \
cppa/util/arg_match_t.hpp \ cppa/util/arg_match_t.hpp \
......
...@@ -258,3 +258,4 @@ cppa/detail/matches.hpp ...@@ -258,3 +258,4 @@ cppa/detail/matches.hpp
unit_testing/test__match.cpp unit_testing/test__match.cpp
cppa/guard_expr.hpp cppa/guard_expr.hpp
src/pattern.cpp src/pattern.cpp
cppa/util/a_matches_b.hpp
...@@ -68,6 +68,10 @@ class abstract_tuple : public ref_counted ...@@ -68,6 +68,10 @@ class abstract_tuple : public ref_counted
virtual void const* at(size_t pos) const = 0; virtual void const* at(size_t pos) const = 0;
virtual uniform_type_info const* type_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. // Identifies the type of the implementation.
// A statically typed tuple implementation can use some optimizations, // A statically typed tuple implementation can use some optimizations,
// e.g., "impl_type() == statically_typed" implies that type_token() // e.g., "impl_type() == statically_typed" implies that type_token()
......
...@@ -39,6 +39,8 @@ ...@@ -39,6 +39,8 @@
#include "cppa/util/at.hpp" #include "cppa/util/at.hpp"
#include "cppa/util/wrapped.hpp" #include "cppa/util/wrapped.hpp"
#include "cppa/util/type_list.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/util/arg_match_t.hpp"
#include "cppa/detail/abstract_tuple.hpp" #include "cppa/detail/abstract_tuple.hpp"
...@@ -75,6 +77,13 @@ struct tdata<> ...@@ -75,6 +77,13 @@ struct tdata<>
util::void_type head; 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() { } constexpr tdata() { }
inline tdata(tdata&&) { } inline tdata(tdata&&) { }
...@@ -84,15 +93,9 @@ struct tdata<> ...@@ -84,15 +93,9 @@ struct tdata<>
// swallow "arg_match" silently // swallow "arg_match" silently
constexpr tdata(util::wrapped<util::arg_match_t> const&) { } constexpr tdata(util::wrapped<util::arg_match_t> const&) { }
tdata<>& tail() tdata<>& tail() { return *this; }
{
throw std::out_of_range("");
}
tdata<> const& tail() const tdata<> const& tail() const { return *this; }
{
throw std::out_of_range("");
}
inline void const* at(size_t) const inline void const* at(size_t) const
{ {
...@@ -119,8 +122,22 @@ struct tdata<Head, Tail...> : tdata<Tail...> ...@@ -119,8 +122,22 @@ struct tdata<Head, Tail...> : tdata<Tail...>
typedef tdata<Tail...> super; typedef tdata<Tail...> super;
typedef util::type_list<Head, Tail...> types;
Head head; 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() { } inline tdata() : super(), head() { }
//tdata(Head const& v0, Tail const&... vals) : super(vals...), head(v0) { } //tdata(Head const& v0, Tail const&... vals) : super(vals...), head(v0) { }
...@@ -141,11 +158,51 @@ struct tdata<Head, Tail...> : tdata<Tail...> ...@@ -141,11 +158,51 @@ struct tdata<Head, Tail...> : tdata<Tail...>
} }
// allow (partial) initialization from a different tdata // 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> 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> 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 // allow initialization with a function pointer or reference
// returning a wrapped<Head> // returning a wrapped<Head>
...@@ -183,75 +240,42 @@ struct tdata<Head, Tail...> : tdata<Tail...> ...@@ -183,75 +240,42 @@ struct tdata<Head, Tail...> : tdata<Tail...>
return (p == 0) ? uniform_typeid(typeid(Head)) : super::type_at(p-1); 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; Head& _back(std::integral_constant<size_t, 0>)
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()
{ {
return head;
} }
template<typename Arg0, typename... Args> template<size_t Pos>
inline void set(Arg0&& arg0, Args&&... args) back_type& _back(std::integral_constant<size_t, Pos>)
{ {
head = std::forward<Arg0>(arg0); std::integral_constant<size_t, Pos - 1> token;
super::set(std::forward<Args>(args)...); return super::_back(token);
} }
template<typename... Y> back_type& back()
tdata& operator=(tdata<Y...> const& other)
{ {
tdata_set(*this, other); std::integral_constant<size_t, sizeof...(Tail)> token;
return *this; return _back(token);
} }
// upcast Head const& _back(std::integral_constant<size_t, 0>) const
inline tdata<Tail...>& tail() { return *this; }
inline tdata<Tail...> const& tail() const { return *this; }
inline void const* at(size_t p) 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> template<typename... X>
......
...@@ -68,6 +68,11 @@ class tuple_vals : public abstract_tuple ...@@ -68,6 +68,11 @@ class tuple_vals : public abstract_tuple
{ {
} }
void const* native_data() const
{
return &m_data;
}
inline data_type& data() inline data_type& data()
{ {
return m_data; return m_data;
......
...@@ -306,6 +306,7 @@ struct ge_reference_wrapper ...@@ -306,6 +306,7 @@ struct ge_reference_wrapper
{ {
T const* value; T const* value;
ge_reference_wrapper(T&&) = delete; ge_reference_wrapper(T&&) = delete;
ge_reference_wrapper() : value(nullptr) { }
ge_reference_wrapper(T const& val_ref) : value(&val_ref) { } ge_reference_wrapper(T const& val_ref) : value(&val_ref) { }
ge_reference_wrapper(ge_reference_wrapper const&) = default; ge_reference_wrapper(ge_reference_wrapper const&) = default;
ge_reference_wrapper& operator=(ge_reference_wrapper const&) = default; ge_reference_wrapper& operator=(ge_reference_wrapper const&) = default;
......
...@@ -115,6 +115,32 @@ struct get_result_type ...@@ -115,6 +115,32 @@ struct get_result_type
typedef typename trait_type::result_type 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 } } // namespace cppa::util
#endif // CPPA_UTIL_CALLABLE_TRAIT #endif // CPPA_UTIL_CALLABLE_TRAIT
...@@ -35,49 +35,46 @@ ...@@ -35,49 +35,46 @@
namespace cppa { namespace util { 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 struct static_foreach_impl
{ {
template<typename Container, typename Fun> template<typename Container, typename Fun, typename... Args>
static inline void _(Container const& c, Fun& f) static inline void _(Container const& c, Fun& f, Args const&... args)
{ {
f(get<Begin>(c)); f(get<Begin>(c), args...);
static_foreach_impl<Begin+1, End, (Begin+1 > End)>::_(c, f); static_foreach_impl<(Begin+1 < End), Begin+1, End>::_(c, f, args...);
} }
template<typename Container, typename Fun> template<typename Container, typename Fun, typename... Args>
static inline bool eval(Container const& c, Fun& f) static inline void _ref(Container& c, Fun& f, Args const&... args)
{ {
return f(get<Begin>(c)) f(get_ref<Begin>(c), args...);
&& static_foreach_impl<Begin+1, End, (Begin+1 > End)>::eval(c, f); static_foreach_impl<(Begin+1 < End), Begin+1, End>::_ref(c, f, args...);
} }
template<typename Container, typename Fun> template<typename Container, typename Fun, typename... Args>
static inline bool eval_or(Container const& c, Fun& f) static inline bool eval(Container const& c, Fun& f, Args const&... args)
{ {
return f(get<Begin>(c)) return f(get<Begin>(c), args...)
|| static_foreach_impl<Begin+1, End, (Begin+1 > End)>::eval_or(c, f); && 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> 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> template<typename... Args>
static inline void _(Container const&, Fun&) { } static inline void _(Args const&...) { }
template<typename Container, typename Fun> template<typename... Args>
static inline bool eval(Container const&, Fun&) { return true; } static inline void _ref(Args const&...) { }
template<typename Container, typename Fun> template<typename... Args>
static inline bool eval_or(Container const&, Fun&) { return true; } 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> ...@@ -85,7 +82,7 @@ struct static_foreach_impl<X, Y, true>
* @brief A for loop that can be used with tuples. * @brief A for loop that can be used with tuples.
*/ */
template<size_t Begin, size_t End> 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 @@ ...@@ -32,7 +32,9 @@
#define LIBCPPA_UTIL_TYPE_LIST_HPP #define LIBCPPA_UTIL_TYPE_LIST_HPP
#include <typeinfo> #include <typeinfo>
#include <type_traits>
#include "cppa/util/tbind.hpp"
#include "cppa/util/if_else.hpp" #include "cppa/util/if_else.hpp"
#include "cppa/util/type_pair.hpp" #include "cppa/util/type_pair.hpp"
#include "cppa/util/void_type.hpp" #include "cppa/util/void_type.hpp"
...@@ -87,6 +89,18 @@ struct type_list<Head, Tail...> ...@@ -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) // static list list::zip(list, list)
template<class ListA, class ListB> template<class ListA, class ListB>
...@@ -109,6 +123,37 @@ struct tl_zip<type_list<LhsElements...>, type_list<RhsElements...> > ...@@ -109,6 +123,37 @@ struct tl_zip<type_list<LhsElements...>, type_list<RhsElements...> >
"Lists have different size"); "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() // list list::reverse()
template<class From, typename... Elements> template<class From, typename... Elements>
...@@ -141,39 +186,47 @@ struct tl_reverse ...@@ -141,39 +186,47 @@ struct tl_reverse
* @brief Finds the first element of type @p What beginning at * @brief Finds the first element of type @p What beginning at
* index @p Pos. * 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; struct tl_find_impl;
template<typename What, int Pos> template<template<typename> class Predicate, int Pos>
struct tl_find_impl<type_list<>, What, Pos> struct tl_find_impl<type_list<>, Predicate, Pos>
{ {
static constexpr int value = -1; static constexpr int value = -1;
typedef type_list<> rest_list;
}; };
template<typename What, int Pos, typename... Tail> template<template<typename> class Predicate, int Pos,
struct tl_find_impl<type_list<What, Tail...>, What, Pos> typename Head, typename... Tail>
struct tl_find_impl<type_list<Head, Tail...>, Predicate, Pos>
{ {
static constexpr int value = Pos; static constexpr int value =
typedef type_list<Tail...> rest_list; 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; static constexpr int value =
typedef typename tl_find_impl<type_list<Tail...>, What, Pos+1>::rest_list rest_list; 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. * index @p Pos.
*/ */
template<class List, class What, int Pos = 0> template<class List, template<typename> class Predicate, int Pos = 0>
struct tl_find struct tl_find_if
{ {
static constexpr int value = tl_find_impl<List, What, Pos>::value; static constexpr int value = tl_find_impl<List, Predicate, Pos>::value;
typedef typename tl_find_impl<List, What, Pos>::rest_list rest_list;
}; };
// list list::first_n(size_t) // list list::first_n(size_t)
...@@ -453,18 +506,192 @@ struct tl_filter<type_list<T...>, Predicate> ...@@ -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. * do not satisfy @p Predicate.
*/ */
template<class List, template<typename> class Predicate> template<class List, template<typename> class Predicate>
struct tl_filter_not; 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> template<template<typename> class Predicate, typename... T>
struct tl_filter_not<type_list<T...>, Predicate> struct tl_filter_not<type_list<T...>, Predicate>
{ {
typedef typename tl_filter_impl<type_list<T...>, !Predicate<T>::value...>::type type; 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 ...@@ -44,6 +44,18 @@ struct type_pair
typedef Second second; 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 } } // namespace cppa::util
#endif // TYPE_PAIR_HPP #endif // TYPE_PAIR_HPP
...@@ -40,6 +40,14 @@ struct void_type ...@@ -40,6 +40,14 @@ struct void_type
{ {
typedef void_type head; typedef void_type head;
typedef type_list<> tail; 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; } inline bool operator==(void_type const&, void_type const&) { return true; }
......
...@@ -50,4 +50,9 @@ std::type_info const* abstract_tuple::type_token() const ...@@ -50,4 +50,9 @@ std::type_info const* abstract_tuple::type_token() const
return &typeid(void); return &typeid(void);
} }
void const* abstract_tuple::native_data() const
{
return nullptr;
}
} } // namespace cppa::detail } } // 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