Commit 754dbbe1 authored by neverlord's avatar neverlord

announcing of list and map typedefs

parent 4a354707
......@@ -151,7 +151,13 @@
* assert(&(get<0>(x)) != &(get<0>(y)));
* @endcode
*
* @defgroup MessageHandling Send and receive messages
* @defgroup MessageHandling Message handling.
*
* This is the beating heart of @p libcppa. Actor programming is all about
* message handling.
*
* A message in @p libcppa is a n-tuple of values (with size >= 1). You can use
* almost every type in messages.
*
* @section UsingOwnTypes Using own types in messages
*
......
......@@ -14,6 +14,7 @@
#include "cppa/detail/map_member.hpp"
#include "cppa/detail/list_member.hpp"
#include "cppa/detail/type_to_ptype.hpp"
#include "cppa/detail/primitive_member.hpp"
namespace cppa { namespace detail {
......@@ -73,14 +74,6 @@ class is_stl_compliant_map
};
template<typename T>
struct has_default_uniform_type_info_impl
{
static const bool value = util::is_primitive<T>::value
|| is_stl_compliant_map<T>::value
|| is_stl_compliant_list<T>::value;
};
template<typename T>
class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T>
{
......@@ -175,7 +168,7 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T
}
// a member that's not a member at all, but "forwards"
// the 'self' pointer to make use *_member implementations
// the 'self' pointer to make use of *_member implementations
static member fake_member(uniform_type_info* mtptr)
{
return {
......@@ -284,28 +277,29 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T
"stl-compliant list/map");
}
template<class C>
void init_(typename
util::enable_if<
util::disjunction<std::is_same<C, util::void_type>,
std::is_same<C, anything>>>::type* = 0)
{
// anything doesn't have any fields (no serialization required)
}
template<typename P>
void init_(typename util::enable_if<util::is_primitive<P>>::type* = 0)
{
m_members.push_back(member::fake_member(new primitive_member<P>()));
}
template<typename Map>
void init_(typename util::enable_if<is_stl_compliant_map<Map>>::type* = 0)
{
m_members.push_back(member::fake_member(new map_member<Map>));
}
template<typename List>
void init_(typename util::enable_if<is_stl_compliant_list<List>>::type* = 0)
{
m_members.push_back(member::fake_member(new list_member<List>));
}
template<typename X>
void init_(typename
util::disable_if<
util::disjunction<util::is_primitive<X>,
std::is_same<X, util::void_type>,
std::is_same<X, anything>>>::type* = 0)
void init_(typename util::enable_if<is_invalid<X>>::type* = 0)
{
// T is neither primitive nor a STL compliant list/map,
// so it has to be an announced type
static_assert(util::is_primitive<X>::value,
"T is neither a primitive type nor a "
"stl-compliant list/map");
......@@ -322,6 +316,10 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T
default_uniform_type_info_impl()
{
init_<T>();
if (m_members.size() != 1)
{
throw std::logic_error("no fake member added");
}
}
void serialize(const void* obj, serializer* s) const
......
#ifndef LIST_MEMBER_HPP
#define LIST_MEMBER_HPP
#include "cppa/util/is_primitive.hpp"
#include "cppa/util/abstract_uniform_type_info.hpp"
namespace cppa { namespace detail {
template<typename List>
class list_member : public util::abstract_uniform_type_info<List>
template<typename List, bool HasPrimitiveValues>
struct list_member_util
{
typedef typename List::value_type value_type;
static constexpr primitive_type vptype = type_to_ptype<value_type>::ptype;
void operator()(const List& list, serializer* s) const
{
s->begin_sequence(list.size());
for (auto i = list.begin(); i != list.end(); ++i)
{
s->write_value(*i);
}
s->end_sequence();
}
void operator()(List& list, deserializer* d) const
{
list.clear();
auto size = d->begin_sequence();
for (decltype(size) i = 0; i < size; ++i)
{
list.push_back(get<value_type>(d->read_value(vptype)));
}
}
};
static_assert(vptype != pt_null,
"List::value_type is not a primitive data type");
template<typename List>
struct list_member_util<List, false>
{
typedef typename List::value_type value_type;
public:
const uniform_type_info* m_value_type;
void serialize(const void* obj, serializer* s) const
list_member_util() : m_value_type(uniform_typeid<value_type>())
{
}
void operator()(const List& list, serializer* s) const
{
auto& ls = *reinterpret_cast<const List*>(obj);
s->begin_sequence(ls.size());
for (const auto& val : ls)
s->begin_sequence(list.size());
for (auto i = list.begin(); i != list.end(); ++i)
{
s->write_value(val);
m_value_type->serialize(&(*i), s);
}
s->end_sequence();
}
void deserialize(void* obj, deserializer* d) const
void operator()(List& list, deserializer* d) const
{
auto& ls = *reinterpret_cast<List*>(obj);
size_t ls_size = d->begin_sequence();
for (size_t i = 0; i < ls_size; ++i)
list.clear();
value_type tmp;
auto size = d->begin_sequence();
for (decltype(size) i = 0; i < size; ++i)
{
primitive_variant val = d->read_value(vptype);
ls.push_back(std::move(get_ref<value_type>(val)));
m_value_type->deserialize(&tmp, d);
list.push_back(tmp);
}
d->end_sequence();
}
};
template<typename List>
class list_member : public util::abstract_uniform_type_info<List>
{
typedef typename List::value_type value_type;
list_member_util<List, util::is_primitive<value_type>::value> m_helper;
public:
void serialize(const void* obj, serializer* s) const
{
auto& list = *reinterpret_cast<const List*>(obj);
m_helper(list, s);
}
void deserialize(void* obj, deserializer* d) const
{
auto& list = *reinterpret_cast<List*>(obj);
m_helper(list, d);
}
};
......
#ifndef MAP_MEMBER_HPP
#define MAP_MEMBER_HPP
#include "cppa/util/abstract_uniform_type_info.hpp"
#include "cppa/detail/primitive_member.hpp"
#include <type_traits>
#include "cppa/detail/pair_member.hpp"
#include "cppa/detail/primitive_member.hpp"
#include "cppa/util/abstract_uniform_type_info.hpp"
namespace cppa { namespace detail {
// matches value_type of std::set
template<typename T>
struct meta_value_type
struct is_pair { static const bool value = false; };
template<typename First, typename Second>
struct is_pair< std::pair<First, Second> > { static const bool value = true; };
template<typename T, bool IsPair, bool IsPrimitive>
struct map_member_util;
// std::set with primitive value
template<typename T>
struct map_member_util<T, false, true>
{
primitive_member<T> impl;
void serialize_value(const T& what, serializer* s) const
{
impl.serialize(&what, s);
}
template<typename M>
void deserialize_and_insert(M& map, deserializer* d) const
{
......@@ -25,24 +37,59 @@ struct meta_value_type
}
};
// matches value_type of std::map
template<typename T1, typename T2>
struct meta_value_type<std::pair<const T1, T2>>
// std::set with non-primitive value
template<typename T>
struct map_member_util<T, false, false>
{
const uniform_type_info* m_type;
map_member_util() : m_type(uniform_typeid<T>())
{
}
void serialize_value(const T& what, serializer* s) const
{
m_type->serialize(&what, s);
}
template<typename M>
void deserialize_and_insert(M& map, deserializer* d) const
{
T value;
m_type->deserialize(&value, d);
map.insert(std::move(value));
}
};
// std::map
template<typename T>
struct map_member_util<T, true, false>
{
pair_member<T1, T2> impl;
void serialize_value(const std::pair<const T1, T2>& what, serializer* s) const
// std::map defines its first half of value_type as const
typedef typename std::remove_const<typename T::first_type>::type first_type;
typedef typename T::second_type second_type;
pair_member<first_type, second_type> impl;
void serialize_value(const T& what, serializer* s) const
{
std::pair<T1, T2> p(what.first, what.second);
// impl needs a pair without const modifier
std::pair<first_type, second_type> p(what.first, what.second);
impl.serialize(&p, s);
}
template<typename M>
void deserialize_and_insert(M& map, deserializer* d) const
{
std::pair<T1, T2> p;
std::pair<first_type, second_type> p;
impl.deserialize(&p, d);
std::pair<const T1, T2> v(std::move(p.first), std::move(p.second));
std::pair<const first_type, second_type> v(std::move(p.first),
std::move(p.second));
map.insert(std::move(v));
}
};
template<typename Map>
......@@ -52,7 +99,9 @@ class map_member : public util::abstract_uniform_type_info<Map>
typedef typename Map::key_type key_type;
typedef typename Map::value_type value_type;
meta_value_type<value_type> m_value_type_meta;
map_member_util<value_type,
is_pair<value_type>::value,
util::is_primitive<value_type>::value> m_helper;
public:
......@@ -62,7 +111,7 @@ class map_member : public util::abstract_uniform_type_info<Map>
s->begin_sequence(mp.size());
for (const auto& val : mp)
{
m_value_type_meta.serialize_value(val, s);
m_helper.serialize_value(val, s);
}
s->end_sequence();
}
......@@ -70,10 +119,11 @@ class map_member : public util::abstract_uniform_type_info<Map>
void deserialize(void* obj, deserializer* d) const
{
auto& mp = *reinterpret_cast<Map*>(obj);
mp.clear();
size_t mp_size = d->begin_sequence();
for (size_t i = 0; i < mp_size; ++i)
{
m_value_type_meta.deserialize_and_insert(mp, d);
m_helper.deserialize_and_insert(mp, d);
}
d->end_sequence();
}
......
......@@ -2,6 +2,11 @@
#define PAIR_MEMBER_HPP
#include <utility>
#include "cppa/serializer.hpp"
#include "cppa/deserializer.hpp"
#include "cppa/primitive_variant.hpp"
#include "cppa/detail/type_to_ptype.hpp"
#include "cppa/util/abstract_uniform_type_info.hpp"
namespace cppa { namespace detail {
......
#include <vector>
#include <cassert>
#include <utility>
#include <iostream>
......@@ -9,10 +10,10 @@ using std::endl;
using namespace cppa;
// POD struct - pair of two ints
// POD struct
struct foo
{
int a;
std::vector<int> a;
int b;
};
......@@ -23,9 +24,10 @@ bool operator==(const foo& lhs, const foo& rhs)
&& lhs.b == rhs.b;
}
// another pair of two ints
// a pair of two ints
typedef std::pair<int,int> foo_pair;
// another pair of two ints
typedef std::pair<int,int> foo_pair2;
int main(int, char**)
......@@ -44,12 +46,16 @@ int main(int, char**)
assert(announce<foo_pair2>(&foo_pair2::first, &foo_pair2::second) == false);
// send a foo to ourselves
send(self(), foo{1,2});
send(self(), foo{ { 1, 2, 3, 4 }, 5 });
// send a foo_pair2 to ourselves
send(self(), foo_pair2{3,4});
send(self(), foo_pair2{3, 4});
// quits the program
send(self(), atom("done"));
// libcppa returns the same uniform_type_info
// instance for foo_pair and foo_pair2
assert(uniform_typeid<foo_pair>() == uniform_typeid<foo_pair2>());
// receive two messages
int i = 0;
receive_while([&]() { return ++i <= 2; })
......@@ -65,10 +71,18 @@ int main(int, char**)
},
on<foo>() >> [](const foo& val)
{
cout << "foo("
<< val.a << ","
<< val.b << ")"
<< endl;
cout << "foo({";
auto i = val.a.begin();
auto end = val.a.end();
if (i != end)
{
cout << *i;
while (++i != end)
{
cout << "," << *i;
}
}
cout << "}," << val.b << ")" << endl;
}
);
return 0;
......
......@@ -190,7 +190,17 @@ int main()
// send a tree to ourselves ...
send(self(), t);
receive
// send a vector of trees to ourselves
typedef std::vector<tree> tree_vector;
announce<tree_vector>();
tree_vector tvec;
tvec.push_back(t);
tvec.push_back(t);
send(self(), tvec);
// receive both messages
int i = 0;
receive_while([&]() { return ++i <= 2; })
(
// ... and receive it
on<tree>() >> [](const tree& tmsg)
......@@ -203,6 +213,19 @@ int main()
// prints the tree using the print member function:
// 0 { 10 { 11, 12, 13 } , 20 { 21, 22 } }
tmsg.print();
},
on<tree_vector>() >> [](const tree_vector& trees)
{
// prints "received 2 trees"
cout << "received " << trees.size() << " trees" << endl;
// prints:
// @<> ( {
// std::vector<tree,std::allocator<tree>> ( {
// tree ( 0, { 10, { 11, { }, 12, { }, 13, { } }, 20, { 21, { }, 22, { } } } ),
// tree ( 0, { 10, { 11, { }, 12, { }, 13, { } }, 20, { 21, { }, 22, { } } } )
// )
// } )
cout << "to_string: " << to_string(last_received()) << endl;
}
);
......
......@@ -647,7 +647,6 @@ class uniform_type_info_map_helper
insert(d, new atom_value_tinfo, { raw_name<atom_value>() });
insert(d, new addr_msg_tinfo, {raw_name<detail::addressed_message>()});
insert<float>(d);
insert<cppa::util::void_type>(d);
if (sizeof(double) == sizeof(long double))
{
std::string dbl = raw_name<double>();
......
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