mirror of
https://github.com/RPCS3/cereal.git
synced 2024-12-04 01:00:41 +00:00
Add possibility to serialize of boost::variant with non default constructible types.
This commit is contained in:
parent
cfbb7b0f25
commit
36ab0c1f89
@ -111,6 +111,7 @@ namespace cereal
|
||||
// forward decl for construct
|
||||
//! @cond PRIVATE_NEVERDEFINED
|
||||
namespace memory_detail{ template <class Ar, class T> struct LoadAndConstructLoadWrapper; }
|
||||
namespace boost_variant_detail{ template <class Ar, class T> struct LoadAndConstructLoadWrapper; }
|
||||
//! @endcond
|
||||
|
||||
//! Used to construct types with no default constructor
|
||||
@ -203,7 +204,8 @@ namespace cereal
|
||||
}
|
||||
|
||||
private:
|
||||
template <class A, class B> friend struct ::cereal::memory_detail::LoadAndConstructLoadWrapper;
|
||||
template <class Ar, class TT> friend struct ::cereal::memory_detail::LoadAndConstructLoadWrapper;
|
||||
template <class Ar, class TT> friend struct ::cereal::boost_variant_detail::LoadAndConstructLoadWrapper;
|
||||
|
||||
construct( T * p ) : itsPtr( p ), itsEnableSharedRestoreFunction( [](){} ), itsValid( false ) {}
|
||||
construct( T * p, std::function<void()> enableSharedFunc ) : // g++4.7 ice with default lambda to std func
|
||||
|
@ -143,4 +143,12 @@
|
||||
#define CEREAL_HAS_CPP14
|
||||
#endif
|
||||
|
||||
// ######################################################################
|
||||
//! Defines the CEREAL_ALIGNOF macro to use instead of alignof
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
#define CEREAL_ALIGNOF __alignof
|
||||
#else // not MSVC 2013 or older
|
||||
#define CEREAL_ALIGNOF alignof
|
||||
#endif // end MSVC check
|
||||
|
||||
#endif // CEREAL_MACROS_HPP_
|
||||
|
@ -31,8 +31,8 @@
|
||||
#define CEREAL_TYPES_BOOST_VARIANT_HPP_
|
||||
|
||||
#include "cereal/cereal.hpp"
|
||||
#include <boost/variant.hpp>
|
||||
#include <boost/mpl/size.hpp>
|
||||
#include <boost/variant/variant_fwd.hpp>
|
||||
#include <boost/variant/static_visitor.hpp>
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
@ -53,34 +53,58 @@ namespace cereal
|
||||
Archive & ar;
|
||||
};
|
||||
|
||||
//! @internal
|
||||
template<int N, class Variant, class ... Args, class Archive>
|
||||
typename std::enable_if<N == boost::mpl::size<typename Variant::types>::value, void>::type
|
||||
load_variant(Archive & /*ar*/, int /*target*/, Variant & /*variant*/)
|
||||
{
|
||||
throw ::cereal::Exception("Error traversing variant during load");
|
||||
}
|
||||
|
||||
//! @internal
|
||||
template<int N, class Variant, class H, class ... T, class Archive>
|
||||
typename std::enable_if<N < boost::mpl::size<typename Variant::types>::value, void>::type
|
||||
load_variant(Archive & ar, int target, Variant & variant)
|
||||
template<class T, class Variant, class Archive>
|
||||
typename std::enable_if<std::is_default_constructible<T>::value>::type
|
||||
load_variant(Archive & ar, Variant & variant)
|
||||
{
|
||||
if(N == target)
|
||||
{
|
||||
H value;
|
||||
T value;
|
||||
ar( CEREAL_NVP_("data", value) );
|
||||
variant = value;
|
||||
}
|
||||
else
|
||||
load_variant<N+1, Variant, T...>(ar, target, variant);
|
||||
variant = std::move(value);
|
||||
}
|
||||
|
||||
template <class Archive, class T>
|
||||
struct LoadAndConstructLoadWrapper
|
||||
{
|
||||
using ST = typename std::aligned_storage<sizeof(T), CEREAL_ALIGNOF(T)>::type;
|
||||
|
||||
LoadAndConstructLoadWrapper() :
|
||||
construct( reinterpret_cast<T *>( &st ) )
|
||||
{ }
|
||||
|
||||
~LoadAndConstructLoadWrapper()
|
||||
{
|
||||
if (construct.itsValid)
|
||||
{
|
||||
construct->~T();
|
||||
}
|
||||
}
|
||||
|
||||
void CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar )
|
||||
{
|
||||
::cereal::detail::Construct<T, Archive>::load_andor_construct( ar, construct );
|
||||
}
|
||||
|
||||
ST st;
|
||||
::cereal::construct<T> construct;
|
||||
};
|
||||
|
||||
template<class T, class Variant, class Archive>
|
||||
typename std::enable_if<!std::is_default_constructible<T>::value>::type
|
||||
load_variant(Archive & ar, Variant & variant)
|
||||
{
|
||||
LoadAndConstructLoadWrapper<Archive, T> loadWrapper;
|
||||
|
||||
ar( CEREAL_NVP_("data", loadWrapper) );
|
||||
variant = std::move(*loadWrapper.construct.ptr());
|
||||
}
|
||||
|
||||
} // namespace boost_variant_detail
|
||||
|
||||
//! Saving for boost::variant
|
||||
template <class Archive, typename VariantType1, typename... VariantTypes> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, boost::variant<VariantType1, VariantTypes...> const & variant )
|
||||
template <class Archive, typename... VariantTypes> inline
|
||||
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, boost::variant<VariantTypes...> const & variant )
|
||||
{
|
||||
int32_t which = variant.which();
|
||||
ar( CEREAL_NVP_("which", which) );
|
||||
@ -89,17 +113,19 @@ namespace cereal
|
||||
}
|
||||
|
||||
//! Loading for boost::variant
|
||||
template <class Archive, typename VariantType1, typename... VariantTypes> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, boost::variant<VariantType1, VariantTypes...> & variant )
|
||||
template <class Archive, typename... VariantTypes> inline
|
||||
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, boost::variant<VariantTypes...> & variant )
|
||||
{
|
||||
typedef typename boost::variant<VariantType1, VariantTypes...>::types types;
|
||||
|
||||
int32_t which;
|
||||
ar( CEREAL_NVP_("which", which) );
|
||||
if(which >= boost::mpl::size<types>::value)
|
||||
|
||||
using LoadFuncType = void(*)(Archive &, boost::variant<VariantTypes...> &);
|
||||
constexpr LoadFuncType loadFuncArray[] = {&boost_variant_detail::load_variant<VariantTypes>...};
|
||||
|
||||
if(which >= int32_t(sizeof(loadFuncArray)/sizeof(loadFuncArray[0])))
|
||||
throw Exception("Invalid 'which' selector when deserializing boost::variant");
|
||||
|
||||
boost_variant_detail::load_variant<0, boost::variant<VariantType1, VariantTypes...>, VariantType1, VariantTypes...>(ar, which, variant);
|
||||
loadFuncArray[which](ar, variant);
|
||||
}
|
||||
} // namespace cereal
|
||||
|
||||
|
@ -34,13 +34,6 @@
|
||||
#include <memory>
|
||||
#include <cstring>
|
||||
|
||||
// Work around MSVC not having alignof
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
#define CEREAL_ALIGNOF __alignof
|
||||
#else // not MSVC 2013 or older
|
||||
#define CEREAL_ALIGNOF alignof
|
||||
#endif // end MSVC check
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
namespace memory_detail
|
||||
@ -423,5 +416,4 @@ namespace cereal
|
||||
// automatically include polymorphic support
|
||||
#include "cereal/types/polymorphic.hpp"
|
||||
|
||||
#undef CEREAL_ALIGNOF
|
||||
#endif // CEREAL_TYPES_SHARED_PTR_HPP_
|
||||
|
@ -29,6 +29,34 @@
|
||||
|
||||
#include "../common.hpp"
|
||||
#include <cereal/types/boost_variant.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
struct NonDefaultConstructible
|
||||
{
|
||||
NonDefaultConstructible(int i) : index(i)
|
||||
{}
|
||||
|
||||
template <class Archive>
|
||||
void CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar )
|
||||
{
|
||||
ar( index );
|
||||
}
|
||||
int index;
|
||||
};
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
template <> struct LoadAndConstruct<NonDefaultConstructible>
|
||||
{
|
||||
template <class Archive>
|
||||
static void load_and_construct( Archive & ar, cereal::construct<NonDefaultConstructible> & construct )
|
||||
{
|
||||
int i;
|
||||
ar( i );
|
||||
construct( i );
|
||||
}
|
||||
};
|
||||
} // end namespace cereal
|
||||
|
||||
template <class IArchive, class OArchive> inline
|
||||
void test_boost_variant()
|
||||
@ -36,9 +64,12 @@ void test_boost_variant()
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
|
||||
boost::variant<int, double, std::string> o_bv1 = random_value<int>(gen);
|
||||
boost::variant<int, double, std::string> o_bv2 = random_value<double>(gen);
|
||||
boost::variant<int, double, std::string> o_bv3 = random_basic_string<char>(gen);
|
||||
using VariantType = boost::variant<int, double, std::string, NonDefaultConstructible>;
|
||||
|
||||
VariantType o_bv1 = random_value<int>(gen);
|
||||
VariantType o_bv2 = random_value<double>(gen);
|
||||
VariantType o_bv3 = random_basic_string<char>(gen);
|
||||
VariantType o_bv4 = NonDefaultConstructible(random_value<int>(gen));
|
||||
|
||||
std::ostringstream os;
|
||||
{
|
||||
@ -47,11 +78,13 @@ void test_boost_variant()
|
||||
oar(o_bv1);
|
||||
oar(o_bv2);
|
||||
oar(o_bv3);
|
||||
oar(o_bv4);
|
||||
}
|
||||
|
||||
decltype(o_bv1) i_bv1;
|
||||
decltype(o_bv2) i_bv2;
|
||||
decltype(o_bv3) i_bv3;
|
||||
decltype(o_bv4) i_bv4;
|
||||
|
||||
std::istringstream is(os.str());
|
||||
{
|
||||
@ -60,11 +93,13 @@ void test_boost_variant()
|
||||
iar(i_bv1);
|
||||
iar(i_bv2);
|
||||
iar(i_bv3);
|
||||
iar(i_bv4);
|
||||
}
|
||||
|
||||
CHECK_EQ( boost::get<int>(i_bv1), boost::get<int>(o_bv1) );
|
||||
CHECK_EQ( boost::get<double>(i_bv2), doctest::Approx(boost::get<double>(o_bv2)).epsilon(1e-5) );
|
||||
CHECK_EQ( boost::get<std::string>(i_bv3), boost::get<std::string>(o_bv3) );
|
||||
CHECK_EQ( boost::get<NonDefaultConstructible>(i_bv4).index, boost::get<NonDefaultConstructible>(o_bv4).index );
|
||||
}
|
||||
|
||||
#endif // CEREAL_TEST_BOOST_VARIANT_H_
|
||||
|
Loading…
Reference in New Issue
Block a user