mirror of
https://github.com/USCiLab/cereal.git
synced 2025-10-02 21:28:06 +02:00
std::shared_ptr works with pointer tracking
This commit is contained in:
@@ -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
|
||||
|
||||
|
@@ -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_
|
||||
|
58
binary_archive/shared_ptr.hpp
Normal file
58
binary_archive/shared_ptr.hpp
Normal 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_
|
@@ -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;
|
||||
|
41
cereal.hpp
41
cereal.hpp
@@ -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
|
||||
}
|
||||
|
||||
|
@@ -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()
|
||||
|
41
test.cpp
41
test.cpp
@@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user