eoserial: comments for Serialize.

This commit is contained in:
Benjamin Bouvier 2013-03-22 01:13:44 +01:00
commit 834dcb1bd6

View file

@ -26,7 +26,7 @@ Authors:
* This file contains primitive to make serialization and
* deserialization easy.
*
* See the snippet example code below.
* See the example code snippet below.
*
* @code
* # include <eoSerial.h>
@ -39,7 +39,7 @@ Authors:
* int value;
* MyObject( int v ) : value(v) {}
*
* eoserial::Entity* pack() const
* eoserial::Object* pack() const
* {
* eoserial::Object* e = new eoserial::Object;
* (*e)["the_value"] = eoserial::serialize( value );
@ -74,6 +74,13 @@ Authors:
* o["vec"] = eoserial::serialize( vec );
*
* o.print( std::cout );
*
* std::list<int> lis;
* eoserial::deserialize( o, "vec", lis );
*
* long oneTwoThreeFourFiveSix;
* eoserial::deserialize( o, "long", oneTwoThreeFourFiveSix);
*
* return 0;
* }
* @endcode
@ -101,9 +108,42 @@ Authors:
namespace eoserial
{
/**
* @brief Tries to serialize the given argument into an Entity.
*
* This function can be called with any argument of the following kinds:
* - basic types (int, bool, float, double, char, short, long)
* - standard STL types (std::string, std::list, std::vector). In
* this case, the serialization is automatically called on the
* contained objects.
* - objects which implement eoserial::Printable
*
* @param arg The argument to serialize.
* @return an Entity to be used with the serialization module.
*
* @throws std::runtime_exception when the type T is not known or
* not convertible to a known type.
*/
template<class T>
eoserial::Entity* serialize( const T & arg );
/**
* @brief Tries to deserialize the given argument from the given field in the entity and loads it into the in-out
* given value.
*
* This function is the reverse operator of the serialize function:
* - basic types are supported
* - standard STL types (std::string, std::list, std::vector)
* - objects which implement eoserial::Persistent
* @see serialize
*
* @param json The entity containing the variable to deserialize
* @param field The name of the field used in the original object
* @param value The in-out value in which we want to store the result of the deserialization.
*
* @throws std::runtime_exception when the type T is not known or
* not convertible to a known type.
*/
template<class T>
void deserialize( const eoserial::Entity& json, const std::string& field, T & value );
@ -112,6 +152,15 @@ namespace eoserial
* Use at your own risk! ***
**************************/
/* *************************
* SERIALIZATION ***********
**************************/
/**
* @brief Function to be called for non eoserial::Printable objects.
*
* The default behaviour is to throw a runtime exception. The function is then specialized for known types.
*/
template<class T>
eoserial::Entity* makeSimple( const T & arg )
{
@ -119,6 +168,12 @@ namespace eoserial
return 0;
}
/**
* @brief Function to be called for eoserial::Printable objects and only these ones.
*
* The default behaviour is to throw a runtime exception. The function is specialized only for eoserial::Printable
* object.
*/
template<class T>
eoserial::Entity* makeObject( const T & arg )
{
@ -126,26 +181,10 @@ namespace eoserial
return 0;
}
template<class T>
void deserializeSimple( const eoserial::Entity* json, T & value )
{
throw std::runtime_error("eoSerial: deserializeSimple called with an unknown basic type.");
}
template<class T>
void deserializeObject( const eoserial::Entity* json, T & value )
{
throw std::runtime_error("eoSerial:: deserializeObject called with a non eoserial::Persistent object.");
}
template<>
eoserial::Entity* makeObject( const eoserial::Printable & arg )
{
return arg.pack();
}
/*
* Specializations of makeSimple<T> for basic types.
* Macro MKSIMPLE can be used to register any type that can be printed into a std::ostream.
*/
# define MKSIMPLE(A) template<>\
eoserial::Entity* makeSimple( const A& arg ) \
{ \
@ -160,31 +199,14 @@ namespace eoserial
MKSIMPLE(double)
MKSIMPLE(char)
MKSIMPLE(std::string)
# undef MKSIMPLE
# define DSSIMPLE(A) template<> \
void deserializeSimple( const eoserial::Entity* json, A & value ) \
{ \
static_cast<const eoserial::String*>(json)->deserialize( value ); \
}
DSSIMPLE(bool);
DSSIMPLE(int);
DSSIMPLE(short);
DSSIMPLE(long);
DSSIMPLE(float);
DSSIMPLE(double);
DSSIMPLE(char);
DSSIMPLE(std::string);
# undef DSSIMPLE
template<>
void deserializeObject( const eoserial::Entity* json, eoserial::Persistent & value )
{
value.unpack( static_cast<const eoserial::Object*>( json ) );
}
# undef MKSIMPLE // avoids undebuggable surprises
/**
* @brief Base specialization for objects iterable thanks to
* begin(), end() and basic iterators.
*
* This specialization is used for std::list and std::vector.
*/
template<class Container>
eoserial::Entity* makeSimpleIterable( const Container & c )
{
@ -210,9 +232,108 @@ namespace eoserial
return makeSimpleIterable( l );
}
/**
* @brief Specialization of makeObject for eoserial::Printable.
*
* For these objects, we can directly use their pack method.
*/
template<>
eoserial::Entity* makeObject( const eoserial::Printable & arg )
{
return arg.pack();
}
/*
* @brief Implementation of Serialize function.
*
* The idea is the following:
* - either the object implements eoserial::Printable and can be serialized directly with makeObject
* - or it's not, and thus we have to try the registered types.
*
* The difficulty of this function is to be callable with any kind of argument, whatever the type. For that purpose,
* templating is frequently used with default behaviours being erroneous. This way, the compiler can try all
* branches of the conditional and find an implementation of the function that works for the given type.
* This trick is used as the templates functions (and methods) are invariant in C++: if A inherits B, the specialization
* f<B>() is not used when calling with the parameter A.
*/
template<class T>
eoserial::Entity* serialize( const T & arg )
{
// static check (introduced by C++11)
// - avoids the invariant template issue
if( std::is_convertible<T*, eoserial::Printable*>::value )
{
// at this point, we are sure that we can cast the argument into an eoserial::Printable.
// reinterpret_cast has to be used, otherwise static_cast and dynamic_cast will fail at compile time for
// basic types.
return eoserial::makeObject( reinterpret_cast<const eoserial::Printable&>(arg) );
} else {
// not an eoserial::Printable, try registered types
return eoserial::makeSimple( arg );
}
}
/* *****************
* DESERIALIZATION *
******************/
/**
* @brief Function to be called for non eoserial::Persistent objects.
*
* The default behaviour is to throw a runtime exception. The function is then specialized for known types.
*/
template<class T>
void deserializeSimple( const eoserial::Entity* json, T & value )
{
throw std::runtime_error("eoSerial: deserializeSimple called with an unknown basic type.");
}
/**
* @brief Function to be called for eoserial::Persistent objects and only these ones.
*
* The default behaviour is to throw a runtime exception. The function is specialized only for eoserial::Persistent
* object.
*/
template<class T>
void deserializeObject( const eoserial::Entity* json, T & value )
{
throw std::runtime_error("eoSerial:: deserializeObject called with a non eoserial::Persistent object.");
}
/*
* Specializations of deserializeSimple<T> for basic types.
* Macro DSSIMPLE can be used to register any type that can be read from a std::istream.
*/
# define DSSIMPLE(A) template<> \
void deserializeSimple( const eoserial::Entity* json, A & value ) \
{ \
static_cast<const eoserial::String*>(json)->deserialize( value ); \
}
DSSIMPLE(bool);
DSSIMPLE(int);
DSSIMPLE(short);
DSSIMPLE(long);
DSSIMPLE(float);
DSSIMPLE(double);
DSSIMPLE(char);
DSSIMPLE(std::string);
# undef DSSIMPLE // avoids undebuggable surprises
/**
* @brief Deserialize function with two arguments.
*
* Used by list and vector containers.
*/
template<class T>
void deserializeBase( const eoserial::Entity* json, T & value );
/**
* @brief Base specialization for objects that implement push_back.
*
* This specialization is used for std::list and std::vector.
*/
template< class Container >
void deserializeSimplePushBack( const eoserial::Entity* json, Container & c )
{
@ -239,6 +360,23 @@ namespace eoserial
deserializeSimplePushBack( json, v );
}
/**
* @brief Specialization of deserializeObject for eoserial::Persistent.
*
* For these objects, we can directly use their unpack method.
*/
template<>
void deserializeObject( const eoserial::Entity* json, eoserial::Persistent & value )
{
value.unpack( static_cast<const eoserial::Object*>( json ) );
}
/*
* Implementation of deserializeBase.
*
* For technical comments, @see makeSimple. The followed scheme
* is exactly the same.
*/
template<class T>
void deserializeBase( const eoserial::Entity* json, T & value )
{
@ -250,17 +388,11 @@ namespace eoserial
}
}
template<class T>
eoserial::Entity* serialize( const T & arg )
{
if( std::is_convertible<T*, eoserial::Printable*>::value )
{
return eoserial::makeObject( reinterpret_cast<const eoserial::Printable&>(arg) );
} else {
return eoserial::makeSimple( arg );
}
}
/*
* Implementation of deserialize.
*
* Simply calls the deserializeBase function with the corresponding Entity.
*/
template<class T>
void deserialize( const eoserial::Entity& json, const std::string& field, T & value )
{