diff --git a/binary_archive/array.hpp b/binary_archive/array.hpp index 3974a5fe..60f4a5c6 100644 --- a/binary_archive/array.hpp +++ b/binary_archive/array.hpp @@ -6,20 +6,42 @@ namespace cereal { - //! Serialization for std::array types to binary + //! Saving for std::array primitive types to binary template + typename std::enable_if::value, void>::type void save( BinaryOutputArchive & ar, std::array const & array ) { - std::cout << "Saving array" << std::endl; + std::cout << "Saving array (arith)" << std::endl; ar.save_binary( array.data(), N * sizeof(T) ); } - //! Serialization for std::array to binary + //! Loading for std::array primitive types to binary template + typename std::enable_if::value, void>::type + void load( BinaryInputArchive & ar, std::array & array ) + { + std::cout << "Loading array (arith)" << std::endl; + ar.load_binary( array.data(), N * sizeof(T) ); + } + + //! Saving for std::array all other types to binary + template + typename std::enable_if::value, void>::type + void save( BinaryOutputArchive & ar, std::array const & array ) + { + std::cout << "Saving array" << std::endl; + for( const auto & i : array ) + ar & i; + } + + //! Loading for std::array all other types to binary + template + typename std::enable_if::value, void>::type void load( BinaryInputArchive & ar, std::array & array ) { std::cout << "Loading array" << std::endl; - ar.load_binary( array.data(), N * sizeof(T) ); + for( auto & i : array ) + ar & i; } } // namespace cereal diff --git a/binary_archive/binary_archive.hpp b/binary_archive/binary_archive.hpp index e8575a15..18771c91 100644 --- a/binary_archive/binary_archive.hpp +++ b/binary_archive/binary_archive.hpp @@ -82,6 +82,12 @@ namespace cereal //std::cout << "Loading NVP... " << std::endl; ar & t.value; } + + template + void serialize( Archive & ar, T * & t ) + { + static_assert(!sizeof(T), "Cereal does not support serializing raw pointers - please use a smart pointer"); + } } #endif // CEREAL_BINARY_ARCHIVE_BINARY_ARCHIVE_HPP_ diff --git a/binary_archive/shared_ptr.hpp b/binary_archive/shared_ptr.hpp new file mode 100644 index 00000000..63b45a1e --- /dev/null +++ b/binary_archive/shared_ptr.hpp @@ -0,0 +1,58 @@ +#ifndef CEREAL_BINARY_ARCHIVE_SHARED_PTR_HPP_ +#define CEREAL_BINARY_ARCHIVE_SHARED_PTR_HPP_ + +#include +#include + +namespace cereal +{ + /* + * + * + * + * + * + * + * + * + * + * + */ + //! Saving std::shared_ptr to binary + template + void save( BinaryOutputArchive & ar, std::shared_ptr const & ptr ) + { + uint32_t id = ar.registerSharedPointer( ptr.get() ); + ar & id; + + std::cout << "ID: " << id << std::endl; + + if( id & msb_32bit ) + { + std::cout << "Serializing the *ptr" << std::endl; + ar & *ptr; + } + } + + //! Loading std::shared_ptr to binary + template + void load( BinaryInputArchive & ar, std::shared_ptr & ptr ) + { + uint32_t id; + + ar & id; + + if( id & msb_32bit ) + { + ptr.reset( new T ); + ar & *ptr; + ar.registerSharedPointer(id, ptr); + } + else + { + ptr = std::static_pointer_cast(ar.getSharedPointer(id)); + } + } +} // namespace cereal + +#endif // CEREAL_BINARY_ARCHIVE_SHARED_PTR_HPP_ diff --git a/binary_archive/vector.hpp b/binary_archive/vector.hpp index 422e9841..7786cfe7 100644 --- a/binary_archive/vector.hpp +++ b/binary_archive/vector.hpp @@ -6,12 +6,12 @@ namespace cereal { - //! Serialization for std::vectors of arithmetic types to binary + //! Serialization for std::vectors of arithmetic (but not bool) types to binary template - typename std::enable_if::value, void>::type - save( BinaryOutputArchive & ar, std::vector const & vector ) + typename std::enable_if::value && !std::is_same::value, void>::type + save( BinaryOutputArchive & ar, std::vector const & vector ) { - std::cout << "Saving vector" << std::endl; + std::cout << "Saving vector (arithmetic)" << std::endl; const size_t dataSize = std::addressof(vector.back()) - std::addressof(vector.front()); @@ -20,12 +20,12 @@ namespace cereal ar.save_binary( array.data(), size ); // actual data } - //! Serialization for std::vectors of arithmetic types to binary + //! Serialization for std::vectors of arithmetic (but not bool) types to binary template - typename std::enable_if::value, void>::type - load( BinaryInputArchive & ar, std::vector & vector ) - { - std::cout << "Loading vector" << std::endl; + typename std::enable_if::value && !std::is_same::value, void>::type + load( BinaryInputArchive & ar, std::vector & vector ) + { + std::cout << "Loading vector (arithmetic)" << std::endl; size_t dataSize; size_t vectorSize; @@ -37,11 +37,11 @@ namespace cereal ar.load_binary( vector.data(), dataSize ); } - //! Serialization for std::vector types to binary - template - void save( BinaryOutputArchive & ar, std::vector const & vector ) + //! Serialization for all other vector types + template + void save( BinaryOutputArchive & ar, std::vector const & vector ) { - std::cout << "Saving vector of bool" << std::endl; + std::cout << "Saving vector" << std::endl; ar & vector.size(); // number of elements for( auto it = vector.begin(), end = vector.end(); it != end; ++it ) @@ -49,8 +49,8 @@ namespace cereal } //! Serialization for std::vector to binary - template - void load( BinaryInputArchive & ar, std::vector & vector ) + template + void load( BinaryInputArchive & ar, std::vector & vector ) { size_t size; ar & size; diff --git a/cereal.hpp b/cereal.hpp index eab4ed56..d92dff61 100644 --- a/cereal.hpp +++ b/cereal.hpp @@ -3,11 +3,15 @@ #include #include +#include +#include #include namespace cereal { + static const int32_t msb_32bit = 0x80000000; + //! For holding name value pairs template struct NameValuePair @@ -34,7 +38,7 @@ namespace cereal class OutputArchive { public: - OutputArchive(ArchiveType * const self) : self(self) + OutputArchive(ArchiveType * const self) : self(self), itsCurrentPointerId(0) { } //! Member serialization @@ -93,8 +97,25 @@ namespace cereal return *self; } + //! Registers a pointer with the archive + uint32_t registerSharedPointer( void * addr ) + { + auto id = itsSharedPointerMap.find( addr ); + if( id == itsSharedPointerMap.end() ) + { + auto ptrId = itsCurrentPointerId++; + itsSharedPointerMap.insert( {addr, ptrId} ); + return ptrId | msb_32bit; // mask MSB to be 1 + } + else + return id->second; + } + private: ArchiveType * const self; + + std::unordered_map itsSharedPointerMap; //!< Maps from addresses to pointer ids + std::size_t itsCurrentPointerId; //!< The id to be given to the next pointer }; // class OutputArchive // ###################################################################### @@ -161,8 +182,26 @@ namespace cereal return *self; } + std::shared_ptr getSharedPointer(uint32_t const id) + { + auto ptr = itsSharedPointerMap.find( id ); + if(ptr == itsSharedPointerMap.end()) + { + // TODO: Throw a Cereal exception; + throw std::runtime_error("Error while trying to deserialize a smart pointer. Could not find id " + std::to_string(id)); + } + return ptr->second; + } + + void registerSharedPointer(uint32_t const id, std::shared_ptr ptr) + { + uint32_t const stripped_id = id & ~msb_32bit; + itsSharedPointerMap.insert( {stripped_id, ptr} ); + } + private: ArchiveType * const self; + std::unordered_map> itsSharedPointerMap; //!< Maps from addresses to pointer ids }; // class InputArchive } diff --git a/details/traits.hpp b/details/traits.hpp index f2e58e79..a06ed9fc 100644 --- a/details/traits.hpp +++ b/details/traits.hpp @@ -99,6 +99,7 @@ namespace cereal has_non_member_serialize(); } + // ###################################################################### constexpr std::false_type is_smart_ptr(...) { return {}; @@ -116,6 +117,7 @@ namespace cereal return {}; } + // ###################################################################### //! Returns true if the type T is a pointer or smart pointer (in std library) template constexpr bool is_any_pointer() diff --git a/test.cpp b/test.cpp index 39ac979b..e999dcd0 100644 --- a/test.cpp +++ b/test.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -135,12 +136,44 @@ int main() assert(e_in == e_out); - cereal::JSONOutputArchive json(std::cout); + //cereal::JSONOutputArchive json(std::cout); - std::string hello = "Hello, World!"; - json & CEREAL_NVP(hello); + //std::string hello = "Hello, World!"; + //json & CEREAL_NVP(hello); //json & CEREAL_NVP(e_out); <<< Need to figure out how to recurse! - // + + { + std::ofstream os("ptr.txt"); + cereal::BinaryOutputArchive archive(os); + std::shared_ptr xptr1 = std::make_shared(5); + std::shared_ptr xptr2 = xptr1; + std::shared_ptr yptr1 = std::make_shared(6); + std::shared_ptr yptr2 = yptr1; + archive & xptr1; + archive & xptr2; + archive & yptr1; + archive & yptr2; + + } + { + std::ifstream is("ptr.txt"); + cereal::BinaryInputArchive archive(is); + std::shared_ptr xptr1; + std::shared_ptr xptr2; + std::shared_ptr yptr1; + std::shared_ptr yptr2; + archive & xptr1; + archive & xptr2; + archive & yptr1; + archive & yptr2; + + assert(xptr1.get() == xptr2.get()); + assert(yptr1.get() == yptr2.get()); + std::cout << *xptr1 << " " << *xptr2 << std::endl; + std::cout << *yptr1 << " " << *yptr2 << std::endl; + } + + return 0; }