Added a MapItem to wrap key/value pairs

This commit is contained in:
Randolph Voorhies
2013-07-03 20:05:34 -07:00
parent 3885d8b537
commit d24c0e2db2
3 changed files with 101 additions and 9 deletions

View File

@@ -99,7 +99,9 @@ namespace cereal
cereal::make_nvp<Archive>(b) ); cereal::make_nvp<Archive>(b) );
} }
}; };
@endcode */ @endcode
@internal */
template <class T> template <class T>
class NameValuePair : detail::NameValuePairCore class NameValuePair : detail::NameValuePairCore
{ {
@@ -121,7 +123,8 @@ namespace cereal
the value can be both loaded and saved to. If you pass an r-value reference, the value can be both loaded and saved to. If you pass an r-value reference,
the NameValuePair will store a copy of it instead of a reference. Thus you should the NameValuePair will store a copy of it instead of a reference. Thus you should
only pass r-values in cases where this makes sense, such as the result of some only pass r-values in cases where this makes sense, such as the result of some
size() call. In either case, any constness will be stripped away */ size() call. In either case, any constness will be stripped away
@internal */
NameValuePair( char const * n, T && v ) : name(n), value(const_cast<Type>(v)) {} NameValuePair( char const * n, T && v ) : name(n), value(const_cast<Type>(v)) {}
char const * name; char const * name;
@@ -129,7 +132,8 @@ namespace cereal
}; };
//! A specialization of make_nvp<> that simply forwards the value for binary archives //! A specialization of make_nvp<> that simply forwards the value for binary archives
/*! @relates NameValuePair */ /*! @relates NameValuePair
@internal */
template<class Archive, class T> template<class Archive, class T>
typename typename
std::enable_if<std::is_same<Archive, ::cereal::BinaryInputArchive>::value || std::enable_if<std::is_same<Archive, ::cereal::BinaryInputArchive>::value ||
@@ -141,7 +145,8 @@ namespace cereal
} }
//! A specialization of make_nvp<> that actually creates an nvp for non-binary archives //! A specialization of make_nvp<> that actually creates an nvp for non-binary archives
/*! @relates NameValuePair */ /*! @relates NameValuePair
@internal */
template<class Archive, class T> template<class Archive, class T>
typename typename
std::enable_if<!std::is_same<Archive, ::cereal::BinaryInputArchive>::value && std::enable_if<!std::is_same<Archive, ::cereal::BinaryInputArchive>::value &&
@@ -157,7 +162,9 @@ namespace cereal
//! A wrapper around data that can be serialized in a binary fashion //! A wrapper around data that can be serialized in a binary fashion
/*! This class is used to demarcate data that can safely be serialized /*! This class is used to demarcate data that can safely be serialized
as a binary chunk of data. Individual archives can then choose how as a binary chunk of data. Individual archives can then choose how
best represent this during serialization. */ best represent this during serialization.
@internal */
template <class T> template <class T>
struct BinaryData struct BinaryData
{ {
@@ -195,7 +202,9 @@ namespace cereal
they choose to serialize size metadata for containers. For some archive they choose to serialize size metadata for containers. For some archive
types, the size may be implicitly encoded in the output (e.g. JSON) and types, the size may be implicitly encoded in the output (e.g. JSON) and
not need an explicit entry. Specializing serialize or load/save for not need an explicit entry. Specializing serialize or load/save for
your archive and SizeTags allows you to choose what happens */ your archive and SizeTags allows you to choose what happens
@internal */
template <class T> template <class T>
class SizeTag class SizeTag
{ {
@@ -212,6 +221,69 @@ namespace cereal
Type size; Type size;
}; };
// ######################################################################
//! A wrapper around a key and value for serializing data into maps.
/*! This class just provides a grouping of keys and values into a struct for
human readable archives. For example, XML archives will use this wrapper
to write maps like so:
@code{.xml}
<mymap>
<item0>
<key>MyFirstKey</key>
<value>MyFirstValue</value>
</item0>
<item1>
<key>MySecondKey</key>
<value>MySecondValue</value>
</item1>
</mymap>
@endcode
\sa make_map_item
@internal */
template <class Key, class Value>
struct MapItem
{
using DecayKey = typename std::decay<Key>::type;
using KeyType = typename std::conditional<
std::is_rvalue_reference<Key>::value,
DecayKey,
typename std::add_lvalue_reference<DecayKey>::type>::type;
using DecayValue = typename std::decay<Value>::type;
using ValueType = typename std::conditional<
std::is_rvalue_reference<Value>::value,
DecayValue,
typename std::add_lvalue_reference<DecayValue>::type>::type;
//! Construct a MapItem from a key and a value
/*! @internal */
MapItem( Key && key, Value && value ) : key(const_cast<KeyType>(key)), value(const_cast<ValueType>(value)) {}
KeyType key;
ValueType value;
//! Serialize the MapItem with the NVPs "key" and "value"
template<class Archive>
void serialize(Archive & archive)
{
archive( make_nvp<Archive>("key", key),
make_nvp<Archive>("value", value) );
}
};
//! Create a MapItem so that human readable archives will group keys and values together
/*! @internal
@relates MapItem */
template<class KeyType, class ValueType>
MapItem<KeyType, ValueType> make_map_item(KeyType && key, ValueType && value)
{
return {std::forward<KeyType>(key), std::forward<ValueType>(value)};
}
} // namespace cereal } // namespace cereal
#endif // CEREAL_DETAILS_HELPERS_HPP_ #endif // CEREAL_DETAILS_HELPERS_HPP_

View File

@@ -30,6 +30,7 @@
#include <cereal/cereal.hpp> #include <cereal/cereal.hpp>
#include <map> #include <map>
namespace cereal namespace cereal
{ {
namespace map_detail namespace map_detail
@@ -40,7 +41,9 @@ namespace cereal
ar( make_size_tag( map.size() ) ); ar( make_size_tag( map.size() ) );
for( const auto & i : map ) for( const auto & i : map )
ar( i.first, i.second ); {
ar( ::cereal::make_map_item(i.first, i.second) );
}
} }
template <class Archive, class MapT> inline template <class Archive, class MapT> inline
@@ -57,7 +60,7 @@ namespace cereal
typename MapT::key_type key; typename MapT::key_type key;
typename MapT::mapped_type value; typename MapT::mapped_type value;
ar( key, value ); ar( ::cereal::make_map_item(key, value) );
hint = map.insert(hint, {key, value} ); hint = map.insert(hint, {key, value} );
} }
} }

View File

@@ -299,9 +299,9 @@ int main()
assert(e_in == e_out); assert(e_in == e_out);
{ {
//std::stringstream os;
std::ofstream os("out.xml"); std::ofstream os("out.xml");
cereal::XMLOutputArchive oar( os ); cereal::XMLOutputArchive oar( os );
//cereal::XMLOutputArchive oar( std::cout );
oar( cereal::make_nvp("hello", 5 ) ); oar( cereal::make_nvp("hello", 5 ) );
@@ -311,6 +311,15 @@ int main()
auto intptr = std::make_shared<int>(99); auto intptr = std::make_shared<int>(99);
oar( CEREAL_NVP(intptr) ); oar( CEREAL_NVP(intptr) );
std::map<std::string, int> map1 =
{
{"one", 1},
{"two", 2},
{"three", 3}
};
oar( CEREAL_NVP(map1) );
int x = 3; int x = 3;
oar( CEREAL_NVP(x) ); oar( CEREAL_NVP(x) );
oar( 5 ); oar( 5 );
@@ -353,6 +362,14 @@ int main()
iar( CEREAL_NVP(intptr) ); iar( CEREAL_NVP(intptr) );
assert( *intptr == 99 ); assert( *intptr == 99 );
std::map<std::string, int> map1;
iar( CEREAL_NVP(map1) );
assert( map1["one"] == 1 );
assert( map1["two"] == 2 );
assert( map1["three"] == 3 );
int x; int x;
iar( CEREAL_NVP(x) ); iar( CEREAL_NVP(x) );
assert( x == 3 ); assert( x == 3 );