mirror of
https://github.com/RPCS3/cereal.git
synced 2025-01-05 18:22:22 +00:00
Merge branch 'issue_46' into develop relates #46
This commit is contained in:
commit
e054ec1b10
156
include/cereal/archives/adapters.hpp
Normal file
156
include/cereal/archives/adapters.hpp
Normal file
@ -0,0 +1,156 @@
|
||||
/*! \file adapters.hpp
|
||||
\brief Archive adapters that provide additional functionality
|
||||
on top of an existing archive */
|
||||
/*
|
||||
Copyright (c) 2014, 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 RANDOLPH VOORHIES OR SHANE GRANT 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_ARCHIVES_ADAPTERS_HPP_
|
||||
#define CEREAL_ARCHIVES_ADAPTERS_HPP_
|
||||
|
||||
#include <cereal/details/helpers.hpp>
|
||||
#include <utility>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
// Forward declaration for friend access
|
||||
template <class U, class A> U & get_user_data( A & );
|
||||
|
||||
//! Wraps an archive and gives access to user data
|
||||
/*! This adapter is useful if you require access to
|
||||
either raw pointers or references within your
|
||||
serialization functions.
|
||||
|
||||
While cereal does not directly support serialization
|
||||
raw pointers or references, it is sometimes the case
|
||||
that you may want to supply something such as a raw
|
||||
pointer or global reference to some constructor.
|
||||
In this situation this adapter would likely be used
|
||||
with the construct class to allow for non-default
|
||||
constructors.
|
||||
|
||||
@code{.cpp}
|
||||
struct MyUserData
|
||||
{
|
||||
int * myRawPointer;
|
||||
std::reference_wrapper<MyOtherType> myReference;
|
||||
};
|
||||
|
||||
struct MyClass
|
||||
{
|
||||
// Note the raw pointer parameter
|
||||
MyClass( int xx, int * rawP );
|
||||
|
||||
int x;
|
||||
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar )
|
||||
{ ar( x ); }
|
||||
|
||||
template <class Archive>
|
||||
static void load_and_construct( Archive & ar, cereal::construct<MyClass> & construct )
|
||||
{
|
||||
int xx;
|
||||
ar( xx );
|
||||
// note the need to use get_user_data to retrieve user data from the archive
|
||||
construct( xx, cereal::get_user_data<MyUserData>( ar ).myRawPointer );
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
MyUserData md;
|
||||
md.myRawPointer = &something;
|
||||
md.myReference = someInstanceOfType;
|
||||
|
||||
std::ifstream is( "data.xml" );
|
||||
cereal::UserDataAdapter<MyUserData, cereal::XMLInputArchive> ar( md, is );
|
||||
|
||||
std::unique_ptr<MyClass> sc;
|
||||
ar( sc ); // use as normal
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@endcode
|
||||
|
||||
@relates get_user_data
|
||||
|
||||
@tparam UserData The type to give the archive access to
|
||||
@tparam Archive The archive to wrap */
|
||||
template <class UserData, class Archive>
|
||||
class UserDataAdapter : public Archive
|
||||
{
|
||||
public:
|
||||
//! Construct the archive with some user data struct
|
||||
/*! This will forward all arguments (other than the user
|
||||
data) to the wrapped archive type. The UserDataAdapter
|
||||
can then be used identically to the wrapped archive type
|
||||
|
||||
@tparam Args The arguments to pass to the constructor of
|
||||
the archive. */
|
||||
template <class ... Args>
|
||||
UserDataAdapter( UserData & ud, Args && ... args ) :
|
||||
Archive( std::forward<Args>( args )... ),
|
||||
userdata( ud )
|
||||
{ }
|
||||
|
||||
private:
|
||||
//! Overload the rtti function to enable dynamic_cast
|
||||
void rtti() {}
|
||||
friend UserData & get_user_data<UserData>( Archive & ar );
|
||||
UserData & userdata; //!< The actual user data
|
||||
};
|
||||
|
||||
//! Retrieves user data from an archive wrapped by UserDataAdapter
|
||||
/*! This will attempt to retrieve the user data associated with
|
||||
some archive wrapped by UserDataAdapter. If this is used on
|
||||
an archive that is not wrapped, a run-time exception will occur.
|
||||
|
||||
@note The correct use of this function cannot be enforced at compile
|
||||
time.
|
||||
|
||||
@relates UserDataAdapter
|
||||
@tparam UserData The data struct contained in the archive
|
||||
@tparam Archive The archive, which should be wrapped by UserDataAdapter
|
||||
@param ar The archive
|
||||
@throws Exception if the archive this is used upon is not wrapped with
|
||||
UserDataAdapter. */
|
||||
template <class UserData, class Archive>
|
||||
UserData & get_user_data( Archive & ar )
|
||||
{
|
||||
try
|
||||
{
|
||||
return dynamic_cast<UserDataAdapter<UserData, Archive> &>( ar ).userdata;
|
||||
}
|
||||
catch( std::bad_cast const & )
|
||||
{
|
||||
throw ::cereal::Exception("Attempting to get user data from archive not wrapped in UserDataAdapter");
|
||||
}
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
#endif // CEREAL_ARCHIVES_ADAPTERS_HPP_
|
@ -220,8 +220,11 @@ namespace cereal
|
||||
namespace detail
|
||||
{
|
||||
// base classes for type checking
|
||||
struct OutputArchiveBase {};
|
||||
struct InputArchiveBase {};
|
||||
/* The rtti virtual function only exists to enable an archive to
|
||||
be used in a polymorphic fashion, if necessary. See the
|
||||
archive adapters for an example of this */
|
||||
class OutputArchiveBase { private: virtual void rtti(){} };
|
||||
class InputArchiveBase { private: virtual void rtti(){} };
|
||||
|
||||
// forward decls for polymorphic support
|
||||
template <class Archive, class T> struct polymorphic_serialization_support;
|
||||
|
134
unittests/user_data_adapters.cpp
Normal file
134
unittests/user_data_adapters.cpp
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
Copyright (c) 2014, 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 RANDOLPH VOORHIES AND SHANE GRANT 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.
|
||||
*/
|
||||
#include "common.hpp"
|
||||
#include <cereal/archives/adapters.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
struct SomeStruct {};
|
||||
|
||||
struct UserData
|
||||
{
|
||||
UserData( SomeStruct * pp, SomeStruct & r ) :
|
||||
p(pp), ref(r) {}
|
||||
|
||||
SomeStruct * p;
|
||||
std::reference_wrapper<SomeStruct> ref;
|
||||
};
|
||||
|
||||
struct UserStruct
|
||||
{
|
||||
UserStruct( std::int32_t i,
|
||||
SomeStruct * pointer,
|
||||
SomeStruct & reference ) :
|
||||
i32( i ),
|
||||
p( pointer ),
|
||||
ref( reference )
|
||||
{ }
|
||||
|
||||
std::int32_t i32;
|
||||
SomeStruct const * p;
|
||||
SomeStruct & ref;
|
||||
|
||||
template <class Archive>
|
||||
void serialize( Archive & ar )
|
||||
{
|
||||
ar( i32 );
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
static void load_and_construct( Archive & ar, cereal::construct<UserStruct> & construct )
|
||||
{
|
||||
std::int32_t ii;
|
||||
ar( ii );
|
||||
auto & data = cereal::get_user_data<UserData>( ar );
|
||||
construct( ii, data.p, data.ref.get() );
|
||||
}
|
||||
};
|
||||
|
||||
template <class IArchive, class OArchive>
|
||||
void test_user_data_adapters()
|
||||
{
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
|
||||
auto rng = [&](){ return random_value<int>(gen); };
|
||||
|
||||
for(int ii=0; ii<100; ++ii)
|
||||
{
|
||||
SomeStruct ss;
|
||||
std::unique_ptr<UserStruct> o_ptr( new UserStruct( rng(), &ss, ss ) );
|
||||
|
||||
std::ostringstream os;
|
||||
{
|
||||
OArchive oar(os);
|
||||
|
||||
oar(o_ptr);
|
||||
}
|
||||
|
||||
decltype( o_ptr ) i_ptr;
|
||||
|
||||
std::istringstream is(os.str());
|
||||
{
|
||||
UserData ud(&ss, ss);
|
||||
cereal::UserDataAdapter<UserData, IArchive> iar(ud, is);
|
||||
|
||||
iar(i_ptr);
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL( i_ptr->p == o_ptr->p, true );
|
||||
BOOST_CHECK_EQUAL( std::addressof(i_ptr->ref) == std::addressof(o_ptr->ref), true );
|
||||
BOOST_CHECK_EQUAL( i_ptr->i32, o_ptr->i32 );
|
||||
|
||||
std::istringstream bad_is(os.str());
|
||||
{
|
||||
IArchive iar(bad_is);
|
||||
|
||||
BOOST_CHECK_THROW( iar(i_ptr), ::cereal::Exception )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( binary_tuple )
|
||||
{
|
||||
test_user_data_adapters<cereal::BinaryInputArchive, cereal::BinaryOutputArchive>();
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( portable_binary_tuple )
|
||||
{
|
||||
test_user_data_adapters<cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive>();
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( xml_tuple )
|
||||
{
|
||||
test_user_data_adapters<cereal::XMLInputArchive, cereal::XMLOutputArchive>();
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( json_tuple )
|
||||
{
|
||||
test_user_data_adapters<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user