mirror of
https://github.com/USCiLab/cereal.git
synced 2025-10-18 01:45:52 +02:00
breaking out access and base_class into their own headers
This commit is contained in:
129
include/cereal/access.hpp
Normal file
129
include/cereal/access.hpp
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef CEREAL_ACCESS_HPP_
|
||||
#define CEREAL_ACCESS_HPP_
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
//! A class that allows cereal to load smart pointers to types that have no default constructor
|
||||
/*! If your class does not have a default constructor, cereal will not be able
|
||||
to load any smart pointers to it unless you overload LoadAndAllocate
|
||||
for your class, and provide an appropriate load_and_allocate method.
|
||||
|
||||
The specialization of LoadAndAllocate must be placed within the cereal namespace:
|
||||
|
||||
@code{.cpp}
|
||||
struct MyType
|
||||
{
|
||||
MyType( int x ); // note: no default ctor
|
||||
int myX;
|
||||
|
||||
// Define a serialize or save/load pair as you normally would
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar )
|
||||
{
|
||||
ar( myX );
|
||||
}
|
||||
};
|
||||
|
||||
// Provide a specialization for LoadAndAllocate for your type
|
||||
namespace cereal
|
||||
{
|
||||
template <> struct LoadAndAllocate<MyType>
|
||||
{
|
||||
// load_and_allocate will be passed the archive that you will be loading
|
||||
// from and should return a raw pointer to a dynamically allocated instance
|
||||
// of your type.
|
||||
//
|
||||
// This will be captured by a smart pointer of some type and you need not
|
||||
// worry about managing the memory
|
||||
template <class Archive>
|
||||
static MyType * load_and_allocate( Archive & ar )
|
||||
{
|
||||
int x;
|
||||
ar( x );
|
||||
return new MyType( x );
|
||||
}
|
||||
};
|
||||
} // end namespace cereal
|
||||
@endcode
|
||||
|
||||
@tparam T The type to specialize for */
|
||||
template <class T>
|
||||
struct LoadAndAllocate
|
||||
{
|
||||
//! Called by cereal if no default constructor exists to load and allocate data simultaneously
|
||||
/*! Overloads of this should return a pointer to T and expect an archive as a parameter */
|
||||
static void load_and_allocate(...)
|
||||
{ }
|
||||
};
|
||||
|
||||
//! A class that can be made a friend to give cereal access to non public functions
|
||||
/*! If you desire non-public serialization functions within a class, cereal can only
|
||||
access these if you declare cereal::access a friend.
|
||||
|
||||
@code{.cpp}
|
||||
class MyClass
|
||||
{
|
||||
private:
|
||||
friend class cereal::access; // gives access to the private serialize
|
||||
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar )
|
||||
{
|
||||
// some code
|
||||
}
|
||||
};
|
||||
@endcode */
|
||||
class access
|
||||
{
|
||||
public:
|
||||
template<class Archive, class T> inline
|
||||
static auto member_serialize(Archive & ar, T & t) -> decltype(t.serialize(ar))
|
||||
{ t.serialize(ar); }
|
||||
|
||||
template<class Archive, class T> inline
|
||||
static auto member_save(Archive & ar, T const & t) -> decltype(t.save(ar))
|
||||
{ t.save(ar); }
|
||||
|
||||
template<class Archive, class T> inline
|
||||
static auto member_load(Archive & ar, T & t) -> decltype(t.load(ar))
|
||||
{ t.load(ar); }
|
||||
|
||||
template <class T>
|
||||
static void load_and_allocate(...)
|
||||
{ }
|
||||
|
||||
template<class T, class Archive> inline
|
||||
static auto load_and_allocate(Archive & ar) -> decltype(T::load_and_allocate(ar))
|
||||
{
|
||||
return T::load_and_allocate( ar );
|
||||
}
|
||||
};
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_ACCESS_HPP_
|
||||
@@ -28,7 +28,6 @@
|
||||
#define CEREAL_ARCHIVES_BINARY_HPP_
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <cereal/types/common.hpp>
|
||||
#include <stack>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
91
include/cereal/base_class.hpp
Normal file
91
include/cereal/base_class.hpp
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
Copyright (c) 2013, Randolph Voorhies, Shane Grant
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of cereal nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef CEREAL_BASE_CLASS_HPP_
|
||||
#define CEREAL_BASE_CLASS_HPP_
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
//! Casts a derived class to its base class in a way that allows cereal to track inheritance
|
||||
/*! This should be used in cases when a derived type features virtual inheritance from some
|
||||
base type. This allows cereal to track the inheritance and to avoid making duplicate copies
|
||||
during serialization.
|
||||
|
||||
It is save to use base_cast in all circumstances for serializing base classes, even in cases
|
||||
where virtual inheritance does not take place, though it may be slightly faster to utilize
|
||||
static_cast<> if you do not need to worry virtual inheritance
|
||||
|
||||
@code{.cpp}
|
||||
struct MyBase
|
||||
{ };
|
||||
|
||||
struct MyLeft : virtual MyBase
|
||||
{
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar )
|
||||
{
|
||||
ar( cereal::base_clas<MyBase>( this ) );
|
||||
}
|
||||
};
|
||||
|
||||
struct MyRight : virtual MyBase
|
||||
{
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar )
|
||||
{
|
||||
ar( cereal::base_clas<MyBase>( this ) );
|
||||
}
|
||||
};
|
||||
|
||||
// diamond virtual inheritance; contains one copy if each base class
|
||||
struct MyDerived : virtual MyLeft, virtual MyRight
|
||||
{
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar )
|
||||
{
|
||||
ar( cereal::base_cast<MyLeft>( this ) ); // safely serialize data members in MyLeft
|
||||
ar( cereal::base_cast<MyRight>( this ) ); // safely serialize data members in MyRight
|
||||
|
||||
// Because we used base_cast, cereal will ensure that only one instance of MyBase is
|
||||
// serialized as we traverse the inheritance heirarchy.
|
||||
|
||||
// If we had chosen to use static_cast<> instead, cereal would perform no tracking and
|
||||
// assume that every base class should be serialized (in this case leading to a duplicate
|
||||
// serialization of MyBase due to diamond inheritance
|
||||
};
|
||||
*/
|
||||
template<class Base>
|
||||
struct base_class
|
||||
{
|
||||
template<class Derived>
|
||||
base_class(Derived const * derived) :
|
||||
base_ptr(const_cast<Base*>(static_cast<Base const *>(derived)))
|
||||
{ }
|
||||
|
||||
Base * base_ptr;
|
||||
};
|
||||
} // namespace cereal
|
||||
#endif // CEREAL_BASE_CLASS_HPP_
|
||||
@@ -32,7 +32,9 @@
|
||||
#include <unordered_set>
|
||||
#include <cstddef>
|
||||
|
||||
#include <cereal/base_class.hpp>
|
||||
#include <cereal/details/traits.hpp>
|
||||
#include <cereal/types/common.hpp>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
@@ -115,20 +117,6 @@ namespace cereal
|
||||
//! Creates a name value pair for the variable T, using the same name
|
||||
#define CEREAL_NVP(T) ::cereal::make_nvp(#T, T)
|
||||
|
||||
// ######################################################################
|
||||
//! Casts a derived class to its base class in a way that allows
|
||||
//! cereal to track inheritance
|
||||
template<class Base>
|
||||
struct base_class
|
||||
{
|
||||
template<class Derived>
|
||||
base_class(Derived const * derived) :
|
||||
base_ptr(const_cast<Base*>(static_cast<Base const *>(derived)))
|
||||
{ }
|
||||
|
||||
Base * base_ptr;
|
||||
};
|
||||
|
||||
// ######################################################################
|
||||
//! Called before a type is serialized to set up any special archive state
|
||||
//! for processing some type
|
||||
@@ -144,6 +132,16 @@ namespace cereal
|
||||
|
||||
// ######################################################################
|
||||
//! Special flags for archives
|
||||
/*! AllowEmptyClassElision
|
||||
This allows for empty classes to be serialized even if they do not provide
|
||||
a serialization function. Classes with no data members are considered to be
|
||||
empty. Be warned that if this is enabled and you attempt to serialize an
|
||||
empty class with improperly formed serialize or save/load functions, no
|
||||
static error will occur - the error will propogate silently and your
|
||||
intended serialization functions may not be called. You can manually
|
||||
ensure that your classes that have custom serialization are correct
|
||||
by using the traits is_output_serializable and is_input_serializable
|
||||
in cereal/details/traits.hpp. */
|
||||
enum Flags { AllowEmptyClassElision = 1 };
|
||||
|
||||
// ######################################################################
|
||||
|
||||
@@ -31,41 +31,10 @@
|
||||
#include <typeindex>
|
||||
#include <memory>
|
||||
|
||||
#include <cereal/access.hpp>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
template <class T>
|
||||
struct LoadAndAllocate
|
||||
{
|
||||
static void load_and_allocate(...)
|
||||
{ }
|
||||
};
|
||||
|
||||
class access
|
||||
{
|
||||
public:
|
||||
template<class Archive, class T> inline
|
||||
static auto member_serialize(Archive & ar, T & t) -> decltype(t.serialize(ar))
|
||||
{ t.serialize(ar); }
|
||||
|
||||
template<class Archive, class T> inline
|
||||
static auto member_save(Archive & ar, T const & t) -> decltype(t.save(ar))
|
||||
{ t.save(ar); }
|
||||
|
||||
template<class Archive, class T> inline
|
||||
static auto member_load(Archive & ar, T & t) -> decltype(t.load(ar))
|
||||
{ t.load(ar); }
|
||||
|
||||
template <class T>
|
||||
static void load_and_allocate(...)
|
||||
{ }
|
||||
|
||||
template<class T, class Archive> inline
|
||||
static auto load_and_allocate(Archive & ar) -> decltype(T::load_and_allocate(ar))
|
||||
{
|
||||
return T::load_and_allocate( ar );
|
||||
}
|
||||
};
|
||||
|
||||
namespace traits
|
||||
{
|
||||
template<typename> struct Void { typedef void type; };
|
||||
|
||||
136
sandbox.cpp
136
sandbox.cpp
@@ -32,6 +32,7 @@
|
||||
#include <cereal/types/memory.hpp>
|
||||
#include <cereal/types/complex.hpp>
|
||||
#include <cereal/types/boost_variant.hpp>
|
||||
#include <cereal/base_class.hpp>
|
||||
|
||||
#include <cxxabi.h>
|
||||
#include <sstream>
|
||||
@@ -40,11 +41,49 @@
|
||||
#include <complex>
|
||||
#include <iostream>
|
||||
|
||||
class Base
|
||||
{
|
||||
private:
|
||||
friend class cereal::access;
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar )
|
||||
{
|
||||
std::cout << "Base serialize" << std::endl;
|
||||
ar( x );
|
||||
}
|
||||
int x;
|
||||
};
|
||||
|
||||
class Derived : public Base
|
||||
{
|
||||
public:
|
||||
//friend class cereal::access;
|
||||
template <class Archive>
|
||||
void save( Archive & ar ) const
|
||||
{
|
||||
std::cout << "Derived save" << std::endl;
|
||||
ar( y );
|
||||
serialize( ar );
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
void load( Archive & ar )
|
||||
{
|
||||
std::cout << "Derived load" << std::endl;
|
||||
ar( y );
|
||||
}
|
||||
|
||||
int y;
|
||||
};
|
||||
//ar( cereal::base_class<Test1>(this) );
|
||||
|
||||
// ###################################
|
||||
struct Test1
|
||||
{
|
||||
int a;
|
||||
|
||||
private:
|
||||
friend class cereal::access;
|
||||
template<class Archive>
|
||||
void serialize(Archive & ar)
|
||||
{
|
||||
@@ -56,6 +95,8 @@ struct Test1
|
||||
class Test2
|
||||
{
|
||||
public:
|
||||
Test2() {}
|
||||
Test2( int x ) : a( x ) {}
|
||||
int a;
|
||||
|
||||
private:
|
||||
@@ -209,44 +250,79 @@ namespace cereal
|
||||
// ######################################################################
|
||||
int main()
|
||||
{
|
||||
std::cout << std::boolalpha << std::endl;
|
||||
std::cout << "Base" << std::endl;
|
||||
std::cout << "ms " << cereal::traits::has_member_save<Base, cereal::BinaryOutputArchive>() << std::endl;
|
||||
std::cout << "nms " << cereal::traits::has_non_member_save<Base, cereal::BinaryOutputArchive>() << std::endl;
|
||||
std::cout << "ml " << cereal::traits::has_member_load<Base, cereal::BinaryInputArchive>() << std::endl;
|
||||
std::cout << "nml " << cereal::traits::has_non_member_load<Base, cereal::BinaryInputArchive>() << std::endl;
|
||||
std::cout << "mse " << cereal::traits::has_member_serialize<Base, cereal::BinaryOutputArchive>() << std::endl;
|
||||
std::cout << "nse " << cereal::traits::has_non_member_serialize<Base, cereal::BinaryOutputArchive>() << std::endl;
|
||||
std::cout << "iser " << cereal::traits::is_input_serializable<Base, cereal::BinaryInputArchive>() << std::endl;
|
||||
std::cout << "oser " << cereal::traits::is_output_serializable<Base, cereal::BinaryOutputArchive>() << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
int x[5];
|
||||
std::cout << "Derived" << std::endl;
|
||||
std::cout << "ms " << cereal::traits::has_member_save<Derived, cereal::BinaryOutputArchive>() << std::endl;
|
||||
std::cout << "nms " << cereal::traits::has_non_member_save<Derived, cereal::BinaryOutputArchive>() << std::endl;
|
||||
std::cout << "ml " << cereal::traits::has_member_load<Derived, cereal::BinaryInputArchive>() << std::endl;
|
||||
std::cout << "nml " << cereal::traits::has_non_member_load<Derived, cereal::BinaryInputArchive>() << std::endl;
|
||||
std::cout << "mse " << cereal::traits::has_member_serialize<Derived, cereal::BinaryOutputArchive>() << std::endl;
|
||||
std::cout << "nse " << cereal::traits::has_non_member_serialize<Derived, cereal::BinaryOutputArchive>() << std::endl;
|
||||
std::cout << "iser " << cereal::traits::is_input_serializable<Derived, cereal::BinaryInputArchive>() << std::endl;
|
||||
std::cout << "oser " << cereal::traits::is_output_serializable<Derived, cereal::BinaryOutputArchive>() << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
|
||||
//{
|
||||
// int x[5];
|
||||
// std::cout << "saving" << std::endl;
|
||||
// std::stringstream os;
|
||||
// cereal::BinaryOutputArchive archive(os);
|
||||
// archive( x );
|
||||
|
||||
// Base b;
|
||||
// archive( b );
|
||||
|
||||
// Derived d;
|
||||
// archive( d );
|
||||
|
||||
// std::cout << "loading" << std::endl;
|
||||
// cereal::BinaryInputArchive iarchive(os);
|
||||
|
||||
// iarchive( x );
|
||||
// iarchive( b );
|
||||
// iarchive( d );
|
||||
//}
|
||||
|
||||
Everything e_out;
|
||||
e_out.x = 99;
|
||||
e_out.y = 100;
|
||||
e_out.t1 = {1};
|
||||
e_out.t2 = {2};
|
||||
e_out.t3 = {3};
|
||||
e_out.t4 = {4};
|
||||
e_out.s = "Hello, World!";
|
||||
|
||||
Test2 t2 = {22};
|
||||
|
||||
{
|
||||
std::ostringstream os;
|
||||
std::ofstream os("out.txt");
|
||||
cereal::BinaryOutputArchive archive(os);
|
||||
archive( x );
|
||||
archive(CEREAL_NVP(e_out));
|
||||
archive(t2);
|
||||
}
|
||||
|
||||
Everything e_in;
|
||||
|
||||
//Everything e_out;
|
||||
//e_out.x = 99;
|
||||
//e_out.y = 100;
|
||||
//e_out.t1 = {1};
|
||||
//e_out.t2 = {2};
|
||||
//e_out.t3 = {3};
|
||||
//e_out.t4 = {4};
|
||||
//e_out.s = "Hello, World!";
|
||||
{
|
||||
std::ifstream is("out.txt");
|
||||
cereal::BinaryInputArchive archive(is);
|
||||
archive(CEREAL_NVP(e_in));
|
||||
archive(t2);
|
||||
}
|
||||
|
||||
//Test2 t2 = {22};
|
||||
|
||||
//{
|
||||
// std::ofstream os("out.txt");
|
||||
// cereal::BinaryOutputArchive archive(os);
|
||||
// archive(CEREAL_NVP(e_out));
|
||||
// archive(t2);
|
||||
//}
|
||||
|
||||
//Everything e_in;
|
||||
|
||||
//{
|
||||
// std::ifstream is("out.txt");
|
||||
// cereal::BinaryInputArchive archive(is);
|
||||
// archive(CEREAL_NVP(e_in));
|
||||
// archive(t2);
|
||||
//}
|
||||
|
||||
//assert(e_in == e_out);//
|
||||
assert(e_in == e_out);//
|
||||
//
|
||||
//{ //
|
||||
// std::ofstream os("pt//r.txt");
|
||||
|
||||
Reference in New Issue
Block a user