mirror of
https://github.com/USCiLab/cereal.git
synced 2025-09-27 20:59:32 +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:
parent
5305078096
commit
f067ba6905
@ -44,7 +44,7 @@ namespace cereal
|
||||
architectures with different endianness, use PortableBinaryOutputArchive.
|
||||
|
||||
When using a binary archive and a file stream, you must use the
|
||||
std::ios::binary format flag to avoid having your data altered
|
||||
std::ios::binary format flag to avoid having your data altered
|
||||
inadvertently.
|
||||
|
||||
\ingroup Archives */
|
||||
@ -77,9 +77,9 @@ namespace cereal
|
||||
/* This archive does nothing to ensure that the endianness of the saved
|
||||
and loaded data is the same. If you need to have portability over
|
||||
architectures with different endianness, use PortableBinaryOutputArchive.
|
||||
|
||||
|
||||
When using a binary archive and a file stream, you must use the
|
||||
std::ios::binary format flag to avoid having your data altered
|
||||
std::ios::binary format flag to avoid having your data altered
|
||||
inadvertently.
|
||||
|
||||
\ingroup Archives */
|
||||
@ -159,4 +159,7 @@ namespace cereal
|
||||
CEREAL_REGISTER_ARCHIVE(cereal::BinaryOutputArchive)
|
||||
CEREAL_REGISTER_ARCHIVE(cereal::BinaryInputArchive)
|
||||
|
||||
// tie input and output archives together
|
||||
CEREAL_SETUP_ARCHIVE_TRAITS(cereal::BinaryInputArchive, cereal::BinaryOutputArchive)
|
||||
|
||||
#endif // CEREAL_ARCHIVES_BINARY_HPP_
|
||||
|
@ -887,4 +887,7 @@ namespace cereal
|
||||
CEREAL_REGISTER_ARCHIVE(cereal::JSONInputArchive)
|
||||
CEREAL_REGISTER_ARCHIVE(cereal::JSONOutputArchive)
|
||||
|
||||
// tie input and output archives together
|
||||
CEREAL_SETUP_ARCHIVE_TRAITS(cereal::JSONInputArchive, cereal::JSONOutputArchive)
|
||||
|
||||
#endif // CEREAL_ARCHIVES_JSON_HPP_
|
||||
|
@ -239,4 +239,7 @@ namespace cereal
|
||||
CEREAL_REGISTER_ARCHIVE(cereal::PortableBinaryOutputArchive)
|
||||
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_
|
||||
|
@ -825,4 +825,7 @@ namespace cereal
|
||||
CEREAL_REGISTER_ARCHIVE(cereal::XMLOutputArchive)
|
||||
CEREAL_REGISTER_ARCHIVE(cereal::XMLInputArchive)
|
||||
|
||||
// tie input and output archives together
|
||||
CEREAL_SETUP_ARCHIVE_TRAITS(cereal::XMLInputArchive, cereal::XMLOutputArchive)
|
||||
|
||||
#endif // CEREAL_ARCHIVES_XML_HPP_
|
||||
|
@ -756,7 +756,8 @@ namespace cereal
|
||||
template <class T, PROCESS_IF(member_load_minimal)> inline
|
||||
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 );
|
||||
access::member_load_minimal(*self, t, value);
|
||||
return *self;
|
||||
@ -766,7 +767,8 @@ namespace cereal
|
||||
template <class T, PROCESS_IF(non_member_load_minimal)> inline
|
||||
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 );
|
||||
CEREAL_LOAD_MINIMAL_FUNCTION_NAME(*self, t, value);
|
||||
return *self;
|
||||
@ -875,8 +877,9 @@ namespace cereal
|
||||
template <class T, PROCESS_IF(member_versioned_load_minimal)> inline
|
||||
ArchiveType & processImpl(T & t)
|
||||
{
|
||||
using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
|
||||
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);
|
||||
access::member_load_minimal(*self, t, value, version);
|
||||
return *self;
|
||||
@ -887,8 +890,9 @@ namespace cereal
|
||||
template <class T, PROCESS_IF(non_member_versioned_load_minimal)> inline
|
||||
ArchiveType & processImpl(T & t)
|
||||
{
|
||||
using OutArchiveType = typename traits::detail::get_output_from_input<ArchiveType>::type;
|
||||
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);
|
||||
CEREAL_LOAD_MINIMAL_FUNCTION_NAME(*self, t, value, version);
|
||||
return *self;
|
||||
|
@ -147,6 +147,32 @@ namespace cereal
|
||||
template <bool ... Conditions>
|
||||
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
|
||||
#define CEREAL_MAKE_VERSIONED_TEST ,0
|
||||
@ -678,11 +704,13 @@ namespace cereal
|
||||
template <class T, class A>
|
||||
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. "
|
||||
"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 valid = has_member_load_minimal_type_impl<T, A, SaveType>::value;
|
||||
|
||||
@ -739,11 +767,13 @@ namespace cereal
|
||||
template <class T, class A>
|
||||
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. "
|
||||
"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 valid = has_member_versioned_load_minimal_type_impl<T, A, SaveType>::value;
|
||||
|
||||
@ -794,11 +824,13 @@ namespace cereal
|
||||
template <class T, class A>
|
||||
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. "
|
||||
"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>;
|
||||
static const bool value = check::exists;
|
||||
|
||||
@ -846,11 +878,13 @@ namespace cereal
|
||||
template <class T, class A>
|
||||
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. "
|
||||
"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>;
|
||||
static const bool value = check::exists;
|
||||
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include <functional>
|
||||
|
||||
struct Archive {};
|
||||
CEREAL_SETUP_ARCHIVE_TRAITS(Archive, Archive)
|
||||
|
||||
struct Test
|
||||
{
|
||||
@ -226,6 +227,6 @@ int main()
|
||||
std::cout << "\textra" << std::endl;
|
||||
std::cout << cereal::traits::has_member_save_minimal<MemberMinimal, Archive>::value << std::endl;
|
||||
std::cout << cereal::traits::has_member_load_minimal<MemberMinimal, Archive>::value << std::endl;
|
||||
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -134,6 +134,41 @@ struct TestStruct
|
||||
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>
|
||||
void test_structs_minimal()
|
||||
{
|
||||
@ -145,18 +180,23 @@ void test_structs_minimal()
|
||||
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 };
|
||||
|
||||
Issue79Struct o_struct2 = { random_value<std::int32_t>(gen) };
|
||||
|
||||
std::ostringstream os;
|
||||
{
|
||||
OArchive oar(os);
|
||||
oar( o_struct );
|
||||
oar( o_struct2 );
|
||||
}
|
||||
|
||||
decltype(o_struct) i_struct;
|
||||
decltype(o_struct2) i_struct2;
|
||||
|
||||
std::istringstream is(os.str());
|
||||
{
|
||||
IArchive iar(is);
|
||||
iar( i_struct );
|
||||
iar( i_struct2 );
|
||||
}
|
||||
|
||||
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.nmmv.x == i_struct.nmmv.x);
|
||||
|
||||
BOOST_CHECK(o_struct2.x == i_struct2.x);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user