From 834dcb1bd602078944a4f500828a98af13ba3181 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 22 Mar 2013 01:13:44 +0100 Subject: [PATCH] eoserial: comments for Serialize. --- eo/src/serial/Serialize.h | 246 +++++++++++++++++++++++++++++--------- 1 file changed, 189 insertions(+), 57 deletions(-) diff --git a/eo/src/serial/Serialize.h b/eo/src/serial/Serialize.h index fe3d21ab8..b3d5c2c1b 100644 --- a/eo/src/serial/Serialize.h +++ b/eo/src/serial/Serialize.h @@ -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 @@ -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 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 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 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 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 eoserial::Entity* makeObject( const T & arg ) { @@ -126,26 +181,10 @@ namespace eoserial return 0; } - - template - void deserializeSimple( const eoserial::Entity* json, T & value ) - { - throw std::runtime_error("eoSerial: deserializeSimple called with an unknown basic type."); - } - - template - 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 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(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( 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 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() is not used when calling with the parameter A. + */ + template + eoserial::Entity* serialize( const T & arg ) + { + // static check (introduced by C++11) + // - avoids the invariant template issue + if( std::is_convertible::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(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 + 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 + void deserializeObject( const eoserial::Entity* json, T & value ) + { + throw std::runtime_error("eoSerial:: deserializeObject called with a non eoserial::Persistent object."); + } + + /* + * Specializations of deserializeSimple 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(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 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( json ) ); + } + + /* + * Implementation of deserializeBase. + * + * For technical comments, @see makeSimple. The followed scheme + * is exactly the same. + */ template void deserializeBase( const eoserial::Entity* json, T & value ) { @@ -250,17 +388,11 @@ namespace eoserial } } - template - eoserial::Entity* serialize( const T & arg ) - { - if( std::is_convertible::value ) - { - return eoserial::makeObject( reinterpret_cast(arg) ); - } else { - return eoserial::makeSimple( arg ); - } - } - + /* + * Implementation of deserialize. + * + * Simply calls the deserializeBase function with the corresponding Entity. + */ template void deserialize( const eoserial::Entity& json, const std::string& field, T & value ) {