From 002b1ceeb104328233489095826f15af2d2b45f9 Mon Sep 17 00:00:00 2001 From: Shane Grant Date: Wed, 3 Jul 2013 11:17:47 -0700 Subject: [PATCH] adding size_tag wrappers, XML output looking good --- include/cereal/archives/binary.hpp | 2 +- include/cereal/archives/xml.hpp | 108 +++++++++++++++++-------- include/cereal/cereal.hpp | 18 ++++- include/cereal/details/helpers.hpp | 17 ++-- include/cereal/types/chrono.hpp | 1 - include/cereal/types/common.hpp | 2 +- include/cereal/types/complex.hpp | 1 - include/cereal/types/deque.hpp | 4 +- include/cereal/types/forward_list.hpp | 4 +- include/cereal/types/list.hpp | 4 +- include/cereal/types/map.hpp | 7 +- include/cereal/types/polymorphic.hpp | 10 ++- include/cereal/types/queue.hpp | 2 +- include/cereal/types/set.hpp | 4 +- include/cereal/types/string.hpp | 4 +- include/cereal/types/unordered_map.hpp | 4 +- include/cereal/types/unordered_set.hpp | 4 +- include/cereal/types/vector.hpp | 10 +-- sandbox.cpp | 15 +++- unittests.cpp | 3 +- 20 files changed, 146 insertions(+), 78 deletions(-) diff --git a/include/cereal/archives/binary.hpp b/include/cereal/archives/binary.hpp index 9244c797..cc739f7d 100644 --- a/include/cereal/archives/binary.hpp +++ b/include/cereal/archives/binary.hpp @@ -111,7 +111,7 @@ namespace cereal ar( t.value ); } - //! Serializing NVP types to binary + //! Serializing SizeTags to binary template inline CEREAL_ARCHIVE_RESTRICT_SERIALIZE(BinaryInputArchive, BinaryOutputArchive) serialize( Archive & ar, SizeTag & t ) diff --git a/include/cereal/archives/xml.hpp b/include/cereal/archives/xml.hpp index 2cf6209c..f68b8bed 100644 --- a/include/cereal/archives/xml.hpp +++ b/include/cereal/archives/xml.hpp @@ -78,16 +78,16 @@ namespace cereal node->append_attribute( itsXML.allocate_attribute( "encoding", "utf-8" ) ); itsXML.append_node( node ); + // allocate root node auto root = itsXML.allocate_node( rapidxml::node_element, "cereal" ); itsXML.append_node( root ); itsNodes.emplace( root ); - // testing + // set attributes on the streams itsStream << std::boolalpha; itsStream.precision( precision ); itsOS << std::boolalpha; itsOS.precision( precision ); - //itsStream.setf( std::ios::floatfield, std::ios::fixed ); } //! Destructor, flushes the XML @@ -132,8 +132,14 @@ namespace cereal itsNodes.top().node->append_node( itsXML.allocate_node( rapidxml::node_data, nullptr, dataPtr ) ); } + //! Creates a new node that is a child of the node at the top of the stack + /*! Nodes will be given a name that has either been pre-set by a name value pair, + or generated based upon a counter unique to the parent node. + + The node will then be pushed onto the node stack. */ void startNode() { + // generate a name for this new node const auto nameString = itsNodes.top().getValueName(); // allocate strings for all of the data in the XML object @@ -145,11 +151,13 @@ namespace cereal itsNodes.emplace( node ); } + //! Designates the most recently added node as finished void finishNode() { itsNodes.pop(); } + //! Sets the name for the next node created with startNode void setNextName( const char * name ) { itsNodes.top().name = name; @@ -165,6 +173,7 @@ namespace cereal //std::cout << zz[0] << " " << zz[1] << " " << zz[2] << std::endl; }; + //! A struct that contains metadata about a node struct NodeInfo { NodeInfo( rapidxml::xml_node<> * n = nullptr, @@ -174,10 +183,14 @@ namespace cereal name( nm ) { } - rapidxml::xml_node<> * node; - size_t counter; - const char * name; + rapidxml::xml_node<> * node; //!< A pointer to this node + size_t counter; //!< The counter for naming child nodes + const char * name; //!< The name for the next child node + //! Gets the name for the next child node created from this node + /*! The name will be automatically generated using the counter if + a name has not been previously set. If a name has been previously + set, that name will be returned only once */ std::string getValueName() { if( name ) @@ -187,21 +200,66 @@ namespace cereal return {n}; } else - { return "value" + std::to_string( counter++ ) + "\0"; - } } - }; + }; // NodeInfo private: std::ostream & itsStream; rapidxml::xml_document<> itsXML; //!< The XML document - std::stack itsNodes; - std::ostringstream itsOS; - }; + std::stack itsNodes; //!< A stack of nodes added to the document + std::ostringstream itsOS; //!< Used to format strings internally + }; // XMLOutputArchive struct XMLInputArchive; + // ###################################################################### + // XMLArchive prologue and epilogue functions + + //! Prologue for NVPs for XML archives + /*! NVPs do not start or finish nodes - they just set up the names */ + template + void prologue( XMLOutputArchive &, NameValuePair const & ) + { } + + //! Epilogue for NVPs for XML archives + /*! NVPs do not start or finish nodes - they just set up the names */ + template + void epilogue( XMLOutputArchive &, NameValuePair const & ) + { } + + //! Prologue for SizeTags for XML archives + /*! SizeTags are strictly ignored for XML */ + template + void prologue( XMLOutputArchive &, SizeTag const & ) + { } + + //! Epilogue for SizeTags for XML archives + /*! SizeTags are strictly ignored for XML */ + template + void epilogue( XMLOutputArchive &, SizeTag const & ) + { } + + //! Prologue for all other types for XML archives + /*! Starts a new node, named either automatically or by some NVP, + that may be given data by the type about to be archived */ + template + void prologue( XMLOutputArchive & ar, T const & data ) + { + ar.startNode(); + } + + //! Epilogue for all other types other for XML archives + /*! Finishes the node created in the prologue */ + template + void epilogue( XMLOutputArchive & ar, T const & data ) + { + ar.finishNode(); + } + + // ###################################################################### + // Common XMLArchive serialization functions + //! Serializing NVP types to XML template inline CEREAL_ARCHIVE_RESTRICT_SERIALIZE(XMLInputArchive, XMLOutputArchive) @@ -211,6 +269,12 @@ namespace cereal ar( t.value ); } + //! Serializing SizeTags to XML + template inline + CEREAL_ARCHIVE_RESTRICT_SERIALIZE(XMLInputArchive, XMLOutputArchive) + serialize( Archive & ar, SizeTag & ) + { } + //! Saving for POD types to xml template inline typename std::enable_if::value, void>::type @@ -226,28 +290,6 @@ namespace cereal ar.saveValue( str ); } - template - void prologue( XMLOutputArchive & ar, NameValuePair const & data ) - { } - - template - void epilogue( XMLOutputArchive & ar, NameValuePair const & data ) - { } - - template - void prologue( XMLOutputArchive & ar, T const & data ) - { - ar.startNode(); - } - - template - void epilogue( XMLOutputArchive & ar, T const & data ) - { - ar.finishNode(); - } - - // ###################################################################### - // Common XMLArchive serialization functions } // namespace cereal // register archives for polymorphic support diff --git a/include/cereal/cereal.hpp b/include/cereal/cereal.hpp index 22db68b4..d9ab2f30 100644 --- a/include/cereal/cereal.hpp +++ b/include/cereal/cereal.hpp @@ -49,6 +49,7 @@ namespace cereal // ###################################################################### //! Creates a name value pair + /*! @relates NameValuePair */ template inline NameValuePair make_nvp( std::string const & name, T && value ) { @@ -56,6 +57,7 @@ namespace cereal } //! Creates a name value pair + /*! @relates NameValuePair */ template inline NameValuePair make_nvp( const char * name, T && value ) { @@ -63,18 +65,32 @@ namespace cereal } //! Creates a name value pair for the variable T with the same name as the variable + /*! @relates NameValuePair */ #define CEREAL_NVP(T) ::cereal::make_nvp(#T, T) // ###################################################################### //! Convenience function to create binary data for both const and non const pointers /*! @param data Pointer to beginning of the data - @param size The size in bytes of the data */ + @param size The size in bytes of the data + @relates BinaryData */ template inline BinaryData binary_data( T && data, size_t size ) { return {std::forward(data), size}; } + // ###################################################################### + //! Creates a size tag from some variable. + /*! Will normally be used to serialize size (e.g. size()) information for + containers. + + @relates SizeTag */ + template + SizeTag make_size_tag( T && sz ) + { + return {std::forward(sz)}; + } + // ###################################################################### //! Called before a type is serialized to set up any special archive state //! for processing some type diff --git a/include/cereal/details/helpers.hpp b/include/cereal/details/helpers.hpp index 771c0879..4ecd48d7 100644 --- a/include/cereal/details/helpers.hpp +++ b/include/cereal/details/helpers.hpp @@ -27,6 +27,10 @@ #ifndef CEREAL_DETAILS_HELPERS_HPP_ #define CEREAL_DETAILS_HELPERS_HPP_ +#include +#include +#include + namespace cereal { // ###################################################################### @@ -103,6 +107,12 @@ namespace cereal } // ###################################################################### + //! A wrapper around size metadata + /*! This class provides a way for archives to have more flexibility over how + they choose to serialize size metadata for containers. For some archive + types, the size may be implicitly encoded in the output (e.g. JSON) and + not need an explicit entry. Specializing serialize or load/save for + your archive and SizeTags allows you to choose what happens */ template class SizeTag { @@ -119,13 +129,6 @@ namespace cereal Type size; }; - - template - SizeTag make_size_tag( T && sz ) - { - return {std::forward(sz)}; - } - } // namespace cereal #endif // CEREAL_DETAILS_HELPERS_HPP_ diff --git a/include/cereal/types/chrono.hpp b/include/cereal/types/chrono.hpp index 9ab6ed96..e04ea748 100644 --- a/include/cereal/types/chrono.hpp +++ b/include/cereal/types/chrono.hpp @@ -27,7 +27,6 @@ #ifndef CEREAL_TYPES_CHRONO_HPP_ #define CEREAL_TYPES_CHRONO_HPP_ -#include #include namespace cereal diff --git a/include/cereal/types/common.hpp b/include/cereal/types/common.hpp index d1c3b0a2..cdd12923 100644 --- a/include/cereal/types/common.hpp +++ b/include/cereal/types/common.hpp @@ -27,7 +27,7 @@ #ifndef CEREAL_TYPES_COMMON_HPP_ #define CEREAL_TYPES_COMMON_HPP_ -#include +#include namespace cereal { diff --git a/include/cereal/types/complex.hpp b/include/cereal/types/complex.hpp index 90261e50..ad3aba95 100644 --- a/include/cereal/types/complex.hpp +++ b/include/cereal/types/complex.hpp @@ -27,7 +27,6 @@ #ifndef CEREAL_TYPES_COMPLEX_HPP_ #define CEREAL_TYPES_COMPLEX_HPP_ -#include #include namespace cereal diff --git a/include/cereal/types/deque.hpp b/include/cereal/types/deque.hpp index ee9b986d..a31d4aad 100644 --- a/include/cereal/types/deque.hpp +++ b/include/cereal/types/deque.hpp @@ -36,7 +36,7 @@ namespace cereal template inline void save( Archive & ar, std::deque const & deque ) { - ar( deque.size() ); + ar( make_size_tag( deque.size() ) ); for( auto const & i : deque ) ar( i ); @@ -47,7 +47,7 @@ namespace cereal void load( Archive & ar, std::deque & deque ) { size_t size; - ar( size ); + ar( make_size_tag( size ) ); deque.resize( size ); diff --git a/include/cereal/types/forward_list.hpp b/include/cereal/types/forward_list.hpp index de6f1d2f..d074d4ab 100644 --- a/include/cereal/types/forward_list.hpp +++ b/include/cereal/types/forward_list.hpp @@ -41,7 +41,7 @@ namespace cereal // since it works in the most general fashion with any archive type const size_t size = std::distance( forward_list.begin(), forward_list.end() ); - ar( size ); + ar( make_size_tag( size ) ); // write the list for( const auto & i : forward_list ) @@ -53,7 +53,7 @@ namespace cereal void load( Archive & ar, std::forward_list & forward_list ) { size_t size; - ar( size ); + ar( make_size_tag( size ) ); forward_list.resize( size ); diff --git a/include/cereal/types/list.hpp b/include/cereal/types/list.hpp index 7f9e9464..2148ccfb 100644 --- a/include/cereal/types/list.hpp +++ b/include/cereal/types/list.hpp @@ -36,7 +36,7 @@ namespace cereal template inline void save( Archive & ar, std::list const & list ) { - ar( list.size() ); + ar( make_size_tag( list.size() ) ); for( auto const & i : list ) ar( i ); @@ -47,7 +47,7 @@ namespace cereal void load( Archive & ar, std::list & list ) { size_t size; - ar( size ); + ar( make_size_tag( size ) ); list.resize( size ); diff --git a/include/cereal/types/map.hpp b/include/cereal/types/map.hpp index 9c335eda..7ccd6910 100644 --- a/include/cereal/types/map.hpp +++ b/include/cereal/types/map.hpp @@ -27,8 +27,7 @@ #ifndef CEREAL_TYPES_MAP_HPP_ #define CEREAL_TYPES_MAP_HPP_ -//#include -#include +#include #include namespace cereal @@ -38,7 +37,7 @@ namespace cereal template inline void save( Archive & ar, MapT const & map ) { - ar( map.size() ); + ar( make_size_tag( map.size() ) ); for( const auto & i : map ) ar( i.first, i.second ); @@ -48,7 +47,7 @@ namespace cereal void load( Archive & ar, MapT & map ) { size_t size; - ar( size ); + ar( make_size_tag( size ) ); map.clear(); diff --git a/include/cereal/types/polymorphic.hpp b/include/cereal/types/polymorphic.hpp index 402b1f07..350ed841 100644 --- a/include/cereal/types/polymorphic.hpp +++ b/include/cereal/types/polymorphic.hpp @@ -29,9 +29,11 @@ #include #include -#include + #include +#include #include +#include //! Registers a polymorphic type with cereal /*! Polymorphic types must be registered before pointers @@ -145,7 +147,7 @@ namespace cereal template inline typename std::enable_if::value && !traits::has_load_and_allocate(), bool>::type serialize_wrapper(Archive & ar, std::unique_ptr & ptr, std::uint32_t const nameid) - { + { if(nameid & detail::msb2_32bit) throw cereal::Exception("Cannot load a polymorphic type that is not default constructable and does not have a load_and_allocate function"); return false; @@ -199,7 +201,7 @@ namespace cereal ar( nameid ); // Check to see if we can skip all of this polymorphism business - if(polymorphic_detail::serialize_wrapper(ar, ptr, nameid)) + if(polymorphic_detail::serialize_wrapper(ar, ptr, nameid)) return; auto binding = polymorphic_detail::getInputBinding(ar, nameid); @@ -271,7 +273,7 @@ namespace cereal ar( nameid ); // Check to see if we can skip all of this polymorphism business - if(polymorphic_detail::serialize_wrapper(ar, ptr, nameid)) + if(polymorphic_detail::serialize_wrapper(ar, ptr, nameid)) return; auto binding = polymorphic_detail::getInputBinding(ar, nameid); diff --git a/include/cereal/types/queue.hpp b/include/cereal/types/queue.hpp index a819367a..d1f200c7 100644 --- a/include/cereal/types/queue.hpp +++ b/include/cereal/types/queue.hpp @@ -27,7 +27,7 @@ #ifndef CEREAL_TYPES_QUEUE_HPP_ #define CEREAL_TYPES_QUEUE_HPP_ -#include +#include #include namespace cereal diff --git a/include/cereal/types/set.hpp b/include/cereal/types/set.hpp index a83a9234..452c8a03 100644 --- a/include/cereal/types/set.hpp +++ b/include/cereal/types/set.hpp @@ -37,7 +37,7 @@ namespace cereal template inline void save( Archive & ar, SetT const & set ) { - ar( set.size() ); + ar( make_size_tag( set.size() ) ); for( const auto & i : set ) ar( i ); @@ -47,7 +47,7 @@ namespace cereal void load( Archive & ar, SetT & set ) { size_t size; - ar( size ); + ar( make_size_tag( size ) ); set.clear(); diff --git a/include/cereal/types/string.hpp b/include/cereal/types/string.hpp index 6501dbb2..85d1f760 100644 --- a/include/cereal/types/string.hpp +++ b/include/cereal/types/string.hpp @@ -27,8 +27,7 @@ #ifndef CEREAL_TYPES_STRING_HPP_ #define CEREAL_TYPES_STRING_HPP_ -#include -#include +#include #include namespace cereal @@ -40,7 +39,6 @@ namespace cereal { // Save number of chars + the data ar( make_size_tag( str.size() ) ); - //ar( str.size() ); ar( binary_data( str.data(), str.size() * sizeof(CharT) ) ); } diff --git a/include/cereal/types/unordered_map.hpp b/include/cereal/types/unordered_map.hpp index 9bb7bc72..e2f87388 100644 --- a/include/cereal/types/unordered_map.hpp +++ b/include/cereal/types/unordered_map.hpp @@ -37,7 +37,7 @@ namespace cereal template inline void save( Archive & ar, MapT const & map ) { - ar( map.size() ); + ar( make_size_tag( map.size() ) ); for( const auto & i : map ) ar( i.first, i.second ); @@ -47,7 +47,7 @@ namespace cereal void load( Archive & ar, MapT & map ) { size_t size; - ar( size ); + ar( make_size_tag( size ) ); map.clear(); map.reserve( size ); diff --git a/include/cereal/types/unordered_set.hpp b/include/cereal/types/unordered_set.hpp index 9835f45d..7a3cae28 100644 --- a/include/cereal/types/unordered_set.hpp +++ b/include/cereal/types/unordered_set.hpp @@ -37,7 +37,7 @@ namespace cereal template inline void save( Archive & ar, SetT const & set ) { - ar( set.size() ); + ar( make_size_tag( set.size() ) ); for( const auto & i : set ) ar( i ); @@ -47,7 +47,7 @@ namespace cereal void load( Archive & ar, SetT & set ) { size_t size; - ar( size ); + ar( make_size_tag( size ) ); set.clear(); set.reserve( size ); diff --git a/include/cereal/types/vector.hpp b/include/cereal/types/vector.hpp index 3bc25573..457a2a43 100644 --- a/include/cereal/types/vector.hpp +++ b/include/cereal/types/vector.hpp @@ -30,8 +30,6 @@ #include #include -#include - namespace cereal { //! Serialization for std::vectors of arithmetic (but not bool) using binary serialization, if supported @@ -40,7 +38,7 @@ namespace cereal && std::is_arithmetic::value && !std::is_same::value, void>::type save( Archive & ar, std::vector const & vector ) { - ar( vector.size() ); // number of elements + ar( make_size_tag( vector.size() ) ); // number of elements ar( binary_data( vector.data(), vector.size() * sizeof(T) ) ); } @@ -51,7 +49,7 @@ namespace cereal load( Archive & ar, std::vector & vector ) { size_t vectorSize; - ar( vectorSize ); + ar( make_size_tag( vectorSize ) ); vector.resize( vectorSize ); ar( binary_data( vector.data(), vectorSize * sizeof(T) ) ); @@ -64,7 +62,7 @@ namespace cereal || std::is_same::value, void>::type save( Archive & ar, std::vector const & vector ) { - ar( vector.size() ); // number of elements + ar( make_size_tag( vector.size() ) ); // number of elements for( auto it = vector.begin(), end = vector.end(); it != end; ++it ) ar( *it ); } @@ -77,7 +75,7 @@ namespace cereal load( Archive & ar, std::vector & vector ) { size_t size; - ar( size ); + ar( make_size_tag( size ) ); vector.resize( size ); for( auto it = vector.begin(), end = vector.end(); it != end; ++it ) diff --git a/sandbox.cpp b/sandbox.cpp index 884baa21..522756ce 100644 --- a/sandbox.cpp +++ b/sandbox.cpp @@ -28,12 +28,14 @@ #include #include #include + #include #include #include #include -#include #include +#include +#include #include #include @@ -309,7 +311,16 @@ int main() oar( 3.2f ); oar( true ); - std::array arr = {1, 2, 3, 4, 5}; + std::array arr = {{1, 2, 3, 4, 5}}; + oar( arr ); + + std::vector vec = {"hey", + "there", + "buddy"}; + + Everything e; + oar( cereal::make_nvp("EVERYTHING?!", e) ); + oar( vec ); //int xxx[] = {-1, 95, 3}; //oar.saveBinaryValue( xxx, sizeof(int)*3); } diff --git a/unittests.cpp b/unittests.cpp index 556d678d..d6e7dfe1 100644 --- a/unittests.cpp +++ b/unittests.cpp @@ -24,7 +24,6 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include #include #include #include @@ -43,6 +42,8 @@ #include #include #include + +#include #include #include