From 43cb068d539d71a08ebf5b25f045c5f4275ffbaf Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 15 Mar 2013 19:17:40 +0100 Subject: [PATCH 01/14] eoserial:: const correctness for String. --- eo/src/serial/String.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/eo/src/serial/String.h b/eo/src/serial/String.h index 526cab365..2ef1f94f5 100644 --- a/eo/src/serial/String.h +++ b/eo/src/serial/String.h @@ -62,7 +62,7 @@ namespace eoserial * @param value The value in which we're writing. */ template - inline void deserialize( T & value ); + inline void deserialize( T & value ) const; protected: // Copy and reaffectation are forbidden @@ -80,7 +80,7 @@ namespace eoserial * invoking. */ template - inline void String::deserialize( T & value ) + inline void String::deserialize( T & value ) const { std::stringstream ss; ss.precision(std::numeric_limits::digits10 + 1); @@ -93,7 +93,7 @@ namespace eoserial * a stringstream. */ template<> - inline void String::deserialize( std::string & value ) + inline void String::deserialize( std::string & value ) const { value = *this; } From 10148ae00bb5e41a73f156db60c949b04847c019 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 15 Mar 2013 19:26:32 +0100 Subject: [PATCH 02/14] eoserial: renamed String/Object/Array into Serial* to avoid compiler confusion. --- eo/src/serial/CMakeLists.txt | 6 +++--- eo/src/serial/Parser.cpp | 6 +++--- eo/src/serial/Parser.h | 4 ++-- eo/src/serial/{Array.cpp => SerialArray.cpp} | 2 +- eo/src/serial/{Array.h => SerialArray.h} | 2 +- eo/src/serial/{Object.cpp => SerialObject.cpp} | 2 +- eo/src/serial/{Object.h => SerialObject.h} | 0 eo/src/serial/{String.cpp => SerialString.cpp} | 2 +- eo/src/serial/{String.h => SerialString.h} | 0 eo/src/serial/Utils.h | 6 +++--- eo/src/serial/eoSerial.h | 6 +++--- 11 files changed, 18 insertions(+), 18 deletions(-) rename eo/src/serial/{Array.cpp => SerialArray.cpp} (98%) rename eo/src/serial/{Array.h => SerialArray.h} (99%) rename eo/src/serial/{Object.cpp => SerialObject.cpp} (98%) rename eo/src/serial/{Object.h => SerialObject.h} (100%) rename eo/src/serial/{String.cpp => SerialString.cpp} (97%) rename eo/src/serial/{String.h => SerialString.h} (100%) diff --git a/eo/src/serial/CMakeLists.txt b/eo/src/serial/CMakeLists.txt index 43d1ce451..efc9f42e2 100644 --- a/eo/src/serial/CMakeLists.txt +++ b/eo/src/serial/CMakeLists.txt @@ -13,10 +13,10 @@ set(EOSERIAL_LIB_OUTPUT_PATH ${EO_BIN_DIR}/lib) set(LIBRARY_OUTPUT_PATH ${EOSERIAL_LIB_OUTPUT_PATH}) set(EOSERIAL_SOURCES - Array.cpp - Object.cpp + SerialArray.cpp + SerialObject.cpp Parser.cpp - String.cpp + SerialString.cpp ) add_library(eoserial STATIC ${EOSERIAL_SOURCES}) diff --git a/eo/src/serial/Parser.cpp b/eo/src/serial/Parser.cpp index 57b52a0dd..e78b35392 100644 --- a/eo/src/serial/Parser.cpp +++ b/eo/src/serial/Parser.cpp @@ -23,9 +23,9 @@ Authors: # include "Parser.h" -# include "Array.h" -# include "Object.h" -# include "String.h" +# include "SerialArray.h" +# include "SerialObject.h" +# include "SerialString.h" // in debug mode only // # define DEBUG(x) std::cout << x << std::endl; diff --git a/eo/src/serial/Parser.h b/eo/src/serial/Parser.h index 20f6a1bb2..392f25ffa 100644 --- a/eo/src/serial/Parser.h +++ b/eo/src/serial/Parser.h @@ -23,8 +23,8 @@ Authors: # define __EOSERIAL_PARSER_H__ # include "Entity.h" -# include "String.h" -# include "Object.h" +# include "SerialString.h" +# include "SerialObject.h" /** * @file Parser.h diff --git a/eo/src/serial/Array.cpp b/eo/src/serial/SerialArray.cpp similarity index 98% rename from eo/src/serial/Array.cpp rename to eo/src/serial/SerialArray.cpp index 180aad16b..5282370f5 100644 --- a/eo/src/serial/Array.cpp +++ b/eo/src/serial/SerialArray.cpp @@ -19,7 +19,7 @@ Contact: http://eodev.sourceforge.net Authors: Benjamin Bouvier */ -# include "Array.h" +# include "SerialArray.h" namespace eoserial { diff --git a/eo/src/serial/Array.h b/eo/src/serial/SerialArray.h similarity index 99% rename from eo/src/serial/Array.h rename to eo/src/serial/SerialArray.h index d453add99..b349953aa 100644 --- a/eo/src/serial/Array.h +++ b/eo/src/serial/SerialArray.h @@ -26,7 +26,7 @@ Authors: # include "Entity.h" # include "Serializable.h" -# include "Object.h" +# include "SerialObject.h" namespace eoserial { diff --git a/eo/src/serial/Object.cpp b/eo/src/serial/SerialObject.cpp similarity index 98% rename from eo/src/serial/Object.cpp rename to eo/src/serial/SerialObject.cpp index dd859052e..e926e448f 100644 --- a/eo/src/serial/Object.cpp +++ b/eo/src/serial/SerialObject.cpp @@ -19,7 +19,7 @@ Contact: http://eodev.sourceforge.net Authors: Benjamin Bouvier */ -# include "Object.h" +# include "SerialObject.h" using namespace eoserial; diff --git a/eo/src/serial/Object.h b/eo/src/serial/SerialObject.h similarity index 100% rename from eo/src/serial/Object.h rename to eo/src/serial/SerialObject.h diff --git a/eo/src/serial/String.cpp b/eo/src/serial/SerialString.cpp similarity index 97% rename from eo/src/serial/String.cpp rename to eo/src/serial/SerialString.cpp index c50882786..6d49106cc 100644 --- a/eo/src/serial/String.cpp +++ b/eo/src/serial/SerialString.cpp @@ -19,7 +19,7 @@ Contact: http://eodev.sourceforge.net Authors: Benjamin Bouvier */ -# include "String.h" +# include "SerialString.h" namespace eoserial { diff --git a/eo/src/serial/String.h b/eo/src/serial/SerialString.h similarity index 100% rename from eo/src/serial/String.h rename to eo/src/serial/SerialString.h diff --git a/eo/src/serial/Utils.h b/eo/src/serial/Utils.h index 33172a747..13b6877b1 100644 --- a/eo/src/serial/Utils.h +++ b/eo/src/serial/Utils.h @@ -22,9 +22,9 @@ Authors: # ifndef __EOSERIAL_UTILS_H__ # define __EOSERIAL_UTILS_H__ -# include "Array.h" -# include "Object.h" -# include "String.h" +# include "SerialArray.h" +# include "SerialObject.h" +# include "SerialString.h" namespace eoserial { diff --git a/eo/src/serial/eoSerial.h b/eo/src/serial/eoSerial.h index 55a116f0c..8ea3a9764 100644 --- a/eo/src/serial/eoSerial.h +++ b/eo/src/serial/eoSerial.h @@ -22,10 +22,10 @@ Authors: # ifndef __EOSERIAL_HEADERS__ # define __EOSERIAL_HEADERS__ -# include "Object.h" +# include "SerialObject.h" # include "Serializable.h" -# include "Array.h" -# include "Object.h" +# include "SerialArray.h" +# include "SerialObject.h" # include "String.h" # include "Parser.h" # include "Utils.h" From f412139549c3b837ecc70cd29dc8aa9940ed5592 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 15 Mar 2013 20:33:25 +0100 Subject: [PATCH 03/14] eoserial: bugfix: String -> SerialString. --- eo/src/serial/eoSerial.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/eo/src/serial/eoSerial.h b/eo/src/serial/eoSerial.h index 8ea3a9764..fec5fb4dd 100644 --- a/eo/src/serial/eoSerial.h +++ b/eo/src/serial/eoSerial.h @@ -22,11 +22,10 @@ Authors: # ifndef __EOSERIAL_HEADERS__ # define __EOSERIAL_HEADERS__ -# include "SerialObject.h" # include "Serializable.h" # include "SerialArray.h" # include "SerialObject.h" -# include "String.h" +# include "SerialString.h" # include "Parser.h" # include "Utils.h" From eb047ed39c5d1e948b76448cad8429c336af0902 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 15 Mar 2013 20:33:50 +0100 Subject: [PATCH 04/14] eoserial: easy serialization with eoserial::serialize and eoserial::deserialize. --- eo/src/serial/Serialize.h | 245 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 245 insertions(+) create mode 100644 eo/src/serial/Serialize.h diff --git a/eo/src/serial/Serialize.h b/eo/src/serial/Serialize.h new file mode 100644 index 000000000..1a1e99ca1 --- /dev/null +++ b/eo/src/serial/Serialize.h @@ -0,0 +1,245 @@ +/* +(c) Benjamin Bouvier, 2013 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; + version 2 of the License. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +Contact: http://eodev.sourceforge.net + +Authors: + Benjamin Bouvier +*/ + +/** + * @file Serialize.h + * + * This file contains primitive to make serialization and + * deserialization easy. + * + * See the snippet example code below. + * + * @code + * # include + * # include + * + * class MyObject: public eoserial::Persistent + * { + * public: + * + * int value; + * MyObject( int v ) : value(v) {} + * + * eoserial::Entity* pack() const + * { + * eoserial::Object* e = new eoserial::Object; + * (*e)["the_value"] = eoserial::serialize( value ); + * return e; + * } + * + * void unpack( const eoserial::Object* o ) + * { + * eoserial::deserialize( *o, "the_value", value ); + * } + * }; + * + * int main() + * { + * eoserial::Object o; + * o["long"] = eoserial::serialize(123456L); + * o["bool"] = eoserial::serialize(true); + * o["double"] = eoserial::serialize(3.141592653); + * o["float"] = eoserial::serialize(3.141592653f); + * + * std::string str = "Hello, world!"; + * o["str"] = eoserial::serialize( str ); + * + * MyObject obj(42); + * o["obj"] = eoserial::serialize( obj ); + * + * std::vector vec; + * vec.push_back(1); + * vec.push_back(3); + * vec.push_back(3); + * vec.push_back(7); + * o["vec"] = eoserial::serialize( vec ); + * + * o.print( std::cout ); + * return 0; + * } + * @endcode + * + * @todo Encapsulate non private functions. As of today (2013-03-19), it is not + * possible as GCC and Clang refuse to have std::vector specializations of template methods (while it works with + * functions). + * + * @todo Comments coming soon. + * + * @author Benjamin Bouvier + */ + +# include +# include +# include // std::runtime_error +# include // std::is_convertible (C++11) + +# include "SerialString.h" +# include "SerialObject.h" +# include "SerialArray.h" +# include "Utils.h" + +namespace eoserial +{ + + template + eoserial::Entity* serialize( const T & arg ); + + template + void deserialize( const eoserial::Entity& json, const std::string& field, T & value ); + + /* ************************* + * PRIVATE FUNCTIONS ******* + * Use at your own risk! *** + **************************/ + + template + eoserial::Entity* makeSimple( const T & arg ) + { + throw std::runtime_error("eoSerial: makeSimple called with an unknown basic type."); + return 0; + } + + template + eoserial::Entity* makeObject( const T & arg ) + { + throw std::runtime_error("eoSerial: makeObject called with an non eoserial::Printable type."); + return 0; + } + + + template + void deserializeSimple( const eoserial::Entity* json, T & value ) + { + std::runtime_error("eoSerial: deserializeSimple called with an unknown basic type."); + } + + template + void deserializeObject( const eoserial::Entity* json, T & value ) + { + std::runtime_error("eoSerial:: deserializeObject called with a non eoserial::Persistent object."); + } + + template<> + eoserial::Entity* makeObject( const eoserial::Printable & arg ) + { + return arg.pack(); + } + + +# define MKSIMPLE(A) template<>\ + eoserial::Entity* makeSimple( const A& arg ) \ + { \ + return eoserial::make(arg); \ + } \ + + MKSIMPLE(bool) + MKSIMPLE(int) + MKSIMPLE(short) + MKSIMPLE(long) + MKSIMPLE(float) + MKSIMPLE(double) + 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(std::string); +# undef DSSIMPLE + + template<> + void deserializeObject( const eoserial::Entity* json, eoserial::Persistent & value ) + { + value.unpack( static_cast( json ) ); + } + + template + eoserial::Entity* makeSimple( const std::vector & v ) + { + eoserial::Array* array = new eoserial::Array; + for( auto it = v.begin(), end = v.end(); + it != end; + ++it ) + { + array->push_back( eoserial::serialize( *it ) ); + } + return array; + } + + template + void deserializeBase( const eoserial::Entity* json, T & value ); + + template< class T > + void deserializeSimple( const eoserial::Entity* json, std::vector & v ) + { + const eoserial::Array* sArray = static_cast(json); + for( auto it = sArray->begin(), end = sArray->end(); + it != end; + ++it ) + { + T single; + eoserial::deserializeBase( *it, single ); + v.push_back( single ); + } + } + + template + void deserializeBase( const eoserial::Entity* json, T & value ) + { + if( std::is_convertible< T*, eoserial::Persistent*>::value ) + { + eoserial::deserializeObject( json, reinterpret_cast( value ) ); + } else { + eoserial::deserializeSimple( json, value ); + } + } + + template + eoserial::Entity* serialize( const T & arg ) + { + if( std::is_convertible::value ) + { + return eoserial::makeObject( reinterpret_cast(arg) ); + } else { + return eoserial::makeSimple( arg ); + } + } + + template + void deserialize( const eoserial::Entity& json, const std::string& field, T & value ) + { + const eoserial::Entity* jField = static_cast(json).find(field)->second; + eoserial::deserializeBase( jField, value ); + } +} + + From dc0f995ff4f0de4a91163c64d45c056ec84f53ff Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 22 Mar 2013 00:37:25 +0100 Subject: [PATCH 05/14] eoserial: typos (comment + throw exceptions) --- eo/src/serial/Serialize.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/eo/src/serial/Serialize.h b/eo/src/serial/Serialize.h index 1a1e99ca1..f833f427a 100644 --- a/eo/src/serial/Serialize.h +++ b/eo/src/serial/Serialize.h @@ -78,7 +78,7 @@ Authors: * } * @endcode * - * @todo Encapsulate non private functions. As of today (2013-03-19), it is not + * @todo Encapsulate private functions. As of today (2013-03-19), it is not * possible as GCC and Clang refuse to have std::vector specializations of template methods (while it works with * functions). * @@ -129,13 +129,13 @@ namespace eoserial template void deserializeSimple( const eoserial::Entity* json, T & value ) { - std::runtime_error("eoSerial: deserializeSimple called with an unknown basic type."); + throw std::runtime_error("eoSerial: deserializeSimple called with an unknown basic type."); } template void deserializeObject( const eoserial::Entity* json, T & value ) { - std::runtime_error("eoSerial:: deserializeObject called with a non eoserial::Persistent object."); + throw std::runtime_error("eoSerial:: deserializeObject called with a non eoserial::Persistent object."); } template<> From f7e2a6ea7fd75fb86f9186877909e17acc346a4e Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 22 Mar 2013 00:37:59 +0100 Subject: [PATCH 06/14] eoserial: support char + std::list --- eo/src/serial/Serialize.h | 41 ++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/eo/src/serial/Serialize.h b/eo/src/serial/Serialize.h index f833f427a..fe3d21ab8 100644 --- a/eo/src/serial/Serialize.h +++ b/eo/src/serial/Serialize.h @@ -88,6 +88,7 @@ Authors: */ # include +# include # include # include // std::runtime_error # include // std::is_convertible (C++11) @@ -157,6 +158,7 @@ namespace eoserial MKSIMPLE(long) MKSIMPLE(float) MKSIMPLE(double) + MKSIMPLE(char) MKSIMPLE(std::string) # undef MKSIMPLE @@ -173,6 +175,7 @@ namespace eoserial DSSIMPLE(long); DSSIMPLE(float); DSSIMPLE(double); + DSSIMPLE(char); DSSIMPLE(std::string); # undef DSSIMPLE @@ -182,11 +185,11 @@ namespace eoserial value.unpack( static_cast( json ) ); } - template - eoserial::Entity* makeSimple( const std::vector & v ) + template + eoserial::Entity* makeSimpleIterable( const Container & c ) { eoserial::Array* array = new eoserial::Array; - for( auto it = v.begin(), end = v.end(); + for( auto it = c.begin(), end = c.end(); it != end; ++it ) { @@ -195,23 +198,47 @@ namespace eoserial return array; } + template + eoserial::Entity* makeSimple( const std::vector & v ) + { + return makeSimpleIterable( v ); + } + + template + eoserial::Entity* makeSimple( const std::list & l ) + { + return makeSimpleIterable( l ); + } + template void deserializeBase( const eoserial::Entity* json, T & value ); - template< class T > - void deserializeSimple( const eoserial::Entity* json, std::vector & v ) + template< class Container > + void deserializeSimplePushBack( const eoserial::Entity* json, Container & c ) { const eoserial::Array* sArray = static_cast(json); for( auto it = sArray->begin(), end = sArray->end(); it != end; ++it ) { - T single; + typename Container::value_type single; eoserial::deserializeBase( *it, single ); - v.push_back( single ); + c.push_back( single ); } } + template< class T > + void deserializeSimple( const eoserial::Entity* json, std::vector & v ) + { + deserializeSimplePushBack( json, v ); + } + + template< class T > + void deserializeSimple( const eoserial::Entity* json, std::list & v ) + { + deserializeSimplePushBack( json, v ); + } + template void deserializeBase( const eoserial::Entity* json, T & value ) { From 834dcb1bd602078944a4f500828a98af13ba3181 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 22 Mar 2013 01:13:44 +0100 Subject: [PATCH 07/14] 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 ) { From 9ff8c7e499967c0bf23079f3a6362662ab2bf1a6 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 22 Mar 2013 01:14:18 +0100 Subject: [PATCH 08/14] eoserial: added Serialize by default for eoserial. --- eo/src/serial/eoSerial.h | 1 + 1 file changed, 1 insertion(+) diff --git a/eo/src/serial/eoSerial.h b/eo/src/serial/eoSerial.h index fec5fb4dd..ee3a70c78 100644 --- a/eo/src/serial/eoSerial.h +++ b/eo/src/serial/eoSerial.h @@ -28,5 +28,6 @@ Authors: # include "SerialString.h" # include "Parser.h" # include "Utils.h" +# include "Serialize.h" # endif // __EOSERIAL_HEADERS__ From d2680f986baf7a7382e308a0bd98137b02019d92 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 22 Mar 2013 17:01:12 +0100 Subject: [PATCH 09/14] eoserial: traits for knowing whether a class is derived from another one at compile time. Thanks Herb Sutter --- eo/src/serial/Traits.h | 58 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 eo/src/serial/Traits.h diff --git a/eo/src/serial/Traits.h b/eo/src/serial/Traits.h new file mode 100644 index 000000000..7cce0959e --- /dev/null +++ b/eo/src/serial/Traits.h @@ -0,0 +1,58 @@ +/* +(c) Benjamin Bouvier, 2013 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; + version 2 of the License. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +Contact: http://eodev.sourceforge.net + +Authors: + Benjamin Bouvier +*/ +# ifndef __EOSERIAL_TRAITS_H__ +# define __EOSERIAL_TRAITS_H__ + +/** + * @file Traits.h + * + * Traits used for serialization purposes. + * + * @author Benjamin Bouvier + */ + +namespace eoserial +{ + + /** + * @brief Trait to know whether Derived is derived from Base or not. + * + * To know whether A is derived from B, just test the boolean IsDerivedFrom::value. + * + * @see http://www.gotw.ca/publications/mxc++-item-4.htm + */ + template + class IsDerivedFrom + { + struct no{}; + struct yes{ no _[2]; }; + + static yes Test( Base* something ); + static no Test( ... ); + + public: + enum { value = sizeof( Test( static_cast(0) ) ) == sizeof(yes) }; + }; + +} + +# endif // __EOSERIAL_TRAITS_H__ From a98563b1189ec59921ab64335784c1b788f271e9 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 22 Mar 2013 17:05:19 +0100 Subject: [PATCH 10/14] eoserial: removed Serialize.h (something else coming soon...) --- eo/src/serial/Serialize.h | 404 -------------------------------------- eo/src/serial/eoSerial.h | 1 - 2 files changed, 405 deletions(-) delete mode 100644 eo/src/serial/Serialize.h diff --git a/eo/src/serial/Serialize.h b/eo/src/serial/Serialize.h deleted file mode 100644 index b3d5c2c1b..000000000 --- a/eo/src/serial/Serialize.h +++ /dev/null @@ -1,404 +0,0 @@ -/* -(c) Benjamin Bouvier, 2013 - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; - version 2 of the License. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -Contact: http://eodev.sourceforge.net - -Authors: - Benjamin Bouvier -*/ - -/** - * @file Serialize.h - * - * This file contains primitive to make serialization and - * deserialization easy. - * - * See the example code snippet below. - * - * @code - * # include - * # include - * - * class MyObject: public eoserial::Persistent - * { - * public: - * - * int value; - * MyObject( int v ) : value(v) {} - * - * eoserial::Object* pack() const - * { - * eoserial::Object* e = new eoserial::Object; - * (*e)["the_value"] = eoserial::serialize( value ); - * return e; - * } - * - * void unpack( const eoserial::Object* o ) - * { - * eoserial::deserialize( *o, "the_value", value ); - * } - * }; - * - * int main() - * { - * eoserial::Object o; - * o["long"] = eoserial::serialize(123456L); - * o["bool"] = eoserial::serialize(true); - * o["double"] = eoserial::serialize(3.141592653); - * o["float"] = eoserial::serialize(3.141592653f); - * - * std::string str = "Hello, world!"; - * o["str"] = eoserial::serialize( str ); - * - * MyObject obj(42); - * o["obj"] = eoserial::serialize( obj ); - * - * std::vector vec; - * vec.push_back(1); - * vec.push_back(3); - * vec.push_back(3); - * vec.push_back(7); - * 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 - * - * @todo Encapsulate private functions. As of today (2013-03-19), it is not - * possible as GCC and Clang refuse to have std::vector specializations of template methods (while it works with - * functions). - * - * @todo Comments coming soon. - * - * @author Benjamin Bouvier - */ - -# include -# include -# include -# include // std::runtime_error -# include // std::is_convertible (C++11) - -# include "SerialString.h" -# include "SerialObject.h" -# include "SerialArray.h" -# include "Utils.h" - -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 ); - - /* ************************* - * PRIVATE FUNCTIONS ******* - * 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 ) - { - throw std::runtime_error("eoSerial: makeSimple called with an unknown basic type."); - 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 ) - { - throw std::runtime_error("eoSerial: makeObject called with an non eoserial::Printable type."); - return 0; - } - - /* - * 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 ) \ - { \ - return eoserial::make(arg); \ - } \ - - MKSIMPLE(bool) - MKSIMPLE(int) - MKSIMPLE(short) - MKSIMPLE(long) - MKSIMPLE(float) - MKSIMPLE(double) - MKSIMPLE(char) - MKSIMPLE(std::string) -# 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 ) - { - eoserial::Array* array = new eoserial::Array; - for( auto it = c.begin(), end = c.end(); - it != end; - ++it ) - { - array->push_back( eoserial::serialize( *it ) ); - } - return array; - } - - template - eoserial::Entity* makeSimple( const std::vector & v ) - { - return makeSimpleIterable( v ); - } - - template - eoserial::Entity* makeSimple( const std::list & l ) - { - 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 ) - { - const eoserial::Array* sArray = static_cast(json); - for( auto it = sArray->begin(), end = sArray->end(); - it != end; - ++it ) - { - typename Container::value_type single; - eoserial::deserializeBase( *it, single ); - c.push_back( single ); - } - } - - template< class T > - void deserializeSimple( const eoserial::Entity* json, std::vector & v ) - { - deserializeSimplePushBack( json, v ); - } - - template< class T > - void deserializeSimple( const eoserial::Entity* json, std::list & v ) - { - 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 ) - { - if( std::is_convertible< T*, eoserial::Persistent*>::value ) - { - eoserial::deserializeObject( json, reinterpret_cast( value ) ); - } else { - eoserial::deserializeSimple( json, value ); - } - } - - /* - * 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 ) - { - const eoserial::Entity* jField = static_cast(json).find(field)->second; - eoserial::deserializeBase( jField, value ); - } -} - - diff --git a/eo/src/serial/eoSerial.h b/eo/src/serial/eoSerial.h index ee3a70c78..fec5fb4dd 100644 --- a/eo/src/serial/eoSerial.h +++ b/eo/src/serial/eoSerial.h @@ -28,6 +28,5 @@ Authors: # include "SerialString.h" # include "Parser.h" # include "Utils.h" -# include "Serialize.h" # endif // __EOSERIAL_HEADERS__ From 5ab91c61392cf42f8d96839013cb7aacd09d3700 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 22 Mar 2013 17:05:42 +0100 Subject: [PATCH 11/14] eoserial: merged former Serialize.h with Utils.h: pack / unpack. --- eo/src/serial/Utils.h | 132 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 130 insertions(+), 2 deletions(-) diff --git a/eo/src/serial/Utils.h b/eo/src/serial/Utils.h index 13b6877b1..8046bb557 100644 --- a/eo/src/serial/Utils.h +++ b/eo/src/serial/Utils.h @@ -26,6 +26,22 @@ Authors: # include "SerialObject.h" # include "SerialString.h" +# include "Traits.h" + +# include + +/** + * @file Utils.h + * + * @brief Contains utilities for simple serialization and deserialization. + * + * @todo comment new version. + * + * @todo encapsulate implementations. + * + * @todo provide more composite implementations (map) + */ + namespace eoserial { /* *************************** @@ -42,11 +58,123 @@ namespace eoserial */ template< class T > - inline void unpack( const Object & obj, const std::string & key, T & value ) + inline void unpackBasePushBack( const Entity* obj, T& container ) { - static_cast( obj.find( key )->second )->deserialize( value ); + const Array* arr = static_cast( obj ); + for( auto it = arr->begin(), end = arr->end(); + it != end; + ++it ) + { + typename T::value_type item; + unpackBase( *it, item ); + container.push_back( item ); + } } + template< class T > + inline void unpackBase( const Entity* obj, std::vector& v ) + { + unpackBasePushBack( obj, v ); + } + + template< class T > + inline void unpackBase( const Entity* obj, std::list& l ) + { + unpackBasePushBack( obj, l ); + } + + template + struct UnpackImpl + { + void operator()( const Entity* obj, T& value ) + { + static_cast( obj )->deserialize( value ); + } + }; + + template + struct UnpackImpl + { + void operator()( const Entity* obj, T& value ) + { + value.unpack( static_cast(obj) ); + } + }; + + template + inline void unpackBase( const Entity* obj, T& value ) + { + UnpackImpl< T, IsDerivedFrom< T, Persistent >::value > impl; + impl( obj, value ); + } + + template + inline void unpack( const Object& obj, const std::string& key, T& value ) + { + unpackBase( obj.find(key)->second, value ); + } + + /* ******************* + * SERIALIZATION ***** + ********************/ + + template + struct PackImpl + { + Entity* operator()( const T& value ) + { + std::stringstream ss; + ss.precision(std::numeric_limits::digits10 + 1); + ss << value; + return new String(ss.str()); + } + }; + + template + struct PackImpl + { + Entity* operator()( const T& value ) + { + return value.pack(); + } + }; + + template + inline Entity* pack( const T& value ); + + template + inline Entity* packIterable( const T& container ) + { + Array* arr = new Array; + for( auto it = container.begin(), end = container.end(); + it != end; + ++it ) + { + arr->push_back( pack(*it) ); + } + return arr; + } + + template + inline Entity* pack( const std::vector& v ) + { + return packIterable( v ); + } + + template + inline Entity* pack( const std::list& l ) + { + return packIterable( l ); + } + + template + inline Entity* pack( const T& value ) + { + PackImpl::value> impl; + return impl( value ); + } + + // Kept for compatibility inline void unpackObject( const Object & obj, const std::string & key, Persistent & value ) { static_cast( obj.find( key )->second )->deserialize( value ); From a9bdf2d51b1e262958f7cd760f430d2010f87651 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 22 Mar 2013 17:46:20 +0100 Subject: [PATCH 12/14] eoserial: comments Utils.h --- eo/src/serial/Utils.h | 95 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 80 insertions(+), 15 deletions(-) diff --git a/eo/src/serial/Utils.h b/eo/src/serial/Utils.h index 8046bb557..323283ccf 100644 --- a/eo/src/serial/Utils.h +++ b/eo/src/serial/Utils.h @@ -35,28 +35,24 @@ Authors: * * @brief Contains utilities for simple serialization and deserialization. * - * @todo comment new version. - * * @todo encapsulate implementations. * * @todo provide more composite implementations (map) + * + * @todo provide example + * + * @author Benjamin Bouvier */ namespace eoserial { - /* *************************** - * DESERIALIZATION FUNCTIONS * - ***************************** - These functions are useful for casting eoserial::objects into simple, primitive - variables or into class instance which implement eoserial::Persistent. - - The model is always quite the same : - - the first argument is the containing object (which is a eoserial::Entity, - an object or an array) - - the second argument is the key or index, - - the last argument is the value in which we're writing. - */ + /* ***************** + * DESERIALIZATION * + ******************/ + /** + * @brief Recursively unpack elements of an object which implements push_back. + */ template< class T > inline void unpackBasePushBack( const Entity* obj, T& container ) { @@ -71,18 +67,30 @@ namespace eoserial } } + /** + * @brief Unpack method for std::vector + */ template< class T > inline void unpackBase( const Entity* obj, std::vector& v ) { unpackBasePushBack( obj, v ); } + /** + * @brief Unpack method for std::list + */ template< class T > inline void unpackBase( const Entity* obj, std::list& l ) { unpackBasePushBack( obj, l ); } + /** + * @brief Unpack implementation for non eoserial::Persistent objects. + * + * This implementation is being used for every objects that can be transmitted + * to a std::ostream (i.e. which implements the operator <<) + */ template struct UnpackImpl { @@ -92,6 +100,9 @@ namespace eoserial } }; + /** + * @brief Unpack implementation for eoserial::Persistent objects. + */ template struct UnpackImpl { @@ -101,6 +112,14 @@ namespace eoserial } }; + /** + * @brief Unpack helper for determining which implementation to use. + * + * The trick comes from Herb Sutter: IsDerivedFrom::value is + * true if and only if T inherits from Persistent. In this case, it's equal + * to 1, thus the partial specialization of UnpackImpl is used. In the other + * case, it's equal to 0 and the generic implementation is used. + */ template inline void unpackBase( const Entity* obj, T& value ) { @@ -108,6 +127,13 @@ namespace eoserial impl( obj, value ); } + /** + * @brief Universal unpack method. + * + * @param obj The eoserial::object containing the value to deserialize. + * @param key Name of the field to deserialize + * @param value The object in which we'll store the deserialized value. + */ template inline void unpack( const Object& obj, const std::string& key, T& value ) { @@ -118,6 +144,12 @@ namespace eoserial * SERIALIZATION ***** ********************/ + /** + * @brief Pack implementation for non eoserial::Printable objects. + * + * This implementation is being used for every objects that can be transmitted + * to a std::istream (i.e. which implements the operator >>) + */ template struct PackImpl { @@ -130,6 +162,9 @@ namespace eoserial } }; + /** + * @brief Pack implementation for eoserial::Printable objects. + */ template struct PackImpl { @@ -139,9 +174,13 @@ namespace eoserial } }; + // Pre declaration for being usable in packIterable. template inline Entity* pack( const T& value ); + /** + * @brief Pack method for iterable (begin, end) objects. + */ template inline Entity* packIterable( const T& container ) { @@ -155,18 +194,32 @@ namespace eoserial return arr; } + /** + * @brief Pack method for std::vector + */ template inline Entity* pack( const std::vector& v ) { return packIterable( v ); } + /** + * @brief Pack method for std::list + */ template inline Entity* pack( const std::list& l ) { return packIterable( l ); } + /** + * @brief Universal pack method. + * + * @see unpackBase to understand the trick with the implementation. + * + * @param value Variable to store into an entity. + * @return An entity to store into an object. + */ template inline Entity* pack( const T& value ) { @@ -174,7 +227,19 @@ namespace eoserial return impl( value ); } - // Kept for compatibility + /** ************** + * OLD FUNCTIONS * + **************** + These functions are useful for casting eoserial::objects into simple, primitive + variables or into class instance which implement eoserial::Persistent. + + The model is always quite the same : + - the first argument is the containing object (which is a eoserial::Entity, + an object or an array) + - the second argument is the key or index, + - the last argument is the value in which we're writing. + + */ inline void unpackObject( const Object & obj, const std::string & key, Persistent & value ) { static_cast( obj.find( key )->second )->deserialize( value ); From 6c148f8ae2c7b49ce1e1567f1f89ca213a207547 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 22 Mar 2013 17:53:50 +0100 Subject: [PATCH 13/14] eoserial: example of using the new-new serialization --- eo/src/serial/Utils.h | 91 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 1 deletion(-) diff --git a/eo/src/serial/Utils.h b/eo/src/serial/Utils.h index 323283ccf..4d943bf63 100644 --- a/eo/src/serial/Utils.h +++ b/eo/src/serial/Utils.h @@ -39,7 +39,96 @@ Authors: * * @todo provide more composite implementations (map) * - * @todo provide example + * Example + * + * @code +# include +# include +# include + +# include "eoSerial.h" + +struct SimpleObject: public eoserial::Persistent +{ + public: + + SimpleObject( int v ) : value(v) + { + // empty + } + + eoserial::Object* pack() const + { + eoserial::Object* obj = new eoserial::Object; + (*obj)["value"] = eoserial::pack( value ); + return obj; + } + + void unpack( const eoserial::Object* json ) + { + eoserial::unpack( *json, "value", value ); + } + + int value; +}; + +int main() +{ + eoserial::Object o; + + std::cout << "packing..." << std::endl; + // directly pack raw types + o["long"] = eoserial::pack(123456L); + o["bool"] = eoserial::pack(true); + o["double"] = eoserial::pack(3.141592653); + o["float"] = eoserial::pack(3.141592653f); + + std::string str = "Hello, world!"; + o["str"] = eoserial::pack( str ); + + // pack objects the same way + SimpleObject obj(42); + o["obj"] = eoserial::pack( obj ); + + // pack vector and list the same way + std::vector vec; + vec.push_back(1); + vec.push_back(3); + vec.push_back(3); + vec.push_back(7); + o["vec"] = eoserial::pack( vec ); + + // print it + o.print( std::cout ); + + std::cout << "unpacking..." << std::endl; + + // unpack as easily raw types + long oneTwoThreeFourFiveSix = 0L; + eoserial::unpack( o, "long", oneTwoThreeFourFiveSix); + std::cout << "the long: " << oneTwoThreeFourFiveSix << std::endl; + + // since vec is encoded as an internal eoserial::Array, it can be + // decoded into a std::vector or a std::list without difference. + std::list lis; + eoserial::unpack( o, "vec", lis ); + + std::cout << "the list: "; + for( auto it = lis.begin(), end = lis.end(); it != end; ++it) + { + std::cout << *it << ';'; + } + std::cout << std::endl; + + obj.value = -1; + // unpack object the same way + eoserial::unpack( o, "obj", obj ); + std::cout << "obj.value = " << obj.value << std::endl; + + return 0; +} + +@endcode * * @author Benjamin Bouvier */ From 95e4dfc625359100aeae219b11d3d751a6642f8f Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 22 Mar 2013 18:03:36 +0100 Subject: [PATCH 14/14] eoserial: packing and unpacking of map --- eo/src/serial/Utils.h | 44 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/eo/src/serial/Utils.h b/eo/src/serial/Utils.h index 4d943bf63..b6ea360b3 100644 --- a/eo/src/serial/Utils.h +++ b/eo/src/serial/Utils.h @@ -29,6 +29,7 @@ Authors: # include "Traits.h" # include +# include /** * @file Utils.h @@ -37,8 +38,6 @@ Authors: * * @todo encapsulate implementations. * - * @todo provide more composite implementations (map) - * * Example * * @code @@ -98,6 +97,12 @@ int main() vec.push_back(7); o["vec"] = eoserial::pack( vec ); + std::map str2int; + str2int["one"] = 1; + str2int["two"] = 2; + str2int["answer"] = 42; + o["map"] = eoserial::pack( str2int ); + // print it o.print( std::cout ); @@ -120,6 +125,10 @@ int main() } std::cout << std::endl; + std::map< std::string, int > readMap; + eoserial::unpack( o, "map", readMap ); + std::cout << "The answer is " << readMap["answer"] << std::endl; + obj.value = -1; // unpack object the same way eoserial::unpack( o, "obj", obj ); @@ -174,6 +183,21 @@ namespace eoserial unpackBasePushBack( obj, l ); } + /** + * @brief Unpack method for std::map< std::string, T > + */ + template< class T > + inline void unpackBase( const Entity* entity, std::map & m ) + { + const Object* obj = static_cast< const Object* >( entity ); + for( auto it = obj->begin(), end = obj->end(); + it != end; + ++it ) + { + unpackBase( it->second, m[ it->first ] ); + } + } + /** * @brief Unpack implementation for non eoserial::Persistent objects. * @@ -301,6 +325,22 @@ namespace eoserial return packIterable( l ); } + /** + * @brief Pack method for std::map< std::string, T > + */ + template + inline Entity* pack( const std::map& map ) + { + Object* obj = new Object; + for( auto it = map.begin(), end = map.end(); + it != end; + ++it ) + { + (*obj)[ it->first ] = pack( it->second ); + } + return obj; + } + /** * @brief Universal pack method. *