mirror of
https://github.com/USCiLab/cereal.git
synced 2025-10-18 01:45:52 +02:00
Fixing issue #79
Added a set of trait classes that can be used to get an input archive from an output archive. Requires specializing a struct for each direction or alternatively using the new macro CEREAL_SETUP_ARCHIVE_TRAITS(InArchive, OutArchive). This has already been added for all built in archive types. This is currently only used for minimal serialization. load_minimal type traits now correctly use the output archive to check the existence of a corresponding save_minimal and get its return type, using the new get_input_from_output type class. Added a test for this case into the minimal structs test. Sandbox_vs needed the new macro to become compliant.
This commit is contained in:
@@ -159,4 +159,7 @@ namespace cereal
|
|||||||
CEREAL_REGISTER_ARCHIVE(cereal::BinaryOutputArchive)
|
CEREAL_REGISTER_ARCHIVE(cereal::BinaryOutputArchive)
|
||||||
CEREAL_REGISTER_ARCHIVE(cereal::BinaryInputArchive)
|
CEREAL_REGISTER_ARCHIVE(cereal::BinaryInputArchive)
|
||||||
|
|
||||||
|
// tie input and output archives together
|
||||||
|
CEREAL_SETUP_ARCHIVE_TRAITS(cereal::BinaryInputArchive, cereal::BinaryOutputArchive)
|
||||||
|
|
||||||
#endif // CEREAL_ARCHIVES_BINARY_HPP_
|
#endif // CEREAL_ARCHIVES_BINARY_HPP_
|
||||||
|
|||||||
@@ -887,4 +887,7 @@ namespace cereal
|
|||||||
CEREAL_REGISTER_ARCHIVE(cereal::JSONInputArchive)
|
CEREAL_REGISTER_ARCHIVE(cereal::JSONInputArchive)
|
||||||
CEREAL_REGISTER_ARCHIVE(cereal::JSONOutputArchive)
|
CEREAL_REGISTER_ARCHIVE(cereal::JSONOutputArchive)
|
||||||
|
|
||||||
|
// tie input and output archives together
|
||||||
|
CEREAL_SETUP_ARCHIVE_TRAITS(cereal::JSONInputArchive, cereal::JSONOutputArchive)
|
||||||
|
|
||||||
#endif // CEREAL_ARCHIVES_JSON_HPP_
|
#endif // CEREAL_ARCHIVES_JSON_HPP_
|
||||||
|
|||||||
@@ -239,4 +239,7 @@ namespace cereal
|
|||||||
CEREAL_REGISTER_ARCHIVE(cereal::PortableBinaryOutputArchive)
|
CEREAL_REGISTER_ARCHIVE(cereal::PortableBinaryOutputArchive)
|
||||||
CEREAL_REGISTER_ARCHIVE(cereal::PortableBinaryInputArchive)
|
CEREAL_REGISTER_ARCHIVE(cereal::PortableBinaryInputArchive)
|
||||||
|
|
||||||
|
// tie input and output archives together
|
||||||
|
CEREAL_SETUP_ARCHIVE_TRAITS(cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive)
|
||||||
|
|
||||||
#endif // CEREAL_ARCHIVES_PORTABLE_BINARY_HPP_
|
#endif // CEREAL_ARCHIVES_PORTABLE_BINARY_HPP_
|
||||||
|
|||||||
@@ -825,4 +825,7 @@ namespace cereal
|
|||||||
CEREAL_REGISTER_ARCHIVE(cereal::XMLOutputArchive)
|
CEREAL_REGISTER_ARCHIVE(cereal::XMLOutputArchive)
|
||||||
CEREAL_REGISTER_ARCHIVE(cereal::XMLInputArchive)
|
CEREAL_REGISTER_ARCHIVE(cereal::XMLInputArchive)
|
||||||
|
|
||||||
|
// tie input and output archives together
|
||||||
|
CEREAL_SETUP_ARCHIVE_TRAITS(cereal::XMLInputArchive, cereal::XMLOutputArchive)
|
||||||
|
|
||||||
#endif // CEREAL_ARCHIVES_XML_HPP_
|
#endif // CEREAL_ARCHIVES_XML_HPP_
|
||||||
|
|||||||
@@ -756,7 +756,8 @@ namespace cereal
|
|||||||
template <class T, PROCESS_IF(member_load_minimal)> inline
|
template <class T, PROCESS_IF(member_load_minimal)> inline
|
||||||
ArchiveType & processImpl(T & t)
|
ArchiveType & processImpl(T & t)
|
||||||
{
|
{
|
||||||
typename traits::has_member_save_minimal<T, ArchiveType>::type value;
|
using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
|
||||||
|
typename traits::has_member_save_minimal<T, OutArchiveType>::type value;
|
||||||
self->process( value );
|
self->process( value );
|
||||||
access::member_load_minimal(*self, t, value);
|
access::member_load_minimal(*self, t, value);
|
||||||
return *self;
|
return *self;
|
||||||
@@ -766,7 +767,8 @@ namespace cereal
|
|||||||
template <class T, PROCESS_IF(non_member_load_minimal)> inline
|
template <class T, PROCESS_IF(non_member_load_minimal)> inline
|
||||||
ArchiveType & processImpl(T & t)
|
ArchiveType & processImpl(T & t)
|
||||||
{
|
{
|
||||||
typename traits::has_non_member_save_minimal<T, ArchiveType>::type value;
|
using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
|
||||||
|
typename traits::has_non_member_save_minimal<T, OutArchiveType>::type value;
|
||||||
self->process( value );
|
self->process( value );
|
||||||
CEREAL_LOAD_MINIMAL_FUNCTION_NAME(*self, t, value);
|
CEREAL_LOAD_MINIMAL_FUNCTION_NAME(*self, t, value);
|
||||||
return *self;
|
return *self;
|
||||||
@@ -875,8 +877,9 @@ namespace cereal
|
|||||||
template <class T, PROCESS_IF(member_versioned_load_minimal)> inline
|
template <class T, PROCESS_IF(member_versioned_load_minimal)> inline
|
||||||
ArchiveType & processImpl(T & t)
|
ArchiveType & processImpl(T & t)
|
||||||
{
|
{
|
||||||
|
using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
|
||||||
const auto version = loadClassVersion<T>();
|
const auto version = loadClassVersion<T>();
|
||||||
typename traits::has_member_versioned_save_minimal<T, ArchiveType>::type value;
|
typename traits::has_member_versioned_save_minimal<T, OutArchiveType>::type value;
|
||||||
self->process(value);
|
self->process(value);
|
||||||
access::member_load_minimal(*self, t, value, version);
|
access::member_load_minimal(*self, t, value, version);
|
||||||
return *self;
|
return *self;
|
||||||
@@ -887,8 +890,9 @@ namespace cereal
|
|||||||
template <class T, PROCESS_IF(non_member_versioned_load_minimal)> inline
|
template <class T, PROCESS_IF(non_member_versioned_load_minimal)> inline
|
||||||
ArchiveType & processImpl(T & t)
|
ArchiveType & processImpl(T & t)
|
||||||
{
|
{
|
||||||
|
using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
|
||||||
const auto version = loadClassVersion<T>();
|
const auto version = loadClassVersion<T>();
|
||||||
typename traits::has_non_member_versioned_save_minimal<T, ArchiveType>::type value;
|
typename traits::has_non_member_versioned_save_minimal<T, OutArchiveType>::type value;
|
||||||
self->process(value);
|
self->process(value);
|
||||||
CEREAL_LOAD_MINIMAL_FUNCTION_NAME(*self, t, value, version);
|
CEREAL_LOAD_MINIMAL_FUNCTION_NAME(*self, t, value, version);
|
||||||
return *self;
|
return *self;
|
||||||
|
|||||||
@@ -147,6 +147,32 @@ namespace cereal
|
|||||||
template <bool ... Conditions>
|
template <bool ... Conditions>
|
||||||
using DisableIf = typename detail::DisableIfHelper<Conditions...>::type;
|
using DisableIf = typename detail::DisableIfHelper<Conditions...>::type;
|
||||||
|
|
||||||
|
// ######################################################################
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
template <class InputArchive>
|
||||||
|
struct get_output_from_input : no
|
||||||
|
{
|
||||||
|
static_assert( detail::delay_static_assert<InputArchive>::value,
|
||||||
|
"Could not find an associated output archive for input archive." );
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class OutputArchive>
|
||||||
|
struct get_input_from_output : no
|
||||||
|
{
|
||||||
|
static_assert( detail::delay_static_assert<OutputArchive>::value,
|
||||||
|
"Could not find an associated input archive for output archive." );
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Sets up traits that relate an input archive to an output archive
|
||||||
|
#define CEREAL_SETUP_ARCHIVE_TRAITS(InputArchive, OutputArchive) \
|
||||||
|
namespace cereal { namespace traits { namespace detail { \
|
||||||
|
template <> struct get_output_from_input<InputArchive> \
|
||||||
|
{ using type = OutputArchive; }; \
|
||||||
|
template <> struct get_input_from_output<OutputArchive> \
|
||||||
|
{ using type = InputArchive; }; } } } /* end namespaces */
|
||||||
|
|
||||||
// ######################################################################
|
// ######################################################################
|
||||||
//! Used to convert a MAKE_HAS_XXX macro into a versioned variant
|
//! Used to convert a MAKE_HAS_XXX macro into a versioned variant
|
||||||
#define CEREAL_MAKE_VERSIONED_TEST ,0
|
#define CEREAL_MAKE_VERSIONED_TEST ,0
|
||||||
@@ -678,11 +704,13 @@ namespace cereal
|
|||||||
template <class T, class A>
|
template <class T, class A>
|
||||||
struct has_member_load_minimal_wrapper<T, A, true>
|
struct has_member_load_minimal_wrapper<T, A, true>
|
||||||
{
|
{
|
||||||
static_assert( has_member_save_minimal<T, A>::value,
|
using AOut = typename detail::get_output_from_input<A>::type;
|
||||||
|
|
||||||
|
static_assert( has_member_save_minimal<T, AOut>::value,
|
||||||
"cereal detected member load_minimal but no valid member save_minimal. "
|
"cereal detected member load_minimal but no valid member save_minimal. "
|
||||||
"cannot evaluate correctness of load_minimal without valid save_minimal." );
|
"cannot evaluate correctness of load_minimal without valid save_minimal." );
|
||||||
|
|
||||||
using SaveType = typename detail::get_member_save_minimal_type<T, A, true>::type;
|
using SaveType = typename detail::get_member_save_minimal_type<T, AOut, true>::type;
|
||||||
const static bool value = has_member_load_minimal_impl<T, A>::value;
|
const static bool value = has_member_load_minimal_impl<T, A>::value;
|
||||||
const static bool valid = has_member_load_minimal_type_impl<T, A, SaveType>::value;
|
const static bool valid = has_member_load_minimal_type_impl<T, A, SaveType>::value;
|
||||||
|
|
||||||
@@ -739,11 +767,13 @@ namespace cereal
|
|||||||
template <class T, class A>
|
template <class T, class A>
|
||||||
struct has_member_versioned_load_minimal_wrapper<T, A, true>
|
struct has_member_versioned_load_minimal_wrapper<T, A, true>
|
||||||
{
|
{
|
||||||
static_assert( has_member_versioned_save_minimal<T, A>::value,
|
using AOut = typename detail::get_output_from_input<A>::type;
|
||||||
|
|
||||||
|
static_assert( has_member_versioned_save_minimal<T, AOut>::value,
|
||||||
"cereal detected member versioned load_minimal but no valid member versioned save_minimal. "
|
"cereal detected member versioned load_minimal but no valid member versioned save_minimal. "
|
||||||
"cannot evaluate correctness of load_minimal without valid save_minimal." );
|
"cannot evaluate correctness of load_minimal without valid save_minimal." );
|
||||||
|
|
||||||
using SaveType = typename detail::get_member_versioned_save_minimal_type<T, A, true>::type;
|
using SaveType = typename detail::get_member_versioned_save_minimal_type<T, AOut, true>::type;
|
||||||
const static bool value = has_member_versioned_load_minimal_impl<T, A>::value;
|
const static bool value = has_member_versioned_load_minimal_impl<T, A>::value;
|
||||||
const static bool valid = has_member_versioned_load_minimal_type_impl<T, A, SaveType>::value;
|
const static bool valid = has_member_versioned_load_minimal_type_impl<T, A, SaveType>::value;
|
||||||
|
|
||||||
@@ -794,11 +824,13 @@ namespace cereal
|
|||||||
template <class T, class A>
|
template <class T, class A>
|
||||||
struct has_non_member_load_minimal_wrapper<T, A, true>
|
struct has_non_member_load_minimal_wrapper<T, A, true>
|
||||||
{
|
{
|
||||||
static_assert( detail::has_non_member_save_minimal_impl<T, A>::valid,
|
using AOut = typename detail::get_output_from_input<A>::type;
|
||||||
|
|
||||||
|
static_assert( detail::has_non_member_save_minimal_impl<T, AOut>::valid,
|
||||||
"cereal detected non-member load_minimal but no valid non-member save_minimal. "
|
"cereal detected non-member load_minimal but no valid non-member save_minimal. "
|
||||||
"cannot evaluate correctness of load_minimal without valid save_minimal." );
|
"cannot evaluate correctness of load_minimal without valid save_minimal." );
|
||||||
|
|
||||||
using SaveType = typename detail::get_non_member_save_minimal_type<T, A, true>::type;
|
using SaveType = typename detail::get_non_member_save_minimal_type<T, AOut, true>::type;
|
||||||
using check = has_non_member_load_minimal_impl<T, A, SaveType>;
|
using check = has_non_member_load_minimal_impl<T, A, SaveType>;
|
||||||
static const bool value = check::exists;
|
static const bool value = check::exists;
|
||||||
|
|
||||||
@@ -846,11 +878,13 @@ namespace cereal
|
|||||||
template <class T, class A>
|
template <class T, class A>
|
||||||
struct has_non_member_versioned_load_minimal_wrapper<T, A, true>
|
struct has_non_member_versioned_load_minimal_wrapper<T, A, true>
|
||||||
{
|
{
|
||||||
static_assert( detail::has_non_member_versioned_save_minimal_impl<T, A>::valid,
|
using AOut = typename detail::get_output_from_input<A>::type;
|
||||||
|
|
||||||
|
static_assert( detail::has_non_member_versioned_save_minimal_impl<T, AOut>::valid,
|
||||||
"cereal detected non-member versioned load_minimal but no valid non-member versioned save_minimal. "
|
"cereal detected non-member versioned load_minimal but no valid non-member versioned save_minimal. "
|
||||||
"cannot evaluate correctness of load_minimal without valid save_minimal." );
|
"cannot evaluate correctness of load_minimal without valid save_minimal." );
|
||||||
|
|
||||||
using SaveType = typename detail::get_non_member_versioned_save_minimal_type<T, A, true>::type;
|
using SaveType = typename detail::get_non_member_versioned_save_minimal_type<T, AOut, true>::type;
|
||||||
using check = has_non_member_versioned_load_minimal_impl<T, A, SaveType>;
|
using check = has_non_member_versioned_load_minimal_impl<T, A, SaveType>;
|
||||||
static const bool value = check::exists;
|
static const bool value = check::exists;
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,7 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
struct Archive {};
|
struct Archive {};
|
||||||
|
CEREAL_SETUP_ARCHIVE_TRAITS(Archive, Archive)
|
||||||
|
|
||||||
struct Test
|
struct Test
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -134,6 +134,41 @@ struct TestStruct
|
|||||||
NonMemberMinimalVersioned nmmv;
|
NonMemberMinimalVersioned nmmv;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Issue79Struct
|
||||||
|
{
|
||||||
|
Issue79Struct() = default;
|
||||||
|
Issue79Struct( std::int32_t xx ) : x(xx) {}
|
||||||
|
std::int32_t x;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Archive, cereal::traits::DisableIf<std::is_same<Archive, cereal::BinaryOutputArchive>::value ||
|
||||||
|
std::is_same<Archive, cereal::PortableBinaryOutputArchive>::value> = cereal::traits::sfinae>
|
||||||
|
std::string save_minimal( Archive const &, Issue79Struct const & val )
|
||||||
|
{
|
||||||
|
return std::to_string( val.x );
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Archive, cereal::traits::DisableIf<std::is_same<Archive, cereal::BinaryInputArchive>::value ||
|
||||||
|
std::is_same<Archive, cereal::PortableBinaryInputArchive>::value> = cereal::traits::sfinae>
|
||||||
|
void load_minimal( Archive const &, Issue79Struct & val, std::string const & str )
|
||||||
|
{
|
||||||
|
val.x = std::stoi( str );
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Archive, cereal::traits::EnableIf<std::is_same<Archive, cereal::BinaryOutputArchive>::value ||
|
||||||
|
std::is_same<Archive, cereal::PortableBinaryOutputArchive>::value> = cereal::traits::sfinae>
|
||||||
|
std::int32_t save_minimal( Archive const &, Issue79Struct const & val )
|
||||||
|
{
|
||||||
|
return val.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Archive, cereal::traits::EnableIf<std::is_same<Archive, cereal::BinaryInputArchive>::value ||
|
||||||
|
std::is_same<Archive, cereal::PortableBinaryInputArchive>::value> = cereal::traits::sfinae>
|
||||||
|
void load_minimal( Archive const &, Issue79Struct & val, std::int32_t const & xx )
|
||||||
|
{
|
||||||
|
val.x = xx;
|
||||||
|
}
|
||||||
|
|
||||||
template <class IArchive, class OArchive>
|
template <class IArchive, class OArchive>
|
||||||
void test_structs_minimal()
|
void test_structs_minimal()
|
||||||
{
|
{
|
||||||
@@ -145,18 +180,23 @@ void test_structs_minimal()
|
|||||||
TestStruct o_struct = { random_basic_string<char>(gen), random_value<double>(gen),
|
TestStruct o_struct = { random_basic_string<char>(gen), random_value<double>(gen),
|
||||||
random_value<std::uint32_t>(gen), random_value<uint8_t>(gen) % 2 ? true : false };
|
random_value<std::uint32_t>(gen), random_value<uint8_t>(gen) % 2 ? true : false };
|
||||||
|
|
||||||
|
Issue79Struct o_struct2 = { random_value<std::int32_t>(gen) };
|
||||||
|
|
||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
{
|
{
|
||||||
OArchive oar(os);
|
OArchive oar(os);
|
||||||
oar( o_struct );
|
oar( o_struct );
|
||||||
|
oar( o_struct2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
decltype(o_struct) i_struct;
|
decltype(o_struct) i_struct;
|
||||||
|
decltype(o_struct2) i_struct2;
|
||||||
|
|
||||||
std::istringstream is(os.str());
|
std::istringstream is(os.str());
|
||||||
{
|
{
|
||||||
IArchive iar(is);
|
IArchive iar(is);
|
||||||
iar( i_struct );
|
iar( i_struct );
|
||||||
|
iar( i_struct2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_CHECK(o_struct.mm.x == i_struct.mm.x);
|
BOOST_CHECK(o_struct.mm.x == i_struct.mm.x);
|
||||||
@@ -164,6 +204,8 @@ void test_structs_minimal()
|
|||||||
|
|
||||||
BOOST_CHECK(o_struct.nmm.x == i_struct.nmm.x);
|
BOOST_CHECK(o_struct.nmm.x == i_struct.nmm.x);
|
||||||
BOOST_CHECK(o_struct.nmmv.x == i_struct.nmmv.x);
|
BOOST_CHECK(o_struct.nmmv.x == i_struct.nmmv.x);
|
||||||
|
|
||||||
|
BOOST_CHECK(o_struct2.x == i_struct2.x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user