Commit 123e61f7 authored by neverlord's avatar neverlord

serialization tests

parent cc1a1fc6
...@@ -6,5 +6,6 @@ test ...@@ -6,5 +6,6 @@ test
*.png *.png
*.dat *.dat
queue_test queue_test
cppa.creator.user.1.3
8threads 8threads
4threads 4threads
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<qtcreator> <qtcreator>
<data> <data>
<variable>GenericProjectManager.GenericProject.Toolchain</variable> <variable>GenericProjectManager.GenericProject.Toolchain</variable>
<value type="QString"></value> <value type="QString">ProjectExplorer.ToolChain.Gcc:/opt/local/bin/g++-mp-4.6.x86-macos-generic-mach_o-64bit.</value>
</data> </data>
<data> <data>
<variable>ProjectExplorer.Project.ActiveTarget</variable> <variable>ProjectExplorer.Project.ActiveTarget</variable>
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
<value key="ProjectExplorer.Target.ActiveRunConfiguration" type="int">0</value> <value key="ProjectExplorer.Target.ActiveRunConfiguration" type="int">0</value>
<valuemap key="ProjectExplorer.Target.BuildConfiguration.0" type="QVariantMap"> <valuemap key="ProjectExplorer.Target.BuildConfiguration.0" type="QVariantMap">
<value key="GenericProjectManager.GenericBuildConfiguration.BuildDirectory" type="QString">/Users/neverlord/libcppa</value> <value key="GenericProjectManager.GenericBuildConfiguration.BuildDirectory" type="QString">/Users/neverlord/libcppa</value>
<value key="ProjectExplorer.BuildCOnfiguration.ToolChain" type="QString">INVALID</value> <value key="ProjectExplorer.BuildCOnfiguration.ToolChain" type="QString">ProjectExplorer.ToolChain.Gcc:/usr/bin/g++.x86-macos-generic-mach_o-64bit.</value>
<valuemap key="ProjectExplorer.BuildConfiguration.BuildStepList.0" type="QVariantMap"> <valuemap key="ProjectExplorer.BuildConfiguration.BuildStepList.0" type="QVariantMap">
<valuemap key="ProjectExplorer.BuildStepList.Step.0" type="QVariantMap"> <valuemap key="ProjectExplorer.BuildStepList.Step.0" type="QVariantMap">
<valuelist key="GenericProjectManager.GenericMakeStep.BuildTargets" type="QVariantList"> <valuelist key="GenericProjectManager.GenericMakeStep.BuildTargets" type="QVariantList">
...@@ -77,7 +77,7 @@ ...@@ -77,7 +77,7 @@
<valuemap key="ProjectExplorer.Target.DeployConfiguration.0" type="QVariantMap"> <valuemap key="ProjectExplorer.Target.DeployConfiguration.0" type="QVariantMap">
<valuemap key="ProjectExplorer.BuildConfiguration.BuildStepList.0" type="QVariantMap"> <valuemap key="ProjectExplorer.BuildConfiguration.BuildStepList.0" type="QVariantMap">
<value key="ProjectExplorer.BuildStepList.StepsCount" type="int">0</value> <value key="ProjectExplorer.BuildStepList.StepsCount" type="int">0</value>
<value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">Deployment</value> <value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">Deploy</value>
<value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Deploy</value> <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Deploy</value>
<value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">ProjectExplorer.BuildSteps.Deploy</value> <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap> </valuemap>
...@@ -115,7 +115,9 @@ ...@@ -115,7 +115,9 @@
<value key="ProjectExplorer.CustomExecutableRunConfiguration.BaseEnvironmentBase" type="int">2</value> <value key="ProjectExplorer.CustomExecutableRunConfiguration.BaseEnvironmentBase" type="int">2</value>
<value key="ProjectExplorer.CustomExecutableRunConfiguration.Executable" type="QString">/Users/neverlord/libcppa/test</value> <value key="ProjectExplorer.CustomExecutableRunConfiguration.Executable" type="QString">/Users/neverlord/libcppa/test</value>
<value key="ProjectExplorer.CustomExecutableRunConfiguration.UseTerminal" type="bool">false</value> <value key="ProjectExplorer.CustomExecutableRunConfiguration.UseTerminal" type="bool">false</value>
<valuelist key="ProjectExplorer.CustomExecutableRunConfiguration.UserEnvironmentChanges" type="QVariantList"/> <valuelist key="ProjectExplorer.CustomExecutableRunConfiguration.UserEnvironmentChanges" type="QVariantList">
<value type="QString">DYLD_LIBRARY_PATH=/Users/neverlord/libcppa</value>
</valuelist>
<value key="ProjectExplorer.CustomExecutableRunConfiguration.WorkingDirectory" type="QString">%{buildDir}</value> <value key="ProjectExplorer.CustomExecutableRunConfiguration.WorkingDirectory" type="QString">%{buildDir}</value>
<value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">Führe /Users/neverlord/libcppa/test aus</value> <value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">Führe /Users/neverlord/libcppa/test aus</value>
<value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">test</value> <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">test</value>
...@@ -133,7 +135,7 @@ ...@@ -133,7 +135,7 @@
</data> </data>
<data> <data>
<variable>ProjectExplorer.Project.Updater.EnvironmentId</variable> <variable>ProjectExplorer.Project.Updater.EnvironmentId</variable>
<value type="QString">{349f52bc-ac64-4a14-898f-d44d989b22a2}</value> <value type="QString">{07fcd197-092d-45a0-8500-3be614e6ae31}</value>
</data> </data>
<data> <data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable> <variable>ProjectExplorer.Project.Updater.FileVersion</variable>
......
...@@ -118,3 +118,6 @@ src/to_uniform_name.cpp ...@@ -118,3 +118,6 @@ src/to_uniform_name.cpp
cppa/detail/default_uniform_type_info_impl.hpp cppa/detail/default_uniform_type_info_impl.hpp
src/object.cpp src/object.cpp
cppa/util/comparable.hpp cppa/util/comparable.hpp
cppa/util/disable_if.hpp
cppa/util/if_else_type.hpp
cppa/util/wrapped_type.hpp
...@@ -47,311 +47,311 @@ uniform_type_info* uniform_typeid(const std::type_info& tinfo); ...@@ -47,311 +47,311 @@ uniform_type_info* uniform_typeid(const std::type_info& tinfo);
class uniform_type_info : cppa::util::comparable<uniform_type_info> class uniform_type_info : cppa::util::comparable<uniform_type_info>
{ {
friend class object; friend class object;
// needs access to by_type_info() // needs access to by_type_info()
template<typename T> template<typename T>
friend uniform_type_info* uniform_typeid(); friend uniform_type_info* uniform_typeid();
friend uniform_type_info* uniform_typeid(const std::type_info&); friend uniform_type_info* uniform_typeid(const std::type_info&);
public: public:
class identifier : cppa::util::comparable<identifier> class identifier : cppa::util::comparable<identifier>
{ {
friend class uniform_type_info; friend class uniform_type_info;
int m_value; int m_value;
identifier(int val) : m_value(val) { } identifier(int val) : m_value(val) { }
// enable copy and move constructors // enable copy and move constructors
identifier(identifier&&) = default; identifier(identifier&&) = default;
identifier(const identifier&) = default; identifier(const identifier&) = default;
// disable assignment operators // disable assignment operators
identifier& operator=(identifier&&) = delete; identifier& operator=(identifier&&) = delete;
identifier& operator=(const identifier&) = delete; identifier& operator=(const identifier&) = delete;
public: public:
// needed by cppa::detail::comparable<identifier> // needed by cppa::detail::comparable<identifier>
inline int compare(const identifier& other) const inline int compare(const identifier& other) const
{ {
return m_value - other.m_value; return m_value - other.m_value;
} }
}; };
private: private:
// unique identifier // unique identifier
identifier m_id; identifier m_id;
// uniform type name // uniform type name
std::string m_name; std::string m_name;
// disable copy and move constructors // disable copy and move constructors
uniform_type_info(uniform_type_info&&) = delete; uniform_type_info(uniform_type_info&&) = delete;
uniform_type_info(const uniform_type_info&) = delete; uniform_type_info(const uniform_type_info&) = delete;
// disable assignment operators // disable assignment operators
uniform_type_info& operator=(uniform_type_info&&) = delete; uniform_type_info& operator=(uniform_type_info&&) = delete;
uniform_type_info& operator=(const uniform_type_info&) = delete; uniform_type_info& operator=(const uniform_type_info&) = delete;
static uniform_type_info* by_type_info(const std::type_info& tinfo); static uniform_type_info* by_type_info(const std::type_info& tinfo);
protected: protected:
explicit uniform_type_info(const std::type_info& tinfo); explicit uniform_type_info(const std::type_info& tinfo);
public: public:
/** /**
* @brief Get instances by its uniform name. * @brief Get instance by uniform name.
* @param uniform_name The libCPPA internal name for a type. * @param uniform_name The libCPPA internal name for a type.
* @return The instance associated to @p uniform_name. * @return The instance associated to @p uniform_name.
*/ */
static uniform_type_info* by_uniform_name(const std::string& uniform_name); static uniform_type_info* by_uniform_name(const std::string& uniform_name);
/** /**
* @brief Get all instances. * @brief Get all instances.
* @return A vector with all known (announced) instances. * @return A vector with all known (announced) instances.
*/ */
static std::vector<uniform_type_info*> instances(); static std::vector<uniform_type_info*> instances();
virtual ~uniform_type_info(); virtual ~uniform_type_info();
/** /**
* @brief Get the internal libCPPA name for this type. * @brief Get the internal libCPPA name for this type.
* @return A string describing the libCPPA internal type name. * @return A string describing the libCPPA internal type name.
*/ */
inline const std::string& name() const { return m_name; } inline const std::string& name() const { return m_name; }
/** /**
* @brief Get the unique identifier of this instance. * @brief Get the unique identifier of this instance.
* @return The unique identifier of this instance. * @return The unique identifier of this instance.
*/ */
inline const identifier& id() const { return m_id; } inline const identifier& id() const { return m_id; }
// needed by cppa::detail::comparable<uniform_type_info> // needed by cppa::detail::comparable<uniform_type_info>
inline int compare(const uniform_type_info& other) const inline int compare(const uniform_type_info& other) const
{ {
return id().compare(other.id()); return id().compare(other.id());
} }
/** /**
* @brief Add a new type mapping to the libCPPA internal type system. * @brief Add a new type mapping to the libCPPA internal type system.
* @return <code>true</code> if @p uniform_type was added as known * @return <code>true</code> if @p uniform_type was added as known
* instance (mapped to @p plain_type); otherwise <code>false</code> * instance (mapped to @p plain_type); otherwise @c false
* is returned and @p uniform_type was deleted. * is returned and @p uniform_type was deleted.
*/ */
static bool announce(const std::type_info& plain_type, static bool announce(const std::type_info& plain_type,
uniform_type_info* uniform_type); uniform_type_info* uniform_type);
/** /**
* auto concept value_type<typename T> * auto concept value_type<typename T>
* { * {
* T(); * T();
* T(const T&); * T(const T&);
* bool operator==(const T&, const T&); * bool operator==(const T&, const T&);
* } * }
*/ */
template<typename T, template<typename T,
class SerializeFun, class DeserializeFun, class SerializeFun, class DeserializeFun,
class ToStringFun, class FromStringFun> class ToStringFun, class FromStringFun>
static bool announce(const SerializeFun& sf, const DeserializeFun& df, static bool announce(const SerializeFun& sf, const DeserializeFun& df,
const ToStringFun& ts, const FromStringFun& fs); const ToStringFun& ts, const FromStringFun& fs);
/** /**
* @brief Create an object of this type. * @brief Create an object of this type.
*/ */
virtual object create() const = 0; virtual object create() const = 0;
virtual object from_string(const std::string& str) const = 0; virtual object from_string(const std::string& str) const = 0;
protected: protected:
// needed to implement subclasses // needed to implement subclasses
inline void*& value_of(object& obj) const { return obj.m_value; } inline void*& value_of(object& obj) const { return obj.m_value; }
inline const void* value_of(const object& obj) const { return obj.m_value; } inline const void* value_of(const object& obj) const { return obj.m_value; }
// object creation // object creation
virtual object copy(const object& what) const = 0; virtual object copy(const object& what) const = 0;
// object modification // object modification
virtual void destroy(object& what) const = 0; virtual void destroy(object& what) const = 0;
virtual void deserialize(deserializer& d, object& what) const = 0; virtual void deserialize(deserializer& d, object& what) const = 0;
// object inspection // object inspection
virtual std::string to_string(const object& obj) const = 0; virtual std::string to_string(const object& obj) const = 0;
virtual bool equal(const object& lhs, const object& rhs) const = 0; virtual bool equal(const object& lhs, const object& rhs) const = 0;
virtual void serialize(serializer& s, const object& what) const = 0; virtual void serialize(serializer& s, const object& what) const = 0;
}; };
template<typename T> template<typename T>
uniform_type_info* uniform_typeid() uniform_type_info* uniform_typeid()
{ {
return uniform_type_info::by_type_info(typeid(T)); return uniform_type_info::by_type_info(typeid(T));
} }
template<typename T, template<typename T,
class SerializeFun, class DeserializeFun, class SerializeFun, class DeserializeFun,
class ToStringFun, class FromStringFun> class ToStringFun, class FromStringFun>
bool uniform_type_info::announce(const SerializeFun& sf, bool uniform_type_info::announce(const SerializeFun& sf,
const DeserializeFun& df, const DeserializeFun& df,
const ToStringFun& ts, const ToStringFun& ts,
const FromStringFun& fs) const FromStringFun& fs)
{ {
// check signature of SerializeFun::operator() // check signature of SerializeFun::operator()
typedef typedef
typename typename
util::callable_trait<decltype(&SerializeFun::operator())>::arg_types util::callable_trait<decltype(&SerializeFun::operator())>::arg_types
sf_args; sf_args;
// assert arg_types == { serializer&, const T& } || { serializer&, T } // assert arg_types == { serializer&, const T& } || { serializer&, T }
static_assert( static_assert(
util::disjunction< util::disjunction<
std::is_same<sf_args, util::type_list<serializer&, const T&>>, std::is_same<sf_args, util::type_list<serializer&, const T&>>,
std::is_same<sf_args, util::type_list<serializer&, T>> std::is_same<sf_args, util::type_list<serializer&, T>>
>::value, >::value,
"Invalid signature of &SerializeFun::operator()"); "Invalid signature of &SerializeFun::operator()");
// check signature of DeserializeFun::operator() // check signature of DeserializeFun::operator()
typedef typedef
typename typename
util::callable_trait<decltype(&DeserializeFun::operator())>::arg_types util::callable_trait<decltype(&DeserializeFun::operator())>::arg_types
df_args; df_args;
// assert arg_types == { deserializer&, T& } // assert arg_types == { deserializer&, T& }
static_assert( static_assert(
std::is_same<df_args, util::type_list<deserializer&, T&>>::value, std::is_same<df_args, util::type_list<deserializer&, T&>>::value,
"Invalid signature of &DeserializeFun::operator()"); "Invalid signature of &DeserializeFun::operator()");
// check signature of ToStringFun::operator() // check signature of ToStringFun::operator()
typedef util::callable_trait<decltype(&ToStringFun::operator())> ts_sig; typedef util::callable_trait<decltype(&ToStringFun::operator())> ts_sig;
typedef typename ts_sig::arg_types ts_args; typedef typename ts_sig::arg_types ts_args;
// assert result_type == std::string // assert result_type == std::string
static_assert( static_assert(
std::is_same<std::string, typename ts_sig::result_type>::value, std::is_same<std::string, typename ts_sig::result_type>::value,
"ToStringFun::operator() doesn't return a string"); "ToStringFun::operator() doesn't return a string");
// assert arg_types == { const T& } || { T } // assert arg_types == { const T& } || { T }
static_assert( static_assert(
util::disjunction< util::disjunction<
std::is_same<ts_args, util::type_list<const T&>>, std::is_same<ts_args, util::type_list<const T&>>,
std::is_same<ts_args, util::type_list<T>> std::is_same<ts_args, util::type_list<T>>
>::value, >::value,
"Invalid signature of &ToStringFun::operator()"); "Invalid signature of &ToStringFun::operator()");
// check signature of ToStringFun::operator() // check signature of ToStringFun::operator()
typedef util::callable_trait<decltype(&FromStringFun::operator())> fs_sig; typedef util::callable_trait<decltype(&FromStringFun::operator())> fs_sig;
typedef typename fs_sig::arg_types fs_args; typedef typename fs_sig::arg_types fs_args;
// assert result_type == T* // assert result_type == T*
static_assert( static_assert(
std::is_same<T*, typename fs_sig::result_type>::value, std::is_same<T*, typename fs_sig::result_type>::value,
"FromStringFun::operator() doesn't return T*"); "FromStringFun::operator() doesn't return T*");
// assert arg_types == { const std::string& } || { std::string } // assert arg_types == { const std::string& } || { std::string }
static_assert( static_assert(
util::disjunction< util::disjunction<
std::is_same<fs_args, util::type_list<const std::string&>>, std::is_same<fs_args, util::type_list<const std::string&>>,
std::is_same<fs_args, util::type_list<std::string>> std::is_same<fs_args, util::type_list<std::string>>
>::value, >::value,
"Invalid signature of &FromStringFun::operator()"); "Invalid signature of &FromStringFun::operator()");
// "on-the-fly" implementation of uniform_type_info // "on-the-fly" implementation of uniform_type_info
class utimpl : public uniform_type_info class utimpl : public uniform_type_info
{ {
SerializeFun m_serialize; SerializeFun m_serialize;
DeserializeFun m_deserialize; DeserializeFun m_deserialize;
ToStringFun m_to_string; ToStringFun m_to_string;
FromStringFun m_from_string; FromStringFun m_from_string;
inline T& to_ref(object& what) const inline T& to_ref(object& what) const
{ {
return *reinterpret_cast<T*>(this->value_of(what)); return *reinterpret_cast<T*>(this->value_of(what));
} }
inline const T& to_ref(const object& what) const inline const T& to_ref(const object& what) const
{ {
return *reinterpret_cast<const T*>(this->value_of(what)); return *reinterpret_cast<const T*>(this->value_of(what));
} }
protected: protected:
object copy(const object& what) const object copy(const object& what) const
{ {
return { new T(this->to_ref(what)), this }; return { new T(this->to_ref(what)), this };
} }
object from_string(const std::string& str) const object from_string(const std::string& str) const
{ {
return { m_from_string(str), this }; return { m_from_string(str), this };
} }
void destroy(object& what) const void destroy(object& what) const
{ {
delete reinterpret_cast<T*>(this->value_of(what)); delete reinterpret_cast<T*>(this->value_of(what));
this->value_of(what) = nullptr; this->value_of(what) = nullptr;
} }
void deserialize(deserializer& d, object& what) const void deserialize(deserializer& d, object& what) const
{ {
m_deserialize(d, to_ref(what)); m_deserialize(d, to_ref(what));
} }
std::string to_string(const object& obj) const std::string to_string(const object& obj) const
{ {
return m_to_string(to_ref(obj)); return m_to_string(to_ref(obj));
} }
bool equal(const object& lhs, const object& rhs) const bool equal(const object& lhs, const object& rhs) const
{ {
return (lhs.type() == *this && rhs.type() == *this) return (lhs.type() == *this && rhs.type() == *this)
? to_ref(lhs) == to_ref(rhs) ? to_ref(lhs) == to_ref(rhs)
: false; : false;
} }
void serialize(serializer& s, const object& what) const void serialize(serializer& s, const object& what) const
{ {
m_serialize(s, to_ref(what)); m_serialize(s, to_ref(what));
} }
public: public:
utimpl(const SerializeFun& sfun, const DeserializeFun dfun, utimpl(const SerializeFun& sfun, const DeserializeFun dfun,
const ToStringFun tfun, const FromStringFun ffun) const ToStringFun tfun, const FromStringFun ffun)
: uniform_type_info(typeid(T)) : uniform_type_info(typeid(T))
, m_serialize(sfun), m_deserialize(dfun) , m_serialize(sfun), m_deserialize(dfun)
, m_to_string(tfun), m_from_string(ffun) , m_to_string(tfun), m_from_string(ffun)
{ {
} }
object create() const object create() const
{ {
return { new T, this }; return { new T, this };
} }
}; };
return announce(typeid(T), new utimpl(sf, df, ts, fs)); return announce(typeid(T), new utimpl(sf, df, ts, fs));
} }
bool operator==(const uniform_type_info& lhs, const std::type_info& rhs); 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) inline bool operator!=(const uniform_type_info& lhs, const std::type_info& rhs)
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
inline bool operator==(const std::type_info& lhs, const uniform_type_info& rhs) inline bool operator==(const std::type_info& lhs, const uniform_type_info& rhs)
{ {
return rhs == lhs; return rhs == lhs;
} }
inline bool operator!=(const std::type_info& lhs, const uniform_type_info& rhs) inline bool operator!=(const std::type_info& lhs, const uniform_type_info& rhs)
{ {
return !(rhs == lhs); return !(rhs == lhs);
} }
} // namespace cppa } // namespace cppa
......
#ifndef DISABLE_IF_HPP
#define DISABLE_IF_HPP
namespace cppa { namespace util {
template<bool Stmt, typename T>
struct disable_if_c { };
template<typename T>
struct disable_if_c<false, T>
{
typedef T type;
};
template<class Trait, typename T = void>
struct disable_if : disable_if_c<Trait::value, T>
{
};
} } // namespace cppa::util
#endif // DISABLE_IF_HPP
...@@ -4,12 +4,14 @@ ...@@ -4,12 +4,14 @@
namespace cppa { namespace util { namespace cppa { namespace util {
template<bool Stmt, typename T = void> template<bool Stmt, typename T = void>
struct enable_if_c { }; struct enable_if_c
{
};
template<typename T> template<typename T>
struct enable_if_c<true, T> struct enable_if_c<true, T>
{ {
typedef T type; typedef T type;
}; };
template<class Trait, typename T = void> template<class Trait, typename T = void>
......
#ifndef IF_ELSE_TYPE_HPP
#define IF_ELSE_TYPE_HPP
#include "cppa/util/wrapped_type.hpp"
namespace cppa { namespace util {
// if (IfStmt == true) type = T; else type = Else::type;
template<bool IfStmt, typename T, class Else>
struct if_else_type_c
{
typedef T type;
};
template<typename T, class Else>
struct if_else_type_c<false, T, Else>
{
typedef typename Else::type type;
};
// if (Stmt::value == true) type = T; else type = Else::type;
template<class Stmt, typename T, class Else>
struct if_else_type : if_else_type_c<Stmt::value, T, Else> { };
} } // namespace cppa::util
#endif // IF_ELSE_TYPE_HPP
#ifndef WRAPPED_TYPE_HPP
#define WRAPPED_TYPE_HPP
namespace cppa { namespace util {
template<typename T>
struct wrapped_type { typedef T type; };
} } // namespace cppa::util
#endif // WRAPPED_TYPE_HPP
...@@ -7,11 +7,15 @@ ...@@ -7,11 +7,15 @@
#include <cstring> #include <cstring>
#include <sstream> #include <sstream>
#include <cstdint> #include <cstdint>
#include <cstring>
#include <cassert>
#include <iterator>
#include <typeinfo> #include <typeinfo>
#include <iostream> #include <iostream>
#include <stdexcept>
#include <algorithm> #include <algorithm>
#include <functional>
#include <type_traits> #include <type_traits>
#include <cassert>
#include "test.hpp" #include "test.hpp"
...@@ -23,270 +27,224 @@ ...@@ -23,270 +27,224 @@
#include "cppa/deserializer.hpp" #include "cppa/deserializer.hpp"
#include "cppa/untyped_tuple.hpp" #include "cppa/untyped_tuple.hpp"
#include "cppa/util/enable_if.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" //#include "cppa/util.hpp"
using std::cout; using std::cout;
using std::cerr; using std::cerr;
using std::endl; using std::endl;
/** using namespace cppa::util;
* @brief Integers, floating points and strings.
*/ template<class C, template <typename> class... Traits>
enum fundamental_type struct apply;
template<class C>
struct apply<C>
{ {
ft_int8, ft_int16, ft_int32, ft_int64, typedef C type;
ft_uint8, ft_uint16, ft_uint32, ft_uint64,
ft_float, ft_double, ft_long_double,
ft_u8string, ft_u16string, ft_u32string,
ft_null
}; };
constexpr const char* fundamental_type_names[] = template<class C,
template <typename> class Trait0,
template <typename> class... Traits>
struct apply<C, Trait0, Traits...>
{ {
"ft_int8", "ft_int16", "ft_int32", "ft_int64", typedef typename apply<typename Trait0<C>::type, Traits...>::type type;
"ft_uint8", "ft_uint16", "ft_uint32", "ft_uint64",
"ft_float", "ft_double", "ft_long_double",
"ft_u8string", "ft_u16string", "ft_u32string",
"ft_null"
}; };
constexpr const char* fundamental_type_name(fundamental_type ftype)
{
return fundamental_type_names[static_cast<int>(ftype)];
}
// achieves static call dispatch (Int-To-Type idiom) template<typename T>
template<fundamental_type FT> struct plain
struct ft_token { static const fundamental_type value = FT; }; {
typedef typename apply<T, std::remove_reference, std::remove_cv>::type type;
};
// if (IfStmt == true) type = T; else type = Else::type; /**
template<bool IfStmt, typename T, class Else> * @brief Integers (signed and unsigned), floating points and strings.
struct if_else_type_c */
enum primitive_type
{ {
typedef T 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
}; };
template<typename T, class Else> constexpr const char* primitive_type_names[] =
struct if_else_type_c<false, T, Else>
{ {
typedef typename Else::type 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"
}; };
// if (Stmt::value == true) type = T; else type = Else::type; constexpr const char* primitive_type_name(primitive_type ptype)
template<class Stmt, typename T, class Else> {
struct if_else_type : if_else_type_c<Stmt::value, T, Else> { }; return primitive_type_names[static_cast<int>(ptype)];
}
template<typename T> // achieves static call dispatch (Int-To-Type idiom)
struct wrapped_type { typedef T type; }; template<primitive_type FT>
struct pt_token { static const primitive_type value = FT; };
// maps the fundamental_type FT to the corresponding type // maps the fundamental_type FT to the corresponding type
template<fundamental_type FT> template<primitive_type FT>
struct ftype_to_type struct ptype_to_type
: if_else_type_c<FT == ft_int8, std::int8_t, : if_else_type_c<FT == pt_int8, std::int8_t,
if_else_type_c<FT == ft_int16, std::int16_t, if_else_type_c<FT == pt_int16, std::int16_t,
if_else_type_c<FT == ft_int32, std::int32_t, if_else_type_c<FT == pt_int32, std::int32_t,
if_else_type_c<FT == ft_int64, std::int64_t, if_else_type_c<FT == pt_int64, std::int64_t,
if_else_type_c<FT == ft_uint8, std::uint8_t, if_else_type_c<FT == pt_uint8, std::uint8_t,
if_else_type_c<FT == ft_uint16, std::uint16_t, if_else_type_c<FT == pt_uint16, std::uint16_t,
if_else_type_c<FT == ft_uint32, std::uint32_t, if_else_type_c<FT == pt_uint32, std::uint32_t,
if_else_type_c<FT == ft_uint64, std::uint64_t, if_else_type_c<FT == pt_uint64, std::uint64_t,
if_else_type_c<FT == ft_float, float, if_else_type_c<FT == pt_float, float,
if_else_type_c<FT == ft_double, double, if_else_type_c<FT == pt_double, double,
if_else_type_c<FT == ft_long_double, long double, if_else_type_c<FT == pt_long_double, long double,
if_else_type_c<FT == ft_u8string, std::string, if_else_type_c<FT == pt_u8string, std::string,
if_else_type_c<FT == ft_u16string, std::u16string, if_else_type_c<FT == pt_u16string, std::u16string,
if_else_type_c<FT == ft_u32string, std::u32string, if_else_type_c<FT == pt_u32string, std::u32string,
wrapped_type<void> > > > > > > > > > > > > > > wrapped_type<void> > > > > > > > > > > > > > >
{ {
}; };
// if (IfStmt == true) ftype = FT; else ftype = Else::ftype; // if (IfStmt == true) ptype = FT; else ptype = Else::ptype;
template<bool IfStmt, fundamental_type FT, class Else> template<bool IfStmt, primitive_type FT, class Else>
struct if_else_ftype_c struct if_else_ptype_c
{ {
static const fundamental_type ftype = FT; static const primitive_type ptype = FT;
}; };
template<fundamental_type FT, class Else> template<primitive_type FT, class Else>
struct if_else_ftype_c<false, FT, Else> struct if_else_ptype_c<false, FT, Else>
{ {
static const fundamental_type ftype = Else::ftype; static const primitive_type ptype = Else::ptype;
}; };
// if (Stmt::value == true) ftype = FT; else ftype = Else::ftype; // if (Stmt::value == true) ptype = FT; else ptype = Else::ptype;
template<class Stmt, fundamental_type FT, class Else> template<class Stmt, primitive_type FT, class Else>
struct if_else_ftype : if_else_ftype_c<Stmt::value, FT, Else> { }; struct if_else_ptype : if_else_ptype_c<Stmt::value, FT, Else> { };
template<fundamental_type FT> template<primitive_type FT>
struct wrapped_ftype { static const fundamental_type ftype = FT; }; struct wrapped_ptype { static const primitive_type ptype = FT; };
// maps type T the the corresponding fundamental_type // maps type T the the corresponding fundamental_type
template<typename T> template<typename T>
struct type_to_ftype struct type_to_ptype_impl
// signed integers // signed integers
: if_else_ftype<std::is_same<T, std::int8_t>, ft_int8, : if_else_ptype<std::is_same<T, std::int8_t>, pt_int8,
if_else_ftype<std::is_same<T, std::int16_t>, ft_int16, if_else_ptype<std::is_same<T, std::int16_t>, pt_int16,
if_else_ftype<std::is_same<T, std::int32_t>, ft_int32, if_else_ptype<std::is_same<T, std::int32_t>, pt_int32,
if_else_ftype<std::is_same<T, std::int64_t>, ft_int64, if_else_ptype<std::is_same<T, std::int64_t>, pt_int64,
if_else_ftype<std::is_same<T, std::uint8_t>, ft_uint8, if_else_ptype<std::is_same<T, std::uint8_t>, pt_uint8,
// unsigned integers // unsigned integers
if_else_ftype<std::is_same<T, std::uint16_t>, ft_uint16, if_else_ptype<std::is_same<T, std::uint16_t>, pt_uint16,
if_else_ftype<std::is_same<T, std::uint32_t>, ft_uint32, if_else_ptype<std::is_same<T, std::uint32_t>, pt_uint32,
if_else_ftype<std::is_same<T, std::uint64_t>, ft_uint64, if_else_ptype<std::is_same<T, std::uint64_t>, pt_uint64,
// float / double // float / double
if_else_ftype<std::is_same<T, float>, ft_float, if_else_ptype<std::is_same<T, float>, pt_float,
if_else_ftype<std::is_same<T, double>, ft_double, if_else_ptype<std::is_same<T, double>, pt_double,
if_else_ftype<std::is_same<T, long double>, ft_long_double, if_else_ptype<std::is_same<T, long double>, pt_long_double,
// strings // strings
if_else_ftype<std::is_convertible<T, std::string>, ft_u8string, if_else_ptype<std::is_convertible<T, std::string>, pt_u8string,
if_else_ftype<std::is_convertible<T, std::u16string>, ft_u16string, if_else_ptype<std::is_convertible<T, std::u16string>, pt_u16string,
if_else_ftype<std::is_convertible<T, std::u32string>, ft_u32string, if_else_ptype<std::is_convertible<T, std::u32string>, pt_u32string,
wrapped_ftype<ft_null> > > > > > > > > > > > > > > wrapped_ptype<pt_null> > > > > > > > > > > > > > >
{ {
}; };
template<typename T> template<typename T>
struct type_to_ftype<T&> : type_to_ftype<T> { }; struct type_to_ptype : type_to_ptype_impl<typename plain<T>::type> { };
template<typename T>
struct type_to_ftype<T&&> : type_to_ftype<T> { };
template<typename T> namespace trait {
struct type_to_ftype<const T&> : type_to_ftype<T> { };
template<typename T> template<typename T>
struct type_to_ftype<const T> : type_to_ftype<T> { }; struct is_primitive
struct value
{ {
fundamental_type type; static const bool value = type_to_ptype<T>::ptype != pt_null;
inline value(const fundamental_type& ftype) : type(ftype) { }
}; };
struct list template<typename T>
class is_iterable
{ {
fundamental_type value_type;
inline list(const fundamental_type& ftype) : value_type(ftype) { }
};
struct map template<class C>
{ static bool cmp_help_fun(C& arg0,
fundamental_type key_type; decltype((arg0.begin() == arg0.end()) &&
fundamental_type value_type; (*(++(arg0.begin())) == *(arg0.end())))*)
inline map(const fundamental_type& key_ft, const fundamental_type& value_ft)
: key_type(key_ft), value_type(value_ft)
{ {
return true;
} }
};
using cppa::util::enable_if;
template<bool Stmt, typename T> template<class C>
struct disable_if_c { }; static void cmp_help_fun(C&, void*) { }
template<typename T> typedef decltype(cmp_help_fun(*static_cast<T*>(nullptr),
struct disable_if_c<false, T> static_cast<bool*>(nullptr)))
{ result_type;
typedef T type;
};
template<class Trait, typename T = void> public:
struct disable_if : disable_if_c<Trait::value, T> { };
template<fundamental_type FT, class T, class V>
void set_fun(fundamental_type& lhs_type, T& lhs, V&& rhs,
typename disable_if<std::is_arithmetic<T>>::type* = nullptr)
{
if (FT == lhs_type)
{
lhs = std::forward<V>(rhs);
}
else
{
new (&lhs) T(std::forward<V>(rhs));
lhs_type = FT;
}
}
template<fundamental_type FT, class T, class V>
void set_fun(fundamental_type& lhs_type, T& lhs, V&& rhs,
typename enable_if<std::is_arithmetic<T>>::type* = nullptr)
{
lhs = rhs;
lhs_type = FT;
}
template<class T> static const bool value = !is_primitive<T>::value
void destroy_fun(T& what, && std::is_same<bool, result_type>::value;
typename disable_if<std::is_arithmetic<T>>::type* = nullptr)
{
what.~T();
}
template<class T> };
void destroy_fun(T&, typename enable_if<std::is_arithmetic<T>>::type* = nullptr)
{
// arithmetic types don't need destruction
}
class ft_value; } // namespace trait
template<typename T> class pt_value;
T ft_value_cast(ft_value&);
template<typename T> template<typename T>
T ft_value_cast(const ft_value&); T pt_value_cast(pt_value&);
template<fundamental_type FT> template<primitive_type FT>
typename ftype_to_type<FT>::type& ft_value_cast(ft_value&); typename ptype_to_type<FT>::type& pt_value_cast(pt_value&);
template<fundamental_type FT>
const typename ftype_to_type<FT>::type& ft_value_cast(const ft_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> template<typename Fun>
void ft_invoke(fundamental_type ftype, Fun&& f) void pt_invoke(primitive_type ptype, Fun&& f)
{ {
switch (ftype) switch (ptype)
{ {
case ft_int8: f(ft_token<ft_int8>()); break; case pt_int8: f(pt_token<pt_int8>()); break;
case ft_int16: f(ft_token<ft_int16>()); break; case pt_int16: f(pt_token<pt_int16>()); break;
case ft_int32: f(ft_token<ft_int32>()); break; case pt_int32: f(pt_token<pt_int32>()); break;
case ft_int64: f(ft_token<ft_int64>()); break; case pt_int64: f(pt_token<pt_int64>()); break;
case ft_uint8: f(ft_token<ft_uint8>()); break; case pt_uint8: f(pt_token<pt_uint8>()); break;
case ft_uint16: f(ft_token<ft_uint16>()); break; case pt_uint16: f(pt_token<pt_uint16>()); break;
case ft_uint32: f(ft_token<ft_uint32>()); break; case pt_uint32: f(pt_token<pt_uint32>()); break;
case ft_uint64: f(ft_token<ft_uint64>()); break; case pt_uint64: f(pt_token<pt_uint64>()); break;
case ft_float: f(ft_token<ft_float>()); break; case pt_float: f(pt_token<pt_float>()); break;
case ft_double: f(ft_token<ft_double>()); break; case pt_double: f(pt_token<pt_double>()); break;
case ft_long_double: f(ft_token<ft_long_double>()); break; case pt_long_double: f(pt_token<pt_long_double>()); break;
case ft_u8string: f(ft_token<ft_u8string>()); break; case pt_u8string: f(pt_token<pt_u8string>()); break;
case ft_u16string: f(ft_token<ft_u16string>()); break; case pt_u16string: f(pt_token<pt_u16string>()); break;
case ft_u32string: f(ft_token<ft_u32string>()); break; case pt_u32string: f(pt_token<pt_u32string>()); break;
default: break; default: break;
} }
} }
/** /**
* @brief Describes a value of a {@link fundamental_type}. * @brief Describes a value of a {@link primitive_type primitive data type}.
*/ */
class ft_value class pt_value
{ {
template<typename T> template<typename T>
friend T ft_value_cast(ft_value&); friend T pt_value_cast(pt_value&);
template<typename T>
friend T ft_value_cast(const ft_value&);
template<fundamental_type FT> template<primitive_type PT>
friend typename ftype_to_type<FT>::type& ft_value_cast(ft_value&); friend typename ptype_to_type<PT>::type& pt_value_cast(pt_value&);
template<fundamental_type FT> primitive_type m_ptype;
friend const typename ftype_to_type<FT>::type& ft_value_cast(const ft_value&);
fundamental_type m_ftype;
union union
{ {
...@@ -307,93 +265,124 @@ class ft_value ...@@ -307,93 +265,124 @@ class ft_value
}; };
// use static call dispatching to select member variable // use static call dispatching to select member variable
inline decltype(i8)& get(ft_token<ft_int8>) { return i8; } inline decltype(i8)& get(pt_token<pt_int8>) { return i8; }
inline decltype(i16)& get(ft_token<ft_int16>) { return i16; } inline decltype(i16)& get(pt_token<pt_int16>) { return i16; }
inline decltype(i32)& get(ft_token<ft_int32>) { return i32; } inline decltype(i32)& get(pt_token<pt_int32>) { return i32; }
inline decltype(i64)& get(ft_token<ft_int64>) { return i64; } inline decltype(i64)& get(pt_token<pt_int64>) { return i64; }
inline decltype(u8)& get(ft_token<ft_uint8>) { return u8; } inline decltype(u8)& get(pt_token<pt_uint8>) { return u8; }
inline decltype(u16)& get(ft_token<ft_uint16>) { return u16; } inline decltype(u16)& get(pt_token<pt_uint16>) { return u16; }
inline decltype(u32)& get(ft_token<ft_uint32>) { return u32; } inline decltype(u32)& get(pt_token<pt_uint32>) { return u32; }
inline decltype(u64)& get(ft_token<ft_uint64>) { return u64; } inline decltype(u64)& get(pt_token<pt_uint64>) { return u64; }
inline decltype(fl)& get(ft_token<ft_float>) { return fl; } inline decltype(fl)& get(pt_token<pt_float>) { return fl; }
inline decltype(dbl)& get(ft_token<ft_double>) { return dbl; } inline decltype(dbl)& get(pt_token<pt_double>) { return dbl; }
inline decltype(ldbl)& get(ft_token<ft_long_double>) { return ldbl; } inline decltype(ldbl)& get(pt_token<pt_long_double>) { return ldbl; }
inline decltype(str8)& get(ft_token<ft_u8string>) { return str8; } inline decltype(str8)& get(pt_token<pt_u8string>) { return str8; }
inline decltype(str16)& get(ft_token<ft_u16string>) { return str16; } inline decltype(str16)& get(pt_token<pt_u16string>) { return str16; }
inline decltype(str32)& get(ft_token<ft_u32string>) { return str32; } 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;
}
}
// get(...) const overload template<primitive_type FT, class T, class V>
template<fundamental_type FT> static void set(primitive_type& lhs_type, T& lhs, V&& rhs,
const typename ftype_to_type<FT>::type& get(ft_token<FT> token) const typename enable_if<std::is_arithmetic<T>>::type* = 0)
{ {
return const_cast<ft_value*>(this)->get(token); // don't call a constructor for arithmetic types
lhs = rhs;
lhs_type = FT;
}
template<class T>
static void destroy(T& what,
typename disable_if<std::is_arithmetic<T>>::type* = 0)
{
what.~T();
}
template<class T>
static void destroy(T&,
typename enable_if<std::is_arithmetic<T>>::type* = 0)
{
// arithmetic types don't need destruction
} }
struct destroyer struct destroyer
{ {
ft_value* m_self; pt_value* m_self;
inline destroyer(ft_value* self) : m_self(self) { } inline destroyer(pt_value* self) : m_self(self) { }
template<fundamental_type FT> template<primitive_type FT>
inline void operator()(ft_token<FT> token) const inline void operator()(pt_token<FT> token) const
{ {
destroy_fun(m_self->get(token)); destroy(m_self->get(token));
} }
}; };
struct initializer struct initializer
{ {
ft_value* m_self; pt_value* m_self;
inline initializer(ft_value* self) : m_self(self) { } inline initializer(pt_value* self) : m_self(self) { }
template<fundamental_type FT> template<primitive_type FT>
inline void operator()(ft_token<FT> token) const inline void operator()(pt_token<FT> token) const
{ {
set_fun<FT>(m_self->m_ftype, set<FT>(m_self->m_ptype,
m_self->get(token), m_self->get(token),
typename ftype_to_type<FT>::type()); typename ptype_to_type<FT>::type());
} }
}; };
struct setter struct setter
{ {
ft_value* m_self; pt_value* m_self;
const ft_value& m_other; const pt_value& m_other;
inline setter(ft_value* self, const ft_value& other) inline setter(pt_value* self, const pt_value& other)
: m_self(self), m_other(other) { } : m_self(self), m_other(other) { }
template<fundamental_type FT> template<primitive_type FT>
inline void operator()(ft_token<FT> token) const inline void operator()(pt_token<FT> token) const
{ {
set_fun<FT>(m_self->m_ftype, set<FT>(m_self->m_ptype,
m_self->get(token), m_self->get(token),
m_other.get(token)); m_other.get(token));
} }
}; };
struct mover struct mover
{ {
ft_value* m_self; pt_value* m_self;
const ft_value& m_other; const pt_value& m_other;
inline mover(ft_value* self, const ft_value& other) inline mover(pt_value* self, const pt_value& other)
: m_self(self), m_other(other) { } : m_self(self), m_other(other) { }
template<fundamental_type FT> template<primitive_type FT>
inline void operator()(ft_token<FT> token) const inline void operator()(pt_token<FT> token) const
{ {
set_fun<FT>(m_self->m_ftype, set<FT>(m_self->m_ptype,
m_self->get(token), m_self->get(token),
std::move(m_other.get(token))); std::move(m_other.get(token)));
} }
}; };
struct comparator struct comparator
{ {
bool m_result; bool m_result;
const ft_value* m_self; const pt_value* m_self;
const ft_value& m_other; const pt_value& m_other;
inline comparator(const ft_value* self, const ft_value& other) inline comparator(const pt_value* self, const pt_value& other)
: m_result(false), m_self(self), m_other(other) { } : m_result(false), m_self(self), m_other(other) { }
template<fundamental_type FT> template<primitive_type FT>
inline void operator()(ft_token<FT> token) inline void operator()(pt_token<FT> token)
{ {
if (m_other.m_ftype == FT) if (m_other.m_ptype == FT)
{ {
m_result = (m_self->get(token) == m_other.get(token)); m_result = (m_self->get(token) == m_other.get(token));
} }
...@@ -401,735 +390,1115 @@ class ft_value ...@@ -401,735 +390,1115 @@ class ft_value
inline bool result() const { return m_result; } inline bool result() const { return m_result; }
}; };
void destroy()
{
ft_invoke(m_ftype, destroyer(this));
m_ftype = ft_null;
}
template<class Self, typename Fun> template<class Self, typename Fun>
struct forwarder struct applier
{ {
Self* m_self; Self* m_self;
Fun& m_f; Fun& m_f;
forwarder(Self* self, Fun& f) : m_self(self), m_f(f) { } applier(Self* self, Fun& f) : m_self(self), m_f(f) { }
template<fundamental_type FT> template<primitive_type FT>
inline void operator()(ft_token<FT> token) inline void operator()(pt_token<FT> token)
{ {
m_f(m_self->get(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: 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> template<typename Fun>
void apply(Fun&& f) void apply(Fun&& f)
{ {
ft_invoke(m_ftype, forwarder<ft_value, Fun>(this, f)); pt_invoke(m_ptype, applier<pt_value, Fun>(this, f));
} }
template<typename Fun> template<typename Fun>
void apply(Fun&& f) const void apply(Fun&& f) const
{ {
ft_invoke(m_ftype, forwarder<const ft_value, Fun>(this, f)); pt_invoke(m_ptype, applier<const pt_value, Fun>(this, f));
} }
ft_value() : m_ftype(ft_null) { } pt_value() : m_ptype(pt_null) { }
template<typename V> template<typename V>
ft_value(V&& value) : m_ftype(ft_null) pt_value(V&& value) : m_ptype(pt_null)
{ {
static_assert(type_to_ftype<V>::ftype != ft_null, static_assert(type_to_ptype<V>::ptype != pt_null,
"T is not a valid value for ft_value"); "T couldn't be mapped to an ptype");
set_fun<type_to_ftype<V>::ftype>(m_ftype, set<type_to_ptype<V>::ptype>(m_ptype,
get(ft_token<type_to_ftype<V>::ftype>()), get(pt_token<type_to_ptype<V>::ptype>()),
std::forward<V>(value)); std::forward<V>(value));
} }
ft_value(fundamental_type ftype) : m_ftype(ft_null) pt_value(primitive_type ptype) : m_ptype(pt_null)
{ {
ft_invoke(ftype, initializer(this)); pt_invoke(ptype, initializer(this));
} }
ft_value(const ft_value& other) : m_ftype(ft_null) pt_value(const pt_value& other) : m_ptype(pt_null)
{ {
//invoke(setter(other)); //invoke(setter(other));
ft_invoke(other.m_ftype, setter(this, other)); pt_invoke(other.m_ptype, setter(this, other));
} }
ft_value(ft_value&& other) : m_ftype(ft_null) pt_value(pt_value&& other) : m_ptype(pt_null)
{ {
//invoke(mover(other)); //invoke(mover(other));
ft_invoke(other.m_ftype, mover(this, other)); pt_invoke(other.m_ptype, mover(this, other));
} }
ft_value& operator=(const ft_value& other) pt_value& operator=(const pt_value& other)
{ {
//invoke(setter(other)); //invoke(setter(other));
ft_invoke(other.m_ftype, setter(this, other)); pt_invoke(other.m_ptype, setter(this, other));
return *this; return *this;
} }
ft_value& operator=(ft_value&& other) pt_value& operator=(pt_value&& other)
{ {
//invoke(mover(other)); //invoke(mover(other));
ft_invoke(other.m_ftype, mover(this, other)); pt_invoke(other.m_ptype, mover(this, other));
return *this; return *this;
} }
bool operator==(const ft_value& other) const bool operator==(const pt_value& other) const
{ {
comparator cmp(this, other); comparator cmp(this, other);
ft_invoke(m_ftype, cmp); pt_invoke(m_ptype, cmp);
return cmp.result(); return cmp.result();
} }
bool operator!=(const ft_value& other) const inline bool operator!=(const pt_value& other) const
{ {
return !(*this == other); return !(*this == other);
} }
inline fundamental_type type() const { return m_ftype; } 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);
}
~ft_value() { destroy(); } ~pt_value() { destroy(); }
}; };
template<typename T> template<typename T>
typename cppa::util::enable_if<std::is_arithmetic<T>, bool>::type typename enable_if<trait::is_primitive<T>, bool>::type
operator==(const T& lhs, const ft_value& rhs) operator==(const T& lhs, const pt_value& rhs)
{ {
return (rhs.type() == type_to_ftype<T>::ftype) constexpr primitive_type ptype = type_to_ptype<T>::ptype;
? lhs == ft_value_cast<const T&>(rhs) static_assert(ptype != pt_null, "T couldn't be mapped to an ptype");
: false; return (rhs.ptype() == ptype) ? lhs == pt_value_cast<ptype>(rhs) : false;
} }
template<typename T> template<typename T>
typename cppa::util::enable_if<std::is_arithmetic<T>, bool>::type typename enable_if<trait::is_primitive<T>, bool>::type
operator==(const ft_value& lhs, const T& rhs) operator==(const pt_value& lhs, const T& rhs)
{ {
return (lhs.type() == type_to_ftype<T>::ftype) return (rhs == lhs);
? ft_value_cast<const T&>(lhs) == rhs
: false;
} }
template<typename T> template<typename T>
typename cppa::util::enable_if<std::is_arithmetic<T>, bool>::type typename enable_if<trait::is_primitive<T>, bool>::type
operator!=(const T& lhs, const ft_value& rhs) operator!=(const pt_value& lhs, const T& rhs)
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
template<typename T> template<typename T>
typename cppa::util::enable_if<std::is_arithmetic<T>, bool>::type typename enable_if<trait::is_primitive<T>, bool>::type
operator!=(const ft_value& lhs, const T& rhs) operator!=(const T& lhs, const pt_value& rhs)
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
template<fundamental_type FT> template<primitive_type FT>
typename ftype_to_type<FT>::type& ft_value_cast(ft_value& v) typename ptype_to_type<FT>::type& pt_value_cast(pt_value& v)
{ {
if (v.type() != FT) throw std::bad_cast(); if (v.ptype() != FT) throw std::bad_cast();
return v.get(ft_token<FT>()); return v.get(pt_token<FT>());
} }
template<fundamental_type FT> template<primitive_type FT>
const typename ftype_to_type<FT>::type& ft_value_cast(const ft_value& v) const typename ptype_to_type<FT>::type& pt_value_cast(const pt_value& v)
{ {
if (v.type() != FT) throw std::bad_cast(); if (v.ptype() != FT) throw std::bad_cast();
return v.get(ft_token<FT>()); return v.get(pt_token<FT>());
} }
template<typename T> template<typename T>
T ft_value_cast(ft_value& v) T pt_value_cast(pt_value& v)
{ {
static const fundamental_type ftype = type_to_ftype<T>::ftype; static const primitive_type ptype = type_to_ptype<T>::ptype;
if (v.type() != ftype) throw std::bad_cast(); if (v.ptype() != ptype) throw std::bad_cast();
return v.get(ft_token<ftype>()); return v.get(pt_token<ptype>());
} }
template<typename T> template<typename T>
T ft_value_cast(const ft_value& v) T pt_value_cast(const pt_value& v)
{ {
typedef typename std::remove_reference<T>::type plain_t; typedef typename std::remove_reference<T>::type plain_t;
static_assert(!std::is_reference<T>::value || std::is_const<plain_t>::value, static_assert(!std::is_reference<T>::value || std::is_const<plain_t>::value,
"Could not get a non-const reference from const ft_value&"); "Could not get a non-const reference from const pt_value&");
static const fundamental_type ftype = type_to_ftype<T>::ftype; static const primitive_type ptype = type_to_ptype<T>::ptype;
if (v.type() != ftype) throw std::bad_cast(); if (v.ptype() != ptype) throw std::bad_cast();
return v.get(ft_token<ftype>()); return v.get(pt_token<ptype>());
} }
class value_property struct getter_setter_pair
{ {
public: 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));
};
}
virtual ~value_property() { } template<class C, typename GT, typename ST>
virtual void set(ft_value&& what) = 0; getter_setter_pair(GT (C::*get_memfn)() const, void (C::*set_memfn)(ST))
virtual void get(ft_value& storage) const = 0; {
virtual fundamental_type type() const = 0; 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 list_property class serializer
{ {
public: public:
class iterator virtual void begin_object(const std::string& type_name) = 0;
{ virtual void end_object() = 0;
public: virtual void begin_list(size_t size) = 0;
virtual void end_list() = 0;
virtual ~iterator() { } virtual void write_value(const pt_value& value) = 0;
virtual void next() = 0;
virtual bool at_end() const = 0;
virtual ft_value get() const = 0;
}; };
class serializer;
class deserializer;
virtual ~list_property() { } class meta_type
virtual size_t size() const = 0; {
virtual iterator* begin() const = 0;
virtual fundamental_type value_type() const = 0; public:
virtual void push_back(ft_value&& what) = 0;
virtual ~meta_type() { }
/**
* @brief Create an instance of this type, initialized
* with its default constructor.
*/
virtual void* default_constructed() = 0;
virtual void delete_instance(void*) = 0;
virtual void serialize(void*, serializer*) = 0;
virtual void deserialize(void*, deserializer*) = 0;
}; };
class map_property std::map<std::string, meta_type*> s_meta_types;
/**
*
*/
class deserializer
{ {
public: public:
class iterator /**
{ * @brief Seek the beginning of the next object and return its type name.
*/
virtual std::string seek_object() = 0;
public: /**
* @brief Seek the beginning of the next object and return its type name,
* but don't modify the internal in-stream position.
*/
virtual std::string peek_object() = 0;
virtual ~iterator() { } virtual void begin_object(const std::string& type_name) = 0;
virtual void next() = 0; virtual void end_object() = 0;
virtual bool at_end() const = 0;
virtual ft_value key() const = 0;
virtual ft_value value() const = 0;
}; virtual size_t begin_list(primitive_type value_type) = 0;
virtual void end_list() = 0;
virtual ~map_property() { } virtual pt_value read_value(primitive_type ptype) = 0;
virtual size_t size() const = 0;
virtual iterator* begin() const = 0;
virtual fundamental_type key_type() const = 0;
virtual fundamental_type value_type() const = 0;
virtual void insert(ft_value&& key, ft_value&& val) = 0;
}; };
template<typename Getter, typename Setter, fundamental_type FT> class root_object
class value_property_impl : public value_property
{ {
Getter m_get;
Setter m_set;
// T* m_ptr;
public: public:
// value_property_impl(T* ptr) : m_ptr(ptr) { } std::pair<void*, meta_type*> deserialize(deserializer* d)
{
void* result;
std::string tname = d->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->default_constructed();
if (result == nullptr)
{
throw std::logic_error("result == nullptr");
}
try
{
mobj->deserialize(result, d);
}
catch (...)
{
mobj->delete_instance(result);
return { nullptr, nullptr };
}
return { result, mobj };
}
};
value_property_impl(Getter g, Setter s) : m_get(g), m_set(s) { } template<typename T>
class meta_value_property : public meta_type
{
void set(ft_value&& what) static constexpr primitive_type ptype = type_to_ptype<T>::ptype;
static_assert(ptype != pt_null, "T is not a primitive type");
public:
meta_value_property() { }
pt_value get(void* obj)
{ {
// *m_ptr = std::move(ft_value_cast<FT>(what)); return *reinterpret_cast<T*>(obj);
m_set(std::move(ft_value_cast<FT>(what)));
} }
void get(ft_value& storage) const void set(void* obj, pt_value&& value)
{ {
// ft_value_cast<FT>(storage) = *m_ptr; *reinterpret_cast<T*>(obj) = std::move(pt_value_cast<T&>(value));
ft_value_cast<FT>(storage) = m_get();
} }
fundamental_type type() const void* default_constructed()
{ {
return FT; return new T();
} }
}; void delete_instance(void* ptr)
template<class List, fundamental_type FT>
class list_property_impl : public list_property
{
class iterator : public list_property::iterator
{ {
delete reinterpret_cast<T*>(ptr);
}
typedef typename List::const_iterator native_iterator; void serialize(void* obj, serializer* s)
{
native_iterator pos; s->write_value(get(obj));
native_iterator end; }
public:
iterator(native_iterator bg, native_iterator nd) : pos(bg), end(nd) { }
bool at_end() const { return pos == end; } void deserialize(void* obj, deserializer* d)
{
set(obj, d->read_value(ptype));
}
void next() { ++pos; } };
ft_value get() const { return *pos; } // std::vector or std::list
template<typename List>
class meta_list_property : public meta_type
{
}; typedef typename List::value_type value_type;
static constexpr primitive_type vptype = type_to_ptype<value_type>::ptype;
List* m_list; static_assert(vptype != pt_null, "T doesn't have a primitive value_type");
public: public:
list_property_impl(List* native_list) : m_list(native_list) { } meta_list_property() { }
size_t size() const { return m_list->size(); } void serialize(void* obj, serializer* s)
{
auto& ls = *reinterpret_cast<List*>(obj);
s->begin_list(ls.size());
for (const auto& val : ls)
{
s->write_value(val);
}
s->end_list();
}
list_property::iterator* begin() const void deserialize(void* obj, deserializer* d)
{ {
return new iterator(m_list->begin(), m_list->end()); auto& ls = *reinterpret_cast<List*>(obj);
size_t ls_size = d->begin_list(vptype);
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_list();
} }
void push_back(ft_value&& what) void* default_constructed()
{ {
m_list->push_back(std::move(ft_value_cast<FT>(what))); return new List();
} }
fundamental_type value_type() const void delete_instance(void* ptr)
{ {
return FT; delete reinterpret_cast<List*>(ptr);
} }
}; };
template<class Map, fundamental_type KeyType, fundamental_type ValueType> template<class Object>
class map_property_impl : public map_property class meta_object : public meta_type
{ {
class iterator : public map_property::iterator class member
{ {
typedef typename Map::const_iterator native_iterator; meta_type* m_meta;
std::function<void* (void*)> m_deref;
native_iterator pos;
native_iterator end;
public: public:
iterator(native_iterator bg, native_iterator nd) : pos(bg), end(nd) { } template<typename T, class C>
member(meta_type* mtptr, T C::*mem_ptr) : m_meta(mtptr)
{
m_deref = [mem_ptr] (void* obj) -> void*
{
return &(*reinterpret_cast<C*>(obj).*mem_ptr);
};
}
void next() { ++pos; } member(meta_type* pptr, std::function<void* (void*)>&& gpm)
: m_meta(pptr), m_deref(std::move(gpm))
{
}
member(member&&) = default;
bool at_end() const { return pos == end; } member(const member&) = default;
ft_value key() const { return pos->first; } inline void serialize(void* parent, serializer* s)
{
m_meta->serialize(m_deref(parent), s);
}
ft_value value() const { return pos->second; } inline void deserialize(void* parent, deserializer* s)
{
m_meta->deserialize(m_deref(parent), s);
}
}; };
Map* m_map; std::string class_name;
std::vector<member> m_members;
public: // terminates recursion
inline void push_back() { }
map_property_impl(Map* ptr) : m_map(ptr) { } template<typename T, class C, typename... Args>
void push_back(std::pair<T C::*, meta_object<T>*> pr, const Args&... args)
{
m_members.push_back({ pr.second, pr.first });
push_back(args...);
}
size_t size() const template<class C, typename T, typename... Args>
typename enable_if<trait::is_primitive<T> >::type
push_back(T C::*mem_ptr, const Args&... args)
{ {
return m_map->size(); m_members.push_back({ new meta_value_property<T>(), mem_ptr });
push_back(args...);
} }
iterator* begin() const template<class C, typename T, typename... Args>
typename enable_if<trait::is_iterable<T> >::type
push_back(T C::*mem_ptr, const Args&... args)
{ {
return new iterator(m_map->begin(), m_map->end()); m_members.push_back({ new meta_list_property<T>(), mem_ptr });
push_back(args...);
} }
void insert(ft_value&& k, ft_value&& v) template<class C, typename T, typename... Args>
typename disable_if_c< trait::is_primitive<T>::value
|| trait::is_iterable<T>::value, void>::type
push_back(T C::*mem_ptr, const Args&... args)
{ {
m_map->insert(std::make_pair( static_assert(trait::is_primitive<T>::value,
std::move(ft_value_cast<KeyType>(k)), "T is neither a primitive type nor an iterable type");
std::move(ft_value_cast<ValueType>(v))));
} }
fundamental_type key_type() const public:
template<typename... Args>
meta_object(const Args&... args) : class_name(cppa::detail::to_uniform_name(cppa::detail::demangle(typeid(Object).name())))
{
push_back(args...);
}
void serialize(void* obj, serializer* s)
{
s->begin_object(class_name);
for (auto& m : m_members)
{
m.serialize(obj, s);
}
s->end_object();
}
void deserialize(void* obj, deserializer* d)
{
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();
}
void* default_constructed()
{ {
return KeyType; return new Object();
} }
fundamental_type value_type() const void delete_instance(void* ptr)
{ {
return ValueType; delete reinterpret_cast<Object*>(ptr);
} }
}; };
template<fundamental_type FT, typename Getter, typename Setter> struct struct_a
value_property* as_value_property(Getter getter, Setter setter)
{ {
return new value_property_impl<Getter, Setter, FT>(getter, setter); int x;
} int y;
};
using cppa::util::enable_if; bool operator==(const struct_a& lhs, const struct_a& rhs)
using cppa::util::conjunction; {
return lhs.x == rhs.x && lhs.y == rhs.y;
}
template<fundamental_type FT, class C, typename Getter, typename Setter> bool operator!=(const struct_a& lhs, const struct_a& rhs)
typename enable_if<conjunction<std::is_member_function_pointer<Getter>,
std::is_member_function_pointer<Setter>>,
value_property*>::type
as_value_property(C* self, Getter getter, Setter setter)
{ {
typedef cppa::util::callable_trait<Getter> getter_trait; return !(lhs == rhs);
typedef cppa::util::callable_trait<Setter> setter_trait;
typedef typename getter_trait::result_type getter_result;
typedef typename ftype_to_type<FT>::type setter_arg;
return as_value_property<FT>(
[=]() -> getter_result { return (*self.*getter)(); },
[=](setter_arg&& val) { (*self.*setter)(std::move(val)); });
} }
template<typename T, fundamental_type FT = type_to_ftype<T>::ftype> struct struct_b
value_property* as_value_property(T* ptr) {
struct_a a;
int z;
std::list<int> ints;
};
bool operator==(const struct_b& lhs, const struct_b& rhs)
{ {
return as_value_property<FT>([ptr]() -> const T& { return *ptr; }, return lhs.a == rhs.a && lhs.z == rhs.z && lhs.ints == rhs.ints;
[ptr](T&& val) { *ptr = std::move(val); });
} }
template<typename List, bool operator!=(const struct_b& lhs, const struct_b& rhs)
fundamental_type FT = type_to_ftype<typename List::value_type>::ftype>
list_property* as_list_property(List* ptr)
{ {
return new list_property_impl<List, FT>(ptr); return !(lhs == rhs);
} }
template<typename Map, template<class C, class Parent, typename... Args>
fundamental_type KT = type_to_ftype<typename Map::key_type>::ftype, std::pair<C Parent::*, meta_object<C>*> compound_member(C Parent::*c_ptr, const Args&... args)
fundamental_type VT = type_to_ftype<typename Map::mapped_type>::ftype>
map_property* as_map_property(Map* ptr)
{ {
return new map_property_impl<Map, KT, VT>(ptr); return std::make_pair(c_ptr, new meta_object<C>(args...));
} }
struct property_ptr class string_serializer : public serializer
{ {
enum flag_type { is_null, is_vp, is_lp, is_mp } m_flag; std::ostream& out;
union struct pt_writer
{ {
value_property* m_vp;
list_property* m_lp;
map_property* m_mp;
};
void set(value_property* vp) std::ostream& out;
{
m_flag = is_vp;
m_vp = vp;
}
void set(list_property* lp) pt_writer(std::ostream& mout) : out(mout) { }
{
m_flag = is_lp;
m_lp = lp;
}
void set(map_property* mp) template<typename T>
{ void operator()(const T& value)
m_flag = is_mp; {
m_mp = mp; out << value;
} }
void destroy() void operator()(const std::string& str)
{
switch (m_flag)
{ {
case is_vp: delete m_vp; break; out << "\"" << str << "\"";
case is_lp: delete m_lp; break;
case is_mp: delete m_mp; break;
default: break;
} }
m_flag = is_null;
}
void move_from(property_ptr& other) void operator()(const std::u16string&) { }
void operator()(const std::u32string&) { }
};
int m_open_objects;
bool m_after_value;
inline void clear()
{ {
m_flag = other.m_flag; if (m_after_value)
switch (other.m_flag)
{ {
case is_vp: m_vp = other.m_vp; break; out << ", ";
case is_lp: m_lp = other.m_lp; break; m_after_value = false;
case is_mp: m_mp = other.m_mp; break;
default: break;
} }
other.m_flag = is_null;
} }
value_property* get(std::true_type, std::false_type, std::false_type) public:
string_serializer(std::ostream& mout)
: out(mout), m_open_objects(0), m_after_value(false) { }
void begin_object(const std::string& type_name)
{ {
if (m_flag != is_vp) throw std::bad_cast(); clear();
return m_vp; ++m_open_objects;
out << type_name << " ( ";
} }
void end_object()
list_property* get(std::false_type, std::true_type, std::false_type)
{ {
if (m_flag != is_lp) throw std::bad_cast(); out << " )";
return m_lp;
} }
map_property* get(std::false_type, std::false_type, std::true_type) void begin_list(size_t)
{ {
if (m_flag != is_mp) throw std::bad_cast(); clear();
return m_mp; out << "{ ";
} }
public: void end_list()
{
if (!m_after_value)
{
out << "}";
}
else
{
out << " }";
}
}
property_ptr(value_property* ptr) { set(ptr); } void write_value(const pt_value& value)
{
clear();
value.apply(pt_writer(out));
m_after_value = true;
}
property_ptr(list_property* ptr) { set(ptr); } };
property_ptr(map_property* ptr) { set(ptr); } class xml_serializer : public serializer
{
property_ptr() : m_flag(is_null) { } std::ostream& out;
std::string indentation;
property_ptr(property_ptr&& other) inline void inc_indentation()
{ {
move_from(other); indentation.resize(indentation.size() + 4, ' ');
} }
property_ptr& operator=(property_ptr&& other) inline void dec_indentation()
{ {
destroy(); auto isize = indentation.size();
move_from(other); indentation.resize((isize > 4) ? (isize - 4) : 0);
return *this;
} }
~property_ptr() struct pt_writer
{ {
destroy();
}
property_ptr(const property_ptr&) = delete; std::ostream& out;
const std::string& indentation;
property_ptr& operator=(const property_ptr&) = delete; pt_writer(std::ostream& ostr, const std::string& indent)
: out(ostr), indentation(indent)
{
}
inline bool is_value_property() const { return m_flag == is_vp; } template<typename T>
void operator()(const T& value)
{
out << indentation << "<value type=\""
<< primitive_type_name(type_to_ptype<T>::ptype)
<< "\">" << value << "</value>\n";
}
void operator()(const std::u16string&) { }
void operator()(const std::u32string&) { }
};
inline bool is_list_property() const { return m_flag == is_lp; } public:
inline bool is_map_property() const { return m_flag == is_mp; } xml_serializer(std::ostream& ostr) : out(ostr), indentation("") { }
inline explicit operator bool() const { return m_flag != is_null; } void begin_object(const std::string& type_name)
{
out << indentation << "<object type=\"" << type_name << "\">\n";
inc_indentation();
}
void end_object()
{
dec_indentation();
out << indentation << "</object>\n";
}
inline bool operator==(const std::nullptr_t&) void begin_list(size_t)
{ {
return m_flag == is_null; out << indentation << "<list>\n";
inc_indentation();
} }
inline bool operator!=(const std::nullptr_t&) void end_list()
{ {
return m_flag != is_null; dec_indentation();
out << indentation << "</list>\n";
} }
template<typename T> void write_value(const pt_value& value)
T* as()
{ {
return get(std::is_same<T, value_property>(), value.apply(pt_writer(out, indentation));
std::is_same<T, list_property>(),
std::is_same<T, map_property>());
} }
}; };
/** class binary_serializer : public serializer
* @brief
*/
class abstract_object
{ {
inline void push_back() { } typedef char* buf_type;
buf_type m_buf;
size_t m_wr_pos;
template<typename T0, typename... Tn> struct pt_writer
void push_back(T0* ptr0, Tn*... ptrs)
{ {
static_assert( std::is_same<T0, value_property>::value
|| std::is_same<T0, list_property>::value
|| std::is_same<T0, map_property>::value,
"invalid type");
m_properties.push_back(property_ptr(ptr0));
push_back(ptrs...);
}
public: buf_type& m_buf;
size_t& m_wr_pos;
typedef std::vector<property_ptr> pptr_vector; pt_writer(buf_type& buf, size_t& pos) : m_buf(buf), m_wr_pos(pos) { }
abstract_object(pptr_vector&& pvec) : m_properties(std::move(pvec)) { } template<typename T>
void operator()(const T& value)
{
memcpy(m_buf + m_wr_pos, &value, sizeof(T));
m_wr_pos += sizeof(T);
}
void operator()(const std::u16string&) { }
void operator()(const std::u32string&) { }
template<typename T0, typename... Tn> };
abstract_object(T0* ptr0, Tn*... ptrs)
template<typename T>
void write(const T& value)
{ {
push_back(ptr0, ptrs...); memcpy(m_buf + m_wr_pos, &value, sizeof(T));
m_wr_pos += sizeof(T);
} }
abstract_object() = default; void write(const std::string& str)
abstract_object(abstract_object&&) = default; {
abstract_object& operator=(abstract_object&&) = default; write(static_cast<std::uint32_t>(str.size()));
memcpy(m_buf + m_wr_pos, str.c_str(), str.size());
m_wr_pos += str.size();
}
public:
abstract_object(const abstract_object&) = delete; binary_serializer(char* buf) : m_buf(buf), m_wr_pos(0) { }
abstract_object& operator=(const abstract_object&) = delete;
size_t properties() void begin_object(const std::string& tname)
{ {
return m_properties.size(); write(tname);
} }
property_ptr& property(size_t pos) void end_object() { }
void begin_list(size_t list_size)
{ {
return m_properties[pos]; write(static_cast<std::uint32_t>(list_size));
} }
private: void end_list() { }
pptr_vector m_properties; void write_value(const pt_value& value)
{
value.apply(pt_writer(m_buf, m_wr_pos));
}
}; };
class sink class binary_deserializer : public deserializer
{ {
public: typedef char* buf_type;
virtual void write(abstract_object&) = 0; buf_type m_buf;
size_t m_rd_pos;
size_t m_buf_size;
}; void range_check(size_t read_size)
{
if (m_rd_pos + read_size >= m_buf_size)
{
std::out_of_range("binary_deserializer::read()");
}
}
struct xml_sink_helper
{
std::ostringstream& ostr;
const std::string& indent;
xml_sink_helper(std::ostringstream& mostr, const std::string& idn) : ostr(mostr), indent(idn) { }
template<typename T> template<typename T>
void operator()(const T& what) void read(T& storage, bool modify_rd_pos = true)
{ {
static const fundamental_type ftype = type_to_ftype<T>::ftype; range_check(sizeof(T));
ostr << indent memcpy(&storage, m_buf + m_rd_pos, sizeof(T));
<< "<" << fundamental_type_name(ftype) << ">" if (modify_rd_pos) m_rd_pos += sizeof(T);
<< what
<< "</" << fundamental_type_name(ftype) << ">\n";
} }
void operator()(const std::u16string&) { }
void operator()(const std::u32string&) { }
};
class xml_sink void read(std::string& str, bool modify_rd_pos = true)
{ {
std::uint32_t str_size;
static const char br = '\n'; read(str_size, modify_rd_pos);
char* cpy_begin;
if (modify_rd_pos)
{
range_check(str_size);
cpy_begin = m_buf + m_rd_pos;
}
else
{
range_check(sizeof(std::uint32_t) + str_size);
cpy_begin = m_buf + m_rd_pos + sizeof(std::uint32_t);
}
str.clear();
str.reserve(str_size);
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;
}
std::ostringstream ostr; template<typename CharType, typename StringType>
void read_unicode_string(StringType& str)
{
std::uint32_t str_size;
read(str_size);
str.reserve(str_size);
for (size_t i = 0; i < str_size; ++i)
{
CharType c;
read(c);
str_size += static_cast<typename StringType::value_type>(c);
}
}
void append(const std::string& indentation, const ft_value& what) void read(std::u16string& str)
{ {
what.apply(xml_sink_helper(ostr, indentation)); // char16_t is guaranteed to has *at least* 16 bytes,
// but not to have *exactly* 16 bytes; thus use uint16_t
read_unicode_string<std::uint16_t>(str);
} }
public: void read(std::u32string& str)
{
// char32_t is guaranteed to has *at least* 32 bytes,
// but not to have *exactly* 32 bytes; thus use uint32_t
read_unicode_string<std::uint32_t>(str);
}
void write(abstract_object& obj) struct pt_reader
{ {
ostr << "<object>" << br; binary_deserializer* self;
for (size_t i = 0; i < obj.properties(); ++i) inline pt_reader(binary_deserializer* mself) : self(mself) { }
template<typename T>
inline void operator()(T& value)
{ {
property_ptr& pptr = obj.property(i); self->read(value);
if (pptr.is_value_property())
{
auto vp = pptr.as<value_property>();
ft_value val(vp->type());
vp->get(val);
append(" ", val);
}
} }
ostr << "</object>"; };
public:
binary_deserializer(buf_type buf, size_t buf_size)
: m_buf(buf), m_rd_pos(0), m_buf_size(buf_size)
{
} }
std::string str() const { return ostr.str(); } std::string seek_object()
{
std::string result;
read(result);
return result;
}
}; std::string peek_object()
{
std::string result;
read(result, false);
return result;
}
class source void begin_object(const std::string&)
{ {
}
public: void end_object()
{
}
virtual void read(abstract_object&) = 0; size_t begin_list(primitive_type)
{
std::uint32_t size;
read(size);
return size;
}
}; void end_list()
{
}
pt_value read_value(primitive_type ptype)
{
pt_value val(ptype);
val.apply(pt_reader(this));
return val;
}
struct point_struct
{
std::uint32_t x, y, z;
}; };
class point_class class string_deserializer : public deserializer
{ {
std::uint32_t m_x, m_y, m_z; std::string m_str;
std::string::iterator m_pos;
size_t m_obj_count;
public: void skip_space_and_comma()
{
while (*m_pos == ' ' || *m_pos == ',') ++m_pos;
}
point_class() : m_x(0), m_y(0), m_z(0) { } void throw_malformed(const std::string& error_msg)
{
throw std::logic_error("malformed string: " + error_msg);
}
point_class(std::uint32_t mx, std::uint32_t my, std::uint32_t mz) void consume(char c)
: m_x(mx), m_y(my), m_z(mz)
{ {
skip_space_and_comma();
if (*m_pos != c)
{
std::string error;
error += "expected '";
error += c;
error += "' found '";
error += *m_pos;
error += "'";
throw_malformed(error);
}
++m_pos;
} }
std::uint32_t x() const { return m_x; } inline std::string::iterator next_delimiter()
{
return std::find_if(m_pos, m_str.end(), [] (char c) -> bool {
switch (c)
{
case '(':
case ')':
case '{':
case '}':
case ' ':
case ',': return true;
default : return false;
}
});
}
std::uint32_t y() const { return m_y; } public:
std::uint32_t z() const { return m_z; } string_deserializer(const std::string& str) : m_str(str)
{
m_pos = m_str.begin();
m_obj_count = 0;
}
void set_x(std::uint32_t value) { m_x = value; } string_deserializer(std::string&& str) : m_str(std::move(str))
{
m_pos = m_str.begin();
m_obj_count = 0;
}
void set_y(std::uint32_t value) { m_y = value; } std::string seek_object()
{
skip_space_and_comma();
auto substr_end = next_delimiter();
// next delimiter must eiter be '(' or "\w+\("
if (substr_end == m_str.end() || *substr_end != '(')
{
auto peeker = substr_end;
while (peeker != m_str.end() && *peeker == ' ') ++peeker;
if (peeker == m_str.end() || *peeker != '(')
{
throw_malformed("type name not followed by '('");
}
}
std::string result(m_pos, substr_end);
m_pos = substr_end;
return result;
}
void set_z(std::uint32_t value) { m_z = value; } std::string peek_object()
{
std::string result = seek_object();
// restore position in stream
m_pos -= result.size();
return result;
}
}; void begin_object(const std::string&)
{
++m_obj_count;
skip_space_and_comma();
consume('(');
}
void plot(value_property* vp) void end_object()
{
ft_value v(vp->type());
vp->get(v);
switch (v.type())
{ {
case ft_uint32: cout << ft_value_cast<ft_uint32>(v) << " "; break; consume(')');
default: break; if (--m_obj_count == 0)
{
skip_space_and_comma();
if (m_pos != m_str.end())
{
throw_malformed("expected end of of string");
}
}
} }
}
void plot(property_ptr& pptr) size_t begin_list(primitive_type)
{
if (pptr.is_value_property())
{ {
plot(pptr.as<value_property>()); consume('{');
auto list_end = std::find(m_pos, m_str.end(), '}');
return std::count(m_pos, list_end, ',') + 1;
} }
}
void plot(abstract_object& what, const std::string& what_name) void end_list()
{
cout << what_name << " (" << what.properties() << " properties): ";
for (size_t i = 0; i < what.properties(); ++i)
{ {
plot(what.property(i)); consume('}');
} }
cout << endl;
struct from_string
{
const std::string& str;
from_string(const std::string& s) : str(s) { }
template<typename T>
void operator()(T& what)
{
std::istringstream s(str);
s >> what;
}
void operator()(std::string& what)
{
what = str;
}
void operator()(std::u16string&) { }
void operator()(std::u32string&) { }
};
pt_value read_value(primitive_type ptype)
{
skip_space_and_comma();
auto substr_end = std::find_if(m_pos, m_str.end(), [] (char c) -> bool {
switch (c)
{
case ')':
case '}':
case ' ':
case ',': return true;
default : return false;
}
});
std::string substr(m_pos, substr_end);
pt_value result(ptype);
result.apply(from_string(substr));
m_pos += substr.size();
return result;
}
};
template<typename T>
std::string to_string(T* what, meta_object<T>* mobj)
{
std::ostringstream osstr;
string_serializer strs(osstr);
mobj->serialize(what, &strs);
return osstr.str();
} }
std::size_t test__serialization() std::size_t test__serialization()
...@@ -1137,150 +1506,84 @@ std::size_t test__serialization() ...@@ -1137,150 +1506,84 @@ std::size_t test__serialization()
CPPA_TEST(test__serialization); CPPA_TEST(test__serialization);
CPPA_CHECK_EQUAL((trait::is_iterable<int>::value), false);
// std::string is primitive and thus not identified by is_iterable
CPPA_CHECK_EQUAL((trait::is_iterable<std::string>::value), false);
CPPA_CHECK_EQUAL((trait::is_iterable<std::list<int>>::value), true);
CPPA_CHECK_EQUAL((trait::is_iterable<std::map<int,int>>::value), true);
// test pt_value implementation
{ {
ft_value v1(42); pt_value v1(42);
ft_value v2(42); pt_value v2(42);
CPPA_CHECK_EQUAL(v1, v2); CPPA_CHECK_EQUAL(v1, v2);
CPPA_CHECK_EQUAL(v1, 42); CPPA_CHECK_EQUAL(v1, 42);
CPPA_CHECK_EQUAL(42, v2); CPPA_CHECK_EQUAL(42, v2);
// type mismatch => unequal
CPPA_CHECK(v2 != static_cast<std::int8_t>(42)); CPPA_CHECK(v2 != static_cast<std::int8_t>(42));
} }
auto manipulate_point = [&](abstract_object& pt) { root_object root;
CPPA_CHECK_EQUAL(pt.properties(), 3);
if (pt.properties() == 3)
{
for (size_t i = 0; i < 3; ++i)
{
property_ptr& pptr = pt.property(i);
bool is_value_property = pptr.is_value_property();
CPPA_CHECK(is_value_property);
if (is_value_property)
{
CPPA_CHECK_EQUAL(pptr.as<value_property>()->type(),
ft_uint32);
if (i == 1)
{
auto vptr = pptr.as<value_property>();
// value must be 2
ft_value val(ft_uint32);
vptr->get(val);
CPPA_CHECK_EQUAL(ft_value_cast<ft_uint32>(val), 2);
vptr->set(ft_value(static_cast<std::uint32_t>(22)));
vptr->get(val);
CPPA_CHECK_EQUAL(ft_value_cast<ft_uint32>(val), 22);
}
}
}
}
};
// test as_value_property with direct member access // test serializers / deserializers
{ {
point_struct pt = { 1, 2, 3 };
abstract_object abstract_pt { as_value_property(&pt.x),
as_value_property(&pt.y),
as_value_property(&pt.z) };
manipulate_point(abstract_pt);
CPPA_CHECK_EQUAL(pt.x, 1);
CPPA_CHECK_EQUAL(pt.y, 22);
CPPA_CHECK_EQUAL(pt.z, 3);
xml_sink xs;
xs.write(abstract_pt);
cout << "XML:" << endl << xs.str() << endl;
}
// test as_value_property with direct getter / setter implementations meta_object<struct_b> meta_b {
{ compound_member(&struct_b::a, &struct_a::x, &struct_a::y),
point_class pt = { 1, 2, 4 }; &struct_b::z,
abstract_object abstract_pt = { &struct_b::ints
as_value_property<ft_uint32>(&pt, &point_class::x, &point_class::set_x),
as_value_property<ft_uint32>(&pt, &point_class::y, &point_class::set_y),
as_value_property<ft_uint32>(&pt, &point_class::z, &point_class::set_z)
}; };
manipulate_point(abstract_pt);
CPPA_CHECK_EQUAL(pt.x(), 1);
CPPA_CHECK_EQUAL(pt.y(), 22);
CPPA_CHECK_EQUAL(pt.z(), 4);
}
{ // "announce" meta types
std::string str = "Hello World"; s_meta_types["struct_b"] = &meta_b;
std::unique_ptr<value_property> p(as_value_property(&str));
p->set(std::string("foobar"));
CPPA_CHECK_EQUAL(str, "foobar");
}
{ struct_b b1 = { { 1, 2 }, 3, { 4, 5, 6, 7, 8, 9, 10 } };
std::vector<std::int32_t> ints; struct_b b2;
std::unique_ptr<list_property> p(as_list_property(&ints)); struct_b b3;
p->push_back(static_cast<std::int32_t>(1));
p->push_back(static_cast<std::int32_t>(2)); auto b1str = "struct_b ( struct_a ( 1, 2 ), 3, "
p->push_back(static_cast<std::int32_t>(3)); "{ 4, 5, 6, 7, 8, 9, 10 } )";
for (std::unique_ptr<list_property::iterator> i(p->begin()); !i->at_end(); i->next())
CPPA_CHECK_EQUAL((to_string(&b1, &meta_b)), b1str);
char buf[512];
// serialize b1 to buf
{ {
cout << ft_value_cast<ft_int32>(i->get()) << " "; binary_serializer bs(buf);
meta_b.serialize(&b1, &bs);
} }
cout << endl;
CPPA_CHECK_EQUAL(ints.size(), 3);
CPPA_CHECK_EQUAL(ints, (std::vector<std::int32_t>({1, 2, 3})));
}
{ // deserialize b2 from buf
std::map<std::int32_t, std::string> strings;
std::unique_ptr<map_property> p(as_map_property(&strings));
p->insert(static_cast<std::int32_t>(2), std::string("two"));
p->insert(static_cast<std::int32_t>(1), std::string("one"));
p->insert(static_cast<std::int32_t>(4), std::string("four"));
std::map<std::int32_t, std::string> verification_map = {
{ 1, "one" },
{ 2, "two" },
{ 4, "four" }
};
CPPA_CHECK_EQUAL(strings.size(), 3);
CPPA_CHECK_EQUAL(strings, verification_map);
// also check equality by iterators
if (strings.size() == verification_map.size())
{ {
auto siter = strings.begin(); binary_deserializer bd(buf, 512);
auto send = strings.end(); auto res = root.deserialize(&bd);
std::unique_ptr<map_property::iterator> viter(p->begin()); CPPA_CHECK_EQUAL(res.second, &meta_b);
while (siter != send) if (res.second == &meta_b)
{ {
CPPA_CHECK_EQUAL(ft_value_cast<ft_int32>(viter->key()), b2 = *reinterpret_cast<struct_b*>(res.first);
siter->first);
CPPA_CHECK_EQUAL(ft_value_cast<ft_u8string>(viter->value()),
siter->second);
viter->next();
++siter;
} }
res.second->delete_instance(res.first);
} }
}
ft_value v1("Hello World"); CPPA_CHECK_EQUAL(b1, b2);
CPPA_CHECK_EQUAL((to_string(&b2, &meta_b)), b1str);
auto plot_objects = [] (const std::vector<cppa::object>& objs) // deserialize b3 from string, using string_deserializer
{
cout << "{ ";
bool first = true;
for (const cppa::object& o : objs)
{ {
if (first) first = false; string_deserializer strd(b1str);
else cout << ", "; auto res = root.deserialize(&strd);
cout << o.type().name() << "("; CPPA_CHECK_EQUAL(res.second, &meta_b);
if (o.type() == typeid(std::string)) if (res.second == &meta_b)
cout << "\"" << o.to_string() << "\""; {
else b3 = *reinterpret_cast<struct_b*>(res.first);
cout << o.to_string(); }
cout << ")"; res.second->delete_instance(res.first);
} }
cout << " }" << endl;
};
plot_objects({ CPPA_CHECK_EQUAL(b1, b3);
cppa::uniform_typeid<int>()->create(),
cppa::uniform_typeid<std::string>()->create() }
});
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