Commit b045c90e authored by neverlord's avatar neverlord

documentation and unit testing

parent e4a39512
......@@ -9,7 +9,6 @@ cppa/util/is_one_of.hpp
cppa/util/conjunction.hpp
cppa/util/disjunction.hpp
unit_testing/test.hpp
unit_testing/test__a_matches_b.cpp
cppa/uniform_type_info.hpp
src/uniform_type_info.cpp
cppa/config.hpp
......
......@@ -172,7 +172,7 @@ class actor : public channel
*/
static intrusive_ptr<actor> by_id(std::uint32_t actor_id);
inline bool is_proxy() const { return m_is_proxy; }
inline bool is_proxy() const;
};
......@@ -181,10 +181,6 @@ class actor : public channel
*/
typedef intrusive_ptr<actor> actor_ptr;
serializer& operator<<(serializer&, const actor_ptr&);
deserializer& operator>>(deserializer&, actor_ptr&);
/******************************************************************************
* inline and template member function implementations *
******************************************************************************/
......@@ -204,6 +200,11 @@ inline std::uint32_t actor::id() const
return m_id;
}
inline bool actor::is_proxy() const
{
return m_is_proxy;
}
template<typename T>
bool actor::attach(std::unique_ptr<T>&& ptr,
typename util::enable_if<std::is_base_of<attachable,T>>::type*)
......
......@@ -37,6 +37,10 @@ T* copy_of(const T* what, std::integral_constant<int, 2>)
namespace cppa {
/**
* @ingroup CopyOnWrite
* @brief A copy-on-write smart pointer implementation.
*/
template<typename T>
class cow_ptr
{
......
......@@ -57,7 +57,7 @@
#include "cppa/detail/receive_loop_helper.hpp"
/**
* @author Dominik Charousset <dominik.charousset\@haw-hamburg.de>
* @author Dominik Charousset <dominik.charousset (at) haw-hamburg.de>
*
* @mainpage libcppa
*
......@@ -82,12 +82,70 @@
* functions of this namespace could change even in minor
* updates of the library and should not be used by outside of libcppa.
*
* @defgroup ReceiveMessages Receive messages
* @brief
* @defgroup CopyOnWrite Copy-on-write optimization.
* @p libcppa uses a copy-on-write optimization for its message
* passing implementation.
*
* {@link tuple Tuples} should @b always be used used with by-value semantic,
* since tuples use a copy-on-write smart pointer internally. Let's assume two
* tuple @p x and @p y, whereas @p y is a copy of @p x:
*
* @code
* auto x = make_tuple(1, 2, 3);
* auto y = x;
* @endcode
*
* Those two tuples initially point to the same data (the addresses of the
* first element of @p x is equal to the address of the first element
* of @p y):
*
* @code
* assert(&(get<0>(x)) == &(get<0>(y)));
* @endcode
*
* <tt>get<0>(x)</tt> returns a const-reference to the first element of @p x.
* The function @p get does not have a const-overload to avoid
* unintended copies. The function @p get_ref could be used to
* modify tuple elements. A call to this function detaches
* the tuple by copying the data before modifying it if there are two or more
* references to the data:
*
* @code
* // detaches x from y
* get_ref<0>(x) = 42;
* // x and y no longer point to the same data
* assert(&(get<0>(x)) != &(get<0>(y)));
* @endcode
*
* @defgroup MessageHandling Send and receive messages
*
* @section UsingOwnTypes Using own types in messages
* @brief
*
* @defgroup ImplicitConversion Implicit type conversions.
*
* The message passing of @p libcppa prohibits pointers in messages because
* it enforces network transparent messaging.
* Unfortunately, string literals in @p C++ have the type <tt>const char*</tt>,
* resp. <tt>const char[]</tt>. Since @p libcppa is a user-friendly library,
* it silently converts string literals and C-strings to @p std::string objects.
* It also converts unicode literals to the corresponding STL container.
*
* A few examples:
* @code
* // sends an std::string containing "hello actor!" to itself
* send(self(), "hello actor!");
*
* const char* cstring = "cstring";
* // sends an std::string containing "cstring" to itself
* send(self(), cstring);
*
* // sends an std::u16string containing the UTF16 string "hello unicode world!"
* send(self(), u"hello unicode world!");
*
* // x has the type tuple<std::string, std::string>
* auto x = make_tuple("hello", "tuple");
*
* @endcode
*/
......
......@@ -29,18 +29,16 @@ class any_tuple;
class local_actor;
/**
* @brief Describes a fixed-length tuple.
* @ingroup CopyOnWrite
* @brief A fixed-length copy-on-write tuple.
*/
template<typename... ElementTypes>
class tuple
{
//friend class any_tuple;
template<size_t N, typename... Types>
friend typename util::at<N, Types...>::type& get_ref(tuple<Types...>&);
public:
typedef util::type_list<ElementTypes...> element_types;
......@@ -58,80 +56,67 @@ class tuple
cow_ptr<vals_t> m_vals;
static bool compare_vals(const detail::tdata<>& v0,
const detail::tdata<>& v1)
{
return true;
}
template<typename Vals0, typename Vals1>
static bool compare_vals(const Vals0& v0, const Vals1& v1)
{
typedef typename Vals0::head_type lhs_type;
typedef typename Vals1::head_type rhs_type;
static_assert(util::is_comparable<lhs_type, rhs_type>::value,
"Types are not comparable");
return v0.head == v1.head && compare_vals(v0.tail(), v1.tail());
}
public:
// enable use of tuple as type_list
typedef typename element_types::head_type head_type;
typedef typename element_types::tail_type tail_type;
/**
* @brief Initializes each element with its default constructor.
*/
tuple() : m_vals(new vals_t)
{
}
/**
* @brief Initializes the tuple with @p args.
* @param args Initialization values.
*/
tuple(const ElementTypes&... args) : m_vals(new vals_t(args...))
{
}
size_t size() const
/**
* @brief Gets the size of this tuple.
* @returns <tt>sizeof...(ElementTypes)</tt>.
*/
inline size_t size() const
{
return m_vals->size();
return sizeof...(ElementTypes);
//return m_vals->size();
}
const void* at(size_t p) const
/**
* @brief Gets a pointer to the internal data.
* @returns A const void pointer to the <tt>N</tt>th element.
*/
inline const void* at(size_t p) const
{
return m_vals->at(p);
}
const uniform_type_info* utype_at(size_t p) const
/**
* @brief Gets {@link uniform_type_info uniform type information}
* of an element.
* @returns The uniform type of the <tt>N</tt>th element.
*/
inline const uniform_type_info* utype_at(size_t p) const
{
return m_vals->utype_info_at(p);
}
const cow_ptr<vals_t>& vals() const
# ifdef CPPA_DOCUMENTATION
/**
* @brief Gets the internal data.
* @returns A pointer to the internal data representation.
*/
cow_ptr<InternalData> vals() const;
# else
inline const cow_ptr<vals_t>& vals() const
{
return m_vals;
}
template<typename... Args>
bool equal_to(const tuple<Args...>& other) const
{
static_assert(sizeof...(ElementTypes) == sizeof...(Args),
"Can't compare tuples of different size");
return compare_vals(vals()->data(), other.vals()->data());
}
# endif
};
template<size_t N, typename... Types>
const typename util::at<N, Types...>::type&
get(const tuple<Types...>& t)
{
return get<N>(t.vals()->data());
}
template<size_t N, typename... Types>
typename util::at<N, Types...>::type&
get_ref(tuple<Types...>& t)
{
return get_ref<N>(t.m_vals->data_ref());
}
template<typename TypeList>
struct tuple_type_from_type_list;
......@@ -141,6 +126,55 @@ struct tuple_type_from_type_list<util::type_list<Types...>>
typedef tuple<Types...> type;
};
#ifdef CPPA_DOCUMENTATION
/**
* @ingroup CopyOnWrite
* @brief Gets a const-reference to the <tt>N</tt>th element of @p tup.
* @param tup The tuple object.
* @returns A const-reference of type T, whereas T is the type of the
* <tt>N</tt>th element of @p tup.
* @relates tuple
*/
template<size_t N, typename T>
const T& get(const tuple<...>& tup);
/**
* @ingroup CopyOnWrite
* @brief Gets a reference to the <tt>N</tt>th element of @p tup.
* @param tup The tuple object.
* @returns A reference of type T, whereas T is the type of the
* <tt>N</tt>th element of @p tup.
* @note Detaches @p tup if there are two or more references to the tuple data.
* @relates tuple
*/
template<size_t N, typename T>
T& get_ref(tuple<...>& tup);
/**
* @ingroup ImplicitConversion
* @brief Creates a new tuple from @p args.
* @param args Values for the tuple elements.
* @returns A tuple object containing the values @p args.
* @relates tuple
*/
template<typename... Types>
tuple<Types...> make_tuple(const Types&... args);
#else
template<size_t N, typename... Types>
const typename util::at<N, Types...>::type& get(const tuple<Types...>& tup)
{
return get<N>(tup.vals()->data());
}
template<size_t N, typename... Types>
typename util::at<N, Types...>::type& get_ref(tuple<Types...>& tup)
{
return get_ref<N>(tup.m_vals->data_ref());
}
template<typename... Types>
typename tuple_type_from_type_list<
typename util::type_list_apply<util::type_list<Types...>,
......@@ -150,6 +184,15 @@ make_tuple(const Types&... args)
return { args... };
}
#endif
/**
* @brief Compares two tuples.
* @param lhs First tuple object.
* @param rhs Second tuple object.
* @returns @p true if @p lhs and @p rhs are equal; otherwise @p false.
* @relates tuple
*/
template<typename... LhsTypes, typename... RhsTypes>
inline bool operator==(const tuple<LhsTypes...>& lhs,
const tuple<RhsTypes...>& rhs)
......@@ -157,6 +200,13 @@ inline bool operator==(const tuple<LhsTypes...>& lhs,
return util::compare_tuples(lhs, rhs);
}
/**
* @brief Compares two tuples.
* @param lhs First tuple object.
* @param rhs Second tuple object.
* @returns @p true if @p lhs and @p rhs are not equal; otherwise @p false.
* @relates tuple
*/
template<typename... LhsTypes, typename... RhsTypes>
inline bool operator!=(const tuple<LhsTypes...>& lhs,
const tuple<RhsTypes...>& rhs)
......
......@@ -6,7 +6,6 @@ noinst_PROGRAMS = unit_tests
unit_tests_SOURCES = hash_of.cpp \
main.cpp \
ping_pong.cpp \
test__a_matches_b.cpp \
test__atom.cpp \
test__intrusive_ptr.cpp \
test__local_group.cpp \
......
......@@ -177,7 +177,6 @@ int main(int argc, char** argv)
RUN_TEST(test__primitive_variant);
RUN_TEST(test__uniform_type);
RUN_TEST(test__intrusive_ptr);
RUN_TEST(test__a_matches_b);
RUN_TEST(test__type_list);
RUN_TEST(test__tuple);
RUN_TEST(test__serialization);
......
......@@ -47,6 +47,7 @@ std::cerr << err_msg << std::endl; \
++cppa_ts.error_count
#define CPPA_CHECK_EQUAL(lhs_loc, rhs_loc) CPPA_CHECK(((lhs_loc) == (rhs_loc)))
#define CPPA_CHECK_NOT_EQUAL(lhs_loc, rhs_loc) CPPA_CHECK(((lhs_loc) != (rhs_loc)))
size_t test__yield_interface();
size_t test__remote_actor(const char* app_path, bool is_client,
......@@ -54,7 +55,6 @@ size_t test__remote_actor(const char* app_path, bool is_client,
size_t test__ripemd_160();
size_t test__uniform_type();
size_t test__type_list();
size_t test__a_matches_b();
size_t test__atom();
size_t test__tuple();
size_t test__spawn();
......
#include <string>
#include <typeinfo>
#include "test.hpp"
#include "cppa/util.hpp"
#include "cppa/anything.hpp"
using namespace cppa;
using namespace cppa::util;
size_t test__a_matches_b()
{
CPPA_TEST(test__a_matches_b);
/*
typedef type_list<int, anything> int_star;
typedef type_list<int, float, int> int_float_int;
typedef type_list<int, int, std::string> int_int_string;
typedef type_list<int, int, const std::string&> int_int_const_string_ref;
typedef typename first_n<2, int_float_int>::type int_float;
typedef type_list_apply<int_int_const_string_ref,
remove_const_reference>::type
int_int_string2;
CPPA_CHECK((std::is_same<int, remove_const_reference<const int&>::type>::value));
CPPA_CHECK((a_matches_b<int_star, int_float_int>::value));
CPPA_CHECK((a_matches_b<int_float_int, int_float_int>::value));
CPPA_CHECK((a_matches_b<int_int_string, int_int_string>::value));
CPPA_CHECK((a_matches_b<int_int_string, int_int_string2>::value));
CPPA_CHECK(!(a_matches_b<int_int_string, int_int_const_string_ref>::value));
CPPA_CHECK(!(a_matches_b<type_list<float>,
type_list<int, float, int>>::value));
CPPA_CHECK((std::is_same<util::type_list<int, float>, int_float>::value));
CPPA_CHECK((a_matches_b<type_list<anything, float>,
type_list<int, float, int>>::value) == false);
CPPA_CHECK((a_matches_b<type_list<anything, float>,
type_list<int, int, float>>::value));
*/
return CPPA_TEST_RESULT;
}
......@@ -2,6 +2,7 @@
#include "test.hpp"
#include "cppa/on.hpp"
#include "cppa/atom.hpp"
#include "cppa/tuple.hpp"
#include "cppa/pattern.hpp"
......@@ -11,9 +12,7 @@ using namespace cppa;
size_t test__pattern()
{
CPPA_TEST(test__pattern);
auto x = make_tuple(atom("FooBar"), 42, "hello world");
// some pattern objects to play with
pattern<atom_value, int, std::string> p0{util::wrapped<atom_value>()};
pattern<atom_value, int, std::string> p1(atom("FooBar"));
pattern<atom_value, int, std::string> p2(atom("FooBar"), 42);
......@@ -23,7 +22,8 @@ size_t test__pattern()
pattern<anything> p6;
pattern<atom_value, anything> p7;
pattern<atom_value, anything, std::string> p8;
// each one should accept x ...
auto x = make_tuple(atom("FooBar"), 42, "hello world");
CPPA_CHECK(p0(x));
CPPA_CHECK(p1(x));
CPPA_CHECK(p2(x));
......@@ -33,6 +33,87 @@ size_t test__pattern()
CPPA_CHECK(p6(x));
CPPA_CHECK(p7(x));
CPPA_CHECK(p8(x));
// ... but p2 and p3 should reject y
auto y = make_tuple(atom("FooBar"), 24, "hello world");
CPPA_CHECK_EQUAL(p0(y), true);
CPPA_CHECK_EQUAL(p1(y), true);
CPPA_CHECK_EQUAL(p2(y), false);
CPPA_CHECK_EQUAL(p3(y), false);
CPPA_CHECK_EQUAL(p4(y), true);
CPPA_CHECK_EQUAL(p5(y), true);
CPPA_CHECK_EQUAL(p6(y), true);
CPPA_CHECK_EQUAL(p7(y), true);
CPPA_CHECK_EQUAL(p8(y), true);
// let's check some invoke rules
constexpr size_t num_lambdas = 6;
bool lambda_invoked[num_lambdas];
auto reset_invoke_states = [&]()
{
for (size_t i = 0; i < num_lambdas; ++i)
{
lambda_invoked[i] = false;
}
};
reset_invoke_states();
auto patterns =
(
on<int, anything, int>() >> [&](int v1, int v2)
{
CPPA_CHECK_EQUAL(v1, 1);
CPPA_CHECK_EQUAL(v2, 3);
lambda_invoked[0] = true;
},
on<std::string>() >> [&](const std::string& str)
{
CPPA_CHECK_EQUAL(str, "hello foo");
lambda_invoked[1] = true;
},
on("1", val<int>(), any_vals) >> [&](int value)
{
CPPA_CHECK_EQUAL(value, 2);
lambda_invoked[2] = true;
},
on(1, val<std::string>(), any_vals) >> [&](const std::string& str)
{
CPPA_CHECK_EQUAL(str, "2");
lambda_invoked[3] = true;
},
on<atom("Foo"), int>() >> [&](int value)
{
CPPA_CHECK_EQUAL(value, 1);
lambda_invoked[4] = true;
},
on_param_match() >> [&](double v1, const float& v2)
{
CPPA_CHECK_EQUAL(v1, 1.0);
CPPA_CHECK_EQUAL(v2, 2.0f);
lambda_invoked[5] = true;
}
);
// invokes lambda 0
patterns(make_tuple(1, "2", 3));
CPPA_CHECK(lambda_invoked[0]);
reset_invoke_states();
// invokes lambda 1
patterns(make_tuple("hello foo"));
CPPA_CHECK(lambda_invoked[1]);
reset_invoke_states();
// invokes lambda 2
patterns(make_tuple("1", 2, 3));
CPPA_CHECK(lambda_invoked[2]);
reset_invoke_states();
// invokes lambda 3
patterns(make_tuple(1, "2", "3"));
CPPA_CHECK(lambda_invoked[3]);
reset_invoke_states();
// invokes lambda 4
patterns(make_tuple(atom("Foo"), 1));
CPPA_CHECK(lambda_invoked[4]);
reset_invoke_states();
// invokes lambda 5
patterns(make_tuple(1.0, 2.0f));
CPPA_CHECK(lambda_invoked[5]);
reset_invoke_states();
return CPPA_TEST_RESULT;
}
......@@ -4,6 +4,7 @@
#include <iostream>
#include <typeinfo>
#include <functional>
#include <type_traits>
#include "test.hpp"
......@@ -26,297 +27,34 @@ using std::cout;
using std::endl;
using namespace cppa;
using namespace cppa::util;
namespace {
bool function_called = false;
void fun(const std::string&)
{
function_called = true;
// CPPA_CHECK((s == "Hello World"));
}
} // namespace <anonymous>
size_t test__tuple()
{
CPPA_TEST(test__tuple);
constexpr size_t num_patterns = 6;
bool pattern_invoked[num_patterns];
auto reset_invoke_states = [&]()
{
for (size_t i = 0; i < num_patterns; ++i)
{
pattern_invoked[i] = false;
}
};
reset_invoke_states();
auto patterns =
(
on<int, anything, int>() >> [&](int v1, int v2)
{
CPPA_CHECK_EQUAL(v1, 1);
CPPA_CHECK_EQUAL(v2, 3);
pattern_invoked[0] = true;
},
on<std::string>() >> [&](const std::string& str)
{
CPPA_CHECK_EQUAL(str, "hello foo");
pattern_invoked[1] = true;
},
on("1", val<int>(), any_vals) >> [&](int value)
{
CPPA_CHECK_EQUAL(value, 2);
pattern_invoked[2] = true;
},
on(1, val<std::string>(), any_vals) >> [&](const std::string& str)
{
CPPA_CHECK_EQUAL(str, "2");
pattern_invoked[3] = true;
},
on<atom("Foo"), int>() >> [&](int value)
{
CPPA_CHECK_EQUAL(value, 1);
pattern_invoked[4] = true;
},
on_param_match() >> [&](double v1, const float& v2)
{
CPPA_CHECK_EQUAL(v1, 1.0);
CPPA_CHECK_EQUAL(v2, 2.0f);
pattern_invoked[5] = true;
}
);
patterns(make_tuple(1, "2", 3));
CPPA_CHECK(pattern_invoked[0]);
reset_invoke_states();
patterns(make_tuple("hello foo"));
CPPA_CHECK(pattern_invoked[1]);
reset_invoke_states();
patterns(make_tuple("1", 2, 3));
CPPA_CHECK(pattern_invoked[2]);
reset_invoke_states();
patterns(make_tuple(1, "2", "3"));
CPPA_CHECK(pattern_invoked[3]);
reset_invoke_states();
patterns(make_tuple(atom("Foo"), 1));
CPPA_CHECK(pattern_invoked[4]);
reset_invoke_states();
patterns(make_tuple(1.0, 2.0f));
CPPA_CHECK(pattern_invoked[5]);
reset_invoke_states();
/*
// test of filter_type_list
typedef filter_type_list<any_type,
util::type_list<any_type*, float,
any_type*, int, any_type>>::type
tv_float_int;
// tuples under test
tuple<int, float, int, std::string> t1(42, .2f, 2, "Hello World");
tuple<std::string> t2("foo");
auto t3 = make_tuple(42, .2f, 2, "Hello World", 0);
tuple<int, float, int, std::string> t4(42, .2f, 2, "Hello World");
tuple<int, std::string, int> t5(42, "foo", 24);
tuple<int> t6;
// untyped tuples under test
any_tuple ut0 = t1;
tuple<int, long, double> t7;
CPPA_CHECK((match<int, long, double>(t7)));
// tuple views under test
auto tv0 = get_view<any_type*, float, any_type*, int, any_type>(t1);
auto tv1 = get_view<any_type*, int, any_type*>(tv0);
auto tv2 = get_view<int, any_type*, std::string>(t1);
auto tv3 = get_view<any_type*, int, std::string>(t1);
CPPA_CHECK(get<0>(t6) == 0);
CPPA_CHECK(get<0>(tv2) == get<0>(t1));
CPPA_CHECK(get<1>(tv2) == get<3>(t1));
CPPA_CHECK(get<1>(tv2) == "Hello World");
{
tuple<int> t1_sub1(42);
tuple<int, float> t1_sub2(42, .2f);
tuple<int, float, int> t1_sub3(42, .2f, 2);
CPPA_CHECK((util::compare_first_elements(t1, t1_sub1)));
CPPA_CHECK((match<int, any_type*>(t1)));
CPPA_CHECK((util::compare_first_elements(t1, t1_sub2)));
CPPA_CHECK((match<int, any_type*, float, any_type*>(t1)));
CPPA_CHECK((util::compare_first_elements(t1, t1_sub3)));
CPPA_CHECK((match<int, float, int, any_type>(t1)));
}
{
std::vector<size_t> tv3_mappings;
match<any_type*, int, std::string>(t1, &tv3_mappings);
CPPA_CHECK(( tv3_mappings.size() == 2
&& tv3_mappings[0] == 2
&& tv3_mappings[1] == 3));
}
CPPA_CHECK(get<0>(tv3) == get<2>(t1));
CPPA_CHECK(get<1>(tv3) == get<3>(t1));
CPPA_CHECK(!(tv2 == tv3));
{
int* foo_int = new int(42);
decltype(new int(*foo_int)) foo_int_2 = new int(*foo_int);
CPPA_CHECK_EQUAL(*foo_int, *foo_int_2);
delete foo_int_2;
delete foo_int;
}
CPPA_CHECK((match<int, any_type*, std::string>(ut0)));
// CPPA_CHECK(ut0 == t1);
CPPA_CHECK(get<0>(tv0) == .2f);
CPPA_CHECK(get<1>(tv0) == 2);
CPPA_CHECK(get<0>(tv1) == 2);
CPPA_CHECK((get<0>(tv1) == get<1>(tv0)));
CPPA_CHECK((&(get<0>(tv1)) == &(get<1>(tv0))));
// force detaching of tv1 from tv0 (and t1)
get_ref<0>(tv1) = 20;
CPPA_CHECK(get<1>(tv0) == 2);
CPPA_CHECK(get<0>(tv1) == 20);
CPPA_CHECK((&(get<0>(tv1)) != &(get<1>(tv0))));
CPPA_CHECK((&(get<1>(t1)) == &(get<0>(tv0))));
bool l1_invoked = false;
bool l2_invoked = false;
bool l3_invoked = false;
auto reset_invoke_states = [&]() {
l1_invoked = l2_invoked = l3_invoked = false;
};
auto l1 = [&](int v0, float v1, int v2, const std::string& v3) {
l1_invoked = true;
CPPA_CHECK((get<0>(t1) == v0));
CPPA_CHECK((get<1>(t1) == v1));
CPPA_CHECK((get<2>(t1) == v2));
CPPA_CHECK((get<3>(t1) == v3));
};
auto l2 = [&](float v0, int v1) {
l2_invoked = true;
CPPA_CHECK((get<0>(tv0) == v0));
CPPA_CHECK((get<1>(tv0) == v1));
};
auto l3 = [&](const std::string& v0) {
l3_invoked = true;
CPPA_CHECK((get<0>(t2) == v0));
};
invoke(l1, t1);
CPPA_CHECK(l1_invoked);
reset_invoke_states();
invoke(l2, tv0);
CPPA_CHECK(l2_invoked);
reset_invoke_states();
invoke(l3, t2);
CPPA_CHECK(l3_invoked);
reset_invoke_states();
auto inv = ( on<any_type*, float, any_type*, int, any_type>() >> l2
, on<int, float, int, std::string, any_type*>() >> l1
, on<any_type*, int, std::string, any_type*>() >> l3);
CPPA_CHECK(inv(t1));
CPPA_CHECK(!l1_invoked && l2_invoked && !l3_invoked);
reset_invoke_states();
CPPA_CHECK(inv(t5));
CPPA_CHECK(!l1_invoked && !l2_invoked && l3_invoked);
reset_invoke_states();
CPPA_CHECK(inv(t3));
CPPA_CHECK(l1_invoked && !l2_invoked && !l3_invoked);
reset_invoke_states();
auto intmd = inv.get_intermediate(t1);
CPPA_CHECK(intmd != nullptr);
if (intmd) intmd->invoke();
CPPA_CHECK(!l1_invoked && l2_invoked && !l3_invoked);
reset_invoke_states();
(on<any_type*, std::string, any_type*>() >> fun)(t2);
CPPA_CHECK(function_called);
reset_invoke_states();
bool l4_invoked = false;
auto l4 = [&]() {
l4_invoked = true;
};
auto inv2 = (
on(any_vals, .1f, any_vals, 2, val<>()) >> l4,
//on<any_type*, float, any_type*, int, any_type>(.1f, 2) >> l4,
on(any_vals, val<float>(), any_vals, 2, val<>()) >> l2
//on<any_type*, float, any_type*, int, any_type>(any_val, 2) >> l2
);
CPPA_CHECK((match<any_type*, float, any_type*, int, any_type>(t1)));
CPPA_CHECK(inv2(t1));
CPPA_CHECK(!l4_invoked);
CPPA_CHECK(l2_invoked);
reset_invoke_states();
{
any_type* x = nullptr;
CPPA_CHECK(x == val<>());
CPPA_CHECK(val<>() == x);
CPPA_CHECK(val<>() == 42);
CPPA_CHECK(val<>() == 24);
}
// test detaching of tuples
auto t1_copy = t1;
CPPA_CHECK((&(get<0>(t1_copy)) == &(get<0>(t1))));
get_ref<0>(t1_copy) = 24; // this detaches t4 from t1
CPPA_CHECK((&(get<0>(t1_copy)) != &(get<0>(t1))));
CPPA_CHECK(get<0>(t1_copy) != get<0>(t1));
CPPA_CHECK(get<1>(t1_copy) == get<1>(t1));
CPPA_CHECK(get<2>(t1_copy) == get<2>(t1));
CPPA_CHECK(get<3>(t1_copy) == get<3>(t1));
CPPA_CHECK(t1 == t4);
// test any_tuple::tail
any_tuple at1 = make_tuple(1, 2, 3, 4.0, "5");
any_tuple at2 = make_tuple(2, 3, 4.0, "5");
any_tuple at1_tail = at1.tail();
CPPA_CHECK_EQUAL(at1.size(), (at1_tail.size() + 1));
CPPA_CHECK_EQUAL(at1_tail.size(), at2.size());
CPPA_CHECK_EQUAL(at1_tail.utype_info_at(0), at2.utype_info_at(0));
CPPA_CHECK((at2.utype_info_at(0).equal(at1_tail.at(0), at2.at(0))));
CPPA_CHECK_EQUAL(at2, at1_tail);
CPPA_CHECK_EQUAL(at1_tail, at2);
*/
// check type correctness of make_tuple()
auto t0 = make_tuple("1", 2);
auto t0_0 = get<0>(t0);
auto t0_1 = get<1>(t0);
// check implicit type conversion
CPPA_CHECK((std::is_same<decltype(t0_0), std::string>::value));
CPPA_CHECK((std::is_same<decltype(t0_1), int>::value));
CPPA_CHECK_EQUAL(t0_0, "1");
CPPA_CHECK_EQUAL(t0_1, 2);
// create a view of t0 that only contains the string
auto v0 = get_view<std::string, anything>(t0);
auto v0_0 = get<0>(v0);
CPPA_CHECK_EQUAL(v0.size(), 1);
CPPA_CHECK((std::is_same<decltype(v0_0), std::string>::value));
CPPA_CHECK_EQUAL(v0_0, "1");
// check cow semantics
CPPA_CHECK_EQUAL(&get<0>(t0), &get<0>(v0)); // point to the same string
get_ref<0>(t0) = "hello world"; // detaches t0 from v0
CPPA_CHECK_EQUAL(get<0>(t0), "hello world"); // t0 contains new value
CPPA_CHECK_EQUAL(get<0>(v0), "1"); // v0 contains old value
CPPA_CHECK_NOT_EQUAL(&get<0>(t0), &get<0>(v0)); // no longer the same
// check operator==
auto lhs = make_tuple(1,2,3,4);
auto rhs = make_tuple(static_cast<std::uint8_t>(1), 2.0, 3, 4);
CPPA_CHECK_EQUAL(lhs, rhs);
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