std::shared_ptr works with pointer tracking

This commit is contained in:
Laurent Itti
2013-06-13 15:54:08 -07:00
parent e11edef4c8
commit 58abf1d2b9
7 changed files with 184 additions and 24 deletions

View File

@@ -6,20 +6,42 @@
namespace cereal
{
//! Serialization for std::array types to binary
//! Saving for std::array primitive types to binary
template <class T, size_t N>
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
void save( BinaryOutputArchive & ar, std::array<T, N> 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 <class T, size_t N>
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
void load( BinaryInputArchive & ar, std::array<T, N> & 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 <class T, size_t N>
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
void save( BinaryOutputArchive & ar, std::array<T, N> 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 <class T, size_t N>
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
void load( BinaryInputArchive & ar, std::array<T, N> & array )
{
std::cout << "Loading array" << std::endl;
ar.load_binary( array.data(), N * sizeof(T) );
for( auto & i : array )
ar & i;
}
} // namespace cereal

View File

@@ -82,6 +82,12 @@ namespace cereal
//std::cout << "Loading NVP... " << std::endl;
ar & t.value;
}
template <class Archive, class T>
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_

View File

@@ -0,0 +1,58 @@
#ifndef CEREAL_BINARY_ARCHIVE_SHARED_PTR_HPP_
#define CEREAL_BINARY_ARCHIVE_SHARED_PTR_HPP_
#include <cereal/binary_archive/binary_archive.hpp>
#include <memory>
namespace cereal
{
/*
*
*
*
*
*
*
*
*
*
*
*/
//! Saving std::shared_ptr to binary
template <class T>
void save( BinaryOutputArchive & ar, std::shared_ptr<T> 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 <class T>
void load( BinaryInputArchive & ar, std::shared_ptr<T> & 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<T>(ar.getSharedPointer(id));
}
}
} // namespace cereal
#endif // CEREAL_BINARY_ARCHIVE_SHARED_PTR_HPP_

View File

@@ -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 <class T, class A>
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
save( BinaryOutputArchive & ar, std::vector<T, A> const & vector )
typename std::enable_if<std::is_arithmetic<T>::value && !std::is_same<T, bool>::value, void>::type
save( BinaryOutputArchive & ar, std::vector<T, A> 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 <class T, class A>
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
load( BinaryInputArchive & ar, std::vector<T, A> & vector )
{
std::cout << "Loading vector" << std::endl;
typename std::enable_if<std::is_arithmetic<T>::value && !std::is_same<T, bool>::value, void>::type
load( BinaryInputArchive & ar, std::vector<T, A> & 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<bool, A> types to binary
template <class A>
void save( BinaryOutputArchive & ar, std::vector<bool, A> const & vector )
//! Serialization for all other vector types
template <class T, class A>
void save( BinaryOutputArchive & ar, std::vector<T, A> 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<bool, A> to binary
template <class A>
void load( BinaryInputArchive & ar, std::vector<bool, A> & vector )
template <class T, class A>
void load( BinaryInputArchive & ar, std::vector<T, A> & vector )
{
size_t size;
ar & size;

View File

@@ -3,11 +3,15 @@
#include <iostream>
#include <type_traits>
#include <unordered_map>
#include <cstddef>
#include <cereal/details/traits.hpp>
namespace cereal
{
static const int32_t msb_32bit = 0x80000000;
//! For holding name value pairs
template <class T>
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<void *, std::size_t> 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<void> 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<void> ptr)
{
uint32_t const stripped_id = id & ~msb_32bit;
itsSharedPointerMap.insert( {stripped_id, ptr} );
}
private:
ArchiveType * const self;
std::unordered_map<std::size_t, std::shared_ptr<void>> itsSharedPointerMap; //!< Maps from addresses to pointer ids
}; // class InputArchive
}

View File

@@ -99,6 +99,7 @@ namespace cereal
has_non_member_serialize<T, InputArchive>();
}
// ######################################################################
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 <class T>
constexpr bool is_any_pointer()

View File

@@ -3,6 +3,7 @@
#include <cereal/binary_archive/binary_archive.hpp>
#include <cereal/binary_archive/string.hpp>
#include <cereal/json_archive/json_archive.hpp>
#include <cereal/binary_archive/shared_ptr.hpp>
#include <cxxabi.h>
#include <sstream>
@@ -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<int> xptr1 = std::make_shared<int>(5);
std::shared_ptr<int> xptr2 = xptr1;
std::shared_ptr<int> yptr1 = std::make_shared<int>(6);
std::shared_ptr<int> yptr2 = yptr1;
archive & xptr1;
archive & xptr2;
archive & yptr1;
archive & yptr2;
}
{
std::ifstream is("ptr.txt");
cereal::BinaryInputArchive archive(is);
std::shared_ptr<int> xptr1;
std::shared_ptr<int> xptr2;
std::shared_ptr<int> yptr1;
std::shared_ptr<int> 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;
}