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:
Shane Grant
2014-05-22 10:59:13 -07:00
parent 5305078096
commit f067ba6905
8 changed files with 110 additions and 17 deletions

View File

@@ -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_

View File

@@ -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_

View File

@@ -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_

View File

@@ -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_

View File

@@ -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;

View File

@@ -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;

View File

@@ -41,6 +41,7 @@
#include <functional> #include <functional>
struct Archive {}; struct Archive {};
CEREAL_SETUP_ARCHIVE_TRAITS(Archive, Archive)
struct Test struct Test
{ {

View File

@@ -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);
} }
} }