Commit 65a71be9 authored by neverlord's avatar neverlord

binary_serializer

parent 010f3f6b
......@@ -2,7 +2,7 @@
<qtcreator>
<data>
<variable>GenericProjectManager.GenericProject.Toolchain</variable>
<value type="QString">ProjectExplorer.ToolChain.Gcc:/opt/local/bin/g++-mp-4.6.x86-macos-generic-mach_o-64bit.</value>
<value type="QString"></value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
......
......@@ -55,7 +55,6 @@ cppa/on.hpp
unit_testing/test__serialization.cpp
cppa/serializer.hpp
cppa/deserializer.hpp
cppa/util/is_serializable.hpp
cppa/util/enable_if.hpp
cppa/object.hpp
cppa/detail/object_impl.hpp
......@@ -121,3 +120,23 @@ cppa/util/comparable.hpp
cppa/util/disable_if.hpp
cppa/util/if_else_type.hpp
cppa/util/wrapped_type.hpp
cppa/util/apply.hpp
cppa/primitive_variant.hpp
cppa/primitive_type.hpp
cppa/util/pt_token.hpp
cppa/detail/type_to_ptype.hpp
cppa/detail/ptype_to_type.hpp
cppa/util/is_primitive.hpp
cppa/util/is_iterable.hpp
src/primitive_variant.cpp
unit_testing/test__primitive_variant.cpp
cppa/util/uniform_type_info_base.hpp
cppa/detail/primitive_member.hpp
cppa/detail/list_member.hpp
cppa/detail/pair_member.hpp
cppa/detail/map_member.hpp
cppa/util/is_forward_iterator.hpp
cppa/util/rm_ref.hpp
cppa/util/is_iterable.hpp
cppa/binary_serializer.hpp
src/binary_serializer.cpp
#ifndef BINARY_SERIALIZER_HPP
#define BINARY_SERIALIZER_HPP
#include <utility>
#include "cppa/serializer.hpp"
namespace cppa {
namespace detail { class binary_writer; }
class binary_serializer : public serializer
{
friend class detail::binary_writer;
char* m_begin;
char* m_end;
char* m_wr_pos;
// make that it's safe to write num_bytes bytes to m_wr_pos
void acquire(size_t num_bytes);
public:
binary_serializer();
~binary_serializer();
void begin_object(const std::string& tname);
void end_object();
void begin_sequence(size_t list_size);
void end_sequence();
void write_value(const primitive_variant& value);
void write_tuple(size_t size, const primitive_variant* values);
/**
* @brief Takes the internal buffer and returns it.
*
*/
std::pair<size_t, char*> take_buffer();
/**
* @brief Returns the number of written bytes.
*/
size_t size() const;
/**
* @brief Returns a pointer to the internal buffer.
*/
const char* data() const;
};
} // namespace cppa
#endif // BINARY_SERIALIZER_HPP
......@@ -3,68 +3,44 @@
#include <string>
#include <cstddef>
#include <type_traits>
#include "cppa/any_type.hpp"
#include "cppa/intrusive_ptr.hpp"
#include "cppa/util/source.hpp"
#include "cppa/util/enable_if.hpp"
#include "cppa/detail/swap_bytes.hpp"
namespace cppa { namespace util {
struct void_type;
} } // namespace util
#include "cppa/primitive_type.hpp"
#include "cppa/primitive_variant.hpp"
namespace cppa {
class deserializer
{
intrusive_ptr<util::source> m_src;
public:
deserializer(const intrusive_ptr<util::source>& data_source);
virtual ~deserializer();
inline void read(std::size_t buf_size, void* buf)
{
m_src->read(buf_size, buf);
}
/**
* @brief Seeks the beginning of the next object and return its
* uniform type name.
*/
virtual std::string seek_object() = 0;
};
/**
* @brief Equal to {@link seek_object()} but doesn't
* modify the internal in-stream position.
*/
virtual std::string peek_object() = 0;
deserializer& operator>>(deserializer&, std::string&);
virtual void begin_object(const std::string& type_name) = 0;
virtual void end_object() = 0;
template<typename T>
typename util::enable_if<std::is_integral<T>, deserializer&>::type
operator>>(deserializer& d, T& value)
{
d.read(sizeof(T), &value);
value = detail::swap_bytes(value);
return d;
}
virtual size_t begin_sequence() = 0;
virtual void end_sequence() = 0;
template<typename T>
typename util::enable_if<std::is_floating_point<T>, deserializer&>::type
operator>>(deserializer& d, T& value)
{
d.read(sizeof(T), &value);
return d;
}
virtual primitive_variant read_value(primitive_type ptype) = 0;
inline deserializer& operator>>(deserializer& d, util::void_type&)
{
return d;
}
virtual void read_tuple(size_t size,
const primitive_type* ptypes,
primitive_variant* storage ) = 0;
inline deserializer& operator>>(deserializer& d, any_type&)
{
return d;
}
};
} // namespace cppa
......
......@@ -11,17 +11,16 @@ namespace cppa { namespace detail {
struct abstract_tuple : ref_counted
{
// mutators
virtual void* mutable_at(std::size_t pos) = 0;
// accessors
virtual std::size_t size() const = 0;
virtual abstract_tuple* copy() const = 0;
virtual const void* at(std::size_t pos) const = 0;
virtual const uniform_type_info* utype_at(std::size_t pos) const = 0;
virtual const util::abstract_type_list& types() const = 0;
virtual bool equal_to(const abstract_tuple& other) const = 0;
virtual void serialize(serializer&) const = 0;
// mutators
virtual void* mutable_at(std::size_t pos) = 0;
// accessors
virtual std::size_t size() const = 0;
virtual abstract_tuple* copy() const = 0;
virtual const void* at(std::size_t pos) const = 0;
virtual const uniform_type_info* utype_at(std::size_t pos) const = 0;
virtual const util::abstract_type_list& types() const = 0;
virtual bool equal_to(const abstract_tuple& other) const = 0;
};
......
......@@ -20,71 +20,65 @@ class decorated_tuple : public abstract_tuple
public:
typedef util::type_list<ElementTypes...> element_types;
typedef cow_ptr<abstract_tuple> ptr_type;
decorated_tuple(const ptr_type& d,
const std::vector<std::size_t>& v)
: m_decorated(d), m_mappings(v)
{
}
virtual void* mutable_at(std::size_t pos)
{
return m_decorated->mutable_at(m_mappings[pos]);
}
virtual std::size_t size() const
{
return m_mappings.size();
}
virtual decorated_tuple* copy() const
{
return new decorated_tuple(*this);
}
virtual const void* at(std::size_t pos) const
{
return m_decorated->at(m_mappings[pos]);
}
virtual const uniform_type_info* utype_at(std::size_t pos) const
{
return m_decorated->utype_at(m_mappings[pos]);
}
virtual const util::abstract_type_list& types() const
{
return m_types;
}
virtual bool equal_to(const abstract_tuple&) const
{
return false;
}
virtual void serialize(serializer& s) const
{
s << static_cast<std::uint8_t>(element_types::type_list_size);
serialize_tuple<element_types>::_(s, this);
}
typedef util::type_list<ElementTypes...> element_types;
typedef cow_ptr<abstract_tuple> ptr_type;
decorated_tuple(const ptr_type& d,
const std::vector<std::size_t>& v)
: m_decorated(d), m_mappings(v)
{
}
virtual void* mutable_at(std::size_t pos)
{
return m_decorated->mutable_at(m_mappings[pos]);
}
virtual std::size_t size() const
{
return m_mappings.size();
}
virtual decorated_tuple* copy() const
{
return new decorated_tuple(*this);
}
virtual const void* at(std::size_t pos) const
{
return m_decorated->at(m_mappings[pos]);
}
virtual const uniform_type_info* utype_at(std::size_t pos) const
{
return m_decorated->utype_at(m_mappings[pos]);
}
virtual const util::abstract_type_list& types() const
{
return m_types;
}
virtual bool equal_to(const abstract_tuple&) const
{
return false;
}
private:
ptr_type m_decorated;
std::vector<std::size_t> m_mappings;
element_types m_types;
ptr_type m_decorated;
std::vector<std::size_t> m_mappings;
element_types m_types;
decorated_tuple(const decorated_tuple& other)
: abstract_tuple()
, m_decorated(other.m_decorated)
, m_mappings(other.m_mappings)
{
}
decorated_tuple(const decorated_tuple& other)
: abstract_tuple()
, m_decorated(other.m_decorated)
, m_mappings(other.m_mappings)
{
}
decorated_tuple& operator=(const decorated_tuple&) = delete;
decorated_tuple& operator=(const decorated_tuple&) = delete;
};
......
#ifndef DEFAULT_UNIFORM_TYPE_INFO_IMPL_HPP
#define DEFAULT_UNIFORM_TYPE_INFO_IMPL_HPP
#include <sstream>
#include "cppa/any_type.hpp"
#include "cppa/util/void_type.hpp"
#include "cppa/uniform_type_info.hpp"
#include "cppa/util/disjunction.hpp"
#include "cppa/util/is_iterable.hpp"
#include "cppa/util/is_primitive.hpp"
#include "cppa/util/is_forward_iterator.hpp"
#include "cppa/util/uniform_type_info_base.hpp"
#include "cppa/detail/map_member.hpp"
#include "cppa/detail/list_member.hpp"
#include "cppa/detail/primitive_member.hpp"
namespace cppa { namespace detail {
template<typename T>
class default_uniform_type_info_impl : public uniform_type_info
class is_stl_compliant_list
{
template<class C>
static bool cmp_help_fun
(
// mutable pointer
C* mc,
// check if there's a 'void push_back()' that takes C::value_type
decltype(mc->push_back(typename C::value_type()))* = 0
)
{
return true;
}
// SFNINAE default
static void cmp_help_fun(void*) { }
typedef decltype(cmp_help_fun(static_cast<T*>(nullptr))) result_type;
public:
static const bool value = util::is_iterable<T>::value
&& std::is_same<bool, result_type>::value;
};
template<typename T>
class is_stl_compliant_map
{
inline T& to_ref(object& what) const
{
return *reinterpret_cast<T*>(this->value_of(what));
}
inline const T& to_ref(const object& what) const
{
return *reinterpret_cast<const T*>(this->value_of(what));
}
protected:
object copy(const object& what) const
{
return { new T(to_ref(what)), this };
}
object from_string(const std::string& str) const
{
std::istringstream istr(str);
T tmp;
istr >> tmp;
return { new T(tmp), this };
}
void destroy(object& what) const
{
delete reinterpret_cast<T*>(value_of(what));
value_of(what) = nullptr;
}
void deserialize(deserializer& d, object& what) const
{
d >> to_ref(what);
}
std::string to_string(const object& obj) const
{
std::ostringstream ostr;
ostr << to_ref(obj);
return ostr.str();
}
bool equal(const object& lhs, const object& rhs) const
{
return (lhs.type() == *this && rhs.type() == *this)
? to_ref(lhs) == to_ref(rhs)
: false;
}
void serialize(serializer& s, const object& what) const
{
s << to_ref(what);
}
template<class C>
static bool cmp_help_fun
(
// mutable pointer
C* mc,
// check if there's an 'insert()' that takes C::value_type
decltype(mc->insert(typename C::value_type()))* = nullptr
)
{
return true;
}
static void cmp_help_fun(...) { }
typedef decltype(cmp_help_fun(static_cast<T*>(nullptr))) result_type;
public:
default_uniform_type_info_impl() : cppa::uniform_type_info(typeid(T)) { }
static const bool value = util::is_iterable<T>::value
&& std::is_same<bool, result_type>::value;
};
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 Struct>
class default_uniform_type_info_impl : public util::uniform_type_info_base<Struct>
{
template<typename T>
struct is_invalid
{
static const bool value = !util::is_primitive<T>::value
&& !is_stl_compliant_map<T>::value
&& !is_stl_compliant_list<T>::value;
};
class member
{
uniform_type_info* m_meta;
std::function<void (const uniform_type_info*,
const void*,
serializer* )> m_serialize;
std::function<void (const uniform_type_info*,
void*,
deserializer* )> m_deserialize;
member(const member&) = delete;
member& operator=(const member&) = delete;
void swap(member& other)
{
std::swap(m_meta, other.m_meta);
std::swap(m_serialize, other.m_serialize);
std::swap(m_deserialize, other.m_deserialize);
}
template<typename S, class D>
member(uniform_type_info* mtptr, S&& s, D&& d)
: m_meta(mtptr)
, m_serialize(std::forward<S>(s))
, m_deserialize(std::forward<D>(d))
{
}
public:
template<typename T, class C>
member(uniform_type_info* mtptr, T C::*mem_ptr) : m_meta(mtptr)
{
m_serialize = [mem_ptr] (const uniform_type_info* mt,
const void* obj,
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);
};
}
member(member&& other) : m_meta(nullptr)
{
swap(other);
}
// a member that's not a member at all, but "forwards"
// the 'self' pointer to make use *_member implementations
static member fake_member(uniform_type_info* mtptr)
{
return {
mtptr,
[] (const uniform_type_info* mt, const void* obj, serializer* s)
{
mt->serialize(obj, s);
},
[] (const uniform_type_info* mt, void* obj, deserializer* d)
{
mt->deserialize(obj, d);
}
};
}
~member()
{
delete m_meta;
}
member& operator=(member&& other)
{
swap(other);
return *this;
}
inline void serialize(const void* parent, serializer* s) const
{
m_serialize(m_meta, parent, s);
}
inline void deserialize(void* parent, deserializer* d) const
{
m_deserialize(m_meta, parent, d);
}
};
std::vector<member> m_members;
// terminates recursion
inline void push_back() { }
// pr.first = member pointer
// pr.second = meta object to handle pr.first
template<typename T, class C, typename... Args>
void push_back(std::pair<T C::*, util::uniform_type_info_base<T>*> pr,
const Args&... args)
{
m_members.push_back({ pr.second, pr.first });
push_back(args...);
}
template<class C, typename T, typename... Args>
typename util::enable_if<util::is_primitive<T> >::type
push_back(T C::*mem_ptr, const Args&... args)
{
m_members.push_back({ new primitive_member<T>(), mem_ptr });
push_back(args...);
}
template<class C, typename T, typename... Args>
typename util::enable_if<is_stl_compliant_list<T> >::type
push_back(T C::*mem_ptr, const Args&... args)
{
m_members.push_back({ new list_member<T>(), mem_ptr });
push_back(args...);
}
template<class C, typename T, typename... Args>
typename util::enable_if<is_stl_compliant_map<T> >::type
push_back(T C::*mem_ptr, const Args&... args)
{
m_members.push_back({ new map_member<T>(), mem_ptr });
push_back(args...);
}
template<class C, typename T, typename... Args>
typename util::enable_if<is_invalid<T>>::type
push_back(T C::*mem_ptr, const Args&... args)
{
static_assert(util::is_primitive<T>::value,
"T is neither a primitive type nor a "
"stl-compliant list/map");
}
template<typename T>
void init_(typename
util::enable_if<
util::disjunction<std::is_same<T,util::void_type>,
std::is_same<T,any_type>>>::type* = 0)
{
// any_type doesn't have any fields (no serialization required)
}
template<typename T>
void init_(typename util::enable_if<util::is_primitive<T>>::type* = 0)
{
m_members.push_back(member::fake_member(new primitive_member<T>()));
}
template<typename T>
void init_(typename
util::disable_if<
util::disjunction<util::is_primitive<T>,
std::is_same<T,util::void_type>,
std::is_same<T,any_type>>>::type* = 0)
{
static_assert(util::is_primitive<T>::value,
"T is neither a primitive type nor a "
"stl-compliant list/map");
}
public:
template<typename... Args>
default_uniform_type_info_impl(const Args&... args)
{
push_back(args...);
}
default_uniform_type_info_impl()
{
init_<Struct>();
}
void serialize(const void* obj, serializer* s) const
{
s->begin_object(this->name());
for (auto& m : m_members)
{
m.serialize(obj, s);
}
s->end_object();
}
void deserialize(void* obj, deserializer* d) const
{
std::string cname = d->seek_object();
if (cname != this->name())
{
throw std::logic_error("wrong type name found");
}
d->begin_object(this->name());
for (auto& m : m_members)
{
m.deserialize(obj, d);
}
d->end_object();
}
object create() const
{
return { new T(), this };
}
};
......
#ifndef LIST_MEMBER_HPP
#define LIST_MEMBER_HPP
#include "cppa/util/uniform_type_info_base.hpp"
namespace cppa { namespace detail {
template<typename List>
class list_member : public util::uniform_type_info_base<List>
{
typedef typename List::value_type value_type;
static constexpr primitive_type vptype = type_to_ptype<value_type>::ptype;
static_assert(vptype != pt_null,
"List::value_type is not a primitive data type");
public:
void serialize(const void* obj, serializer* s) const
{
auto& ls = *reinterpret_cast<const List*>(obj);
s->begin_sequence(ls.size());
for (const auto& val : ls)
{
s->write_value(val);
}
s->end_sequence();
}
void deserialize(void* obj, 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)
{
primitive_variant val = d->read_value(vptype);
ls.push_back(std::move(get<value_type>(val)));
}
d->end_sequence();
}
};
} } // namespace cppa::detail
#endif // LIST_MEMBER_HPP
#ifndef MAP_MEMBER_HPP
#define MAP_MEMBER_HPP
#include "cppa/util/uniform_type_info_base.hpp"
#include "cppa/detail/primitive_member.hpp"
#include "cppa/detail/pair_member.hpp"
namespace cppa { namespace detail {
// matches value_type of std::set
template<typename T>
struct meta_value_type
{
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));
}
};
// matches value_type of std::map
template<typename T1, typename T2>
struct meta_value_type<std::pair<const T1, T2>>
{
pair_member<T1, T2> impl;
void serialize_value(const std::pair<const T1, T2>& what, serializer* s) const
{
std::pair<T1, T2> 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;
impl.deserialize(&p, d);
std::pair<const T1, T2> v(std::move(p.first), std::move(p.second));
map.insert(std::move(v));
}
};
template<typename Map>
class map_member : public util::uniform_type_info_base<Map>
{
typedef typename Map::key_type key_type;
typedef typename Map::value_type value_type;
meta_value_type<value_type> m_value_type_meta;
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_value_type_meta.serialize_value(val, s);
}
s->end_sequence();
}
void deserialize(void* obj, deserializer* d) const
{
auto& mp = *reinterpret_cast<Map*>(obj);
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);
}
d->end_sequence();
}
};
} } // namespace cppa::detail
#endif // MAP_MEMBER_HPP
#ifndef PAIR_MEMBER_HPP
#define PAIR_MEMBER_HPP
#include <utility>
#include "cppa/util/uniform_type_info_base.hpp"
namespace cppa { namespace detail {
template<typename T1, typename T2>
class pair_member : public util::uniform_type_info_base<std::pair<T1,T2>>
{
static constexpr primitive_type ptype1 = type_to_ptype<T1>::ptype;
static constexpr primitive_type ptype2 = type_to_ptype<T2>::ptype;
static_assert(ptype1 != pt_null, "T1 is not a primitive type");
static_assert(ptype2 != pt_null, "T2 is not a primitive type");
typedef std::pair<T1, T2> pair_type;
public:
void serialize(const void* obj, serializer* s) const
{
auto& p = *reinterpret_cast<const pair_type*>(obj);
primitive_variant values[2] = { p.first, p.second };
s->write_tuple(2, values);
}
void deserialize(void* obj, deserializer* d) const
{
primitive_type ptypes[2] = { ptype1, ptype2 };
primitive_variant values[2];
d->read_tuple(2, ptypes, values);
auto& p = *reinterpret_cast<pair_type*>(obj);
p.first = std::move(get<T1>(values[0]));
p.second = std::move(get<T2>(values[1]));
}
};
} } // namespace cppa::detail
#endif // PAIR_MEMBER_HPP
#ifndef PRIMITIVE_MEMBER_HPP
#define PRIMITIVE_MEMBER_HPP
#include "cppa/primitive_type.hpp"
#include "cppa/primitive_variant.hpp"
#include "cppa/detail/type_to_ptype.hpp"
#include "cppa/util/uniform_type_info_base.hpp"
namespace cppa { namespace detail {
// uniform_type_info implementation for primitive data types.
template<typename T>
class primitive_member : public util::uniform_type_info_base<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 // PRIMITIVE_MEMBER_HPP
#ifndef PTYPE_TO_TYPE_HPP
#define PTYPE_TO_TYPE_HPP
#include <cstdint>
#include "cppa/primitive_type.hpp"
#include "cppa/util/if_else_type.hpp"
#include "cppa/util/wrapped_type.hpp"
namespace cppa { namespace detail {
// maps the primitive_type PT to the corresponding type
template<primitive_type PT>
struct ptype_to_type :
// signed integers
util::if_else_type_c<PT == pt_int8, std::int8_t,
util::if_else_type_c<PT == pt_int16, std::int16_t,
util::if_else_type_c<PT == pt_int32, std::int32_t,
util::if_else_type_c<PT == pt_int64, std::int64_t,
util::if_else_type_c<PT == pt_uint8, std::uint8_t,
// unsigned integers
util::if_else_type_c<PT == pt_uint16, std::uint16_t,
util::if_else_type_c<PT == pt_uint32, std::uint32_t,
util::if_else_type_c<PT == pt_uint64, std::uint64_t,
// floating points
util::if_else_type_c<PT == pt_float, float,
util::if_else_type_c<PT == pt_double, double,
util::if_else_type_c<PT == pt_long_double, long double,
// strings
util::if_else_type_c<PT == pt_u8string, std::string,
util::if_else_type_c<PT == pt_u16string, std::u16string,
util::if_else_type_c<PT == pt_u32string, std::u32string,
// default case
util::wrapped_type<void> > > > > > > > > > > > > > >
{
};
} } // namespace cppa::detail
#endif // PTYPE_TO_TYPE_HPP
......@@ -15,91 +15,85 @@ template<typename... ElementTypes>
class tuple_vals : public abstract_tuple
{
typedef abstract_tuple super;
typedef abstract_tuple super;
typedef tdata<ElementTypes...> data_type;
typedef tdata<ElementTypes...> data_type;
typedef util::type_list<ElementTypes...> element_types;
typedef util::type_list<ElementTypes...> element_types;
data_type m_data;
data_type m_data;
element_types m_types;
element_types m_types;
template<typename... Types>
void* tdata_mutable_at(tdata<Types...>& d, std::size_t pos)
{
return (pos == 0) ? &(d.head) : tdata_mutable_at(d.tail(), pos - 1);
}
template<typename... Types>
void* tdata_mutable_at(tdata<Types...>& d, std::size_t pos)
{
return (pos == 0) ? &(d.head) : tdata_mutable_at(d.tail(), pos - 1);
}
template<typename... Types>
const void* tdata_at(const tdata<Types...>& d, std::size_t pos) const
{
return (pos == 0) ? &(d.head) : tdata_at(d.tail(), pos - 1);
}
template<typename... Types>
const void* tdata_at(const tdata<Types...>& d, std::size_t pos) const
{
return (pos == 0) ? &(d.head) : tdata_at(d.tail(), pos - 1);
}
public:
typedef typename element_types::head_type head_type;
typedef typename element_types::head_type head_type;
typedef typename element_types::tail_type tail_type;
typedef typename element_types::tail_type tail_type;
static const std::size_t type_list_size = element_types::type_list_size;
static const std::size_t type_list_size = element_types::type_list_size;
tuple_vals(const tuple_vals& other) : super(), m_data(other.m_data) { }
tuple_vals(const tuple_vals& other) : super(), m_data(other.m_data) { }
tuple_vals() : m_data() { }
tuple_vals() : m_data() { }
tuple_vals(const ElementTypes&... args) : m_data(args...) { }
tuple_vals(const ElementTypes&... args) : m_data(args...) { }
inline const data_type& data() const { return m_data; }
inline const data_type& data() const { return m_data; }
inline data_type& data_ref() { return m_data; }
inline data_type& data_ref() { return m_data; }
virtual void* mutable_at(std::size_t pos)
{
return tdata_mutable_at(m_data, pos);
}
virtual void* mutable_at(std::size_t pos)
{
return tdata_mutable_at(m_data, pos);
}
virtual std::size_t size() const
{
return element_types::type_list_size;
}
virtual std::size_t size() const
{
return element_types::type_list_size;
}
virtual tuple_vals* copy() const
{
return new tuple_vals(*this);
}
virtual tuple_vals* copy() const
{
return new tuple_vals(*this);
}
virtual const void* at(std::size_t pos) const
{
return tdata_at(m_data, pos);
}
virtual const void* at(std::size_t pos) const
{
return tdata_at(m_data, pos);
}
virtual const uniform_type_info* utype_at(std::size_t pos) const
{
return m_types.at(pos);
}
virtual const uniform_type_info* utype_at(std::size_t pos) const
{
return m_types.at(pos);
}
virtual const util::abstract_type_list& types() const
{
return m_types;
}
virtual const util::abstract_type_list& types() const
{
return m_types;
}
virtual bool equal_to(const abstract_tuple& other) const
{
const tuple_vals* o = dynamic_cast<const tuple_vals*>(&other);
if (o)
{
return m_data == (o->m_data);
}
return false;
}
virtual void serialize(serializer& s) const
{
s << static_cast<std::uint8_t>(element_types::type_list_size);
serialize_tuple<element_types>::_(s, this);
}
virtual bool equal_to(const abstract_tuple& other) const
{
const tuple_vals* o = dynamic_cast<const tuple_vals*>(&other);
if (o)
{
return m_data == (o->m_data);
}
return false;
}
};
......
#ifndef TYPE_TO_PTYPE_HPP
#define TYPE_TO_PTYPE_HPP
#include <cstdint>
#include <type_traits>
#include "cppa/primitive_type.hpp"
#include "cppa/util/apply.hpp"
namespace cppa { namespace detail {
// if (IfStmt == true) ptype = PT; else ptype = Else::ptype;
template<bool IfStmt, primitive_type PT, class Else>
struct if_else_ptype_c
{
static const primitive_type ptype = PT;
};
template<primitive_type PT, class Else>
struct if_else_ptype_c<false, PT, Else>
{
static const primitive_type ptype = Else::ptype;
};
// if (Stmt::value == true) ptype = FT; else ptype = Else::ptype;
template<class Stmt, primitive_type PT, class Else>
struct if_else_ptype : if_else_ptype_c<Stmt::value, PT, Else> { };
template<primitive_type PT>
struct wrapped_ptype { static const primitive_type ptype = PT; };
// maps type T the the corresponding fundamental_type
template<typename T>
struct type_to_ptype_impl :
// signed integers
if_else_ptype<std::is_same<T, std::int8_t>, pt_int8,
if_else_ptype<std::is_same<T, std::int16_t>, pt_int16,
if_else_ptype<std::is_same<T, std::int32_t>, pt_int32,
if_else_ptype<std::is_same<T, std::int64_t>, pt_int64,
if_else_ptype<std::is_same<T, std::uint8_t>, pt_uint8,
// unsigned integers
if_else_ptype<std::is_same<T, std::uint16_t>, pt_uint16,
if_else_ptype<std::is_same<T, std::uint32_t>, pt_uint32,
if_else_ptype<std::is_same<T, std::uint64_t>, pt_uint64,
// floating points
if_else_ptype<std::is_same<T, float>, pt_float,
if_else_ptype<std::is_same<T, double>, pt_double,
if_else_ptype<std::is_same<T, long double>, pt_long_double,
// strings
if_else_ptype<std::is_convertible<T, std::string>, pt_u8string,
if_else_ptype<std::is_convertible<T, std::u16string>, pt_u16string,
if_else_ptype<std::is_convertible<T, std::u32string>, pt_u32string,
// default case
wrapped_ptype<pt_null> > > > > > > > > > > > > > >
{
};
template<typename T>
struct type_to_ptype
{
typedef typename util::apply<T,
std::remove_reference,
std::remove_cv >::type type;
static const primitive_type ptype = type_to_ptype_impl<type>::ptype;
};
} } // namespace cppa::detail
#endif // TYPE_TO_PTYPE_HPP
......@@ -22,123 +22,123 @@ bool operator==(const uniform_type_info& lhs, const std::type_info& rhs);
class object
{
friend class uniform_type_info;
friend class uniform_type_info;
template<typename T>
friend struct detail::object_caster;
template<typename T>
friend struct detail::object_caster;
void* m_value;
const uniform_type_info* m_type;
void* m_value;
const uniform_type_info* m_type;
void swap(object& other);
void swap(object& other);
object copy() const;
object copy() const;
public:
/**
* @brief Create an object of type @p utinfo with value @p val.
* @warning {@link object} takes ownership of @p val.
* @pre {@code val != nullptr && utinfo != nullptr}
*/
object(void* val, const uniform_type_info* utinfo);
/**
* @brief Create an object of type @p utinfo with value @p val.
* @warning {@link object} takes ownership of @p val.
* @pre {@code val != nullptr && utinfo != nullptr}
*/
object(void* val, const uniform_type_info* utinfo);
/**
* @brief Create a void object.
* @post {@code type() == uniform_typeid<util::void_type>()}
*/
object();
/**
* @brief Create a void object.
* @post {@code type() == uniform_typeid<util::void_type>()}
*/
object();
~object();
~object();
/**
* @brief Create an object and move type and value from @p other to this.
* @post {@code other.type() == uniform_typeid<util::void_type>()}
*/
object(object&& other);
/**
* @brief Create an object and move type and value from @p other to this.
* @post {@code other.type() == uniform_typeid<util::void_type>()}
*/
object(object&& other);
/**
* @brief Create a copy of @p other.
*/
object(const object& other);
/**
* @brief Create a copy of @p other.
*/
object(const object& other);
/**
* @brief Move the content from @p other to this.
* @post {@code other.type() == nullptr}
*/
object& operator=(object&& other);
object& operator=(const object& other);
/**
* @brief Move the content from @p other to this.
* @post {@code other.type() == nullptr}
*/
object& operator=(object&& other);
object& operator=(const object& other);
bool equal(const object& other) const;
bool equal(const object& other) const;
const uniform_type_info& type() const;
const uniform_type_info& type() const;
std::string to_string() const;
std::string to_string() const;
};
inline bool operator==(const object& lhs, const object& rhs)
{
return lhs.equal(rhs);
return lhs.equal(rhs);
}
inline bool operator!=(const object& lhs, const object& rhs)
{
return !(lhs == rhs);
return !(lhs == rhs);
}
namespace detail {
inline void assert_type(const object& obj, const std::type_info& tinfo)
{
if (!(obj.type() == tinfo))
{
throw std::logic_error("object type doesnt match T");
}
if (!(obj.type() == tinfo))
{
throw std::logic_error("object type doesnt match T");
}
}
// get a const reference
template<typename T>
struct object_caster<const T&>
{
static const T& _(const object& obj)
{
assert_type(obj, typeid(T));
return *reinterpret_cast<const T*>(obj.m_value);
}
static const T& _(const object& obj)
{
assert_type(obj, typeid(T));
return *reinterpret_cast<const T*>(obj.m_value);
}
};
// get a mutable reference
template<typename T>
struct object_caster<T&>
{
static T& _(object& obj)
{
assert_type(obj, typeid(T));
return *reinterpret_cast<T*>(obj.m_value);
}
static T& _(object& obj)
{
assert_type(obj, typeid(T));
return *reinterpret_cast<T*>(obj.m_value);
}
};
// get a const pointer
template<typename T>
struct object_caster<const T*>
{
static const T* _(const object& obj)
{
assert_type(obj, typeid(T));
return reinterpret_cast<const T*>(obj.m_value);
}
static const T* _(const object& obj)
{
assert_type(obj, typeid(T));
return reinterpret_cast<const T*>(obj.m_value);
}
};
// get a mutable pointer
template<typename T>
struct object_caster<T*>
{
static T* _(object& obj)
{
assert_type(obj, typeid(T));
return reinterpret_cast<T*>(obj.m_value);
}
static T* _(object& obj)
{
assert_type(obj, typeid(T));
return reinterpret_cast<T*>(obj.m_value);
}
};
template<typename T>
......@@ -158,19 +158,19 @@ struct is_const_pointer<const T*> : std::true_type { };
template<typename T>
T object_cast(object& obj)
{
static_assert(util::disjunction<std::is_pointer<T>,
std::is_reference<T>>::value,
"T is neither a reference nor a pointer type.");
return detail::object_caster<T>::_(obj);
static_assert(util::disjunction<std::is_pointer<T>,
std::is_reference<T>>::value,
"T is neither a reference nor a pointer type.");
return detail::object_caster<T>::_(obj);
}
template<typename T>
const T& object_cast(const object& obj)
{
static_assert(util::disjunction<detail::is_const_pointer<T>,
detail::is_const_reference<T>>::value,
"T is neither a const reference nor a const pointer type.");
return detail::object_caster<T>::_(obj);
static_assert(util::disjunction<detail::is_const_pointer<T>,
detail::is_const_reference<T>>::value,
"T is neither a const reference nor a const pointer type.");
return detail::object_caster<T>::_(obj);
}
} // namespace cppa
......
#ifndef PRIMITIVE_TYPE_HPP
#define PRIMITIVE_TYPE_HPP
namespace cppa {
/**
* @brief Includes integers (signed and unsigned), floating points
* and unicode strings (std::string, std::u16string and std::u32string).
*/
enum primitive_type
{
pt_int8, pt_int16, pt_int32, pt_int64,
pt_uint8, pt_uint16, pt_uint32, pt_uint64,
pt_float, pt_double, pt_long_double,
pt_u8string, pt_u16string, pt_u32string,
pt_null
};
constexpr const char* primitive_type_names[] =
{
"pt_int8", "pt_int16", "pt_int32", "pt_int64",
"pt_uint8", "pt_uint16", "pt_uint32", "pt_uint64",
"pt_float", "pt_double", "pt_long_double",
"pt_u8string", "pt_u16string", "pt_u32string",
"pt_null"
};
constexpr const char* primitive_type_name(primitive_type ptype)
{
return primitive_type_names[static_cast<int>(ptype)];
}
} // namespace cppa
#endif // PRIMITIVE_TYPE_HPP
#ifndef PRIMITIVE_VARIANT_HPP
#define PRIMITIVE_VARIANT_HPP
#include <new>
#include <cstdint>
#include <stdexcept>
#include <type_traits>
#include "cppa/primitive_type.hpp"
#include "cppa/util/pt_token.hpp"
#include "cppa/util/enable_if.hpp"
#include "cppa/util/disable_if.hpp"
#include "cppa/util/is_primitive.hpp"
#include "cppa/detail/type_to_ptype.hpp"
#include "cppa/detail/ptype_to_type.hpp"
namespace cppa { namespace detail {
template<primitive_type FT, class T, class V>
void ptv_set(primitive_type& lhs_type, T& lhs, V&& rhs,
typename util::disable_if<std::is_arithmetic<T>>::type* = 0);
template<primitive_type FT, class T, class V>
void ptv_set(primitive_type& lhs_type, T& lhs, V&& rhs,
typename util::enable_if<std::is_arithmetic<T>, int>::type* = 0);
} } // namespace cppa::detail
namespace cppa {
/**
* @brief A stack-based union container for
* {@link primitive_type primitive data types}.
*/
class primitive_variant
{
primitive_type m_ptype;
union
{
std::int8_t i8;
std::int16_t i16;
std::int32_t i32;
std::int64_t i64;
std::uint8_t u8;
std::uint16_t u16;
std::uint32_t u32;
std::uint64_t u64;
float fl;
double db;
long double ldb;
std::string s8;
std::u16string s16;
std::u32string s32;
};
// use static call dispatching to select member variable
inline decltype(i8)& get(util::pt_token<pt_int8>) { return i8; }
inline decltype(i16)& get(util::pt_token<pt_int16>) { return i16; }
inline decltype(i32)& get(util::pt_token<pt_int32>) { return i32; }
inline decltype(i64)& get(util::pt_token<pt_int64>) { return i64; }
inline decltype(u8)& get(util::pt_token<pt_uint8>) { return u8; }
inline decltype(u16)& get(util::pt_token<pt_uint16>) { return u16; }
inline decltype(u32)& get(util::pt_token<pt_uint32>) { return u32; }
inline decltype(u64)& get(util::pt_token<pt_uint64>) { return u64; }
inline decltype(fl)& get(util::pt_token<pt_float>) { return fl; }
inline decltype(db)& get(util::pt_token<pt_double>) { return db; }
inline decltype(ldb)& get(util::pt_token<pt_long_double>) { return ldb; }
inline decltype(s8)& get(util::pt_token<pt_u8string>) { return s8; }
inline decltype(s16)& get(util::pt_token<pt_u16string>) { return s16; }
inline decltype(s32)& get(util::pt_token<pt_u32string>) { return s32; }
// get(...) const overload
template<primitive_type PT>
const typename detail::ptype_to_type<PT>::type&
get(util::pt_token<PT> token) const
{
return const_cast<primitive_variant*>(this)->get(token);
}
template<class Self, typename Fun>
struct applier
{
Self* m_self;
Fun& m_f;
applier(Self* self, Fun& f) : m_self(self), m_f(f) { }
template<primitive_type FT>
inline void operator()(util::pt_token<FT> token)
{
m_f(m_self->get(token));
}
};
void destroy();
template<primitive_type PT>
void type_check() const
{
if (m_ptype != PT) throw std::logic_error("type check failed");
}
public:
template<typename V>
void set(V&& value)
{
static constexpr primitive_type ptype = detail::type_to_ptype<V>::ptype;
util::pt_token<ptype> token;
static_assert(ptype != pt_null, "T is not a primitive type");
destroy();
detail::ptv_set<ptype>(m_ptype, get(token), std::forward<V>(value));
}
template<primitive_type PT>
typename detail::ptype_to_type<PT>::type& get_as()
{
static_assert(PT != pt_null, "PT == pt_null");
type_check<PT>();
util::pt_token<PT> token;
return get(token);
}
template<primitive_type PT>
const typename detail::ptype_to_type<PT>::type& get_as() const
{
static_assert(PT != pt_null, "PT == pt_null");
type_check<PT>();
util::pt_token<PT> token;
return const_cast<primitive_variant*>(this)->get(token);
}
template<typename T>
explicit operator T()
{
static constexpr primitive_type ptype = detail::type_to_ptype<T>::ptype;
static_assert(ptype != pt_null, "V is not a primitive type");
return get_as<ptype>();
}
template<typename T>
explicit operator T() const
{
static constexpr primitive_type ptype = detail::type_to_ptype<T>::ptype;
static_assert(ptype != pt_null, "V is not a primitive type");
return get_as<ptype>();
}
template<typename Fun>
void apply(Fun&& f)
{
util::pt_dispatch(m_ptype, applier<primitive_variant, Fun>(this, f));
}
template<typename Fun>
void apply(Fun&& f) const
{
util::pt_dispatch(m_ptype,
applier<const primitive_variant, Fun>(this, f));
}
primitive_variant();
template<typename V>
primitive_variant(V&& value) : m_ptype(pt_null)
{
static constexpr primitive_type ptype = detail::type_to_ptype<V>::ptype;
static_assert(ptype != pt_null, "V is not a primitive type");
detail::ptv_set<ptype>(m_ptype,
get(util::pt_token<ptype>()),
std::forward<V>(value));
}
primitive_variant(primitive_type ptype);
primitive_variant(const primitive_variant& other);
primitive_variant(primitive_variant&& other);
template<typename V>
primitive_variant& operator=(V&& value)
{
static constexpr primitive_type ptype = detail::type_to_ptype<V>::ptype;
static_assert(ptype != pt_null, "V is not a primitive type");
if (ptype == m_ptype)
{
util::pt_token<ptype> token;
get(token) = std::forward<V>(value);
}
else
{
set(std::forward<V>(value));
}
return *this;
}
primitive_variant& operator=(const primitive_variant& other);
primitive_variant& operator=(primitive_variant&& other);
bool operator==(const primitive_variant& other) const;
inline bool operator!=(const primitive_variant& other) const
{
return !(*this == other);
}
inline primitive_type ptype() const { return m_ptype; }
const std::type_info& type() const;
~primitive_variant();
};
template<typename T>
T& get(primitive_variant& pv)
{
static const primitive_type ptype = detail::type_to_ptype<T>::ptype;
return pv.get_as<ptype>();
}
template<typename T>
const T& get(const primitive_variant& pv)
{
static const primitive_type ptype = detail::type_to_ptype<T>::ptype;
return pv.get_as<ptype>();
}
template<primitive_type PT>
typename detail::ptype_to_type<PT>::type& get(primitive_variant& pv)
{
static_assert(PT != pt_null, "PT == pt_null");
return pv.get_as<PT>();
}
template<primitive_type PT>
const typename detail::ptype_to_type<PT>::type& get(const primitive_variant& pv)
{
static_assert(PT != pt_null, "PT == pt_null");
return pv.get_as<PT>();
}
template<typename T>
typename util::enable_if<util::is_primitive<T>, bool>::type
operator==(const T& lhs, const primitive_variant& rhs)
{
static constexpr primitive_type ptype = detail::type_to_ptype<T>::ptype;
static_assert(ptype != pt_null, "T couldn't be mapped to an ptype");
return (rhs.ptype() == ptype) ? lhs == get<ptype>(rhs) : false;
}
template<typename T>
typename util::enable_if<util::is_primitive<T>, bool>::type
operator==(const primitive_variant& lhs, const T& rhs)
{
return (rhs == lhs);
}
template<typename T>
typename util::enable_if<util::is_primitive<T>, bool>::type
operator!=(const primitive_variant& lhs, const T& rhs)
{
return !(lhs == rhs);
}
template<typename T>
typename util::enable_if<util::is_primitive<T>, bool>::type
operator!=(const T& lhs, const primitive_variant& rhs)
{
return !(lhs == rhs);
}
} // namespace cppa
namespace cppa { namespace detail {
template<primitive_type FT, class T, class V>
void ptv_set(primitive_type& lhs_type, T& lhs, V&& rhs,
typename util::disable_if<std::is_arithmetic<T>>::type*)
{
if (FT == lhs_type)
{
lhs = std::forward<V>(rhs);
}
else
{
new (&lhs) T(std::forward<V>(rhs));
lhs_type = FT;
}
}
template<primitive_type FT, class T, class V>
void ptv_set(primitive_type& lhs_type, T& lhs, V&& rhs,
typename util::enable_if<std::is_arithmetic<T>, int>::type*)
{
// don't call a constructor for arithmetic types
lhs = rhs;
lhs_type = FT;
}
} } // namespace cppa::detail
#endif // PRIMITIVE_VARIANT_HPP
......@@ -2,76 +2,39 @@
#define SERIALIZER_HPP
#include <string>
#include <cstddef>
#include <type_traits>
#include "cppa/any_type.hpp"
#include "cppa/intrusive_ptr.hpp"
#include "cppa/util/sink.hpp"
#include "cppa/util/enable_if.hpp"
#include "cppa/detail/swap_bytes.hpp"
namespace cppa { namespace util {
struct void_type;
} } // namespace util
#include <cstddef> // size_t
namespace cppa {
// forward declaration
class primitive_variant;
class serializer
{
intrusive_ptr<util::sink> m_sink;
public:
serializer(const intrusive_ptr<util::sink>& data_sink);
virtual ~serializer();
inline void write(std::size_t buf_size, const void* buf)
{
m_sink->write(buf_size, buf);
}
virtual void begin_object(const std::string& type_name) = 0;
template<typename T>
typename util::enable_if<std::is_integral<T>, void>::type
write_int(const T& value)
{
T tmp = detail::swap_bytes(value);
write(sizeof(T), &tmp);
}
virtual void end_object() = 0;
};
virtual void begin_sequence(size_t size) = 0;
serializer& operator<<(serializer&, const std::string&);
virtual void end_sequence() = 0;
template<typename T>
typename util::enable_if<std::is_integral<T>, serializer&>::type
operator<<(serializer& s, const T& value)
{
s.write_int(value);
return s;
}
/**
* @brief Writes a single value.
*/
virtual void write_value(const primitive_variant& value) = 0;
template<typename T>
typename util::enable_if<std::is_floating_point<T>, serializer&>::type
operator<<(serializer& s, const T& value)
{
s.write(sizeof(T), &value);
return s;
}
/**
* @brief Writes @p size values.
*/
virtual void write_tuple(size_t size, const primitive_variant* values) = 0;
inline serializer& operator<<(serializer& s, const util::void_type&)
{
return s;
}
inline serializer& operator<<(serializer& s, const any_type&)
{
return s;
}
};
} // namespace cppa
......
......@@ -16,7 +16,6 @@
#include "cppa/util/compare_tuples.hpp"
#include "cppa/util/eval_type_list.hpp"
#include "cppa/util/type_list_apply.hpp"
#include "cppa/util/is_serializable.hpp"
#include "cppa/util/is_legal_tuple_type.hpp"
#include "cppa/detail/tuple_vals.hpp"
......@@ -26,20 +25,20 @@ namespace cppa { namespace detail {
template<typename T>
struct is_char_array
{
typedef typename std::remove_all_extents<T>::type step1_type;
typedef typename std::remove_cv<step1_type>::type step2_type;
static const bool value = std::is_array<T>::value
&& std::is_same<step2_type, char>::value;
typedef typename std::remove_all_extents<T>::type step1_type;
typedef typename std::remove_cv<step1_type>::type step2_type;
static const bool value = std::is_array<T>::value
&& std::is_same<step2_type, char>::value;
};
template<typename T>
struct chars_to_string
{
typedef typename util::replace_type<T, std::string,
std::is_same<T, const char*>,
std::is_same<T, char*>,
is_char_array<T>>::type
type;
typedef typename util::replace_type<T, std::string,
std::is_same<T, const char*>,
std::is_same<T, char*>,
is_char_array<T>>::type
type;
};
} } // namespace cppa::detail
......@@ -53,87 +52,82 @@ template<typename... ElementTypes>
class tuple
{
friend class untyped_tuple;
friend class untyped_tuple;
public:
typedef util::type_list<ElementTypes...> element_types;
typedef util::type_list<ElementTypes...> element_types;
private:
static_assert(element_types::type_list_size > 0, "tuple is empty");
static_assert(element_types::type_list_size > 0, "tuple is empty");
static_assert(util::eval_type_list<element_types,
util::is_legal_tuple_type>::value,
"illegal types in tuple definition: "
"pointers and references are prohibited");
static_assert(util::eval_type_list<element_types,
util::is_legal_tuple_type>::value,
"illegal types in tuple definition: "
"pointers and references are prohibited");
static_assert(util::eval_type_list<element_types,
util::is_serializable>::value,
"illegal types in tuple definition: "
"only serializable types are allowed");
typedef detail::tuple_vals<ElementTypes...> vals_t;
typedef detail::tuple_vals<ElementTypes...> vals_t;
cow_ptr<vals_t> m_vals;
cow_ptr<vals_t> m_vals;
static bool compare_vals(const detail::tdata<>& v0,
const detail::tdata<>& v1)
{
return true;
}
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());
}
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:
typedef typename element_types::head_type head_type;
typedef typename element_types::head_type head_type;
typedef typename element_types::tail_type tail_type;
typedef typename element_types::tail_type tail_type;
static const std::size_t type_list_size = element_types::type_list_size;
static const std::size_t type_list_size = element_types::type_list_size;
tuple() : m_vals(new vals_t) { }
tuple() : m_vals(new vals_t) { }
tuple(const ElementTypes&... args) : m_vals(new vals_t(args...)) { }
tuple(const ElementTypes&... args) : m_vals(new vals_t(args...)) { }
template<std::size_t N>
const typename util::type_at<N, element_types>::type& get() const
{
return detail::tdata_get<N>(m_vals->data());
}
template<std::size_t N>
const typename util::type_at<N, element_types>::type& get() const
{
return detail::tdata_get<N>(m_vals->data());
}
template<std::size_t N>
typename util::type_at<N, element_types>::type& get_ref()
{
return detail::tdata_get_ref<N>(m_vals->data_ref());
}
template<std::size_t N>
typename util::type_at<N, element_types>::type& get_ref()
{
return detail::tdata_get_ref<N>(m_vals->data_ref());
}
std::size_t size() const { return m_vals->size(); }
std::size_t size() const { return m_vals->size(); }
const void* at(std::size_t p) const { return m_vals->at(p); }
const void* at(std::size_t p) const { return m_vals->at(p); }
const uniform_type_info* utype_at(std::size_t p) const { return m_vals->utype_at(p); }
const uniform_type_info* utype_at(std::size_t p) const { return m_vals->utype_at(p); }
const util::abstract_type_list& types() const { return m_vals->types(); }
const util::abstract_type_list& types() const { return m_vals->types(); }
cow_ptr<vals_t> vals() const { return m_vals; }
cow_ptr<vals_t> vals() const { return m_vals; }
template<typename... Args>
bool equal_to(const tuple<Args...>& other) const
{
static_assert(type_list_size == tuple<Args...>::type_list_size,
"Can't compare tuples of different size");
return compare_vals(vals()->data(), other.vals()->data());
}
template<typename... Args>
bool equal_to(const tuple<Args...>& other) const
{
static_assert(type_list_size == tuple<Args...>::type_list_size,
"Can't compare tuples of different size");
return compare_vals(vals()->data(), other.vals()->data());
}
};
......@@ -141,14 +135,14 @@ template<std::size_t N, typename... Types>
const typename util::type_at<N, util::type_list<Types...>>::type&
get(const tuple<Types...>& t)
{
return t.get<N>();
return t.get<N>();
}
template<std::size_t N, typename... Types>
typename util::type_at<N, util::type_list<Types...>>::type&
get_ref(tuple<Types...>& t)
{
return t.get_ref<N>();
return t.get_ref<N>();
}
template<typename TypeList>
......@@ -157,30 +151,30 @@ struct tuple_type_from_type_list;
template<typename... Types>
struct tuple_type_from_type_list<util::type_list<Types...>>
{
typedef tuple<Types...> type;
typedef tuple<Types...> type;
};
template<typename... Types>
typename tuple_type_from_type_list<
typename util::type_list_apply<util::type_list<Types...>,
detail::chars_to_string>::type>::type
typename util::type_list_apply<util::type_list<Types...>,
detail::chars_to_string>::type>::type
make_tuple(const Types&... args)
{
return { args... };
return { args... };
}
template<typename... LhsTypes, typename... RhsTypes>
inline bool operator==(const tuple<LhsTypes...>& lhs,
const tuple<RhsTypes...>& rhs)
const tuple<RhsTypes...>& rhs)
{
return util::compare_tuples(lhs, rhs);
return util::compare_tuples(lhs, rhs);
}
template<typename... LhsTypes, typename... RhsTypes>
inline bool operator!=(const tuple<LhsTypes...>& lhs,
const tuple<RhsTypes...>& rhs)
const tuple<RhsTypes...>& rhs)
{
return !(lhs == rhs);
return !(lhs == rhs);
}
} // namespace cppa
......
......@@ -21,10 +21,6 @@
namespace cppa {
class uniform_type_info;
uniform_type_info* uniform_typeid(const std::type_info& tinfo);
/**
* @brief Provides a platform independent type name and (very primitive)
* reflection in combination with {@link cppa::object object}.
......@@ -66,16 +62,14 @@ class uniform_type_info : cppa::util::comparable<uniform_type_info>
identifier(int val) : m_value(val) { }
// enable copy and move constructors
identifier(identifier&&) = default;
identifier(const identifier&) = default;
// disable assignment operators
identifier& operator=(identifier&&) = delete;
identifier& operator=(const identifier&) = delete;
public:
// enable copy constructor
identifier(const identifier&) = default;
// needed by cppa::detail::comparable<identifier>
inline int compare(const identifier& other) const
{
......@@ -104,7 +98,7 @@ class uniform_type_info : cppa::util::comparable<uniform_type_info>
protected:
explicit uniform_type_info(const std::type_info& tinfo);
explicit uniform_type_info(const std::string& uniform_name);
public:
......@@ -140,15 +134,14 @@ class uniform_type_info : cppa::util::comparable<uniform_type_info>
{
return id().compare(other.id());
}
/**
* @brief Add a new type mapping to the libCPPA internal type system.
* @return <code>true</code> if @p uniform_type was added as known
* instance (mapped to @p plain_type); otherwise @c false
* is returned and @p uniform_type was deleted.
*/
static bool announce(const std::type_info& plain_type,
uniform_type_info* uniform_type);
// static bool announce(const std::type_info& plain_type,
// uniform_type_info* uniform_type);
/**
* auto concept value_type<typename T>
......@@ -158,185 +151,66 @@ class uniform_type_info : cppa::util::comparable<uniform_type_info>
* bool operator==(const T&, const T&);
* }
*/
template<typename T,
class SerializeFun, class DeserializeFun,
class ToStringFun, class FromStringFun>
static bool announce(const SerializeFun& sf, const DeserializeFun& df,
const ToStringFun& ts, const FromStringFun& fs);
// template<typename T,
// class SerializeFun, class DeserializeFun,
// class ToStringFun, class FromStringFun>
// static bool announce(const SerializeFun& sf, const DeserializeFun& df,
// const ToStringFun& ts, const FromStringFun& fs);
/**
* @brief Create an object of this type.
*/
virtual object create() const = 0;
object create() const;
virtual object from_string(const std::string& str) const = 0;
object deserialize(deserializer* from) const;
protected:
// needed to implement subclasses
inline void*& value_of(object& obj) const { return obj.m_value; }
inline const void* value_of(const object& obj) const { return obj.m_value; }
/**
* @brief Compares two instances of this type.
*/
virtual bool equal(const void* instance1, const void* instance2) const = 0;
/**
* @brief Creates an instance of this type, either as a copy of
* @p instance or initialized with the default constructor
* if @p instance @c == @c nullptr.
*/
virtual void* new_instance(const void* instance = nullptr) const = 0;
// object creation
virtual object copy(const object& what) const = 0;
/**
* @brief Cast @p instance to the native type and delete it.
*/
virtual void delete_instance(void* instance) const = 0;
// object modification
virtual void destroy(object& what) const = 0;
virtual void deserialize(deserializer& d, object& what) const = 0;
public:
// object inspection
virtual std::string to_string(const object& obj) const = 0;
virtual bool equal(const object& lhs, const object& rhs) const = 0;
virtual void serialize(serializer& s, const object& what) const = 0;
/**
* @brief Determines if this uniform_type_info describes the same
* type than @p tinfo.
*/
virtual bool equal(const std::type_info& tinfo) const = 0;
/**
* @brief Serializes @p instance to @p sink.
*/
virtual void serialize(const void* instance, serializer* sink) const = 0;
/**
* @brief Deserializes @p instance from @p source.
*/
virtual void deserialize(void* instance, deserializer* source) const = 0;
};
uniform_type_info* uniform_typeid(const std::type_info& tinfo);
template<typename T>
uniform_type_info* uniform_typeid()
{
return uniform_type_info::by_type_info(typeid(T));
}
template<typename T,
class SerializeFun, class DeserializeFun,
class ToStringFun, class FromStringFun>
bool uniform_type_info::announce(const SerializeFun& sf,
const DeserializeFun& df,
const ToStringFun& ts,
const FromStringFun& fs)
{
// check signature of SerializeFun::operator()
typedef
typename
util::callable_trait<decltype(&SerializeFun::operator())>::arg_types
sf_args;
// assert arg_types == { serializer&, const T& } || { serializer&, T }
static_assert(
util::disjunction<
std::is_same<sf_args, util::type_list<serializer&, const T&>>,
std::is_same<sf_args, util::type_list<serializer&, T>>
>::value,
"Invalid signature of &SerializeFun::operator()");
// check signature of DeserializeFun::operator()
typedef
typename
util::callable_trait<decltype(&DeserializeFun::operator())>::arg_types
df_args;
// assert arg_types == { deserializer&, T& }
static_assert(
std::is_same<df_args, util::type_list<deserializer&, T&>>::value,
"Invalid signature of &DeserializeFun::operator()");
// check signature of ToStringFun::operator()
typedef util::callable_trait<decltype(&ToStringFun::operator())> ts_sig;
typedef typename ts_sig::arg_types ts_args;
// assert result_type == std::string
static_assert(
std::is_same<std::string, typename ts_sig::result_type>::value,
"ToStringFun::operator() doesn't return a string");
// assert arg_types == { const T& } || { T }
static_assert(
util::disjunction<
std::is_same<ts_args, util::type_list<const T&>>,
std::is_same<ts_args, util::type_list<T>>
>::value,
"Invalid signature of &ToStringFun::operator()");
// check signature of ToStringFun::operator()
typedef util::callable_trait<decltype(&FromStringFun::operator())> fs_sig;
typedef typename fs_sig::arg_types fs_args;
// assert result_type == T*
static_assert(
std::is_same<T*, typename fs_sig::result_type>::value,
"FromStringFun::operator() doesn't return T*");
// assert arg_types == { const std::string& } || { std::string }
static_assert(
util::disjunction<
std::is_same<fs_args, util::type_list<const std::string&>>,
std::is_same<fs_args, util::type_list<std::string>>
>::value,
"Invalid signature of &FromStringFun::operator()");
// "on-the-fly" implementation of uniform_type_info
class utimpl : public uniform_type_info
{
SerializeFun m_serialize;
DeserializeFun m_deserialize;
ToStringFun m_to_string;
FromStringFun m_from_string;
inline T& to_ref(object& what) const
{
return *reinterpret_cast<T*>(this->value_of(what));
}
inline const T& to_ref(const object& what) const
{
return *reinterpret_cast<const T*>(this->value_of(what));
}
protected:
object copy(const object& what) const
{
return { new T(this->to_ref(what)), this };
}
object from_string(const std::string& str) const
{
return { m_from_string(str), this };
}
void destroy(object& what) const
{
delete reinterpret_cast<T*>(this->value_of(what));
this->value_of(what) = nullptr;
}
void deserialize(deserializer& d, object& what) const
{
m_deserialize(d, to_ref(what));
}
std::string to_string(const object& obj) const
{
return m_to_string(to_ref(obj));
}
bool equal(const object& lhs, const object& rhs) const
{
return (lhs.type() == *this && rhs.type() == *this)
? to_ref(lhs) == to_ref(rhs)
: false;
}
void serialize(serializer& s, const object& what) const
{
m_serialize(s, to_ref(what));
}
public:
utimpl(const SerializeFun& sfun, const DeserializeFun dfun,
const ToStringFun tfun, const FromStringFun ffun)
: uniform_type_info(typeid(T))
, m_serialize(sfun), m_deserialize(dfun)
, m_to_string(tfun), m_from_string(ffun)
{
}
object create() const
{
return { new T, this };
}
};
return announce(typeid(T), new utimpl(sf, df, ts, fs));
}
bool operator==(const uniform_type_info& lhs, const std::type_info& rhs);
inline bool operator!=(const uniform_type_info& lhs, const std::type_info& rhs)
......
......@@ -3,6 +3,7 @@
#include "cppa/util/a_matches_b.hpp"
#include "cppa/util/abstract_type_list.hpp"
#include "cppa/util/apply.hpp"
#include "cppa/util/callable_trait.hpp"
#include "cppa/util/compare_tuples.hpp"
#include "cppa/util/concat_type_lists.hpp"
......@@ -20,7 +21,6 @@
#include "cppa/util/is_copyable.hpp"
#include "cppa/util/is_legal_tuple_type.hpp"
#include "cppa/util/is_one_of.hpp"
#include "cppa/util/is_serializable.hpp"
#include "cppa/util/remove_const_reference.hpp"
#include "cppa/util/replace_type.hpp"
#include "cppa/util/reverse_type_list.hpp"
......
#ifndef APPLY_HPP
#define APPLY_HPP
namespace cppa { namespace util {
template<class C, template <typename> class... Traits>
struct apply;
template<class C>
struct apply<C>
{
typedef C type;
};
template<class C,
template <typename> class Trait0,
template <typename> class... Traits>
struct apply<C, Trait0, Traits...>
{
typedef typename apply<typename Trait0<C>::type, Traits...>::type type;
};
} }
#endif // APPLY_HPP
#ifndef IS_FORWARD_ITERATOR_HPP
#define IS_FORWARD_ITERATOR_HPP
#include "cppa/util/rm_ref.hpp"
#include "cppa/util/enable_if.hpp"
#include "cppa/util/disable_if.hpp"
namespace cppa { namespace util {
template<typename T>
class is_forward_iterator
{
template<class C>
static bool sfinae_fun
(
C* iter,
// check for 'C::value_type C::operator*()' returning a non-void type
typename rm_ref<decltype(*(*iter))>::type* = 0,
// check for 'C& C::operator++()'
typename enable_if<std::is_same<C&, decltype(++(*iter))>>::type* = 0,
// check for 'bool C::operator==()'
typename enable_if<std::is_same<bool, decltype(*iter == *iter)>>::type* = 0,
// check for 'bool C::operator!=()'
typename enable_if<std::is_same<bool, decltype(*iter != *iter)>>::type* = 0
)
{
return true;
}
static void sfinae_fun(...) { }
typedef decltype(sfinae_fun(static_cast<T*>(nullptr))) result_type;
public:
static const bool value = std::is_same<bool, result_type>::value;
};
} } // namespace cppa::util
#endif // IS_FORWARD_ITERATOR_HPP
#ifndef IS_ITERABLE_HPP
#define IS_ITERABLE_HPP
#include "cppa/util/is_primitive.hpp"
#include "cppa/util/is_forward_iterator.hpp"
namespace cppa { namespace util {
template<typename T>
class is_iterable
{
// this horrible code would just disappear if we had concepts
template<class C>
static bool sfinae_fun
(
const C* cc,
// check for 'C::begin()' returning a forward iterator
typename util::enable_if<util::is_forward_iterator<decltype(cc->begin())>>::type* = 0,
// check for 'C::end()' returning the same kind of forward iterator
typename util::enable_if<std::is_same<decltype(cc->begin()), decltype(cc->end())>>::type* = 0
)
{
return true;
}
// SFNINAE default
static void sfinae_fun(...) { }
typedef decltype(sfinae_fun(static_cast<const T*>(nullptr))) result_type;
public:
static const bool value = util::is_primitive<T>::value == false
&& std::is_same<bool, result_type>::value;
};
} } // namespace cppa::util
#endif // IS_ITERABLE_HPP
#ifndef IS_PRIMITIVE_HPP
#define IS_PRIMITIVE_HPP
#include "cppa/detail/type_to_ptype.hpp"
namespace cppa { namespace util {
/**
* @brief Evaluates to @c true if @c T is a primitive type.
*
* <code>is_primitive<T>::value == true</code> if and only if @c T
* is a signed / unsigned integer or one of the following types:
* - @c float
* - @c double
* - @c long @c double
* - @c std::string
* - @c std::u16string
* - @c std::u32string
*/
template<typename T>
struct is_primitive
{
static const bool value = detail::type_to_ptype<T>::ptype != pt_null;
};
} } // namespace cppa::util
#endif // IS_PRIMITIVE_HPP
#ifndef IS_SERIALIZABLE_HPP
#define IS_SERIALIZABLE_HPP
namespace cppa {
struct serializer;
struct deserializer;
} // namespace cppa
namespace cppa { namespace util {
template<typename T>
class is_serializable
{
template<typename A>
static auto help_fun1(A* arg, serializer* s) -> decltype((*s) << (*arg))
{
return true;
}
template<typename A>
static void help_fun1(A*, void*) { }
typedef decltype(help_fun1((T*) 0, (serializer*) 0)) type1;
template<typename A>
static auto help_fun2(A* arg, deserializer* d) -> decltype((*d) >> (*arg))
{
return true;
}
template<typename A>
static void help_fun2(A*, void*) { }
typedef decltype(help_fun2((T*) 0, (deserializer*) 0)) type2;
public:
static const bool value = std::is_same< serializer&, type1>::value
&& std::is_same<deserializer&, type2>::value;
};
} } // namespace cppa::util
#endif // IS_SERIALIZABLE_HPP
#ifndef PT_TOKEN_HPP
#define PT_TOKEN_HPP
#include "cppa/primitive_type.hpp"
namespace cppa { namespace util {
/**
* @brief Achieves static call dispatch (int-to-type idiom).
*/
template<primitive_type PT>
struct pt_token { static const primitive_type value = PT; };
/**
* @brief Creates a {@link pt_token} from the runtime value @p ptype
* and invokes @p f with this token.
* @note Does nothing if ptype == pt_null.
*/
template<typename Fun>
void pt_dispatch(primitive_type ptype, Fun&& f)
{
switch (ptype)
{
case pt_int8: f(pt_token<pt_int8>()); break;
case pt_int16: f(pt_token<pt_int16>()); break;
case pt_int32: f(pt_token<pt_int32>()); break;
case pt_int64: f(pt_token<pt_int64>()); break;
case pt_uint8: f(pt_token<pt_uint8>()); break;
case pt_uint16: f(pt_token<pt_uint16>()); break;
case pt_uint32: f(pt_token<pt_uint32>()); break;
case pt_uint64: f(pt_token<pt_uint64>()); break;
case pt_float: f(pt_token<pt_float>()); break;
case pt_double: f(pt_token<pt_double>()); break;
case pt_long_double: f(pt_token<pt_long_double>()); break;
case pt_u8string: f(pt_token<pt_u8string>()); break;
case pt_u16string: f(pt_token<pt_u16string>()); break;
case pt_u32string: f(pt_token<pt_u32string>()); break;
default: break;
}
}
} } // namespace cppa::util
#endif // PT_TOKEN_HPP
#ifndef RM_REF_HPP
#define RM_REF_HPP
namespace cppa { namespace util {
/**
* @brief Like std::remove_reference but prohibits void and removes const
* references.
*/
template<typename T>
struct rm_ref { typedef T type; };
template<typename T>
struct rm_ref<const T&> { typedef T type; };
template<typename T>
struct rm_ref<T&> { typedef T type; };
template<>
struct rm_ref<void> { };
} } // namespace cppa::util
#endif // RM_REF_HPP
#ifndef UNIFORM_TYPE_INFO_BASE_HPP
#define UNIFORM_TYPE_INFO_BASE_HPP
#include "cppa/uniform_type_info.hpp"
#include "cppa/detail/to_uniform_name.hpp"
namespace cppa { namespace util {
/**
* @brief Implements all pure virtual functions of {@link uniform_type_info}
* except serialize() and deserialize().
*/
template<typename T>
class uniform_type_info_base : public uniform_type_info
{
inline static const T& deref(const void* ptr)
{
return *reinterpret_cast<const T*>(ptr);
}
inline static T& deref(void* ptr)
{
return *reinterpret_cast<T*>(ptr);
}
protected:
uniform_type_info_base(const std::string& uname
= detail::to_uniform_name(typeid(T)))
: uniform_type_info(uname)
{
}
bool equal(const void* lhs, const void* rhs) const
{
return deref(lhs) == deref(rhs);
}
void* new_instance(const void* ptr) const
{
return (ptr) ? new T(deref(ptr)) : new T();
}
void delete_instance(void* instance) const
{
delete reinterpret_cast<T*>(instance);
}
public:
bool equal(const std::type_info& tinfo) const
{
return typeid(T) == tinfo;
}
};
} }
#endif // UNIFORM_TYPE_INFO_BASE_HPP
......@@ -21,6 +21,8 @@ HEADERS = cppa/actor.hpp \
cppa/message_queue.hpp \
cppa/object.hpp \
cppa/on.hpp \
cppa/primitive_type.hpp \
cppa/primitive_variant.hpp \
cppa/ref_counted.hpp \
cppa/scheduler.hpp \
cppa/scheduling_hint.hpp \
......@@ -64,6 +66,7 @@ HEADERS = cppa/actor.hpp \
cppa/util/void_type.hpp
SOURCES = src/actor_behavior.cpp \
src/binary_serializer.cpp \
src/blocking_message_queue.cpp \
src/channel.cpp \
src/context.cpp \
......@@ -73,6 +76,7 @@ SOURCES = src/actor_behavior.cpp \
src/group.cpp \
src/mock_scheduler.cpp \
src/object.cpp \
src/primitive_variant.cpp \
src/scheduler.cpp \
src/serializer.cpp \
src/to_uniform_name.cpp \
......
#include <string>
#include <cstring>
#include <cstdint>
#include <type_traits>
#include "cppa/util/enable_if.hpp"
#include "cppa/primitive_variant.hpp"
#include "cppa/binary_serializer.hpp"
using cppa::util::enable_if;
namespace {
constexpr size_t chunk_size = 512;
} // namespace <anonymous>
namespace cppa {
namespace detail {
class binary_writer
{
binary_serializer* self;
public:
binary_writer(binary_serializer* s) : self(s) { }
template<typename T>
inline static void write_int(binary_serializer* self, const T& value)
{
memcpy(self->m_wr_pos, &value, sizeof(T));
self->m_wr_pos += sizeof(T);
}
inline static void write_string(binary_serializer* self,
const std::string& str)
{
write_int(self, static_cast<std::uint32_t>(str.size()));
memcpy(self->m_wr_pos, str.c_str(), str.size());
self->m_wr_pos += str.size();
}
template<typename T>
void operator()(const T& value,
typename enable_if< std::is_integral<T> >::type* = 0)
{
self->acquire(sizeof(T));
write_int(self, value);
}
template<typename T>
void operator()(const T& value,
typename enable_if< std::is_floating_point<T> >::type* = 0)
{
}
void operator()(const std::string& str)
{
self->acquire(sizeof(std::uint32_t) + str.size());
write_string(self, str);
}
void operator()(const std::u16string& str)
{
self->acquire(sizeof(std::uint32_t) + str.size());
write_int(self, static_cast<std::uint32_t>(str.size()));
for (char16_t c : str)
{
// force writer to use exactly 16 bit
write_int(self, static_cast<std::uint16_t>(c));
}
}
void operator()(const std::u32string& str)
{
self->acquire(sizeof(std::uint32_t) + str.size());
write_int(self, static_cast<std::uint32_t>(str.size()));
for (char32_t c : str)
{
// force writer to use exactly 32 bit
write_int(self, static_cast<std::uint32_t>(c));
}
}
};
} // namespace detail
binary_serializer::binary_serializer() : m_begin(0), m_end(0), m_wr_pos(0)
{
}
binary_serializer::~binary_serializer()
{
delete[] m_begin;
}
void binary_serializer::acquire(size_t num_bytes)
{
if (m_begin == nullptr)
{
size_t new_size = chunk_size;
while (new_size <= num_bytes)
{
new_size += chunk_size;
}
m_begin = new char[new_size];
m_end = m_begin + new_size;
m_wr_pos = m_begin;
}
else
{
char* next_wr_pos = m_wr_pos + num_bytes;
if (next_wr_pos > m_end)
{
size_t new_size = static_cast<size_t>(m_end - m_begin)
+ chunk_size;
while ((m_begin + new_size) < next_wr_pos)
{
new_size += chunk_size;
}
char* begin = new char[new_size];
auto used_bytes = static_cast<size_t>(m_wr_pos - m_begin);
if (used_bytes > 0)
{
memcpy(m_begin, begin, used_bytes);
}
delete[] m_begin;
m_begin = begin;
m_end = m_begin + new_size;
m_wr_pos = m_begin + used_bytes;
}
}
}
void binary_serializer::begin_object(const std::string& tname)
{
acquire(sizeof(std::uint32_t) + tname.size());
detail::binary_writer::write_string(this, tname);
}
void binary_serializer::end_object()
{
}
void binary_serializer::begin_sequence(size_t list_size)
{
acquire(sizeof(std::uint32_t));
detail::binary_writer::write_int(this,
static_cast<std::uint32_t>(list_size));
}
void binary_serializer::end_sequence()
{
}
void binary_serializer::write_value(const primitive_variant& value)
{
value.apply(detail::binary_writer(this));
}
void binary_serializer::write_tuple(size_t size,
const primitive_variant* values)
{
const primitive_variant* end = values + size;
for ( ; values != end; ++values)
{
write_value(*values);
}
}
std::pair<size_t, char*> binary_serializer::take_buffer()
{
char* begin = m_begin;
char* end = m_end;
m_begin = m_end = m_wr_pos = nullptr;
return { static_cast<size_t>(end - begin), begin };
}
size_t binary_serializer::size() const
{
return static_cast<size_t>(m_wr_pos - m_begin);
}
const char* binary_serializer::data() const
{
return m_begin;
}
} // namespace cppa
#include <cstdint>
#include "cppa/actor.hpp"
#include "cppa/deserializer.hpp"
namespace cppa {
deserializer::deserializer(const intrusive_ptr<util::source>& src) : m_src(src)
{
}
deserializer& operator>>(deserializer& d, actor_ptr&)
{
return d;
}
deserializer& operator>>(deserializer& d, std::string& str)
deserializer::~deserializer()
{
std::uint32_t str_size;
d >> str_size;
char* cbuf = new char[str_size + 1];
d.read(str_size, cbuf);
cbuf[str_size] = 0;
str = cbuf;
delete[] cbuf;
return d;
}
} // namespace cppa
......@@ -15,23 +15,24 @@ namespace cppa {
void object::swap(object& other)
{
std::swap(m_value, other.m_value);
std::swap(m_type, other.m_type);
std::swap(m_value, other.m_value);
std::swap(m_type, other.m_type);
}
object object::copy() const
{
return (m_value) ? m_type->copy(*this) : object();
return (m_value != &s_void) ? object(m_type->new_instance(m_value), m_type)
: object();
}
object::object(void* val, const uniform_type_info* utype)
: m_value(val), m_type(utype)
: m_value(val), m_type(utype)
{
if (val && !utype)
{
throw std::invalid_argument("val && !utype");
}
if (val && !utype)
{
throw std::invalid_argument("val && !utype");
}
}
object::object() : m_value(&s_void), m_type(uniform_typeid<util::void_type>())
......@@ -40,48 +41,53 @@ object::object() : m_value(&s_void), m_type(uniform_typeid<util::void_type>())
object::~object()
{
if (m_value != &s_void) m_type->destroy(*this);
if (m_value != &s_void) m_type->delete_instance(m_value);
}
object::object(const object& other) : m_value(&s_void), m_type(uniform_typeid<util::void_type>())
{
object tmp = other.copy();
swap(tmp);
object tmp = other.copy();
swap(tmp);
}
object::object(object&& other) : m_value(&s_void), m_type(uniform_typeid<util::void_type>())
{
swap(other);
swap(other);
}
object& object::operator=(object&& other)
{
object tmp(std::move(other));
swap(tmp);
return *this;
object tmp(std::move(other));
swap(tmp);
return *this;
}
object& object::operator=(const object& other)
{
object tmp = other.copy();
swap(tmp);
return *this;
object tmp = other.copy();
swap(tmp);
return *this;
}
bool object::equal(const object& other) const
{
return m_type->equal(*this, other);
if (m_type == other.m_type)
{
return (m_value != &s_void) ? m_type->equal(m_value, other.m_value)
: true;
}
return false;
}
const uniform_type_info& object::type() const
{
return *m_type;
return *m_type;
}
std::string object::to_string() const
{
return m_type->to_string(*this);
return "";
}
} // namespace cppa
#include <typeinfo>
#include "cppa/primitive_variant.hpp"
#include "cppa/detail/type_to_ptype.hpp"
namespace cppa {
namespace {
template<class T>
void ptv_del(T&,
typename util::enable_if<std::is_arithmetic<T>, int>::type* = 0)
{
// arithmetic types don't need destruction
}
template<class T>
void ptv_del(T& what,
typename util::disable_if< std::is_arithmetic<T> >::type* = 0)
{
what.~T();
}
struct destroyer
{
template<typename T>
inline void operator()(T& what) const
{
ptv_del(what);
}
};
struct type_reader
{
const std::type_info* tinfo;
type_reader() : tinfo(nullptr) { }
template<typename T>
void operator()(const T&)
{
tinfo = &typeid(T);
}
};
struct comparator
{
bool result;
const primitive_variant& lhs;
const primitive_variant& rhs;
comparator(const primitive_variant& pv1, const primitive_variant& pv2)
: result(false), lhs(pv1), rhs(pv2)
{
}
template<primitive_type PT>
void operator()(util::pt_token<PT>)
{
if (rhs.ptype() == PT)
{
result = (lhs.get_as<PT>() == rhs.get_as<PT>());
}
}
};
struct initializer
{
primitive_variant& lhs;
inline initializer(primitive_variant& pv) : lhs(pv) { }
template<primitive_type PT>
inline void operator()(util::pt_token<PT>)
{
typedef typename detail::ptype_to_type<PT>::type T;
lhs.set(T());
}
};
struct setter
{
primitive_variant& lhs;
setter(primitive_variant& pv) : lhs(pv) { }
template<typename T>
inline void operator()(const T& rhs)
{
lhs.set(rhs);
}
};
struct mover
{
primitive_variant& lhs;
mover(primitive_variant& pv) : lhs(pv) { }
template<typename T>
inline void operator()(T& rhs)
{
lhs.set(std::move(rhs));
}
};
} // namespace <anonymous>
primitive_variant::primitive_variant() : m_ptype(pt_null) { }
primitive_variant::primitive_variant(primitive_type ptype) : m_ptype(pt_null)
{
util::pt_dispatch(ptype, initializer(*this));
}
primitive_variant::primitive_variant(const primitive_variant& other)
: m_ptype(pt_null)
{
other.apply(setter(*this));
}
primitive_variant::primitive_variant(primitive_variant&& other)
: m_ptype(pt_null)
{
other.apply(mover(*this));
}
primitive_variant& primitive_variant::operator=(const primitive_variant& other)
{
other.apply(setter(*this));
return *this;
}
primitive_variant& primitive_variant::operator=(primitive_variant&& other)
{
other.apply(mover(*this));
return *this;
}
bool primitive_variant::operator==(const primitive_variant& other) const
{
comparator cmp(*this, other);
util::pt_dispatch(m_ptype, cmp);
return cmp.result;
}
const std::type_info& primitive_variant::type() const
{
type_reader tr;
apply(tr);
return (tr.tinfo) ? *tr.tinfo : typeid(void);
}
primitive_variant::~primitive_variant()
{
destroy();
}
void primitive_variant::destroy()
{
apply(destroyer());
m_ptype = pt_null;
}
} // namespace cppa
#include <cstdint>
#include "cppa/actor.hpp"
#include "cppa/serializer.hpp"
namespace cppa {
serializer::serializer(const intrusive_ptr<util::sink>& dsink) : m_sink(dsink)
{
}
serializer& operator<<(serializer& s, const actor_ptr&)
{
return s;
}
serializer& operator<<(serializer& s, const std::string& str)
serializer::~serializer()
{
auto str_size = static_cast<std::uint32_t>(str.size());
s << str_size;
s.write(str.size(), str.c_str());
return s;
}
} // namespace cppa
......@@ -14,15 +14,15 @@ namespace {
constexpr const char* mapped_int_names[][2] =
{
{ nullptr, nullptr }, // sizeof 0 { invalid }
{ "@i8", "@u8" }, // sizeof 1 -> signed / unsigned int8
{ "@i16", "@u16" }, // sizeof 2 -> signed / unsigned int16
{ nullptr, nullptr }, // sizeof 3 { invalid }
{ "@i32", "@u32" }, // sizeof 4 -> signed / unsigned int32
{ nullptr, nullptr }, // sizeof 5 { invalid }
{ nullptr, nullptr }, // sizeof 6 { invalid }
{ nullptr, nullptr }, // sizeof 7 { invalid }
{ "@i64", "@u64" } // sizeof 8 -> signed / unsigned int64
{ nullptr, nullptr }, // sizeof 0 { invalid }
{ "@i8", "@u8" }, // sizeof 1 -> signed / unsigned int8
{ "@i16", "@u16" }, // sizeof 2 -> signed / unsigned int16
{ nullptr, nullptr }, // sizeof 3 { invalid }
{ "@i32", "@u32" }, // sizeof 4 -> signed / unsigned int32
{ nullptr, nullptr }, // sizeof 5 { invalid }
{ nullptr, nullptr }, // sizeof 6 { invalid }
{ nullptr, nullptr }, // sizeof 7 { invalid }
{ "@i64", "@u64" } // sizeof 8 -> signed / unsigned int64
};
template<typename T>
......@@ -72,12 +72,14 @@ std::string to_uniform_name_impl(Iterator begin, Iterator end,
{ demangled<long long>(), mapped_int_name<long long>() },
{ demangled<signed long long>(), mapped_int_name<signed long long>() },
{ demangled<unsigned long long>(), mapped_int_name<unsigned long long>()},
{ demangled<wchar_t>(), mapped_int_name<wchar_t>() },
// { demangled<wchar_t>(), mapped_int_name<wchar_t>() },
{ demangled<char16_t>(), mapped_int_name<char16_t>() },
{ demangled<char32_t>(), mapped_int_name<char32_t>() },
{ demangled<cppa::util::void_type>(), "@0" },
{ demangled<std::wstring>(), "@wstr" },
{ demangled<std::string>(), "@str" }
// { demangled<std::wstring>(), "@wstr" },
{ demangled<std::string>(), "@str" },
{ demangled<std::u16string>(), "@u16str" },
{ demangled<std::u32string>(), "@u32str" }
};
// check if we could find the whole string in our lookup map
......
......@@ -41,121 +41,45 @@ namespace {
inline const char* raw_name(const std::type_info& tinfo)
{
#ifdef CPPA_WINDOWS
return tinfo.raw_name();
return tinfo.raw_name();
#else
return tinfo.name();
return tinfo.name();
#endif
}
class wstring_utype : public cppa::uniform_type_info
{
typedef std::ctype<wchar_t> wchar_ctype;
inline std::wstring& to_ref(cppa::object& what) const
{
return *reinterpret_cast<std::wstring*>(this->value_of(what));
}
inline const std::wstring& to_ref(const cppa::object& what) const
{
return *reinterpret_cast<const std::wstring*>(this->value_of(what));
}
const wchar_ctype& m_facet;
protected:
cppa::object copy(const cppa::object& what) const
{
return { new std::wstring(to_ref(what)), this };
}
cppa::object from_string(const std::string& str) const
{
std::vector<wchar_t> wstr_buf(str.size());
m_facet.widen(str.data(), str.data() + str.size(), &wstr_buf[0]);
return { new std::wstring(&wstr_buf[0], wstr_buf.size()), this };
}
std::string to_string(const cppa::object& obj) const
{
const std::wstring& wstr = to_ref(obj);
std::string result(wstr.size(), ' ');
m_facet.narrow(wstr.c_str(), wstr.c_str() + wstr.size(), '?',
&result[0]);
return std::move(result);
}
void destroy(cppa::object& what) const
{
delete reinterpret_cast<std::wstring*>(value_of(what));
value_of(what) = nullptr;
}
void deserialize(cppa::deserializer& d, cppa::object& what) const
{
}
bool equal(const cppa::object& lhs, const cppa::object& rhs) const
{
return (lhs.type() == *this && rhs.type() == *this)
? to_ref(lhs) == to_ref(rhs)
: false;
}
void serialize(cppa::serializer& s, const cppa::object& what) const
{
}
public:
wstring_utype()
: cppa::uniform_type_info(typeid(std::wstring))
, m_facet(std::use_facet<wchar_ctype>(std::locale()))
{
}
cppa::object create() const
{
return { new std::wstring, this };
}
};
template<typename T>
inline const char* raw_name()
{
return raw_name(typeid(T));
return raw_name(typeid(T));
}
typedef std::set<std::string> string_set;
template<typename Int>
void push(std::map<int, std::pair<string_set, string_set>>& ints,
std::integral_constant<bool, true>)
std::integral_constant<bool, true>)
{
ints[sizeof(Int)].first.insert(raw_name<Int>());
ints[sizeof(Int)].first.insert(raw_name<Int>());
}
template<typename Int>
void push(std::map<int, std::pair<string_set, string_set>>& ints,
std::integral_constant<bool, false>)
std::integral_constant<bool, false>)
{
ints[sizeof(Int)].second.insert(raw_name<Int>());
ints[sizeof(Int)].second.insert(raw_name<Int>());
}
template<typename Int>
void push(std::map<int, std::pair<string_set, string_set>>& ints)
{
push<Int>(ints, std::integral_constant<bool, std::numeric_limits<Int>::is_signed>());
push<Int>(ints, std::integral_constant<bool, std::numeric_limits<Int>::is_signed>());
}
template<typename Int0, typename Int1, typename... Ints>
void push(std::map<int, std::pair<string_set, string_set>>& ints)
{
push<Int0>(ints, std::integral_constant<bool, std::numeric_limits<Int0>::is_signed>());
push<Int1, Ints...>(ints);
push<Int0>(ints, std::integral_constant<bool, std::numeric_limits<Int0>::is_signed>());
push<Int1, Ints...>(ints);
}
} // namespace <anonymous>
......@@ -165,153 +89,153 @@ namespace cppa { namespace detail { namespace {
class uniform_type_info_map
{
typedef std::map<std::string, uniform_type_info*> uti_map;
// maps typeid names to uniform type informations
uti_map m_by_tname;
// maps uniform names to uniform type informations
uti_map m_by_uname;
void insert(uniform_type_info* uti, const std::set<std::string>& tnames)
{
if (tnames.empty())
{
throw std::logic_error("tnames.empty()");
}
for (const std::string& tname : tnames)
{
m_by_tname.insert(std::make_pair(tname, uti));
}
m_by_uname.insert(std::make_pair(uti->name(), uti));
}
template<typename T>
inline void insert(const std::set<std::string>& tnames)
{
insert(new default_uniform_type_info_impl<T>(), tnames);
}
template<typename T>
inline void insert()
{
insert<T>({ std::string(raw_name<T>()) });
}
typedef std::map<std::string, uniform_type_info*> uti_map;
// maps raw typeid names to uniform type informations
uti_map m_by_rname;
// maps uniform names to uniform type informations
uti_map m_by_uname;
void insert(uniform_type_info* uti, const std::set<std::string>& tnames)
{
if (tnames.empty())
{
throw std::logic_error("tnames.empty()");
}
for (const std::string& tname : tnames)
{
m_by_rname.insert(std::make_pair(tname, uti));
}
m_by_uname.insert(std::make_pair(uti->name(), uti));
}
template<typename T>
inline void insert(const std::set<std::string>& tnames)
{
insert(new default_uniform_type_info_impl<T>(), tnames);
}
template<typename T>
inline void insert()
{
insert<T>({ std::string(raw_name<T>()) });
}
public:
uniform_type_info_map()
{
insert<std::string>();
//insert<wstring_obj>({std::string(raw_name<std::wstring>())});
insert(new wstring_utype, { std::string(raw_name<std::wstring>()) });
insert<float>();
insert<cppa::util::void_type>();
if (sizeof(double) == sizeof(long double))
{
std::string dbl = raw_name<double>();
std::string ldbl = raw_name<long double>();
insert<double>({ dbl, ldbl });
}
else
{
insert<double>();
insert<long double>();
}
insert<any_type>();
insert<actor_ptr>();
// first: signed
// second: unsigned
std::map<int, std::pair<string_set, string_set>> ints;
push<char,
signed char,
unsigned char,
short,
signed short,
unsigned short,
short int,
signed short int,
unsigned short int,
int,
signed int,
unsigned int,
long int,
signed long int,
unsigned long int,
long,
signed long,
unsigned long,
long long,
signed long long,
unsigned long long,
wchar_t,
char16_t,
char32_t>(ints);
insert<std::int8_t>(ints[sizeof(std::int8_t)].first);
insert<std::uint8_t>(ints[sizeof(std::uint8_t)].second);
insert<std::int16_t>(ints[sizeof(std::int16_t)].first);
insert<std::uint16_t>(ints[sizeof(std::uint16_t)].second);
insert<std::int32_t>(ints[sizeof(std::int32_t)].first);
insert<std::uint32_t>(ints[sizeof(std::uint32_t)].second);
insert<std::int64_t>(ints[sizeof(std::int64_t)].first);
insert<std::uint64_t>(ints[sizeof(std::uint64_t)].second);
}
uniform_type_info* by_raw_name(const std::string& name)
{
auto i = m_by_tname.find(name);
if (i != m_by_tname.end())
{
return i->second;
}
return nullptr;
}
uniform_type_info* by_uniform_name(const std::string& name)
{
auto i = m_by_uname.find(name);
if (i != m_by_uname.end())
{
return i->second;
}
return nullptr;
}
bool insert(std::set<std::string> plain_names,
uniform_type_info* what)
{
if (m_by_uname.count(what->name()) > 0)
{
return false;
}
m_by_uname.insert(std::make_pair(what->name(), what));
for (const std::string& plain_name : plain_names)
{
if (!m_by_tname.insert(std::make_pair(plain_name, what)).second)
{
throw std::runtime_error(plain_name + " already mapped to an uniform_type_info");
}
}
return true;
}
std::vector<uniform_type_info*> get_all()
{
std::vector<uniform_type_info*> result;
result.reserve(m_by_uname.size());
for (const uti_map::value_type& i : m_by_uname)
{
result.push_back(i.second);
}
return std::move(result);
}
uniform_type_info_map()
{
insert<std::string>();
//insert<wstring_obj>({std::string(raw_name<std::wstring>())});
//insert(new wstring_utype, { std::string(raw_name<std::wstring>()) });
insert<float>();
insert<cppa::util::void_type>();
if (sizeof(double) == sizeof(long double))
{
std::string dbl = raw_name<double>();
std::string ldbl = raw_name<long double>();
insert<double>({ dbl, ldbl });
}
else
{
insert<double>();
insert<long double>();
}
insert<any_type>();
// insert<actor_ptr>();
// first: signed
// second: unsigned
std::map<int, std::pair<string_set, string_set>> ints;
push<char,
signed char,
unsigned char,
short,
signed short,
unsigned short,
short int,
signed short int,
unsigned short int,
int,
signed int,
unsigned int,
long int,
signed long int,
unsigned long int,
long,
signed long,
unsigned long,
long long,
signed long long,
unsigned long long,
wchar_t,
char16_t,
char32_t>(ints);
insert<std::int8_t>(ints[sizeof(std::int8_t)].first);
insert<std::uint8_t>(ints[sizeof(std::uint8_t)].second);
insert<std::int16_t>(ints[sizeof(std::int16_t)].first);
insert<std::uint16_t>(ints[sizeof(std::uint16_t)].second);
insert<std::int32_t>(ints[sizeof(std::int32_t)].first);
insert<std::uint32_t>(ints[sizeof(std::uint32_t)].second);
insert<std::int64_t>(ints[sizeof(std::int64_t)].first);
insert<std::uint64_t>(ints[sizeof(std::uint64_t)].second);
}
uniform_type_info* by_raw_name(const std::string& name)
{
auto i = m_by_rname.find(name);
if (i != m_by_rname.end())
{
return i->second;
}
return nullptr;
}
uniform_type_info* by_uniform_name(const std::string& name)
{
auto i = m_by_uname.find(name);
if (i != m_by_uname.end())
{
return i->second;
}
return nullptr;
}
bool insert(std::set<std::string> plain_names,
uniform_type_info* what)
{
if (m_by_uname.count(what->name()) > 0)
{
return false;
}
m_by_uname.insert(std::make_pair(what->name(), what));
for (const std::string& plain_name : plain_names)
{
if (!m_by_rname.insert(std::make_pair(plain_name, what)).second)
{
throw std::runtime_error(plain_name + " already mapped to an uniform_type_info");
}
}
return true;
}
std::vector<uniform_type_info*> get_all()
{
std::vector<uniform_type_info*> result;
result.reserve(m_by_uname.size());
for (const uti_map::value_type& i : m_by_uname)
{
result.push_back(i.second);
}
return std::move(result);
}
};
uniform_type_info_map& s_uniform_type_info_map()
{
static uniform_type_info_map s_utimap;
return s_utimap;
static uniform_type_info_map s_utimap;
return s_utimap;
}
} } } // namespace cppa::detail::<anonymous>
......@@ -327,9 +251,8 @@ inline int next_id() { return s_ids.fetch_add(1); }
namespace cppa {
uniform_type_info::uniform_type_info(const std::type_info& tinfo)
: m_id(next_id())
, m_name(detail::to_uniform_name(detail::demangle(raw_name(tinfo))))
uniform_type_info::uniform_type_info(const std::string& uname)
: m_id(next_id()), m_name(uname)
{
}
......@@ -339,50 +262,59 @@ uniform_type_info::~uniform_type_info()
uniform_type_info* uniform_type_info::by_type_info(const std::type_info& tinf)
{
auto result = detail::s_uniform_type_info_map().by_raw_name(raw_name(tinf));
if (!result)
{
throw std::runtime_error(std::string(raw_name(tinf))
+ " is an unknown typeid name");
}
return result;
auto result = detail::s_uniform_type_info_map().by_raw_name(raw_name(tinf));
if (!result)
{
throw std::runtime_error(std::string(raw_name(tinf))
+ " is an unknown typeid name");
}
return result;
}
uniform_type_info* uniform_type_info::by_uniform_name(const std::string& name)
{
auto result = detail::s_uniform_type_info_map().by_uniform_name(name);
if (!result)
{
throw std::runtime_error(name + " is an unknown typeid name");
}
return result;
auto result = detail::s_uniform_type_info_map().by_uniform_name(name);
if (!result)
{
throw std::runtime_error(name + " is an unknown typeid name");
}
return result;
}
/*
bool uniform_type_info::announce(const std::type_info& plain_type,
uniform_type_info* uniform_type)
uniform_type_info* uniform_type)
{
string_set tmp = { std::string(raw_name(plain_type)) };
if (!detail::s_uniform_type_info_map().insert(tmp, uniform_type))
{
delete uniform_type;
return false;
}
return true;
}
*/
object uniform_type_info::deserialize(deserializer* from) const
{
string_set tmp = { std::string(raw_name(plain_type)) };
if (!detail::s_uniform_type_info_map().insert(tmp, uniform_type))
{
delete uniform_type;
return false;
}
return true;
auto ptr = new_instance();
deserialize(ptr, from);
return { ptr, this };
}
std::vector<uniform_type_info*> uniform_type_info::instances()
{
return detail::s_uniform_type_info_map().get_all();
return detail::s_uniform_type_info_map().get_all();
}
uniform_type_info* uniform_typeid(const std::type_info& tinfo)
{
return uniform_type_info::by_type_info(tinfo);
return uniform_type_info::by_type_info(tinfo);
}
bool operator==(const uniform_type_info& lhs, const std::type_info& rhs)
{
return lhs == *uniform_typeid(rhs);
return lhs.equal(rhs);
}
} // namespace cppa
......@@ -18,6 +18,7 @@ SOURCES = hash_of.cpp \
test__atom.cpp \
test__intrusive_ptr.cpp \
test__local_group.cpp \
test__primitive_variant.cpp \
test__queue_performance.cpp \
test__serialization.cpp \
test__spawn.cpp \
......
......@@ -27,45 +27,46 @@ using std::endl;
int main(int argc, char** c_argv)
{
std::vector<std::string> argv;
for (int i = 1; i < argc; ++i)
{
argv.push_back(c_argv[i]);
}
std::vector<std::string> argv;
for (int i = 1; i < argc; ++i)
{
argv.push_back(c_argv[i]);
}
if (!argv.empty())
{
if (argv.size() == 1 && argv.front() == "performance_test")
{
cout << endl << "run queue performance test ... " << endl;
test__queue_performance();
}
else
{
cerr << "unrecognized options"
<< endl
<< "no options:\n\tunit tests"
<< endl
<< "performance_test:\n\trun single reader queue tests"
<< endl;
}
}
else
{
std::cout << std::boolalpha;
std::size_t errors = 0;
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);
RUN_TEST(test__spawn);
RUN_TEST(test__local_group);
RUN_TEST(test__atom);
cout << endl
<< "error(s) in all tests: " << errors
<< endl;
}
return 0;
if (!argv.empty())
{
if (argv.size() == 1 && argv.front() == "performance_test")
{
cout << endl << "run queue performance test ... " << endl;
test__queue_performance();
}
else
{
cerr << "unrecognized options"
<< endl
<< "no options:\n\tunit tests"
<< endl
<< "performance_test:\n\trun single reader queue tests"
<< endl;
}
}
else
{
std::cout << std::boolalpha;
std::size_t errors = 0;
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);
RUN_TEST(test__spawn);
RUN_TEST(test__local_group);
RUN_TEST(test__atom);
cout << endl
<< "error(s) in all tests: " << errors
<< endl;
}
return 0;
}
......@@ -7,31 +7,40 @@
#define CPPA_TEST(name) \
struct cppa_test_scope \
{ \
std::size_t error_count; \
cppa_test_scope() : error_count(0) { } \
~cppa_test_scope() \
{ \
std::cout << error_count << " error(s) detected" << std::endl; \
} \
std::size_t error_count; \
cppa_test_scope() : error_count(0) { } \
~cppa_test_scope() \
{ \
std::cout << error_count << " error(s) detected" << std::endl; \
} \
} cppa_ts;
#define CPPA_TEST_RESULT cppa_ts.error_count
#ifdef CPPA_VERBOSE_CHECK
#define CPPA_CHECK(line_of_code) \
if (!(line_of_code)) \
{ \
std::cerr << "ERROR in file " << __FILE__ << " on line " << __LINE__ \
<< " => " << #line_of_code << std::endl; \
++cppa_ts.error_count; \
} ((void) 0)
#define CPPA_CHECK_EQUAL(lhs_loc, rhs_loc) \
if ((lhs_loc) != (rhs_loc)) \
std::cerr << "ERROR in file " << __FILE__ << " on line " << __LINE__ \
<< " => " << #line_of_code << std::endl; \
++cppa_ts.error_count; \
} \
else \
{ \
std::cout << "line " << __LINE__ << " passed" << endl; \
} \
((void) 0)
#else
#define CPPA_CHECK(line_of_code) \
if (!(line_of_code)) \
{ \
std::cerr << "ERROR in file " << __FILE__ << " on line " << __LINE__ \
<< " => " << #lhs_loc << " != " << #rhs_loc << std::endl; \
++cppa_ts.error_count; \
std::cerr << "ERROR in file " << __FILE__ << " on line " << __LINE__ \
<< " => " << #line_of_code << std::endl; \
++cppa_ts.error_count; \
} ((void) 0)
#endif
#define CPPA_CHECK_EQUAL(lhs_loc, rhs_loc) CPPA_CHECK(((lhs_loc) == (rhs_loc)))
std::size_t test__uniform_type();
std::size_t test__type_list();
......@@ -42,6 +51,7 @@ std::size_t test__spawn();
std::size_t test__intrusive_ptr();
std::size_t test__serialization();
std::size_t test__local_group();
std::size_t test__primitive_variant();
void test__queue_performance();
......
#include "test.hpp"
#include "cppa/primitive_variant.hpp"
using namespace cppa;
std::size_t test__primitive_variant()
{
CPPA_TEST(test__primitive_variant);
std::uint32_t forty_two = 42;
primitive_variant v1(forty_two);
primitive_variant v2(pt_uint32);
// type checking
CPPA_CHECK_EQUAL(v1.ptype(), pt_uint32);
CPPA_CHECK_EQUAL(v2.ptype(), pt_uint32);
get<std::uint32_t&>(v2) = forty_two;
CPPA_CHECK_EQUAL(v1, v2);
CPPA_CHECK_EQUAL(v1, forty_two);
CPPA_CHECK_EQUAL(forty_two, v2);
// type mismatch => unequal
CPPA_CHECK(v2 != static_cast<std::int8_t>(forty_two));
v1 = "Hello world";
CPPA_CHECK_EQUAL(v1.ptype(), pt_u8string);
v2 = "Hello";
CPPA_CHECK_EQUAL(v2.ptype(), pt_u8string);
get<std::string>(v2) += " world";
CPPA_CHECK_EQUAL(v1, v2);
v2 = u"Hello World";
CPPA_CHECK(v1 != v2);
return CPPA_TEST_RESULT;
}
#include <new>
#include <set>
#include <list>
#include <locale>
#include <memory>
#include <string>
......@@ -20,1208 +21,38 @@
#include "test.hpp"
#include "cppa/util.hpp"
#include "cppa/match.hpp"
#include "cppa/tuple.hpp"
#include "cppa/serializer.hpp"
#include "cppa/ref_counted.hpp"
#include "cppa/deserializer.hpp"
#include "cppa/untyped_tuple.hpp"
#include "cppa/util/enable_if.hpp"
#include "cppa/util/disable_if.hpp"
#include "cppa/util/if_else_type.hpp"
#include "cppa/util/wrapped_type.hpp"
//#include "cppa/util.hpp"
using std::cout;
using std::cerr;
using std::endl;
using namespace cppa::util;
template<class C, template <typename> class... Traits>
struct apply;
template<class C>
struct apply<C>
{
typedef C type;
};
template<class C,
template <typename> class Trait0,
template <typename> class... Traits>
struct apply<C, Trait0, Traits...>
{
typedef typename apply<typename Trait0<C>::type, Traits...>::type type;
};
template<typename T>
struct plain
{
typedef typename apply<T, std::remove_reference, std::remove_cv>::type type;
};
/**
* @brief Integers (signed and unsigned), floating points and strings.
*/
enum primitive_type
{
pt_int8, pt_int16, pt_int32, pt_int64,
pt_uint8, pt_uint16, pt_uint32, pt_uint64,
pt_float, pt_double, pt_long_double,
pt_u8string, pt_u16string, pt_u32string,
pt_null
};
constexpr const char* primitive_type_names[] =
{
"pt_int8", "pt_int16", "pt_int32", "pt_int64",
"pt_uint8", "pt_uint16", "pt_uint32", "pt_uint64",
"pt_float", "pt_double", "pt_long_double",
"pt_u8string", "pt_u16string", "pt_u32string",
"pt_null"
};
constexpr const char* primitive_type_name(primitive_type ptype)
{
return primitive_type_names[static_cast<int>(ptype)];
}
// achieves static call dispatch (Int-To-Type idiom)
template<primitive_type FT>
struct pt_token { static const primitive_type value = FT; };
// maps the fundamental_type FT to the corresponding type
template<primitive_type FT>
struct ptype_to_type
: if_else_type_c<FT == pt_int8, std::int8_t,
if_else_type_c<FT == pt_int16, std::int16_t,
if_else_type_c<FT == pt_int32, std::int32_t,
if_else_type_c<FT == pt_int64, std::int64_t,
if_else_type_c<FT == pt_uint8, std::uint8_t,
if_else_type_c<FT == pt_uint16, std::uint16_t,
if_else_type_c<FT == pt_uint32, std::uint32_t,
if_else_type_c<FT == pt_uint64, std::uint64_t,
if_else_type_c<FT == pt_float, float,
if_else_type_c<FT == pt_double, double,
if_else_type_c<FT == pt_long_double, long double,
if_else_type_c<FT == pt_u8string, std::string,
if_else_type_c<FT == pt_u16string, std::u16string,
if_else_type_c<FT == pt_u32string, std::u32string,
wrapped_type<void> > > > > > > > > > > > > > >
{
};
// if (IfStmt == true) ptype = FT; else ptype = Else::ptype;
template<bool IfStmt, primitive_type FT, class Else>
struct if_else_ptype_c
{
static const primitive_type ptype = FT;
};
template<primitive_type FT, class Else>
struct if_else_ptype_c<false, FT, Else>
{
static const primitive_type ptype = Else::ptype;
};
// if (Stmt::value == true) ptype = FT; else ptype = Else::ptype;
template<class Stmt, primitive_type FT, class Else>
struct if_else_ptype : if_else_ptype_c<Stmt::value, FT, Else> { };
template<primitive_type FT>
struct wrapped_ptype { static const primitive_type ptype = FT; };
// maps type T the the corresponding fundamental_type
template<typename T>
struct type_to_ptype_impl
// signed integers
: if_else_ptype<std::is_same<T, std::int8_t>, pt_int8,
if_else_ptype<std::is_same<T, std::int16_t>, pt_int16,
if_else_ptype<std::is_same<T, std::int32_t>, pt_int32,
if_else_ptype<std::is_same<T, std::int64_t>, pt_int64,
if_else_ptype<std::is_same<T, std::uint8_t>, pt_uint8,
// unsigned integers
if_else_ptype<std::is_same<T, std::uint16_t>, pt_uint16,
if_else_ptype<std::is_same<T, std::uint32_t>, pt_uint32,
if_else_ptype<std::is_same<T, std::uint64_t>, pt_uint64,
// float / double
if_else_ptype<std::is_same<T, float>, pt_float,
if_else_ptype<std::is_same<T, double>, pt_double,
if_else_ptype<std::is_same<T, long double>, pt_long_double,
// strings
if_else_ptype<std::is_convertible<T, std::string>, pt_u8string,
if_else_ptype<std::is_convertible<T, std::u16string>, pt_u16string,
if_else_ptype<std::is_convertible<T, std::u32string>, pt_u32string,
wrapped_ptype<pt_null> > > > > > > > > > > > > > >
{
};
template<typename T>
struct type_to_ptype : type_to_ptype_impl<typename plain<T>::type> { };
template<typename T>
struct is_primitive
{
static const bool value = type_to_ptype<T>::ptype != pt_null;
};
template<typename T>
class is_iterable
{
template<class C>
static bool cmp_help_fun(C& arg0,
decltype((arg0.begin() == arg0.end()) &&
(*(++(arg0.begin())) == *(arg0.end())))*)
{
return true;
}
template<class C>
static void cmp_help_fun(C&, void*) { }
typedef decltype(cmp_help_fun(*static_cast<T*>(nullptr),
static_cast<bool*>(nullptr)))
result_type;
public:
static const bool value = is_primitive<T>::value == false
&& std::is_same<bool, result_type>::value;
};
template<typename T>
class has_push_back
{
template<class C>
static bool cmp_help_fun(C* arg0,
decltype(arg0->push_back(typename C::value_type()))*)
{
return true;
}
static void cmp_help_fun(void*, void*) { }
typedef decltype(cmp_help_fun(static_cast<T*>(nullptr),
static_cast<void*>(nullptr)))
result_type;
public:
static const bool value = is_iterable<T>::value
&& std::is_same<bool, result_type>::value;
};
template<typename T>
class has_insert
{
template<class C>
static bool cmp_help_fun(C* arg0,
decltype((arg0->insert(typename C::value_type())).second)*)
{
return true;
}
static void cmp_help_fun(void*, void*) { }
typedef decltype(cmp_help_fun(static_cast<T*>(nullptr),
static_cast<bool*>(nullptr)))
result_type;
public:
static const bool value = is_iterable<T>::value
&& std::is_same<bool, result_type>::value;
};
class pt_value;
template<typename T>
T pt_value_cast(pt_value&);
template<primitive_type FT>
typename ptype_to_type<FT>::type& pt_value_cast(pt_value&);
// Utility function for static call dispatching.
// Invokes pt_token<X>(), where X is the value of ptype.
// Does nothing if ptype == pt_null
template<typename Fun>
void pt_invoke(primitive_type ptype, Fun&& f)
{
switch (ptype)
{
case pt_int8: f(pt_token<pt_int8>()); break;
case pt_int16: f(pt_token<pt_int16>()); break;
case pt_int32: f(pt_token<pt_int32>()); break;
case pt_int64: f(pt_token<pt_int64>()); break;
case pt_uint8: f(pt_token<pt_uint8>()); break;
case pt_uint16: f(pt_token<pt_uint16>()); break;
case pt_uint32: f(pt_token<pt_uint32>()); break;
case pt_uint64: f(pt_token<pt_uint64>()); break;
case pt_float: f(pt_token<pt_float>()); break;
case pt_double: f(pt_token<pt_double>()); break;
case pt_long_double: f(pt_token<pt_long_double>()); break;
case pt_u8string: f(pt_token<pt_u8string>()); break;
case pt_u16string: f(pt_token<pt_u16string>()); break;
case pt_u32string: f(pt_token<pt_u32string>()); break;
default: break;
}
}
/**
* @brief Describes a value of a {@link primitive_type primitive data type}.
*/
class pt_value
{
template<typename T>
friend T pt_value_cast(pt_value&);
template<primitive_type PT>
friend typename ptype_to_type<PT>::type& pt_value_cast(pt_value&);
primitive_type m_ptype;
union
{
std::int8_t i8;
std::int16_t i16;
std::int32_t i32;
std::int64_t i64;
std::uint8_t u8;
std::uint16_t u16;
std::uint32_t u32;
std::uint64_t u64;
float fl;
double dbl;
long double ldbl;
std::string str8;
std::u16string str16;
std::u32string str32;
};
// use static call dispatching to select member variable
inline decltype(i8)& get(pt_token<pt_int8>) { return i8; }
inline decltype(i16)& get(pt_token<pt_int16>) { return i16; }
inline decltype(i32)& get(pt_token<pt_int32>) { return i32; }
inline decltype(i64)& get(pt_token<pt_int64>) { return i64; }
inline decltype(u8)& get(pt_token<pt_uint8>) { return u8; }
inline decltype(u16)& get(pt_token<pt_uint16>) { return u16; }
inline decltype(u32)& get(pt_token<pt_uint32>) { return u32; }
inline decltype(u64)& get(pt_token<pt_uint64>) { return u64; }
inline decltype(fl)& get(pt_token<pt_float>) { return fl; }
inline decltype(dbl)& get(pt_token<pt_double>) { return dbl; }
inline decltype(ldbl)& get(pt_token<pt_long_double>) { return ldbl; }
inline decltype(str8)& get(pt_token<pt_u8string>) { return str8; }
inline decltype(str16)& get(pt_token<pt_u16string>) { return str16; }
inline decltype(str32)& get(pt_token<pt_u32string>) { return str32; }
template<primitive_type FT, class T, class V>
static void set(primitive_type& lhs_type, T& lhs, V&& rhs,
typename disable_if< std::is_arithmetic<T> >::type* = 0)
{
if (FT == lhs_type)
{
lhs = std::forward<V>(rhs);
}
else
{
new (&lhs) T(std::forward<V>(rhs));
lhs_type = FT;
}
}
template<primitive_type FT, class T, class V>
static void set(primitive_type& lhs_type, T& lhs, V&& rhs,
typename enable_if<std::is_arithmetic<T>, int>::type* = 0)
{
// don't call a constructor for arithmetic types
lhs = rhs;
lhs_type = FT;
}
template<class T>
inline static void destroy(T&,
typename enable_if<std::is_arithmetic<T>, int>::type* = 0)
{
// arithmetic types don't need destruction
}
template<class T>
inline static void destroy(T& what,
typename disable_if< std::is_arithmetic<T> >::type* = 0)
{
what.~T();
}
struct destroyer
{
pt_value* m_self;
inline destroyer(pt_value* self) : m_self(self) { }
template<primitive_type FT>
inline void operator()(pt_token<FT> token) const
{
destroy(m_self->get(token));
}
};
struct initializer
{
pt_value* m_self;
inline initializer(pt_value* self) : m_self(self) { }
template<primitive_type FT>
inline void operator()(pt_token<FT> token) const
{
set<FT>(m_self->m_ptype,
m_self->get(token),
typename ptype_to_type<FT>::type());
}
};
struct setter
{
pt_value* m_self;
const pt_value& m_other;
inline setter(pt_value* self, const pt_value& other)
: m_self(self), m_other(other) { }
template<primitive_type FT>
inline void operator()(pt_token<FT> token) const
{
set<FT>(m_self->m_ptype,
m_self->get(token),
m_other.get(token));
}
};
struct mover
{
pt_value* m_self;
const pt_value& m_other;
inline mover(pt_value* self, const pt_value& other)
: m_self(self), m_other(other) { }
template<primitive_type FT>
inline void operator()(pt_token<FT> token) const
{
set<FT>(m_self->m_ptype,
m_self->get(token),
std::move(m_other.get(token)));
}
};
struct comparator
{
bool m_result;
const pt_value* m_self;
const pt_value& m_other;
inline comparator(const pt_value* self, const pt_value& other)
: m_result(false), m_self(self), m_other(other) { }
template<primitive_type FT>
inline void operator()(pt_token<FT> token)
{
if (m_other.m_ptype == FT)
{
m_result = (m_self->get(token) == m_other.get(token));
}
}
inline bool result() const { return m_result; }
};
template<class Self, typename Fun>
struct applier
{
Self* m_self;
Fun& m_f;
applier(Self* self, Fun& f) : m_self(self), m_f(f) { }
template<primitive_type FT>
inline void operator()(pt_token<FT> token)
{
m_f(m_self->get(token));
}
};
struct type_reader
{
const std::type_info* tinfo;
type_reader() : tinfo(nullptr) { }
template<primitive_type FT>
inline void operator()(pt_token<FT>)
{
tinfo = &typeid(typename ptype_to_type<FT>::type);
}
};
void destroy()
{
pt_invoke(m_ptype, destroyer(this));
m_ptype = pt_null;
}
public:
// get(...) const overload
template<primitive_type FT>
const typename ptype_to_type<FT>::type& get(pt_token<FT> token) const
{
return const_cast<pt_value*>(this)->get(token);
}
template<typename Fun>
void apply(Fun&& f)
{
pt_invoke(m_ptype, applier<pt_value, Fun>(this, f));
}
template<typename Fun>
void apply(Fun&& f) const
{
pt_invoke(m_ptype, applier<const pt_value, Fun>(this, f));
}
pt_value() : m_ptype(pt_null) { }
template<typename V>
pt_value(V&& value) : m_ptype(pt_null)
{
static_assert(type_to_ptype<V>::ptype != pt_null,
"V is not a primitive type");
set<type_to_ptype<V>::ptype>(m_ptype,
get(pt_token<type_to_ptype<V>::ptype>()),
std::forward<V>(value));
}
pt_value(primitive_type ptype) : m_ptype(pt_null)
{
pt_invoke(ptype, initializer(this));
}
pt_value(const pt_value& other) : m_ptype(pt_null)
{
//invoke(setter(other));
pt_invoke(other.m_ptype, setter(this, other));
}
pt_value(pt_value&& other) : m_ptype(pt_null)
{
//invoke(mover(other));
pt_invoke(other.m_ptype, mover(this, other));
}
pt_value& operator=(const pt_value& other)
{
//invoke(setter(other));
pt_invoke(other.m_ptype, setter(this, other));
return *this;
}
pt_value& operator=(pt_value&& other)
{
//invoke(mover(other));
pt_invoke(other.m_ptype, mover(this, other));
return *this;
}
bool operator==(const pt_value& other) const
{
comparator cmp(this, other);
pt_invoke(m_ptype, cmp);
return cmp.result();
}
inline bool operator!=(const pt_value& other) const
{
return !(*this == other);
}
inline primitive_type ptype() const { return m_ptype; }
const std::type_info& type() const
{
type_reader tr;
pt_invoke(m_ptype, tr);
return (tr.tinfo) ? *tr.tinfo : typeid(void);
}
~pt_value() { destroy(); }
};
template<typename T>
typename enable_if<is_primitive<T>, bool>::type
operator==(const T& lhs, const pt_value& rhs)
{
static constexpr primitive_type ptype = type_to_ptype<T>::ptype;
static_assert(ptype != pt_null, "T couldn't be mapped to an ptype");
return (rhs.ptype() == ptype) ? lhs == pt_value_cast<ptype>(rhs) : false;
}
template<typename T>
typename enable_if<is_primitive<T>, bool>::type
operator==(const pt_value& lhs, const T& rhs)
{
return (rhs == lhs);
}
template<typename T>
typename enable_if<is_primitive<T>, bool>::type
operator!=(const pt_value& lhs, const T& rhs)
{
return !(lhs == rhs);
}
template<typename T>
typename enable_if<is_primitive<T>, bool>::type
operator!=(const T& lhs, const pt_value& rhs)
{
return !(lhs == rhs);
}
template<primitive_type FT>
typename ptype_to_type<FT>::type& pt_value_cast(pt_value& v)
{
if (v.ptype() != FT) throw std::bad_cast();
return v.get(pt_token<FT>());
}
template<primitive_type FT>
const typename ptype_to_type<FT>::type& pt_value_cast(const pt_value& v)
{
if (v.ptype() != FT) throw std::bad_cast();
return v.get(pt_token<FT>());
}
template<typename T>
T pt_value_cast(pt_value& v)
{
static const primitive_type ptype = type_to_ptype<T>::ptype;
if (v.ptype() != ptype) throw std::bad_cast();
return v.get(pt_token<ptype>());
}
template<typename T>
T pt_value_cast(const pt_value& v)
{
typedef typename std::remove_reference<T>::type plain_t;
static_assert(!std::is_reference<T>::value || std::is_const<plain_t>::value,
"Could not get a non-const reference from const pt_value&");
static const primitive_type ptype = type_to_ptype<T>::ptype;
if (v.ptype() != ptype) throw std::bad_cast();
return v.get(pt_token<ptype>());
}
struct getter_setter_pair
{
std::function<pt_value (void*)> getter;
std::function<void (void*, pt_value&&)> setter;
getter_setter_pair(getter_setter_pair&&) = default;
getter_setter_pair(const getter_setter_pair&) = default;
template<class C, typename T>
getter_setter_pair(T C::*member_ptr)
{
getter = [=] (void* self) -> pt_value {
return *reinterpret_cast<C*>(self).*member_ptr;
};
setter = [=] (void* self, pt_value&& value) {
*reinterpret_cast<C*>(self).*member_ptr = std::move(pt_value_cast<T&>(value));
};
}
template<class C, typename GT, typename ST>
getter_setter_pair(GT (C::*get_memfn)() const, void (C::*set_memfn)(ST))
{
getter = [=] (void* self) -> pt_value {
return (*reinterpret_cast<C*>(self).*get_memfn)();
};
setter = [=] (void* self, pt_value&& value) {
(*reinterpret_cast<C*>(self).*set_memfn)(std::move(pt_value_cast<typename plain<ST>::type&>(value)));
};
}
};
class serializer
{
public:
virtual void begin_object(const std::string& type_name) = 0;
virtual void end_object() = 0;
virtual void begin_sequence(size_t size) = 0;
virtual void end_sequence() = 0;
/**
* @brief Writes a single value.
*/
virtual void write_value(const pt_value& value) = 0;
/**
* @brief Writes @p size values.
*/
virtual void write_tuple(size_t size, const pt_value* values) = 0;
};
class deserializer
{
public:
/**
* @brief Seeks the beginning of the next object and return its type name.
*/
virtual std::string seek_object() = 0;
/**
* @brief Equal to {@link seek_object()} but doesn't
* modify the internal in-stream position.
*/
virtual std::string peek_object() = 0;
virtual void begin_object(const std::string& type_name) = 0;
virtual void end_object() = 0;
virtual size_t begin_sequence() = 0;
virtual void end_sequence() = 0;
virtual pt_value read_value(primitive_type ptype) = 0;
virtual void read_tuple(size_t size,
const primitive_type* ptypes,
pt_value* storage ) = 0;
};
class meta_type
{
public:
virtual ~meta_type() { }
/**
* @brief Creates an instance of this type, initialized
* with the default constructor.
*/
virtual void* new_instance() const = 0;
/**
* @brief Cast @p instance to the native type and delete it.
*/
virtual void delete_instance(void* instance) const = 0;
/**
* @brief Serializes @p instance to @p sink.
*/
virtual void serialize(const void* instance, serializer* sink) const = 0;
/**
* @brief Deserializes @p instance from @p source.
*/
virtual void deserialize(void* instance, deserializer* source) const = 0;
};
std::map<std::string, meta_type*> s_meta_types;
class root_object
{
public:
/**
* @brief Deserializes a new object from @p source and returns the
* new (deserialized) instance with its meta_type.
*/
std::pair<void*, meta_type*> deserialize(deserializer* source) const
{
void* result;
std::string tname = source->peek_object();
auto i = s_meta_types.find(tname);
if (i == s_meta_types.end())
{
throw std::logic_error("no meta object found for " + tname);
}
auto mobj = i->second;
if (mobj == nullptr)
{
throw std::logic_error("mobj == nullptr");
}
result = mobj->new_instance();
if (result == nullptr)
{
throw std::logic_error("result == nullptr");
}
try
{
mobj->deserialize(result, source);
}
catch (...)
{
mobj->delete_instance(result);
return { nullptr, nullptr };
}
return { result, mobj };
}
};
/**
* @brief {@link meta_type} implementation for primitive data types.
*/
template<typename T>
class primitive_member : public meta_type
{
static constexpr primitive_type ptype = type_to_ptype<T>::ptype;
static_assert(ptype != pt_null, "T is not a primitive type");
public:
void* new_instance() const
{
return new T();
}
void delete_instance(void* ptr) const
{
delete reinterpret_cast<T*>(ptr);
}
void serialize(const void* obj, serializer* s) const
{
s->write_value(*reinterpret_cast<const T*>(obj));
}
void deserialize(void* obj, deserializer* d) const
{
pt_value val(d->read_value(ptype));
*reinterpret_cast<T*>(obj) = std::move(pt_value_cast<T&>(val));
}
};
/**
* @brief {@link meta_type} implementation for STL compliant
* lists (such as std::vector and std::list).
*
* This implementation requires a primitive List::value_type.
*/
template<typename List>
class list_member : public meta_type
{
typedef typename List::value_type value_type;
static constexpr primitive_type vptype = type_to_ptype<value_type>::ptype;
static_assert(vptype != pt_null,
"List::value_type is not a primitive data type");
public:
void serialize(const void* obj, serializer* s) const
{
auto& ls = *reinterpret_cast<const List*>(obj);
s->begin_sequence(ls.size());
for (const auto& val : ls)
{
s->write_value(val);
}
s->end_sequence();
}
void deserialize(void* obj, 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)
{
pt_value val = d->read_value(vptype);
ls.push_back(std::move(pt_value_cast<value_type&>(val)));
}
d->end_sequence();
}
void* new_instance() const
{
return new List();
}
void delete_instance(void* ptr) const
{
delete reinterpret_cast<List*>(ptr);
}
};
/**
* @brief {@link meta_type} implementation for std::pair.
*/
template<typename T1, typename T2>
class pair_member : public meta_type
{
static constexpr primitive_type ptype1 = type_to_ptype<T1>::ptype;
static constexpr primitive_type ptype2 = type_to_ptype<T2>::ptype;
static_assert(ptype1 != pt_null, "T1 is not a primitive type");
static_assert(ptype2 != pt_null, "T2 is not a primitive type");
typedef std::pair<T1, T2> pair_type;
public:
void serialize(const void* obj, serializer* s) const
{
auto& p = *reinterpret_cast<const pair_type*>(obj);
pt_value values[2] = { p.first, p.second };
s->write_tuple(2, values);
}
void deserialize(void* obj, deserializer* d) const
{
primitive_type ptypes[2] = { ptype1, ptype2 };
pt_value values[2];
d->read_tuple(2, ptypes, values);
auto& p = *reinterpret_cast<pair_type*>(obj);
p.first = std::move(pt_value_cast<T1&>(values[0]));
p.second = std::move(pt_value_cast<T2&>(values[1]));
}
void* new_instance() const
{
return new pair_type();
}
void delete_instance(void* ptr) const
{
delete reinterpret_cast<pair_type*>(ptr);
}
};
// matches value_type of std::set
template<typename T>
struct meta_value_type
{
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));
}
};
// matches value_type of std::map
template<typename T1, typename T2>
struct meta_value_type<std::pair<const T1, T2>>
{
pair_member<T1, T2> impl;
void serialize_value(const std::pair<const T1, T2>& what, serializer* s) const
{
std::pair<T1, T2> 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;
impl.deserialize(&p, d);
std::pair<const T1, T2> v(std::move(p.first), std::move(p.second));
map.insert(std::move(v));
}
};
/**
* @brief {@link meta_type} implementation for STL compliant
* maps (such as std::map and std::set).
*
* This implementation requires primitive key and value types
* (or a pair of primitive types as value type).
*/
template<typename Map>
class map_member : public meta_type
{
typedef typename Map::key_type key_type;
typedef typename Map::value_type value_type;
meta_value_type<value_type> m_value_type_meta;
public:
#include "cppa/primitive_type.hpp"
#include "cppa/primitive_variant.hpp"
#include "cppa/binary_serializer.hpp"
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_value_type_meta.serialize_value(val, s);
}
s->end_sequence();
}
void deserialize(void* obj, deserializer* d) const
{
auto& mp = *reinterpret_cast<Map*>(obj);
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);
}
d->end_sequence();
}
void* new_instance() const
{
return new Map();
}
void delete_instance(void* ptr) const
{
delete reinterpret_cast<Map*>(ptr);
}
};
/**
* @brief {@link meta_type} implementation for user-defined structs.
*/
template<class Struct>
class meta_struct : public meta_type
{
template<typename T>
struct is_invalid
{
static const bool value = !is_primitive<T>::value
&& !has_push_back<T>::value
&& !has_insert<T>::value;
};
class member
{
meta_type* m_meta;
std::function<void (const meta_type*,
const void*,
serializer* )> m_serialize;
std::function<void (const meta_type*,
void*,
deserializer* )> m_deserialize;
member(const member&) = delete;
member& operator=(const member&) = delete;
void swap(member& other)
{
std::swap(m_meta, other.m_meta);
std::swap(m_serialize, other.m_serialize);
std::swap(m_deserialize, other.m_deserialize);
}
template<typename S, class D>
member(meta_type* mtptr, S&& s, D&& d)
: m_meta(mtptr)
, m_serialize(std::forward<S>(s))
, m_deserialize(std::forward<D>(d))
{
}
public:
template<typename T, class C>
member(meta_type* mtptr, T C::*mem_ptr) : m_meta(mtptr)
{
m_serialize = [mem_ptr] (const meta_type* mt,
const void* obj,
serializer* s)
{
mt->serialize(&(*reinterpret_cast<const C*>(obj).*mem_ptr), s);
};
m_deserialize = [mem_ptr] (const meta_type* mt,
void* obj,
deserializer* d)
{
mt->deserialize(&(*reinterpret_cast<C*>(obj).*mem_ptr), d);
};
}
member(member&& other) : m_meta(nullptr)
{
swap(other);
}
// a member that's not a member at all, but "forwards"
// the 'self' pointer to make use *_member implementations
static member fake_member(meta_type* mtptr)
{
return {
mtptr,
[] (const meta_type* mt, const void* obj, serializer* s)
{
mt->serialize(obj, s);
},
[] (const meta_type* mt, void* obj, deserializer* d)
{
mt->deserialize(obj, d);
}
};
}
~member()
{
delete m_meta;
}
member& operator=(member&& other)
{
swap(other);
return *this;
}
inline void serialize(const void* parent, serializer* s) const
{
m_serialize(m_meta, parent, s);
}
inline void deserialize(void* parent, deserializer* d) const
{
m_deserialize(m_meta, parent, d);
}
};
std::string class_name;
std::vector<member> m_members;
// terminates recursion
inline void push_back() { }
// pr.first = member pointer
// pr.second = meta object to handle pr.first
template<typename T, class C, typename... Args>
void push_back(std::pair<T C::*, meta_struct<T>*> pr, const Args&... args)
{
m_members.push_back({ pr.second, pr.first });
push_back(args...);
}
template<class C, typename T, typename... Args>
typename enable_if<is_primitive<T> >::type
push_back(T C::*mem_ptr, const Args&... args)
{
m_members.push_back({ new primitive_member<T>(), mem_ptr });
push_back(args...);
}
template<class C, typename T, typename... Args>
typename enable_if<has_push_back<T> >::type
push_back(T C::*mem_ptr, const Args&... args)
{
m_members.push_back({ new list_member<T>(), mem_ptr });
push_back(args...);
}
template<class C, typename T, typename... Args>
typename enable_if<has_insert<T> >::type
push_back(T C::*mem_ptr, const Args&... args)
{
m_members.push_back({ new map_member<T>(), mem_ptr });
push_back(args...);
}
template<class C, typename T, typename... Args>
typename enable_if<is_invalid<T>>::type
push_back(T C::*mem_ptr, const Args&... args)
{
static_assert(is_primitive<T>::value,
"T is neither a primitive type nor a list nor a map");
}
template<typename T>
void init_(typename enable_if<is_primitive<T>>::type* = nullptr)
{
m_members.push_back(member::fake_member(new primitive_member<T>()));
}
template<typename T>
void init_(typename disable_if<is_primitive<T>>::type* = nullptr)
{
static_assert(is_primitive<T>::value,
"T is neither a primitive type nor a list nor a map");
}
public:
template<typename... Args>
meta_struct(const Args&... args)
: class_name(cppa::detail::to_uniform_name(typeid(Struct)))
{
push_back(args...);
}
meta_struct() : class_name(cppa::detail::to_uniform_name(typeid(Struct)))
{
init_<Struct>();
}
void serialize(const void* obj, serializer* s) const
{
s->begin_object(class_name);
for (auto& m : m_members)
{
m.serialize(obj, s);
}
s->end_object();
}
#include "cppa/util/apply.hpp"
#include "cppa/util/pt_token.hpp"
#include "cppa/util/enable_if.hpp"
#include "cppa/util/disable_if.hpp"
#include "cppa/util/if_else_type.hpp"
#include "cppa/util/wrapped_type.hpp"
#include "cppa/util/is_primitive.hpp"
#include "cppa/util/is_iterable.hpp"
void deserialize(void* obj, deserializer* d) const
{
std::string cname = d->seek_object();
if (cname != class_name)
{
throw std::logic_error("wrong type name found");
}
d->begin_object(class_name);
for (auto& m : m_members)
{
m.deserialize(obj, d);
}
d->end_object();
}
#include "cppa/detail/type_to_ptype.hpp"
#include "cppa/detail/ptype_to_type.hpp"
#include "cppa/detail/default_uniform_type_info_impl.hpp"
void* new_instance() const
{
return new Struct();
}
using std::cout;
using std::cerr;
using std::endl;
void delete_instance(void* ptr) const
{
delete reinterpret_cast<Struct*>(ptr);
}
using namespace cppa;
using namespace cppa::util;
};
using cppa::detail::type_to_ptype;
using cppa::detail::ptype_to_type;
struct struct_a
{
......@@ -1340,18 +171,18 @@ class string_serializer : public serializer
out << (m_after_value ? " }" : "}");
}
void write_value(const pt_value& value)
void write_value(const primitive_variant& value)
{
clear();
value.apply(pt_writer(out));
m_after_value = true;
}
void write_tuple(size_t size, const pt_value* values)
void write_tuple(size_t size, const primitive_variant* values)
{
clear();
out << " {";
const pt_value* end = values + size;
const primitive_variant* end = values + size;
for ( ; values != end; ++values)
{
write_value(*values);
......@@ -1439,105 +270,10 @@ class xml_serializer : public serializer
};
*/
class binary_serializer : public serializer
{
typedef char* buf_type;
buf_type m_buf;
size_t m_wr_pos;
template<typename T>
void write(const T& value)
{
memcpy(m_buf + m_wr_pos, &value, sizeof(T));
m_wr_pos += sizeof(T);
}
void write(const std::string& str)
{
write(static_cast<std::uint32_t>(str.size()));
memcpy(m_buf + m_wr_pos, str.c_str(), str.size());
m_wr_pos += str.size();
}
void write(const std::u16string& str)
{
write(static_cast<std::uint32_t>(str.size()));
for (char16_t c : str)
{
write(static_cast<std::uint16_t>(c));
}
}
void write(const std::u32string& str)
{
write(static_cast<std::uint32_t>(str.size()));
for (char32_t c : str)
{
write(static_cast<std::uint32_t>(c));
}
}
struct pt_writer
{
binary_serializer* self;
inline pt_writer(binary_serializer* mself) : self(mself) { }
template<typename T>
inline void operator()(const T& value)
{
self->write(value);
}
};
public:
binary_serializer(char* buf) : m_buf(buf), m_wr_pos(0) { }
void begin_object(const std::string& tname)
{
write(tname);
}
void end_object()
{
}
void begin_sequence(size_t list_size)
{
write(static_cast<std::uint32_t>(list_size));
}
void end_sequence()
{
}
void write_value(const pt_value& value)
{
value.apply(pt_writer(this));
}
void write_tuple(size_t size, const pt_value* values)
{
const pt_value* end = values + size;
for ( ; values != end; ++values)
{
write_value(*values);
}
}
};
class binary_deserializer : public deserializer
{
typedef char* buf_type;
buf_type m_buf;
const char* m_buf;
size_t m_rd_pos;
size_t m_buf_size;
......@@ -1561,7 +297,7 @@ class binary_deserializer : public deserializer
{
std::uint32_t str_size;
read(str_size, modify_rd_pos);
char* cpy_begin;
const char* cpy_begin;
if (modify_rd_pos)
{
range_check(str_size);
......@@ -1574,7 +310,7 @@ class binary_deserializer : public deserializer
}
str.clear();
str.reserve(str_size);
char* cpy_end = cpy_begin + str_size;
const char* cpy_end = cpy_begin + str_size;
std::copy(cpy_begin, cpy_end, std::back_inserter(str));
if (modify_rd_pos) m_rd_pos += str_size;
}
......@@ -1620,7 +356,7 @@ class binary_deserializer : public deserializer
public:
binary_deserializer(buf_type buf, size_t buf_size)
binary_deserializer(const char* buf, size_t buf_size)
: m_buf(buf), m_rd_pos(0), m_buf_size(buf_size)
{
}
......@@ -1658,16 +394,16 @@ class binary_deserializer : public deserializer
{
}
pt_value read_value(primitive_type ptype)
primitive_variant read_value(primitive_type ptype)
{
pt_value val(ptype);
primitive_variant val(ptype);
val.apply(pt_reader(this));
return val;
}
void read_tuple(size_t size,
const primitive_type* ptypes,
pt_value* storage)
primitive_variant* storage)
{
const primitive_type* end = ptypes + size;
for ( ; ptypes != end; ++ptypes)
......@@ -1819,7 +555,7 @@ class string_deserializer : public deserializer
void operator()(std::u32string&) { }
};
pt_value read_value(primitive_type ptype)
primitive_variant read_value(primitive_type ptype)
{
skip_space_and_comma();
auto substr_end = std::find_if(m_pos, m_str.end(), [] (char c) -> bool {
......@@ -1833,7 +569,7 @@ class string_deserializer : public deserializer
}
});
std::string substr(m_pos, substr_end);
pt_value result(ptype);
primitive_variant result(ptype);
result.apply(from_string(substr));
m_pos += substr.size();
return result;
......@@ -1841,7 +577,7 @@ class string_deserializer : public deserializer
void foo() {}
void read_tuple(size_t size, const primitive_type* begin, pt_value* storage)
void read_tuple(size_t size, const primitive_type* begin, primitive_variant* storage)
{
consume('{');
const primitive_type* end = begin + size;
......@@ -1855,29 +591,128 @@ class string_deserializer : public deserializer
};
std::string to_string(void* what, meta_type* mobj)
std::map<std::string, std::unique_ptr<uniform_type_info> > s_types;
void announce(uniform_type_info* utype)
{
const auto& uname = utype->name();
if (s_types.count(uname) == 0)
{
std::unique_ptr<uniform_type_info> uptr(utype);
s_types.insert(std::make_pair(uname, std::move(uptr)));
}
else
{
cerr << utype->name() << " already announced" << endl;
delete utype;
}
}
uniform_type_info* get_meta_type(const std::string& tname)
{
auto i = s_types.find(tname);
return (i != s_types.end()) ? i->second.get() : nullptr;
}
uniform_type_info* get_meta_type(const std::type_info& tinfo)
{
return get_meta_type(detail::to_uniform_name(tinfo));
}
template<typename T>
uniform_type_info* get_meta_type()
{
return get_meta_type(detail::to_uniform_name(typeid(T)));
}
template<int>
inline void _announce_all() { }
template<int, typename T0, typename... Tn>
inline void _announce_all()
{
announce(new detail::default_uniform_type_info_impl<T0>);
_announce_all<0, Tn...>();
}
template<typename... Tn>
void announce_all()
{
_announce_all<0, Tn...>();
}
namespace {
class root_object_type
{
public:
root_object_type()
{
announce_all<std::int8_t, std::int16_t, std::int32_t, std::int64_t,
std::uint8_t, std::uint16_t, std::uint32_t, std::uint64_t,
float, double, long double,
std::string, std::u16string, std::u32string>();
}
template<typename T>
void serialize(const T& what, serializer* where) const
{
uniform_type_info* mtype = get_meta_type(detail::to_uniform_name(typeid(T)));
if (!mtype)
{
throw std::logic_error("no meta found for "
+ cppa::detail::to_uniform_name(typeid(T)));
}
mtype->serialize(&what, where);
}
/**
* @brief Deserializes a new object from @p source and returns the
* new (deserialized) instance with its meta_type.
*/
object deserialize(deserializer* source) const
{
std::string tname = source->peek_object();
uniform_type_info* mtype = get_meta_type(tname);
if (!mtype)
{
throw std::logic_error("no meta object found for " + tname);
}
return mtype->deserialize(source);
}
}
root_object;
} // namespace <anonymous>
template<typename T>
std::string to_string(const T& what)
{
std::string tname = detail::to_uniform_name(typeid(T));
auto mobj = get_meta_type(tname);
if (!mobj) throw std::logic_error(tname + " not found");
std::ostringstream osstr;
string_serializer strs(osstr);
mobj->serialize(what, &strs);
mobj->serialize(&what, &strs);
return osstr.str();
}
template<class C, class Parent, typename... Args>
std::pair<C Parent::*, meta_struct<C>*>
compound_member(C Parent::*c_ptr, const Args&... args)
template<typename T, typename... Args>
uniform_type_info* meta_object(const Args&... args)
{
return std::make_pair(c_ptr, new meta_struct<C>(args...));
return new detail::default_uniform_type_info_impl<T>(args...);
}
template<class C, typename... Args>
meta_type* meta_object(const Args&... args)
template<class C, class Parent, typename... Args>
std::pair<C Parent::*, uniform_type_info_base<C>*>
compound_member(C Parent::*c_ptr, const Args&... args)
{
return new meta_struct<C>(args...);
return std::make_pair(c_ptr, meta_object<C>(args...));
}
std::size_t test__serialization()
{
CPPA_TEST(test__serialization);
......@@ -1887,35 +722,29 @@ std::size_t test__serialization()
CPPA_CHECK_EQUAL((is_iterable<std::string>::value), false);
CPPA_CHECK_EQUAL((is_iterable<std::list<int>>::value), true);
CPPA_CHECK_EQUAL((is_iterable<std::map<int,int>>::value), true);
// test pt_value implementation
{
pt_value v1(42);
pt_value v2(42);
CPPA_CHECK_EQUAL(v1, v2);
CPPA_CHECK_EQUAL(v1, 42);
CPPA_CHECK_EQUAL(42, v2);
// type mismatch => unequal
CPPA_CHECK(v2 != static_cast<std::int8_t>(42));
}
root_object root;
// test meta_struct implementation for primitive types
// test meta_object implementation for primitive types
{
meta_struct<std::uint32_t> meta_int;
auto i = meta_int.new_instance();
auto str = to_string(i, &meta_int);
meta_int.delete_instance(i);
cout << "str: " << str << endl;
auto meta_int = get_meta_type<std::uint32_t>();
CPPA_CHECK(meta_int != nullptr);
if (meta_int)
{
/*
auto o = meta_int->create();
auto str = to_string(*i);
CPPA_CHECK_EQUAL(*i, 0);
CPPA_CHECK_EQUAL(str, "@u32 ( 0 )");
meta_int->delete_instance(i);
*/
}
}
// test serializers / deserializers with struct_b
{
// get meta object for struct_b
auto meta_b = meta_object<struct_b>(compound_member(&struct_b::a,
&struct_a::x,
&struct_a::y),
&struct_b::z,
&struct_b::ints);
// "announce" meta types
s_meta_types["struct_b"] = meta_b;
announce(meta_object<struct_b>(compound_member(&struct_b::a,
&struct_a::x,
&struct_a::y),
&struct_b::z,
&struct_b::ints));
// testees
struct_b b1 = { { 1, 2 }, 3, { 4, 5, 6, 7, 8, 9, 10 } };
struct_b b2;
......@@ -1924,70 +753,56 @@ std::size_t test__serialization()
auto b1str = "struct_b ( struct_a ( 1, 2 ), 3, "
"{ 4, 5, 6, 7, 8, 9, 10 } )";
// verify
CPPA_CHECK_EQUAL((to_string(&b1, meta_b)), b1str);
CPPA_CHECK_EQUAL((to_string(b1)), b1str);
// binary buffer
char buf[512];
// serialize b1 to buf
{
binary_serializer bs(buf);
meta_b->serialize(&b1, &bs);
}
// deserialize b2 from buf
std::pair<size_t, char*> buf;
{
binary_deserializer bd(buf, 512);
auto res = root.deserialize(&bd);
CPPA_CHECK_EQUAL(res.second, meta_b);
if (res.second == meta_b)
{
b2 = *reinterpret_cast<struct_b*>(res.first);
}
res.second->delete_instance(res.first);
// serialize b1 to buf
binary_serializer bs;
root_object.serialize(b1, &bs);
// deserialize b2 from buf
binary_deserializer bd(bs.data(), bs.size());
object res = root_object.deserialize(&bd);
CPPA_CHECK_EQUAL(res.type().name(), "struct_b");
b2 = object_cast<const struct_b&>(res);
}
// cleanup
delete buf.second;
// verify result of serialization / deserialization
CPPA_CHECK_EQUAL(b1, b2);
CPPA_CHECK_EQUAL((to_string(&b2, meta_b)), b1str);
CPPA_CHECK_EQUAL(to_string(b2), b1str);
// deserialize b3 from string, using string_deserializer
{
string_deserializer strd(b1str);
auto res = root.deserialize(&strd);
CPPA_CHECK_EQUAL(res.second, meta_b);
if (res.second == meta_b)
{
b3 = *reinterpret_cast<struct_b*>(res.first);
}
res.second->delete_instance(res.first);
auto res = root_object.deserialize(&strd);
CPPA_CHECK_EQUAL(res.type().name(), "struct_b");
b3 = object_cast<const struct_b&>(res);
}
CPPA_CHECK_EQUAL(b1, b3);
// cleanup
s_meta_types.clear();
delete meta_b;
}
// test serializers / deserializers with struct_c
{
// get meta type of struct_c and "announce"
auto meta_c = meta_object<struct_c>(&struct_c::strings,&struct_c::ints);
s_meta_types["struct_c"] = meta_c;
announce(meta_object<struct_c>(&struct_c::strings,&struct_c::ints));
// testees
struct_c c1 = { { { "abc", u"cba" }, { "x", u"y" } }, { 9, 4, 5 } };
struct_c c2;
// binary buffer
char buf[512];
std::pair<size_t, char*> buf;
// serialize c1 to buf
{
binary_serializer bs(buf);
meta_c->serialize(&c1, &bs);
binary_serializer bs;
root_object.serialize(c1, &bs);
buf = bs.take_buffer();
}
// serialize c2 from buf
{
binary_deserializer bd(buf, 512);
auto res = root.deserialize(&bd);
CPPA_CHECK_EQUAL(res.second, meta_c);
if (res.second == meta_c)
{
c2 = *reinterpret_cast<struct_c*>(res.first);
}
res.second->delete_instance(res.first);
binary_deserializer bd(buf.second, buf.first);
auto res = root_object.deserialize(&bd);
CPPA_CHECK_EQUAL(res.type().name(), "struct_c");
c2 = object_cast<const struct_c&>(res);
}
delete buf.second;
// verify result of serialization / deserialization
CPPA_CHECK_EQUAL(c1, c2);
}
......
......@@ -14,52 +14,46 @@ using std::is_same;
using namespace cppa::util;
template <typename T, template <typename> class What>
struct apply
{
typedef typename What<T>::type type;
};
std::size_t test__type_list()
{
CPPA_TEST(test__type_list);
CPPA_TEST(test__type_list);
typedef apply<const int&, remove_const_reference>::type int_typedef;
typedef apply<const int&, remove_const_reference>::type int_typedef;
CPPA_CHECK((is_same<int, int_typedef>::value));
CPPA_CHECK((is_same<int, int_typedef>::value));
typedef type_list<int, float, std::string> l1;
typedef reverse_type_list<l1>::type r1;
typedef type_list<int, float, std::string> l1;
typedef reverse_type_list<l1>::type r1;
CPPA_CHECK((is_same<int, type_at<0, l1>::type>::value));
CPPA_CHECK((is_same<float, type_at<1, l1>::type>::value));
CPPA_CHECK((is_same<std::string, type_at<2, l1>::type>::value));
CPPA_CHECK((is_same<int, type_at<0, l1>::type>::value));
CPPA_CHECK((is_same<float, type_at<1, l1>::type>::value));
CPPA_CHECK((is_same<std::string, type_at<2, l1>::type>::value));
CPPA_CHECK_EQUAL(l1::type_list_size, 3);
CPPA_CHECK_EQUAL(l1::type_list_size, r1::type_list_size);
CPPA_CHECK((is_same<type_at<0, l1>::type, type_at<2, r1>::type>::value));
CPPA_CHECK((is_same<type_at<1, l1>::type, type_at<1, r1>::type>::value));
CPPA_CHECK((is_same<type_at<2, l1>::type, type_at<0, r1>::type>::value));
CPPA_CHECK_EQUAL(l1::type_list_size, 3);
CPPA_CHECK_EQUAL(l1::type_list_size, r1::type_list_size);
CPPA_CHECK((is_same<type_at<0, l1>::type, type_at<2, r1>::type>::value));
CPPA_CHECK((is_same<type_at<1, l1>::type, type_at<1, r1>::type>::value));
CPPA_CHECK((is_same<type_at<2, l1>::type, type_at<0, r1>::type>::value));
typedef concat_type_lists<type_list<int>, l1>::type l2;
typedef concat_type_lists<type_list<int>, l1>::type l2;
CPPA_CHECK((is_same<int, l2::head_type>::value));
CPPA_CHECK((is_same<l1, l2::tail_type>::value));
CPPA_CHECK((is_same<int, l2::head_type>::value));
CPPA_CHECK((is_same<l1, l2::tail_type>::value));
type_list<std::int32_t, float, char> ifc;
auto i = ifc.begin();
CPPA_CHECK((i != ifc.end()));
CPPA_CHECK(((*i)->name() == "@i32"));
++i;
CPPA_CHECK((i != ifc.end()));
CPPA_CHECK(((*i)->name() == "float"));
++i;
CPPA_CHECK((i != ifc.end()));
CPPA_CHECK(((*i)->name() == "@i8"));
++i;
CPPA_CHECK((i == ifc.end()));
type_list<std::int32_t, float, char> ifc;
auto i = ifc.begin();
CPPA_CHECK((i != ifc.end()));
CPPA_CHECK(((*i)->name() == "@i32"));
++i;
CPPA_CHECK((i != ifc.end()));
CPPA_CHECK(((*i)->name() == "float"));
++i;
CPPA_CHECK((i != ifc.end()));
CPPA_CHECK(((*i)->name() == "@i8"));
++i;
CPPA_CHECK((i == ifc.end()));
return CPPA_TEST_RESULT;
return CPPA_TEST_RESULT;
}
......@@ -29,13 +29,13 @@ namespace {
struct foo
{
int value;
explicit foo(int val = 0) : value(val) { }
int value;
explicit foo(int val = 0) : value(val) { }
};
bool operator==(const foo& lhs, const foo& rhs)
{
return lhs.value == rhs.value;
return lhs.value == rhs.value;
}
} // namespace <anonymous>
......@@ -44,26 +44,29 @@ using namespace cppa;
namespace {
static bool unused1 =
uniform_type_info::announce<foo>(
[] (serializer& s, const foo& f) {
s << f.value;
},
[] (deserializer& d, foo& f) {
d >> f.value;
},
[] (const foo& f) -> std::string {
std::ostringstream ostr;
ostr << f.value;
return ostr.str();
},
[] (const std::string& str) -> foo* {
std::istringstream istr(str);
int tmp;
istr >> tmp;
return new foo(tmp);
}
);
bool unused1 = true;
/*
bool unused1 =
uniform_type_info::announce<foo>(
[] (serializer& s, const foo& f) {
s << f.value;
},
[] (deserializer& d, foo& f) {
d >> f.value;
},
[] (const foo& f) -> std::string {
std::ostringstream ostr;
ostr << f.value;
return ostr.str();
},
[] (const std::string& str) -> foo* {
std::istringstream istr(str);
int tmp;
istr >> tmp;
return new foo(tmp);
}
);
*/
bool unused2 = false;// = uniform_type_info::announce(typeid(foo), new uti_impl<foo>);
bool unused3 = false;//= uniform_type_info::announce(typeid(foo), new uti_impl<foo>);
bool unused4 = false;//= uniform_type_info::announce(typeid(foo), new uti_impl<foo>);
......@@ -72,99 +75,92 @@ bool unused4 = false;//= uniform_type_info::announce(typeid(foo), new uti_impl<f
std::size_t test__uniform_type()
{
CPPA_TEST(test__uniform_type);
{
//bar.create_object();
object obj1 = uniform_typeid<foo>()->create();
object obj2(obj1);
CPPA_CHECK_EQUAL(obj1, obj2);
}
{
object wstr_obj1 = uniform_typeid<std::wstring>()->create();
object_cast<std::wstring&>(wstr_obj1) = L"hello wstring!";
object wstr_obj2 = uniform_typeid<std::wstring>()->from_string("hello wstring!");
CPPA_CHECK_EQUAL(wstr_obj1, wstr_obj2);
const object& obj2_ref = wstr_obj2;
CPPA_CHECK_EQUAL(object_cast<std::wstring&>(wstr_obj1),
object_cast<const std::wstring&>(obj2_ref));
// couldn't be converted to ASCII
object_cast<std::wstring&>(wstr_obj1) = L"hello wstring\x05D4";
std::string narrowed = wstr_obj1.to_string();
CPPA_CHECK_EQUAL(narrowed, "hello wstring?");
}
int successful_announces = (unused1 ? 1 : 0)
+ (unused2 ? 1 : 0)
+ (unused3 ? 1 : 0)
+ (unused4 ? 1 : 0);
CPPA_CHECK_EQUAL(successful_announces, 1);
// test foo_object implementation
CPPA_TEST(test__uniform_type);
/*
obj_ptr o = uniform_typeid<foo>()->create();
o->from_string("123");
CPPA_CHECK_EQUAL(o->to_string(), "123");
int val = reinterpret_cast<const foo*>(o->value())->value;
CPPA_CHECK_EQUAL(val, 123);
{
//bar.create_object();
object obj1 = uniform_typeid<foo>()->create();
object obj2(obj1);
CPPA_CHECK_EQUAL(obj1, obj2);
}
{
object wstr_obj1 = uniform_typeid<std::wstring>()->create();
object_cast<std::wstring&>(wstr_obj1) = L"hello wstring!";
object wstr_obj2 = uniform_typeid<std::wstring>()->from_string("hello wstring!");
CPPA_CHECK_EQUAL(wstr_obj1, wstr_obj2);
const object& obj2_ref = wstr_obj2;
CPPA_CHECK_EQUAL(object_cast<std::wstring&>(wstr_obj1),
object_cast<const std::wstring&>(obj2_ref));
// couldn't be converted to ASCII
object_cast<std::wstring&>(wstr_obj1) = L"hello wstring\x05D4";
std::string narrowed = wstr_obj1.to_string();
CPPA_CHECK_EQUAL(narrowed, "hello wstring?");
}
int successful_announces = (unused1 ? 1 : 0)
+ (unused2 ? 1 : 0)
+ (unused3 ? 1 : 0)
+ (unused4 ? 1 : 0);
CPPA_CHECK_EQUAL(successful_announces, 1);
// these types (and only those) are present if
// the uniform_type_info implementation is correct
std::set<std::string> expected =
{
"@_::foo", // name of <anonymous namespace>::foo
"@i8", "@i16", "@i32", "@i64", // signed integer names
"@u8", "@u16", "@u32", "@u64", // unsigned integer names
"@str", "@wstr", // strings
"float", "double", // floating points
"@0", // util::void_type
// default announced cppa types
"cppa::any_type",
"cppa::intrusive_ptr<cppa::actor>"
};
if (sizeof(double) != sizeof(long double))
{
// long double is only present if it's not an alias for double
expected.insert("long double");
}
// holds the type names we see at runtime
std::set<std::string> found;
// fetch all available type names
auto types = uniform_type_info::instances();
for (uniform_type_info* tinfo : types)
{
found.insert(tinfo->name());
}
// compare the two sets
CPPA_CHECK_EQUAL(expected.size(), found.size());
if (expected.size() == found.size())
{
bool expected_equals_found = std::equal(found.begin(),
found.end(),
expected.begin());
CPPA_CHECK(expected_equals_found);
if (!expected_equals_found)
{
cout << "found:" << endl;
for (const std::string& tname : found)
{
cout << " - " << tname << endl;
}
cout << "expected: " << endl;
for (const std::string& tname : expected)
{
cout << " - " << tname << endl;
}
}
}
*/
// these types (and only those) are present if
// the uniform_type_info implementation is correct
std::set<std::string> expected =
{
"@_::foo", // name of <anonymous namespace>::foo
"@i8", "@i16", "@i32", "@i64", // signed integer names
"@u8", "@u16", "@u32", "@u64", // unsigned integer names
"@str", "@wstr", // strings
"float", "double", // floating points
"@0", // util::void_type
// default announced cppa types
"cppa::any_type",
"cppa::intrusive_ptr<cppa::actor>"
};
if (sizeof(double) != sizeof(long double))
{
// long double is only present if it's not an alias for double
expected.insert("long double");
}
// holds the type names we see at runtime
std::set<std::string> found;
// fetch all available type names
auto types = uniform_type_info::instances();
for (uniform_type_info* tinfo : types)
{
found.insert(tinfo->name());
}
// compare the two sets
CPPA_CHECK_EQUAL(expected.size(), found.size());
if (expected.size() == found.size())
{
bool expected_equals_found = std::equal(found.begin(),
found.end(),
expected.begin());
CPPA_CHECK(expected_equals_found);
if (!expected_equals_found)
{
cout << "found:" << endl;
for (const std::string& tname : found)
{
cout << " - " << tname << endl;
}
cout << "expected: " << endl;
for (const std::string& tname : expected)
{
cout << " - " << tname << endl;
}
}
}
return CPPA_TEST_RESULT;
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