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
...@@ -18,6 +18,10 @@ ...@@ -18,6 +18,10 @@
#include "cppa/uniform_type_info.hpp" #include "cppa/uniform_type_info.hpp"
#include "cppa/detail/invokable.hpp" #include "cppa/detail/invokable.hpp"
#include "cppa/detail/types_array.hpp"
#include "cppa/detail/object_array.hpp"
#include <cxxabi.h>
using std::cout; using std::cout;
using std::endl; using std::endl;
...@@ -28,6 +32,15 @@ template<class Expr, class Guard, typename Result, typename... Args> ...@@ -28,6 +32,15 @@ template<class Expr, class Guard, typename Result, typename... Args>
class tpartial_function class tpartial_function
{ {
bool collect(detail::tdata<>&) { return true; }
template<typename TData, typename T0, typename... Ts>
bool collect(TData& td, T0 const& arg0, Ts const&... args)
{
td.head = arg0;
return collect(td.tail(), args...);
}
public: public:
tpartial_function(Guard&& g, Expr&& e) tpartial_function(Guard&& g, Expr&& e)
...@@ -35,7 +48,12 @@ class tpartial_function ...@@ -35,7 +48,12 @@ class tpartial_function
{ {
} }
tpartial_function(tpartial_function&&) = default; tpartial_function(tpartial_function&& other)
: m_guard(std::move(other.m_guard))
, m_expr(std::move(other.m_expr))
{
}
tpartial_function(tpartial_function const&) = default; tpartial_function(tpartial_function const&) = default;
bool defined_at(Args const&... args) bool defined_at(Args const&... args)
...@@ -45,44 +63,797 @@ class tpartial_function ...@@ -45,44 +63,797 @@ class tpartial_function
Result operator()(Args const&... args) Result operator()(Args const&... args)
{ {
return m_expr(args...); if (collect(m_args, args...)) return m_expr(args...);
throw std::logic_error("oops");
}
private:
typedef util::type_list<ge_reference_wrapper<Args>...> TransformedArgs;
typename detail::tdata_from_type_list<TransformedArgs>::type m_args;
Guard m_guard;
Expr m_expr;
};
template<typename T>
T const& fw(T const& value) { return value; }
template<typename T>
struct rm_option
{
typedef T type;
};
template<typename T>
struct rm_option<option<T> >
{
typedef T type;
};
template<typename ArgType, typename Transformer>
struct cf_transformed_type
{
typedef typename util::get_callable_trait<Transformer>::result_type result;
typedef typename rm_option<result>::type type;
};
template<typename ArgType>
struct cf_transformed_type<ArgType, util::void_type>
{
typedef ge_reference_wrapper<ArgType> type;
};
struct invoke_policy_helper
{
size_t i;
detail::abstract_tuple const& tup;
invoke_policy_helper(detail::abstract_tuple const& tp) : i(0), tup(tp) { }
template<typename T>
void operator()(ge_reference_wrapper<T>& storage)
{
storage = *reinterpret_cast<T const*>(tup.at(i++));
} }
};
template<wildcard_position, class ArgsList>
struct invoke_policy;
template<typename... Args>
struct invoke_policy<wildcard_position::nil, util::type_list<Args...> >
{
template<typename Target>
static bool invoke_args(Target& target, Args const&... args)
{
return target(args...);
}
template<typename Target, typename... WrongArgs>
static bool invoke_args(Target&, WrongArgs const&...)
{
return false;
}
template<typename Target>
static bool invoke(Target& target,
std::type_info const& arg_types,
detail::tuple_impl_info timpl,
void const* native_arg,
detail::abstract_tuple const& tup)
{
if (arg_types == typeid(util::type_list<Args...>))
{
if (native_arg)
{
auto arg = reinterpret_cast<detail::tdata<Args...> const*>(native_arg);
return util::unchecked_apply_tuple<bool>(target, *arg);
}
// 'fall through'
}
else if (timpl == detail::dynamically_typed)
{
auto& arr = detail::static_types_array<Args...>::arr;
if (tup.size() != sizeof...(Args))
{
return false;
}
for (size_t i = 0; i < sizeof...(Args); ++i)
{
if (arr[i] != tup.type_at(i))
{
return false;
}
}
// 'fall through'
}
else
{
return false;
}
// either dynamically typed or statically typed but not a native tuple
detail::tdata<ge_reference_wrapper<Args>...> ttup;
invoke_policy_helper iph{tup};
util::static_foreach<0, sizeof...(Args)>::_ref(ttup, iph);
return util::apply_tuple(target, ttup);
}
};
template<class Transformers, class Args>
class apply_policy
{
public:
template<typename... Ts>
apply_policy(Ts&&... args) : m_transformer(std::forward<Ts>(args)...) { }
apply_policy(apply_policy&&) = default;
apply_policy(apply_policy const&) = default;
template<class Guard, class Expr, typename... Ts>
bool operator()(Guard& guard, Expr& expr, Ts const&... args) const
{
typename detail::tdata_from_type_list<
typename util::tl_zipped_apply<
typename util::tl_zip<
Args,
typename util::tl_resize<
Transformers,
Args::size,
util::void_type
>::type
>::type,
cf_transformed_type
>::type
>::type
m_args;
if (collect(m_args, m_transformer, args...))
{
if (util::unchecked_apply_tuple<bool>(guard, m_args))
{
util::apply_tuple(expr, m_args);
return true;
}
}
return false;
}
private: private:
detail::tdata<Args...> m_args; template<class Storage, typename T>
static inline bool fetch_(Storage& storage, T const& value)
{
storage = value;
return true;
}
template<class Result>
static inline bool fetch_(Result& storage, option<Result>&& value)
{
if (value)
{
storage = std::move(*value);
return true;
}
return false;
}
template<class Storage, typename Fun, typename T>
static inline bool fetch(Storage& storage, Fun const& fun, T const& arg)
{
return fetch_(storage, fun(arg));
}
template<typename T>
static inline bool fetch(ge_reference_wrapper<T>& storage,
util::void_type const&,
T const& arg)
{
storage = arg;
return true;
}
static inline bool collect(detail::tdata<>&, detail::tdata<> const&) { return true; }
template<class TData, typename T0, typename... Ts>
static inline bool collect(TData& td, detail::tdata<> const&, T0 const& arg0, Ts const&... args)
{
td.set(arg0, args...);
return true;
}
template<class TData, class Trans, typename T0, typename... Ts>
static inline bool collect(TData& td, Trans const& tr, T0 const& arg0, Ts const&... args)
{
return fetch(td.head, tr.head, arg0)
&& collect(td.tail(), tr.tail(), args...);
}
typename detail::tdata_from_type_list<Transformers>::type m_transformer;
};
template<typename Expr, size_t ExprArgs, size_t NumArgs>
struct apply_args
{
template<typename Arg0, typename... Args>
static inline void _(Expr& expr, Arg0 const&, Args const&... args)
{
apply_args<Expr, ExprArgs, NumArgs-1>::_(expr, args...);
}
};
template<typename Expr, size_t Num>
struct apply_args<Expr, Num, Num>
{
template<typename... Args>
static inline void _(Expr& expr, Args const&... args)
{
expr(args...);
}
};
template<class Args>
class apply_policy<util::type_list<>, Args>
{
public:
apply_policy(detail::tdata<> const&) { }
apply_policy() = default;
apply_policy(apply_policy const&) = default;
template<class Guard, class Expr, typename... Ts>
bool operator()(Guard& guard, Expr& expr, Ts const&... args) const
{
if (guard(args...))
{
typedef typename util::get_callable_trait<Expr>::type ctrait;
apply_args<Expr, ctrait::arg_types::size, sizeof...(Ts)>::_(expr, args...);
return true;
}
return false;
}
};
template<class InvokePolicy>
struct invoke_helper_
{
template<class Leaf>
bool operator()(Leaf const& leaf,
std::type_info const& v0,
detail::tuple_impl_info v1,
void const* v2,
detail::abstract_tuple const& v3) const
{
return InvokePolicy::invoke(leaf, v0, v1, v2, v3);
}
template<class Leaf, typename... Args>
bool operator()(Leaf const& leaf, Args const&... args) const
{
return InvokePolicy::invoke_args(leaf, args...);
}
};
struct invoke_helper
{
template<class ArgTypes, class... Leaves, typename... Args>
bool operator()(detail::tdata<ArgTypes, Leaves...> const& list,
Args const&... args) const
{
typedef invoke_policy<get_wildcard_position<ArgTypes>(), ArgTypes> ipolicy;
invoke_helper_<ipolicy> fun;
return util::static_foreach<1, sizeof...(Leaves)+1>::eval_or(list, fun, args...);
}
};
template<class Expr, class Guard, class Transformers, class ArgTypes>
class conditional_fun_leaf;
template<class Expr, class Guard, class Transformers, typename... Args>
class conditional_fun_leaf<Expr, Guard, Transformers, util::type_list<Args...> >
{
public:
typedef util::type_list<Args...> args_list;
template<typename G, typename E, typename... TFuns>
conditional_fun_leaf(G&& g, E&& e, TFuns&&... tfuns)
: m_apply(std::forward<TFuns>(tfuns)...)
, m_guard(std::forward<G>(g)), m_expr(std::forward<E>(e))
{
}
conditional_fun_leaf(conditional_fun_leaf const&) = default;
bool operator()(Args const&... args) const
{
return m_apply(m_guard, m_expr, args...);
}
private:
typedef typename util::tl_trim<Transformers, util::void_type>::type trimmed;
apply_policy<trimmed, args_list> m_apply;
Guard m_guard; Guard m_guard;
Expr m_expr; Expr m_expr;
}; };
template<class Expr, class Guard, typename Result, class ArgTypes> template<class ArgTypes, class Expr, class Guard, typename... TFuns>
struct tpf_; struct cfl_
{
typedef conditional_fun_leaf<Expr, Guard,
util::type_list<TFuns...>, ArgTypes>
type;
};
template<class ArgTypes, class LeavesTData, class... LeafImpl>
struct cfh_
{
typedef LeavesTData leaves_type; // tdata<tdata...>
typedef typename leaves_type::back_type back_leaf; // tdata
// manipulate leaves type to push back leaf_impl
typedef typename util::tl_pop_back<typename leaves_type::types>::type
prefix;
// type_list<tdata...>
typedef typename detail::tdata_from_type_list<
typename util::tl_concat<
typename back_leaf::types,
util::type_list<LeafImpl...>
>::type
>::type
suffix; // tdata
typedef typename util::tl_push_back<prefix, suffix>::type
concatenated; // type_list<tdata...>
typedef typename detail::tdata_from_type_list<concatenated>::type type;
};
namespace cppa { namespace detail {
template<class Lhs, class Rhs>
struct tdata_concatenate;
template<class... Lhs, class... Rhs>
struct tdata_concatenate<tdata<Lhs...>, tdata<Rhs...> >
{
typedef tdata<Lhs..., Rhs...> type;
};
} } // namespace cppa::detail
template<class Leaves>
class conditional_fun
{
public:
template<typename... Args>
conditional_fun(Args&&... args) : m_leaves(std::forward<Args>(args)...)
{
}
conditional_fun(conditional_fun&& other) : m_leaves(std::move(other.m_leaves))
{
}
conditional_fun(conditional_fun const&) = default;
//conditional_fun& operator=(conditional_fun&&) = default;
//conditional_fun& operator=(conditional_fun const&) = default;
typedef void const* const_void_ptr;
bool invoke(std::type_info const& arg_types,
detail::tuple_impl_info timpl,
const_void_ptr native_arg,
detail::abstract_tuple const& tup) const
{
invoke_helper fun;
return util::static_foreach<0, Leaves::tdata_size>::eval_or(m_leaves, fun, arg_types, timpl, native_arg, tup);
}
bool invoke(any_tuple const& tup) const
{
auto const& cvals = *(tup.cvals());
return invoke(*(cvals.type_token()),
cvals.impl_type(),
cvals.native_data(),
cvals);
}
template<typename... Args>
bool operator()(Args const&... args)
{
invoke_helper fun;
return util::static_foreach<0, Leaves::tdata_size>::eval_or(m_leaves, fun, args...);
}
typedef typename Leaves::back_type back_leaf;
typedef typename back_leaf::head_type back_arg_types;
template<typename OtherLeaves>
conditional_fun<typename detail::tdata_concatenate<Leaves, OtherLeaves>::type>
or_else(conditional_fun<OtherLeaves> const& other) const
{
return {m_leaves, other.m_leaves};
}
template<class... LeafImpl>
conditional_fun<typename cfh_<back_arg_types, Leaves, LeafImpl...>::type>
or_else(conditional_fun<detail::tdata<detail::tdata<back_arg_types, LeafImpl...>>> const& other) const
{
return {m_leaves, other.m_leaves.back().tail()};
}
template<class... LeafImpl, class Others0, class... Others>
conditional_fun<
typename detail::tdata_concatenate<
typename cfh_<back_arg_types, Leaves, LeafImpl...>::type,
detail::tdata<Others0, Others...>
>::type>
or_else(conditional_fun<detail::tdata<detail::tdata<back_arg_types, LeafImpl...>, Others0, Others...>> const& other) const
{
typedef conditional_fun<detail::tdata<detail::tdata<back_arg_types, LeafImpl...>>>
head_fun;
typedef conditional_fun<detail::tdata<Others0, Others...>> tail_fun;
return or_else(head_fun{other.m_leaves.head})
.or_else(tail_fun{other.m_leaves.tail()});
}
//private:
// structure: tdata< tdata<type_list<...>, ...>,
// tdata<type_list<...>, ...>,
// ...>
Leaves m_leaves;
};
template<class ArgTypes, class Expr, class Guard, typename... TFuns>
conditional_fun<
detail::tdata<
detail::tdata<ArgTypes,
typename cfl_<ArgTypes, Expr, Guard, TFuns...>::type>>>
cfun(Expr e, Guard g, TFuns... tfs)
{
typedef detail::tdata<
ArgTypes,
typename cfl_<ArgTypes, Expr, Guard, TFuns...>::type>
result;
typedef typename result::tail_type ttype;
typedef typename ttype::head_type leaf_type;
typedef typename util::get_callable_trait<Expr>::arg_types expr_args;
static_assert(ArgTypes::size >= expr_args::size,
"Functor has too many arguments");
return result{
ArgTypes{},
leaf_type{std::move(g), std::move(e), std::move(tfs)...}
};
}
#define VERBOSE(LineOfCode) cout << #LineOfCode << " = " << (LineOfCode) << endl
float tofloat(int i) { return i; }
template<class Expr, class Guard, typename Result, typename... Ts> struct dummy_guard
struct tpf_<Expr, Guard, Result, util::type_list<Ts...> >
{ {
typedef tpartial_function<Expr, Guard, Result, Ts...> type; template<typename... Args>
inline bool operator()(Args const&...) const
{
return true;
}
}; };
template<class Expr, class Guard> template<typename... Args>
any_tuple make_any_tuple(Args&&... args)
{
return make_cow_tuple(std::forward<Args>(args)...);
}
struct from_args { };
typename tpf_<Expr, Guard, template<class Guard, class Transformers, class Pattern>
typename util::get_callable_trait<Expr>::result_type, struct cf_builder
typename util::get_callable_trait<Expr>::arg_types
>::type
tfun(Expr e, Guard g)
{ {
return {std::move(g), std::move(e)};
Guard m_guard;
typename detail::tdata_from_type_list<Transformers>::type m_funs;
public:
template<typename... Args>
cf_builder(from_args const&, Args const&... args) : m_guard(args...), m_funs(args...)
{
}
template<typename G>
cf_builder(G&& g) : m_guard(std::forward<G>(g))
{
}
template<typename G, typename F>
cf_builder(G&& g, F&& f) : m_guard(std::forward<G>(g)), m_funs(std::forward<F>(f))
{
}
template<typename NewGuard>
cf_builder<NewGuard, Transformers, Pattern> when(NewGuard ng)
{
return {ng, m_funs};
}
template<typename Expr>
conditional_fun<
detail::tdata<
detail::tdata<Pattern,
conditional_fun_leaf<Expr, Guard, Transformers, Pattern>>>>
operator>>(Expr expr) const
{
typedef conditional_fun_leaf<Expr, Guard, Transformers, Pattern> tfun;
typedef detail::tdata<Pattern, tfun> result;
return result{Pattern{}, tfun{m_guard, std::move(expr), m_funs}};
}
};
template<typename... T>
cf_builder<dummy_guard, util::type_list<>, util::type_list<T...> > _on()
{
return {dummy_guard{}};
} }
template<bool IsFun, typename T>
struct add_ptr_to_fun_
{
typedef T* type;
};
template<typename T>
struct add_ptr_to_fun_<false, T>
{
typedef T type;
};
template<typename T>
struct add_ptr_to_fun : add_ptr_to_fun_<std::is_function<T>::value, T>
{
};
template<bool ToVoid, typename T>
struct to_void_impl
{
typedef util::void_type type;
};
template<typename T>
struct to_void_impl<false, T>
{
typedef typename add_ptr_to_fun<T>::type type;
};
template<typename T>
struct not_callable_to_void : to_void_impl<detail::is_boxed<T>::value || !util::is_callable<T>::value, T>
{
};
template<typename T>
struct boxed_and_callable_to_void : to_void_impl<detail::is_boxed<T>::value || util::is_callable<T>::value, T>
{
};
template<typename Pattern>
class value_guard;
template<typename... Types>
class value_guard<util::type_list<Types...> >
{
detail::tdata<Types...> m_args;
inline bool _eval(util::void_type const&, detail::tdata<> const&) const
{
return true;
}
template<class Tail, typename Arg0, typename... Args>
inline bool _eval(util::void_type const&, Tail const& tail,
Arg0 const&, Args const&... args) const
{
return _eval(tail.head, tail.tail(), args...);
}
template<typename Head, class Tail, typename Arg0, typename... Args>
inline bool _eval(Head const& head, Tail const& tail,
Arg0 const& arg0, Args const&... args) const
{
return head == arg0 && _eval(tail.head, tail.tail(), args...);
}
public:
template<typename... Args>
value_guard(Args const&... args) : m_args(args...) { }
inline bool operator()(Types const&... args) const
{
return _eval(m_args.head, m_args.tail(), args...);
}
};
template<bool IsCallable, typename T>
struct pattern_type_
{
typedef util::get_callable_trait<T> ctrait;
typedef typename ctrait::arg_types args;
static_assert(args::size == 1, "only unary functions allowed");
typedef typename util::rm_ref<typename args::head>::type type;
};
template<typename T>
struct pattern_type_<false, T>
{
typedef typename util::rm_ref<T>::type type;
};
template<typename T>
struct pattern_type : pattern_type_<util::is_callable<T>::value && !detail::is_boxed<T>::value, T>
{
};
template<typename Arg0, typename... Args>
cf_builder<
value_guard<typename util::tl_apply<util::type_list<Arg0, Args...>, boxed_and_callable_to_void>::type>,
typename util::tl_apply<util::type_list<Arg0, Args...>, not_callable_to_void>::type,
util::type_list<typename pattern_type<Arg0>::type,
typename pattern_type<Args>::type...> >
_on(Arg0 const& arg0, Args const&... args)
{
return {from_args{}, arg0, args...};
}
std::string int2str(int i)
{
return std::to_string(i);
}
option<int> str2int(std::string const& str)
{
if (str == "42") return 42;
if (str == "41") return 41;
return {};
}
typedef util::type_list<int, int, int, float, int, float, float> zz0;
typedef util::type_list<util::type_list<int, int, int>,
util::type_list<float>,
util::type_list<int>,
util::type_list<float, float> > zz8;
typedef util::type_list<
util::type_list<
util::type_pair<std::integral_constant<size_t,0>, int>,
util::type_pair<std::integral_constant<size_t,1>, int>,
util::type_pair<std::integral_constant<size_t,2>, int>
>,
util::type_list<
util::type_pair<std::integral_constant<size_t,3>, float>
>,
util::type_list<
util::type_pair<std::integral_constant<size_t,4>, int>
>,
util::type_list<
util::type_pair<std::integral_constant<size_t,5>, float>,
util::type_pair<std::integral_constant<size_t,6>, float>
>
>
zz9;
template<typename First, typename Second>
struct is_same_ : std::is_same<typename First::second, typename Second::second>
{
};
size_t test__tuple() size_t test__tuple()
{ {
CPPA_TEST(test__tuple); CPPA_TEST(test__tuple);
using namespace cppa::placeholders; using namespace cppa::placeholders;
typedef typename util::tl_group_by<zz0, std::is_same>::type zz1;
typedef typename util::tl_zip_with_index<zz0>::type zz2;
static_assert(std::is_same<zz1, zz8>::value, "group_by failed");
typedef typename util::tl_group_by<zz2, is_same_>::type zz3;
static_assert(std::is_same<zz3, zz9>::value, "group_by failed");
cout << detail::demangle(typeid(zz3).name()) << endl;
exit(0);
typedef util::type_list<int, int> token1;
typedef util::type_list<float> token2;
//auto f00 = cfun<token1>([](int, int) { cout << "f0[1]!" << endl; }, _x1 > _x2)
// .or_else(cfun<token1>([](int, int) { cout << "f0[2]!" << endl; }, _x1 == 2 && _x2 == 2))
// .or_else(cfun<token2>([](float) { cout << "f0[3]!" << endl; }, dummy_guard{}));
auto f00 = _on<int, int>() >> []() { };
auto f01 = _on<int, int>().when(_x1 == 42) >> []() { };
auto f02 = _on<int, int>().when(_x1 == 42 && _x2 * 2 == _x1) >> []() { };
auto f03 = _on(42, val<int>) >> [](int) { };
auto f04 = _on(42, int2str).when(_x2 == "42") >> []() { };
auto f05 = _on(42, str2int).when(_x2 % 2 == 0) >> []() { };
VERBOSE(f00(42, 42));
VERBOSE(f01(42, 42));
VERBOSE(f02(42, 42));
VERBOSE(f02(42, 21));
VERBOSE(f03(42, 42));
VERBOSE(f04(42, 42));
VERBOSE(f04(42, std::string("42")));
VERBOSE(f05(42, 42));
VERBOSE(f05(42, std::string("41")));
VERBOSE(f05(42, std::string("42")));
VERBOSE(f05(42, std::string("hello world!")));
exit(0);
auto f0 = cfun<token1>([](int, int) { cout << "f0[0]!" << endl; }, _x1 < _x2)
//.or_else(f00)
.or_else(cfun<token1>([](int, int) { cout << "f0[1]!" << endl; }, _x1 > _x2))
.or_else(cfun<token1>([](int, int) { cout << "f0[2]!" << endl; }, _x1 == 2 && _x2 == 2))
.or_else(cfun<token2>([](float) { cout << "f0[3]!" << endl; }, dummy_guard{}))
.or_else(cfun<token1>([](int, int) { cout << "f0[4]" << endl; }, dummy_guard{}));
//VERBOSE(f0(make_cow_tuple(1, 2)));
VERBOSE(f0(3, 3));
VERBOSE(f0.invoke(make_any_tuple(3, 3)));
VERBOSE(f0.invoke(make_any_tuple(2, 2)));
VERBOSE(f0.invoke(make_any_tuple(3, 2)));
VERBOSE(f0.invoke(make_any_tuple(1.f)));
auto f1 = cfun<token1>([](float, int) { cout << "f1!" << endl; }, _x1 < 6, tofloat);
VERBOSE(f1.invoke(make_any_tuple(5, 6)));
VERBOSE(f1.invoke(make_any_tuple(6, 7)));
auto i2 = make_any_tuple(1, 2);
VERBOSE(f0.invoke(*i2.vals()->type_token(), i2.vals()->impl_type(), i2.vals()->native_data(), *(i2.vals())));
VERBOSE(f1.invoke(*i2.vals()->type_token(), i2.vals()->impl_type(), i2.vals()->native_data(), *(i2.vals())));
any_tuple dt1;
{
auto oarr = new detail::object_array;
oarr->push_back(object::from(1));
oarr->push_back(object::from(2));
dt1 = any_tuple{static_cast<detail::abstract_tuple*>(oarr)};
}
VERBOSE(f0.invoke(*dt1.cvals()->type_token(), dt1.cvals()->impl_type(), dt1.cvals()->native_data(), *dt1.cvals()));
VERBOSE(f1.invoke(*dt1.cvals()->type_token(), dt1.cvals()->impl_type(), dt1.cvals()->native_data(), *dt1.cvals()));
exit(0);
// check type correctness of make_cow_tuple() // check type correctness of make_cow_tuple()
auto t0 = make_cow_tuple("1", 2); auto t0 = make_cow_tuple("1", 2);
CPPA_CHECK((std::is_same<decltype(t0), cppa::cow_tuple<std::string, int>>::value)); CPPA_CHECK((std::is_same<decltype(t0), cppa::cow_tuple<std::string, int>>::value));
......
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