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;
}
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