Commit af0db378 authored by Dominik Charousset's avatar Dominik Charousset

improved announce interface, i.e., allow user-defined types as POD members and...

improved announce interface, i.e., allow user-defined types as POD members and auto-detect recursive containers such as vector<vector<double>>
parent cc998bac
Version 0.4.2 Version 0.4.2
2012-XX-XX 2012-10-1
- Bugfix: evaluate `errno` whenever select() fails and handle errors properly - Bugfix: evaluate `errno` whenever select() fails and handle errors properly
- Refactored announce
* accept recursive containers, e.g., vector<vector<double>>
* allow user-defined types as members of announced types
* all-new, policy-based implementation
Version 0.4.1 Version 0.4.1
......
...@@ -54,14 +54,11 @@ cppa/detail/empty_tuple.hpp ...@@ -54,14 +54,11 @@ cppa/detail/empty_tuple.hpp
cppa/detail/get_behavior.hpp cppa/detail/get_behavior.hpp
cppa/detail/group_manager.hpp cppa/detail/group_manager.hpp
cppa/detail/implicit_conversions.hpp cppa/detail/implicit_conversions.hpp
cppa/detail/list_member.hpp
cppa/detail/map_member.hpp
cppa/detail/matches.hpp cppa/detail/matches.hpp
cppa/detail/network_manager.hpp cppa/detail/network_manager.hpp
cppa/detail/object_array.hpp cppa/detail/object_array.hpp
cppa/detail/object_impl.hpp cppa/detail/object_impl.hpp
cppa/detail/pair_member.hpp cppa/detail/pair_member.hpp
cppa/detail/primitive_member.hpp
cppa/detail/projection.hpp cppa/detail/projection.hpp
cppa/detail/pseudo_tuple.hpp cppa/detail/pseudo_tuple.hpp
cppa/detail/ptype_to_type.hpp cppa/detail/ptype_to_type.hpp
......
...@@ -83,7 +83,7 @@ class container_tuple_view : public abstract_tuple { ...@@ -83,7 +83,7 @@ class container_tuple_view : public abstract_tuple {
private: private:
std::unique_ptr<Container, disablable_delete<Container> > m_ptr; std::unique_ptr<Container, disablable_delete> m_ptr;
}; };
......
...@@ -31,6 +31,8 @@ ...@@ -31,6 +31,8 @@
#ifndef CPPA_DEFAULT_UNIFORM_TYPE_INFO_IMPL_HPP #ifndef CPPA_DEFAULT_UNIFORM_TYPE_INFO_IMPL_HPP
#define CPPA_DEFAULT_UNIFORM_TYPE_INFO_IMPL_HPP #define CPPA_DEFAULT_UNIFORM_TYPE_INFO_IMPL_HPP
#include <memory>
#include "cppa/anything.hpp" #include "cppa/anything.hpp"
#include "cppa/util/rm_ref.hpp" #include "cppa/util/rm_ref.hpp"
...@@ -41,13 +43,12 @@ ...@@ -41,13 +43,12 @@
#include "cppa/util/is_forward_iterator.hpp" #include "cppa/util/is_forward_iterator.hpp"
#include "cppa/util/abstract_uniform_type_info.hpp" #include "cppa/util/abstract_uniform_type_info.hpp"
#include "cppa/detail/map_member.hpp"
#include "cppa/detail/list_member.hpp"
#include "cppa/detail/type_to_ptype.hpp" #include "cppa/detail/type_to_ptype.hpp"
#include "cppa/detail/primitive_member.hpp"
namespace cppa { namespace detail { namespace cppa { namespace detail {
typedef std::unique_ptr<uniform_type_info> unique_uti;
template<typename T> template<typename T>
class is_stl_compliant_list { class is_stl_compliant_list {
...@@ -97,6 +98,12 @@ class is_stl_compliant_map { ...@@ -97,6 +98,12 @@ class is_stl_compliant_map {
}; };
template<typename T>
struct is_stl_pair : std::false_type { };
template<typename F, typename S>
struct is_stl_pair<std::pair<F,S> > : std::true_type { };
template<typename T> template<typename T>
class builtin_member : public util::abstract_uniform_type_info<T> { class builtin_member : public util::abstract_uniform_type_info<T> {
...@@ -118,211 +125,344 @@ class builtin_member : public util::abstract_uniform_type_info<T> { ...@@ -118,211 +125,344 @@ class builtin_member : public util::abstract_uniform_type_info<T> {
}; };
typedef std::integral_constant<int,0> primitive_impl;
typedef std::integral_constant<int,1> list_impl;
typedef std::integral_constant<int,2> map_impl;
typedef std::integral_constant<int,3> pair_impl;
typedef std::integral_constant<int,9> recursive_impl;
template<typename T> template<typename T>
class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T> { constexpr int impl_id() {
return util::is_primitive<T>::value
? 0
: (is_stl_compliant_list<T>::value
? 1
: (is_stl_compliant_map<T>::value
? 2
: (is_stl_pair<T>::value
? 3
: 9)));
}
template<typename T>
struct deconst_pair {
typedef T type;
};
template<typename X> template<typename K, typename V>
struct is_invalid { struct deconst_pair<std::pair<K,V> > {
static constexpr bool value = !util::is_primitive<X>::value typedef typename std::remove_const<K>::type first_type;
&& !is_stl_compliant_map<X>::value typedef typename std::remove_const<V>::type second_type;
&& !is_stl_compliant_list<X>::value; typedef std::pair<first_type,second_type> type;
}; };
class member { class default_serialize_policy {
uniform_type_info* m_meta; public:
std::function<void (const uniform_type_info*, template<typename T>
const void*, void operator()(const T& val, serializer* s) const {
serializer* )> m_serialize; std::integral_constant<int,impl_id<T>()> token;
simpl(val, s, token);
}
std::function<void (const uniform_type_info*, template<typename T>
void*, void operator()(T& val, deserializer* d) const {
deserializer* )> m_deserialize; std::integral_constant<int,impl_id<T>()> token;
dimpl(val, d, token);
//static_types_array<T>::arr[0]->deserialize(&val, d);
}
member(const member&) = delete; private:
member& operator=(const member&) = delete;
void swap(member& other) { template<typename T>
std::swap(m_meta, other.m_meta); void simpl(const T& val, serializer* s, primitive_impl) const {
std::swap(m_serialize, other.m_serialize); s->write_value(val);
std::swap(m_deserialize, other.m_deserialize);
} }
template<typename S, class D> template<typename T>
member(uniform_type_info* mtptr, S&& s, D&& d) void simpl(const T& val, serializer* s, list_impl) const {
: m_meta(mtptr) s->begin_sequence(val.size());
, m_serialize(std::forward<S>(s)) for (auto i = val.begin(); i != val.end(); ++i) {
, m_deserialize(std::forward<D>(d)) { (*this)(*i, s);
}
s->end_sequence();
} }
public: template<typename T>
void simpl(const T& val, serializer* s, map_impl) const {
// lists and maps share code for serialization
list_impl token;
simpl(val, s, token);
}
template<typename R, class C> template<typename T>
member(uniform_type_info* mtptr, R C::*mem_ptr) : m_meta(mtptr) { void simpl(const T& val, serializer* s, pair_impl) const {
m_serialize = [mem_ptr] (const uniform_type_info* mt, (*this)(val.first, s);
const void* obj, (*this)(val.second, s);
serializer* s) {
mt->serialize(&(*reinterpret_cast<const C*>(obj).*mem_ptr), s);
};
m_deserialize = [mem_ptr] (const uniform_type_info* mt,
void* obj,
deserializer* d) {
mt->deserialize(&(*reinterpret_cast<C*>(obj).*mem_ptr), d);
};
} }
template<typename GRes, typename SRes, typename SArg, class C> template<typename T>
member(uniform_type_info* mtptr, void simpl(const T& val, serializer* s, recursive_impl) const {
GRes (C::*getter)() const, static_types_array<T>::arr[0]->serialize(&val, s);
SRes (C::*setter)(SArg)) : m_meta(mtptr) {
typedef typename util::rm_ref<GRes>::type getter_result;
typedef typename util::rm_ref<SArg>::type setter_arg;
static_assert(std::is_same<getter_result, setter_arg>::value,
"getter result doesn't match setter argument");
m_serialize = [getter] (const uniform_type_info* mt,
const void* obj,
serializer* s) {
GRes v = (*reinterpret_cast<const C*>(obj).*getter)();
mt->serialize(&v, s);
};
m_deserialize = [setter] (const uniform_type_info* mt,
void* obj,
deserializer* d) {
setter_arg value;
mt->deserialize(&value, d); (*reinterpret_cast<C*>(obj).*setter)(value);
};
} }
member(member&& other) : m_meta(nullptr) { template<typename T>
swap(other); void dimpl(T& storage, deserializer* d, primitive_impl) const {
primitive_variant val = d->read_value(type_to_ptype<T>::ptype);
storage = std::move(get<T>(val));
} }
// a member that's not a member at all, but "forwards" template<typename T>
// the 'self' pointer to make use of *_member implementations void dimpl(T& storage, deserializer* d, list_impl) const {
static member fake_member(uniform_type_info* mtptr) { typedef typename T::value_type value_type;
return { storage.clear();
mtptr, size_t size = d->begin_sequence();
[] (const uniform_type_info* mt, const void* obj, serializer* s) { for (size_t i = 0; i < size; ++i) {
mt->serialize(obj, s); value_type tmp;
}, (*this)(tmp, d);
[] (const uniform_type_info* mt, void* obj, deserializer* d) { storage.push_back(std::move(tmp));
mt->deserialize(obj, d);
} }
}; d->end_sequence();
} }
~member() { template<typename T>
delete m_meta; void dimpl(T& storage, deserializer* d, map_impl) const {
storage.clear();
size_t size = d->begin_sequence();
for (size_t i = 0; i < size; ++i) {
typename deconst_pair<typename T::value_type>::type tmp;
(*this)(tmp, d);
storage.insert(tmp);
}
d->end_sequence();
} }
member& operator=(member&& other) { template<typename T>
swap(other); void dimpl(T& storage, deserializer* d, pair_impl) const {
return *this; (*this)(storage.first, d);
(*this)(storage.second, d);
} }
inline void serialize(const void* parent, serializer* s) const { template<typename T>
m_serialize(m_meta, parent, s); void dimpl(T& storage, deserializer* d, recursive_impl) const {
static_types_array<T>::arr[0]->deserialize(&storage, d);
} }
inline void deserialize(void* parent, deserializer* d) const { };
m_deserialize(m_meta, parent, d);
class forwarding_serialize_policy {
public:
forwarding_serialize_policy(const forwarding_serialize_policy&) = delete;
forwarding_serialize_policy& operator=(const forwarding_serialize_policy&) = delete;
forwarding_serialize_policy(forwarding_serialize_policy&&) = default;
forwarding_serialize_policy& operator=(forwarding_serialize_policy&&) = default;
inline forwarding_serialize_policy(unique_uti uti)
: m_uti(std::move(uti)) { }
template<typename T>
inline void operator()(const T& val, serializer* s) const {
m_uti->serialize(&val, s);
} }
}; template<typename T>
inline void operator()(T& val, deserializer* d) const {
m_uti->deserialize(&val, d);
}
std::vector<member> m_members; private:
// terminates recursion unique_uti m_uti;
inline void push_back() { }
// pr.first = member pointer };
// pr.second = meta object to handle pr.first
template<typename R, class C, typename... Args> template<typename T, class AccessPolicy, class SerializePolicy = default_serialize_policy>
void push_back(std::pair<R C::*, util::abstract_uniform_type_info<R>*> pr, class member_tinfo : public util::abstract_uniform_type_info<T> {
Args&&... args) {
m_members.push_back({ pr.second, pr.first }); public:
push_back(std::forward<Args>(args)...);
member_tinfo(AccessPolicy apol, SerializePolicy spol)
: m_apol(std::move(apol)), m_spol(std::move(spol)) { }
member_tinfo(AccessPolicy apol) : m_apol(std::move(apol)) { }
member_tinfo() { }
void serialize(const void* vptr, serializer* s) const {
m_spol(m_apol(vptr), s);
} }
// pr.first = getter / setter pair void deserialize(void* vptr, deserializer* d) const {
// pr.second = meta object to handle pr.first std::integral_constant<bool, AccessPolicy::grants_mutable_access> token;
template<typename GRes, typename SRes, typename SArg, typename C, typename... Args> ds(vptr, d, token);
void push_back(const std::pair<std::pair<GRes (C::*)() const, SRes (C::*)(SArg)>, util::abstract_uniform_type_info<typename util::rm_ref<GRes>::type>*>& pr,
Args&&... args) {
m_members.push_back({ pr.second, pr.first.first, pr.first.second });
push_back(std::forward<Args>(args)...);
} }
// pr.first = getter member const function pointer private:
// pr.second = setter member function pointer
template<typename GRes, typename SRes, typename SArg, class C, typename... Args> void ds(void* p, deserializer* d, std::true_type) const {
typename std::enable_if<util::is_primitive<typename util::rm_ref<GRes>::type>::value>::type m_spol(m_apol(p), d);
push_back(const std::pair<GRes (C::*)() const, SRes (C::*)(SArg)>& pr,
Args&&... args) {
typedef typename util::rm_ref<GRes>::type memtype;
m_members.push_back({ new primitive_member<memtype>(), pr.first, pr.second });
push_back(std::forward<Args>(args)...);
} }
template<typename R, class C, typename... Args> void ds(void* p, deserializer* d, std::false_type) const {
typename std::enable_if<util::is_primitive<R>::value>::type T tmp;
push_back(R C::*mem_ptr, Args&&... args) { m_spol(tmp, d);
m_members.push_back({ new primitive_member<R>(), mem_ptr }); m_apol(p, std::move(tmp));
push_back(std::forward<Args>(args)...);
} }
template< typename R, class C,typename... Args> AccessPolicy m_apol;
typename std::enable_if<is_stl_compliant_list<R>::value>::type SerializePolicy m_spol;
push_back(R C::*mem_ptr, Args&&... args) {
m_members.push_back({ new list_member<R>(), mem_ptr }); };
push_back(std::forward<Args>(args)...);
template<typename T, class C>
class memptr_access_policy {
public:
memptr_access_policy(const memptr_access_policy&) = default;
memptr_access_policy& operator=(const memptr_access_policy&) = default;
inline memptr_access_policy(T C::* memptr) : m_memptr(memptr) { }
inline T& operator()(void* vptr) const {
auto ptr = reinterpret_cast<C*>(vptr);
return *ptr.*m_memptr;
} }
template<typename R, class C, typename... Args> inline const T& operator()(const void* vptr) const {
typename std::enable_if<is_stl_compliant_map<R>::value>::type auto ptr = reinterpret_cast<const C*>(vptr);
push_back(R C::*mem_ptr, Args&&... args) { return *ptr.*m_memptr;
m_members.push_back({ new map_member<R>(), mem_ptr });
push_back(std::forward<Args>(args)...);
} }
template<typename R, class C, typename... Args> static constexpr bool grants_mutable_access = true;
typename std::enable_if<is_invalid<R>::value && util::is_builtin<R>::value>::type
push_back(R C::* mem_ptr, Args&&... args) { private:
m_members.push_back({new builtin_member<R>(), mem_ptr});
push_back(std::forward<Args>(args)...); T C::* m_memptr;
};
template<class C, typename GRes, typename SRes, typename SArg>
class getter_setter_access_policy {
public:
typedef GRes (C::*getter)() const;
typedef SRes (C::*setter)(SArg);
getter_setter_access_policy(const getter_setter_access_policy&) = default;
getter_setter_access_policy& operator=(const getter_setter_access_policy&) = default;
getter_setter_access_policy(getter g, setter s) : m_get(g), m_set(s) { }
inline GRes operator()(const void* vptr) const {
auto ptr = reinterpret_cast<const C*>(vptr);
return (*ptr.*m_get)();
} }
template<typename R, class C, typename... Args> template<typename Arg>
typename std::enable_if<is_invalid<R>::value && !util::is_builtin<R>::value>::type inline void operator()(void* vptr, Arg&& value) const {
push_back(R C::*, Args&&...) { auto ptr = reinterpret_cast<C*>(vptr);
static_assert(util::is_primitive<R>::value, return (*ptr.*m_set)(std::forward<Arg>(value));
"T is neither a primitive type nor a " }
"stl-compliant list/map");
static constexpr bool grants_mutable_access = false;
private:
getter m_get;
setter m_set;
};
template<typename T>
struct fake_access_policy {
inline T& operator()(void* vptr) const {
return *reinterpret_cast<T*>(vptr);
}
inline const T& operator()(const void* vptr) const {
return *reinterpret_cast<const T*>(vptr);
} }
template<typename P> static constexpr bool grants_mutable_access = true;
void init_(typename std::enable_if<util::is_primitive<P>::value>::type* = 0) {
m_members.push_back(member::fake_member(new primitive_member<P>())); };
template<typename T, class C>
unique_uti new_member_tinfo(T C::* memptr) {
typedef memptr_access_policy<T,C> access_policy;
typedef member_tinfo<T,access_policy> result_type;
return unique_uti(new result_type(memptr));
}
template<typename T, class C>
unique_uti new_member_tinfo(T C::* memptr, std::unique_ptr<uniform_type_info> meminf) {
typedef memptr_access_policy<T,C> access_policy;
typedef member_tinfo<T,access_policy,forwarding_serialize_policy> result_type;
return unique_uti(new result_type(memptr, std::move(meminf)));
}
template<class C, typename GRes, typename SRes, typename SArg>
unique_uti new_member_tinfo(GRes (C::*getter)() const, SRes (C::*setter)(SArg)) {
typedef getter_setter_access_policy<C, GRes, SRes, SArg> access_policy;
typedef typename util::rm_ref<GRes>::type value_type;
typedef member_tinfo<value_type,access_policy> result_type;
return unique_uti(new result_type(access_policy(getter, setter)));
}
template<class C, typename GRes, typename SRes, typename SArg>
unique_uti new_member_tinfo(GRes (C::*getter)() const, SRes (C::*setter)(SArg), std::unique_ptr<uniform_type_info> meminf) {
typedef getter_setter_access_policy<C, GRes, SRes, SArg> access_policy;
typedef typename util::rm_ref<GRes>::type value_type;
typedef member_tinfo<value_type,access_policy,forwarding_serialize_policy> result_type;
return unique_uti(new result_type(access_policy(getter, setter), std::move(meminf)));
}
template<typename T>
class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T> {
std::vector<unique_uti> m_members;
// terminates recursion
inline void push_back() { }
template<typename R, class C, typename... Args>
void push_back(R C::* memptr, Args&&... args) {
m_members.push_back(new_member_tinfo(memptr));
push_back(std::forward<Args>(args)...);
} }
template<typename Map> // pr.first = member pointer
void init_(typename std::enable_if<is_stl_compliant_map<Map>::value>::type* = 0) { // pr.second = meta object to handle pr.first
m_members.push_back(member::fake_member(new map_member<Map>)); template<typename R, class C, typename... Args>
void push_back(const std::pair<R C::*, util::abstract_uniform_type_info<R>*>& pr,
Args&&... args) {
m_members.push_back(new_member_tinfo(pr.first, unique_uti(pr.second)));
push_back(std::forward<Args>(args)...);
} }
template<typename List> // pr.first = getter / setter pair
void init_(typename std::enable_if<is_stl_compliant_list<List>::value>::type* = 0) { // pr.second = meta object to handle pr.first
m_members.push_back(member::fake_member(new list_member<List>)); template<typename GRes, typename SRes, typename SArg, typename C, typename... Args>
void push_back(const std::pair<GRes (C::*)() const, SRes (C::*)(SArg)>& pr,
Args&&... args) {
m_members.push_back(new_member_tinfo(pr.first, pr.second));
push_back(std::forward<Args>(args)...);
} }
template<typename X> // pr.first = getter / setter pair
void init_(typename std::enable_if<is_invalid<X>::value>::type* = 0) { // pr.second = meta object to handle pr.first
// T is neither primitive nor a STL compliant list/map, template<typename GRes, typename SRes, typename SArg, typename C, typename... Args>
// so it has to be an announced type void push_back(const std::pair<std::pair<GRes (C::*)() const, SRes (C::*)(SArg)>, util::abstract_uniform_type_info<typename util::rm_ref<GRes>::type>*>& pr,
static_assert(util::is_primitive<X>::value, Args&&... args) {
"T is neither a primitive type nor a " m_members.push_back(new_member_tinfo(pr.first.first, pr.first.second, unique_uti(pr.second)));
"stl-compliant list/map"); push_back(std::forward<Args>(args)...);
} }
public: public:
...@@ -333,16 +473,14 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T ...@@ -333,16 +473,14 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T
} }
default_uniform_type_info_impl() { default_uniform_type_info_impl() {
init_<T>(); typedef member_tinfo<T,fake_access_policy<T> > result_type;
if (m_members.size() != 1) { m_members.push_back(unique_uti(new result_type));
throw std::logic_error("no fake member added");
}
} }
void serialize(const void* obj, serializer* s) const { void serialize(const void* obj, serializer* s) const {
s->begin_object(this->name()); s->begin_object(this->name());
for (auto& m : m_members) { for (auto& m : m_members) {
m.serialize(obj, s); m->serialize(obj, s);
} }
s->end_object(); s->end_object();
} }
...@@ -351,7 +489,7 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T ...@@ -351,7 +489,7 @@ class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T
this->assert_type_name(d); this->assert_type_name(d);
d->begin_object(this->name()); d->begin_object(this->name());
for (auto& m : m_members) { for (auto& m : m_members) {
m.deserialize(obj, d); m->deserialize(obj, d);
} }
d->end_object(); d->end_object();
} }
......
...@@ -33,21 +33,25 @@ ...@@ -33,21 +33,25 @@
namespace cppa { namespace detail { namespace cppa { namespace detail {
template<typename T>
class disablable_delete { class disablable_delete {
bool m_enabled;
public: public:
disablable_delete() : m_enabled(true) { } constexpr disablable_delete() : m_enabled(true) { }
inline void disable() { m_enabled = false; } inline void disable() {
m_enabled = false;
}
template<typename T>
inline void operator()(T* ptr) { inline void operator()(T* ptr) {
if (m_enabled) delete ptr; if (m_enabled) delete ptr;
} }
private:
bool m_enabled;
}; };
} } // namespace cppa::detail } } // namespace cppa::detail
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011, 2012 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation, either version 3 of the License *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CPPA_LIST_MEMBER_HPP
#define CPPA_LIST_MEMBER_HPP
#include "cppa/util/is_primitive.hpp"
#include "cppa/util/abstract_uniform_type_info.hpp"
namespace cppa { namespace detail {
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)));
}
d->end_sequence();
}
};
template<typename List>
struct list_member_util<List, false> {
typedef typename List::value_type value_type;
const uniform_type_info* m_value_type;
list_member_util() : m_value_type(uniform_typeid<value_type>()) {
}
void operator()(const List& list, serializer* s) const {
s->begin_sequence(list.size());
for (auto i = list.begin(); i != list.end(); ++i) {
m_value_type->serialize(&(*i), s);
}
s->end_sequence();
}
void operator()(List& list, deserializer* d) const {
list.clear();
value_type tmp;
auto size = d->begin_sequence();
for (decltype(size) i = 0; i < size; ++i) {
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);
}
};
} } // namespace cppa::detail
#endif // CPPA_LIST_MEMBER_HPP
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011, 2012 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation, either version 3 of the License *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CPPA_MAP_MEMBER_HPP
#define CPPA_MAP_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 {
template<typename T>
struct is_pair { static constexpr bool value = false; };
template<typename First, typename Second>
struct is_pair< std::pair<First, Second> > { static constexpr 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 {
T value;
impl.deserialize(&value, d);
map.insert(std::move(value));
}
};
// 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> {
// 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 {
// 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<first_type, second_type> p;
impl.deserialize(&p, d);
std::pair<const first_type, second_type> v(std::move(p.first),
std::move(p.second));
map.insert(std::move(v));
}
};
template<typename Map>
class map_member : public util::abstract_uniform_type_info<Map> {
typedef typename Map::key_type key_type;
typedef typename Map::value_type value_type;
map_member_util<value_type,
is_pair<value_type>::value,
util::is_primitive<value_type>::value> m_helper;
public:
void serialize(const void* obj, serializer* s) const {
auto& mp = *reinterpret_cast<const Map*>(obj);
s->begin_sequence(mp.size());
for (const auto& val : mp) {
m_helper.serialize_value(val, s);
}
s->end_sequence();
}
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_helper.deserialize_and_insert(mp, d);
}
d->end_sequence();
}
};
} } // namespace cppa::detail
#endif // CPPA_MAP_MEMBER_HPP
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011, 2012 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation, either version 3 of the License *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CPPA_PRIMITIVE_MEMBER_HPP
#define CPPA_PRIMITIVE_MEMBER_HPP
#include "cppa/serializer.hpp"
#include "cppa/deserializer.hpp"
#include "cppa/primitive_type.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 {
// uniform_type_info implementation for primitive data types.
template<typename T>
class primitive_member : public util::abstract_uniform_type_info<T> {
static constexpr primitive_type ptype = type_to_ptype<T>::ptype;
static_assert(ptype != pt_null, "T is not a primitive type");
public:
void serialize(const void* obj, serializer* s) const {
s->write_value(*reinterpret_cast<const T*>(obj));
}
void deserialize(void* obj, deserializer* d) const {
primitive_variant val(d->read_value(ptype));
*reinterpret_cast<T*>(obj) = std::move(get<T>(val));
}
};
} } // namespace cppa::detail
#endif // CPPA_PRIMITIVE_MEMBER_HPP
...@@ -4,10 +4,13 @@ ...@@ -4,10 +4,13 @@
#include <iostream> #include <iostream>
#include "cppa/cppa.hpp" #include "cppa/cppa.hpp"
#include "cppa/binary_serializer.hpp"
#include "cppa/binary_deserializer.hpp"
using std::cout; using std::cout;
using std::endl; using std::endl;
using namespace std;
using namespace cppa; using namespace cppa;
// POD struct // POD struct
...@@ -28,11 +31,41 @@ typedef std::pair<int,int> foo_pair; ...@@ -28,11 +31,41 @@ typedef std::pair<int,int> foo_pair;
// another pair of two ints // another pair of two ints
typedef std::pair<int,int> foo_pair2; typedef std::pair<int,int> foo_pair2;
// a struct with member vector<vector<...>>
struct foo2 {
int a;
vector<vector<double> > b;
};
bool operator==( const foo2& lhs, const foo2& rhs ) {
return lhs.a == rhs.a && lhs.b == rhs.b;
}
int main(int, char**) { int main(int, char**) {
// announces foo to the libcppa type system; // announces foo to the libcppa type system;
// the function expects member pointers to all elements of foo // the function expects member pointers to all elements of foo
assert(announce<foo>(&foo::a, &foo::b) == true); assert(announce<foo>(&foo::a, &foo::b) == true);
// announce foo2 to the libcppa type system,
// note that recursive containers are managed automatically by libcppa
assert(announce<foo2>(&foo2::a, &foo2::b) == true);
foo2 vd;
vd.a = 5;
vd.b.resize(1);
vd.b.back().push_back(42);
util::buffer buf;
binary_serializer bs(&buf);
bs << vd;
binary_deserializer bd(buf.data(), buf.size());
foo2 vd2;
uniform_typeid<foo2>()->deserialize(&vd2, &bd);
assert(vd == vd2);
// announce std::pair<int,int> to the type system; // announce std::pair<int,int> to the type system;
// NOTE: foo_pair is NOT distinguishable from foo_pair2! // NOTE: foo_pair is NOT distinguishable from foo_pair2!
assert(announce<foo_pair>(&foo_pair::first, &foo_pair::second) == true); assert(announce<foo_pair>(&foo_pair::first, &foo_pair::second) == true);
......
...@@ -24,6 +24,9 @@ inline void exec_plugin() { ...@@ -24,6 +24,9 @@ inline void exec_plugin() {
} }
} }
} }
else {
cerr << "*** plugin did not define symbol exec_plugin!" << endl;
}
} }
} }
......
#define CPPA_VERBOSE_CHECK
#include "cppa/config.hpp" #include "cppa/config.hpp"
#include <new> #include <new>
...@@ -185,7 +187,7 @@ int main() { ...@@ -185,7 +187,7 @@ int main() {
} }
{ {
any_tuple ttup = make_cow_tuple(1, 2, actor_ptr(self)); auto ttup = make_any_tuple(1, 2, actor_ptr(self));
util::buffer wr_buf; util::buffer wr_buf;
binary_serializer bs(&wr_buf); binary_serializer bs(&wr_buf);
bs << ttup; bs << ttup;
......
...@@ -73,6 +73,7 @@ int main() { ...@@ -73,6 +73,7 @@ int main() {
"@i8", "@i16", "@i32", "@i64", // signed integer names "@i8", "@i16", "@i32", "@i64", // signed integer names
"@u8", "@u16", "@u32", "@u64", // unsigned integer names "@u8", "@u16", "@u32", "@u64", // unsigned integer names
"@str", "@u16str", "@u32str", // strings "@str", "@u16str", "@u32str", // strings
"@strmap", // string containers
"float", "double", // floating points "float", "double", // floating points
"@0", // cppa::util::void_type "@0", // cppa::util::void_type
// default announced cppa types // default announced cppa types
......
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