[alohalytics] Updated cereal (transport level) library to 1.1

This commit is contained in:
Alex Zolotarev 2015-03-12 19:37:58 +03:00
parent 7be9f4946a
commit ffcc7babb6
40 changed files with 2105 additions and 1576 deletions

View file

@ -1,4 +1,7 @@
cxa_demangle.cpp was copied here to avoid compilation bug on Android, when
compiler can't detect abi::__cxa_demangle() function from cxxabi.h include file.
The patch was applied to include/details.util.hpp by Alex Zolotarev
The patch was applied to include/details.util.hpp by Alex Zolotarev (me@alex.bio)
Another simple patch changes includes in all headers to avoid -I compiler parameter.
Also removed Windows-style line endings from files in external folder.

View file

@ -1,16 +1,84 @@
Header-only Cereal with no dependencies and no extra ```-I``` flags required.
cereal - A C++11 library for serialization
==========================================
See [examples/cereal/message.h](https://github.com/KnowSheet/3party/blob/master/examples/cereal/message.h) for example usage.
<img src="http://uscilab.github.io/cereal/assets/img/cerealboxside.png" align="right"/><p>cereal is a header-only C++11 serialization library. cereal takes arbitrary data types and reversibly turns them into different representations, such as compact binary encodings, XML, or JSON. cereal was designed to be fast, light-weight, and easy to extend - it has no external dependencies and can be easily bundled with other code or used standalone.</p>
Ported by Dmitry "Dima" Korolev.
### cereal has great documentation
On Linux, it took the below commands. (MacOS has different ```sed -i``` setting, tweak by changing ```-i``` into ```-i ''```).
Looking for more information on how cereal works and its documentation? Visit [cereal's web page](http://USCiLab.github.com/cereal) to get the latest information.
### cereal is easy to use
Installation and use of of cereal is fully documented on the [main web page](http://USCiLab.github.com/cereal), but this is a quick and dirty version:
* Download cereal and place the headers somewhere your code can see them
* Write serialization functions for your custom types or use the built in support for the standard library cereal provides
* Use the serialization archives to load and save data
```cpp
#include <cereal/types/unordered_map.hpp>
#include <cereal/types/memory.hpp>
#include <cereal/archives/binary.hpp>
#include <fstream>
struct MyRecord
{
uint8_t x, y;
float z;
template <class Archive>
void serialize( Archive & ar )
{
ar( x, y, z );
}
};
struct SomeData
{
int32_t id;
std::shared_ptr<std::unordered_map<uint32_t, MyRecord>> data;
template <class Archive>
void save( Archive & ar ) const
{
ar( data );
}
template <class Archive>
void load( Archive & ar )
{
static int32_t idGen = 0;
id = idGen++;
ar( data );
}
};
int main()
{
std::ofstream os("out.cereal", std::ios::binary);
cereal::BinaryOutputArchive archive( os );
SomeData myData;
archive( myData );
return 0;
}
```
wget https://github.com/USCiLab/cereal/archive/v1.0.0.tar.gz
(tar xzf cereal-1.0.0.tar.gz; cp -r cereal-1.0.0/include/cereal include; rm -rf cereal-1.0.0)
find include/ -mindepth 1 -maxdepth 1 -type f | xargs sed -i "s/^#include <cereal\/\(.*\)>$/#include \".\/\1\"/"
find include/ -mindepth 2 -maxdepth 2 -type f | xargs sed -i "s/^#include <cereal\/\(.*\)>$/#include \"..\/\1\"/"
find include/ -mindepth 3 -maxdepth 3 -type f | xargs sed -i "s/^#include <cereal\/\(.*\)>$/#include \"..\/..\/\1\"/"
find include/ -mindepth 4 -maxdepth 4 -type f | xargs sed -i "s/^#include <cereal\/\(.*\)>$/#include \"..\/..\/..\/\1\"/"
```
### cereal has a mailing list
Either get in touch over <a href="mailto:cerealcpp@googlegroups.com">email</a> or [on the web](https://groups.google.com/forum/#!forum/cerealcpp).
## cereal has a permissive license
cereal is licensed under the [BSD license](http://opensource.org/licenses/BSD-3-Clause).
## cereal build status
* develop : [![Build Status](https://travis-ci.org/USCiLab/cereal.png?branch=develop)](https://travis-ci.org/USCiLab/cereal)
---
Were you looking for the Haskell cereal? Go <a href="https://github.com/GaloisInc/cereal">here</a>.

View file

@ -33,7 +33,8 @@
#include <iostream>
#include <cstdint>
#include "./details/helpers.hpp"
#include "macros.hpp"
#include "details/helpers.hpp"
namespace cereal
{
@ -224,61 +225,61 @@ namespace cereal
public:
// ####### Standard Serialization ########################################
template<class Archive, class T> inline
static auto member_serialize(Archive & ar, T & t) -> decltype(t.serialize(ar))
{ t.serialize(ar); }
static auto member_serialize(Archive & ar, T & t) -> decltype(t.CEREAL_SERIALIZE_FUNCTION_NAME(ar))
{ return t.CEREAL_SERIALIZE_FUNCTION_NAME(ar); }
template<class Archive, class T> inline
static auto member_save(Archive & ar, T const & t) -> decltype(t.save(ar))
{ t.save(ar); }
static auto member_save(Archive & ar, T const & t) -> decltype(t.CEREAL_SAVE_FUNCTION_NAME(ar))
{ return t.CEREAL_SAVE_FUNCTION_NAME(ar); }
template<class Archive, class T> inline
static auto member_save_non_const(Archive & ar, T & t) -> decltype(t.save(ar))
{ t.save(ar); }
static auto member_save_non_const(Archive & ar, T & t) -> decltype(t.CEREAL_SAVE_FUNCTION_NAME(ar))
{ return t.CEREAL_SAVE_FUNCTION_NAME(ar); }
template<class Archive, class T> inline
static auto member_load(Archive & ar, T & t) -> decltype(t.load(ar))
{ t.load(ar); }
static auto member_load(Archive & ar, T & t) -> decltype(t.CEREAL_LOAD_FUNCTION_NAME(ar))
{ return t.CEREAL_LOAD_FUNCTION_NAME(ar); }
template<class Archive, class T> inline
static auto member_save_minimal(Archive const & ar, T const & t) -> decltype(t.save_minimal(ar))
{ return t.save_minimal(ar); }
static auto member_save_minimal(Archive const & ar, T const & t) -> decltype(t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar))
{ return t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar); }
template<class Archive, class T> inline
static auto member_save_minimal_non_const(Archive const & ar, T & t) -> decltype(t.save_minimal(ar))
{ return t.save_minimal(ar); }
static auto member_save_minimal_non_const(Archive const & ar, T & t) -> decltype(t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar))
{ return t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar); }
template<class Archive, class T, class U> inline
static auto member_load_minimal(Archive const & ar, T & t, U && u) -> decltype(t.load_minimal(ar, std::forward<U>(u)))
{ t.load_minimal(ar, std::forward<U>(u)); }
static auto member_load_minimal(Archive const & ar, T & t, U && u) -> decltype(t.CEREAL_LOAD_MINIMAL_FUNCTION_NAME(ar, std::forward<U>(u)))
{ return t.CEREAL_LOAD_MINIMAL_FUNCTION_NAME(ar, std::forward<U>(u)); }
// ####### Versioned Serialization #######################################
template<class Archive, class T> inline
static auto member_serialize(Archive & ar, T & t, const std::uint32_t version ) -> decltype(t.serialize(ar, version))
{ t.serialize(ar, version); }
static auto member_serialize(Archive & ar, T & t, const std::uint32_t version ) -> decltype(t.CEREAL_SERIALIZE_FUNCTION_NAME(ar, version))
{ return t.CEREAL_SERIALIZE_FUNCTION_NAME(ar, version); }
template<class Archive, class T> inline
static auto member_save(Archive & ar, T const & t, const std::uint32_t version ) -> decltype(t.save(ar, version))
{ t.save(ar, version); }
static auto member_save(Archive & ar, T const & t, const std::uint32_t version ) -> decltype(t.CEREAL_SAVE_FUNCTION_NAME(ar, version))
{ return t.CEREAL_SAVE_FUNCTION_NAME(ar, version); }
template<class Archive, class T> inline
static auto member_save_non_const(Archive & ar, T & t, const std::uint32_t version ) -> decltype(t.save(ar, version))
{ t.save(ar, version); }
static auto member_save_non_const(Archive & ar, T & t, const std::uint32_t version ) -> decltype(t.CEREAL_SAVE_FUNCTION_NAME(ar, version))
{ return t.CEREAL_SAVE_FUNCTION_NAME(ar, version); }
template<class Archive, class T> inline
static auto member_load(Archive & ar, T & t, const std::uint32_t version ) -> decltype(t.load(ar, version))
{ t.load(ar, version); }
static auto member_load(Archive & ar, T & t, const std::uint32_t version ) -> decltype(t.CEREAL_LOAD_FUNCTION_NAME(ar, version))
{ return t.CEREAL_LOAD_FUNCTION_NAME(ar, version); }
template<class Archive, class T> inline
static auto member_save_minimal(Archive const & ar, T const & t, const std::uint32_t version) -> decltype(t.save_minimal(ar, version))
{ return t.save_minimal(ar, version); }
static auto member_save_minimal(Archive const & ar, T const & t, const std::uint32_t version) -> decltype(t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar, version))
{ return t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar, version); }
template<class Archive, class T> inline
static auto member_save_minimal_non_const(Archive const & ar, T & t, const std::uint32_t version) -> decltype(t.save_minimal(ar, version))
{ return t.save_minimal(ar, version); }
static auto member_save_minimal_non_const(Archive const & ar, T & t, const std::uint32_t version) -> decltype(t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar, version))
{ return t.CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar, version); }
template<class Archive, class T, class U> inline
static auto member_load_minimal(Archive const & ar, T & t, U && u, const std::uint32_t version) -> decltype(t.load_minimal(ar, std::forward<U>(u), version))
{ t.load_minimal(ar, std::forward<U>(u), version); }
static auto member_load_minimal(Archive const & ar, T & t, U && u, const std::uint32_t version) -> decltype(t.CEREAL_LOAD_MINIMAL_FUNCTION_NAME(ar, std::forward<U>(u), version))
{ return t.CEREAL_LOAD_MINIMAL_FUNCTION_NAME(ar, std::forward<U>(u), version); }
// ####### Other Functionality ##########################################
// for detecting inheritance from enable_shared_from_this
@ -292,6 +293,13 @@ namespace cereal
new (ptr) T( std::forward<Args>( args )... );
}
// for non-placement new with a default constructor
template <class T> inline
static T * construct()
{
return new T();
}
template <class T> inline
static std::false_type load_and_construct(...)
{ return std::false_type(); }

View file

@ -0,0 +1,163 @@
/*! \file adapters.hpp
\brief Archive adapters that provide additional functionality
on top of an existing archive */
/*
Copyright (c) 2014, Randolph Voorhies, Shane Grant
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of cereal nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CEREAL_ARCHIVES_ADAPTERS_HPP_
#define CEREAL_ARCHIVES_ADAPTERS_HPP_
#include "../details/helpers.hpp"
#include <utility>
namespace cereal
{
#ifdef CEREAL_FUTURE_EXPERIMENTAL
// Forward declaration for friend access
template <class U, class A> U & get_user_data( A & );
//! Wraps an archive and gives access to user data
/*! This adapter is useful if you require access to
either raw pointers or references within your
serialization functions.
While cereal does not directly support serialization
raw pointers or references, it is sometimes the case
that you may want to supply something such as a raw
pointer or global reference to some constructor.
In this situation this adapter would likely be used
with the construct class to allow for non-default
constructors.
@note This feature is experimental and may be altered or removed in a future release. See issue #46.
@code{.cpp}
struct MyUserData
{
int * myRawPointer;
std::reference_wrapper<MyOtherType> myReference;
};
struct MyClass
{
// Note the raw pointer parameter
MyClass( int xx, int * rawP );
int x;
template <class Archive>
void serialize( Archive & ar )
{ ar( x ); }
template <class Archive>
static void load_and_construct( Archive & ar, cereal::construct<MyClass> & construct )
{
int xx;
ar( xx );
// note the need to use get_user_data to retrieve user data from the archive
construct( xx, cereal::get_user_data<MyUserData>( ar ).myRawPointer );
}
};
int main()
{
{
MyUserData md;
md.myRawPointer = &something;
md.myReference = someInstanceOfType;
std::ifstream is( "data.xml" );
cereal::UserDataAdapter<MyUserData, cereal::XMLInputArchive> ar( md, is );
std::unique_ptr<MyClass> sc;
ar( sc ); // use as normal
}
return 0;
}
@endcode
@relates get_user_data
@tparam UserData The type to give the archive access to
@tparam Archive The archive to wrap */
template <class UserData, class Archive>
class UserDataAdapter : public Archive
{
public:
//! Construct the archive with some user data struct
/*! This will forward all arguments (other than the user
data) to the wrapped archive type. The UserDataAdapter
can then be used identically to the wrapped archive type
@tparam Args The arguments to pass to the constructor of
the archive. */
template <class ... Args>
UserDataAdapter( UserData & ud, Args && ... args ) :
Archive( std::forward<Args>( args )... ),
userdata( ud )
{ }
private:
//! Overload the rtti function to enable dynamic_cast
void rtti() {}
friend UserData & get_user_data<UserData>( Archive & ar );
UserData & userdata; //!< The actual user data
};
//! Retrieves user data from an archive wrapped by UserDataAdapter
/*! This will attempt to retrieve the user data associated with
some archive wrapped by UserDataAdapter. If this is used on
an archive that is not wrapped, a run-time exception will occur.
@note This feature is experimental and may be altered or removed in a future release. See issue #46.
@note The correct use of this function cannot be enforced at compile
time.
@relates UserDataAdapter
@tparam UserData The data struct contained in the archive
@tparam Archive The archive, which should be wrapped by UserDataAdapter
@param ar The archive
@throws Exception if the archive this is used upon is not wrapped with
UserDataAdapter. */
template <class UserData, class Archive>
UserData & get_user_data( Archive & ar )
{
try
{
return dynamic_cast<UserDataAdapter<UserData, Archive> &>( ar ).userdata;
}
catch( std::bad_cast const & )
{
throw ::cereal::Exception("Attempting to get user data from archive not wrapped in UserDataAdapter");
}
}
#endif // CEREAL_FUTURE_EXPERIMENTAL
} // namespace cereal
#endif // CEREAL_ARCHIVES_ADAPTERS_HPP_

View file

@ -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 */
@ -111,7 +111,7 @@ namespace cereal
//! Saving for POD types to binary
template<class T> inline
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
save(BinaryOutputArchive & ar, T const & t)
CEREAL_SAVE_FUNCTION_NAME(BinaryOutputArchive & ar, T const & t)
{
ar.saveBinary(std::addressof(t), sizeof(t));
}
@ -119,7 +119,7 @@ namespace cereal
//! Loading for POD types from binary
template<class T> inline
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
load(BinaryInputArchive & ar, T & t)
CEREAL_LOAD_FUNCTION_NAME(BinaryInputArchive & ar, T & t)
{
ar.loadBinary(std::addressof(t), sizeof(t));
}
@ -127,7 +127,7 @@ namespace cereal
//! Serializing NVP types to binary
template <class Archive, class T> inline
CEREAL_ARCHIVE_RESTRICT(BinaryInputArchive, BinaryOutputArchive)
serialize( Archive & ar, NameValuePair<T> & t )
CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, NameValuePair<T> & t )
{
ar( t.value );
}
@ -135,21 +135,21 @@ namespace cereal
//! Serializing SizeTags to binary
template <class Archive, class T> inline
CEREAL_ARCHIVE_RESTRICT(BinaryInputArchive, BinaryOutputArchive)
serialize( Archive & ar, SizeTag<T> & t )
CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, SizeTag<T> & t )
{
ar( t.size );
}
//! Saving binary data
template <class T> inline
void save(BinaryOutputArchive & ar, BinaryData<T> const & bd)
void CEREAL_SAVE_FUNCTION_NAME(BinaryOutputArchive & ar, BinaryData<T> const & bd)
{
ar.saveBinary( bd.data, static_cast<std::size_t>( bd.size ) );
}
//! Loading binary data
template <class T> inline
void load(BinaryInputArchive & ar, BinaryData<T> & bd)
void CEREAL_LOAD_FUNCTION_NAME(BinaryInputArchive & ar, BinaryData<T> & bd)
{
ar.loadBinary(bd.data, static_cast<std::size_t>(bd.size));
}
@ -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_

View file

@ -85,7 +85,7 @@ namespace cereal
that the container is variable sized and may be edited.
\ingroup Archives */
class JSONOutputArchive : public OutputArchive<JSONOutputArchive>
class JSONOutputArchive : public OutputArchive<JSONOutputArchive>, public traits::TextArchive
{
enum class NodeType { StartObject, InObject, StartArray, InArray };
@ -153,7 +153,8 @@ namespace cereal
//! Destructor, flushes the JSON
~JSONOutputArchive()
{
itsWriter.EndObject();
if (itsNodeStack.top() == NodeType::InObject)
itsWriter.EndObject();
}
//! Saves some binary data, encoded as a base64 string, with an optional name
@ -240,24 +241,24 @@ namespace cereal
// special overloads to handle these cases.
//! 32 bit signed long saving to current node
template <class T> inline
typename std::enable_if<sizeof(T) == sizeof(std::int32_t) && std::is_signed<T>::value, void>::type
saveLong(T l){ saveValue( static_cast<std::int32_t>( l ) ); }
template <class T, traits::EnableIf<sizeof(T) == sizeof(std::int32_t),
std::is_signed<T>::value> = traits::sfinae> inline
void saveLong(T l){ saveValue( static_cast<std::int32_t>( l ) ); }
//! non 32 bit signed long saving to current node
template <class T> inline
typename std::enable_if<sizeof(T) != sizeof(std::int32_t) && std::is_signed<T>::value, void>::type
saveLong(T l){ saveValue( static_cast<std::int64_t>( l ) ); }
template <class T, traits::EnableIf<sizeof(T) != sizeof(std::int32_t),
std::is_signed<T>::value> = traits::sfinae> inline
void saveLong(T l){ saveValue( static_cast<std::int64_t>( l ) ); }
//! 32 bit unsigned long saving to current node
template <class T> inline
typename std::enable_if<sizeof(T) == sizeof(std::uint32_t) && !std::is_signed<T>::value, void>::type
saveLong(T lu){ saveValue( static_cast<std::uint32_t>( lu ) ); }
template <class T, traits::EnableIf<sizeof(T) == sizeof(std::int32_t),
std::is_unsigned<T>::value> = traits::sfinae> inline
void saveLong(T lu){ saveValue( static_cast<std::uint32_t>( lu ) ); }
//! non 32 bit unsigned long saving to current node
template <class T> inline
typename std::enable_if<sizeof(T) != sizeof(std::uint32_t) && !std::is_signed<T>::value, void>::type
saveLong(T lu){ saveValue( static_cast<std::uint64_t>( lu ) ); }
template <class T, traits::EnableIf<sizeof(T) != sizeof(std::int32_t),
std::is_unsigned<T>::value> = traits::sfinae> inline
void saveLong(T lu){ saveValue( static_cast<std::uint64_t>( lu ) ); }
public:
#ifdef _MSC_VER
@ -265,30 +266,27 @@ namespace cereal
void saveValue( unsigned long lu ){ saveLong( lu ); };
#else // _MSC_VER
//! Serialize a long if it would not be caught otherwise
template <class T> inline
typename std::enable_if<std::is_same<T, long>::value &&
!std::is_same<T, std::int32_t>::value &&
!std::is_same<T, std::int64_t>::value, void>::type
saveValue( T t ){ saveLong( t ); }
template <class T, traits::EnableIf<std::is_same<T, long>::value,
!std::is_same<T, std::int32_t>::value,
!std::is_same<T, std::int64_t>::value> = traits::sfinae> inline
void saveValue( T t ){ saveLong( t ); }
//! Serialize an unsigned long if it would not be caught otherwise
template <class T> inline
typename std::enable_if<std::is_same<T, unsigned long>::value &&
!std::is_same<T, std::uint32_t>::value &&
!std::is_same<T, std::uint64_t>::value, void>::type
saveValue( T t ){ saveLong( t ); }
template <class T, traits::EnableIf<std::is_same<T, unsigned long>::value,
!std::is_same<T, std::uint32_t>::value,
!std::is_same<T, std::uint64_t>::value> = traits::sfinae> inline
void saveValue( T t ){ saveLong( t ); }
#endif // _MSC_VER
//! Save exotic arithmetic as strings to current node
/*! Handles long long (if distinct from other types), unsigned long (if distinct), and long double */
template<class T> inline
typename std::enable_if<std::is_arithmetic<T>::value &&
!std::is_same<T, long>::value &&
!std::is_same<T, unsigned long>::value &&
!std::is_same<T, std::int64_t>::value &&
!std::is_same<T, std::uint64_t>::value &&
(sizeof(T) >= sizeof(long double) || sizeof(T) >= sizeof(long long)), void>::type
saveValue(T const & t)
template <class T, traits::EnableIf<std::is_arithmetic<T>::value,
!std::is_same<T, long>::value,
!std::is_same<T, unsigned long>::value,
!std::is_same<T, std::int64_t>::value,
!std::is_same<T, std::uint64_t>::value,
(sizeof(T) >= sizeof(long double) || sizeof(T) >= sizeof(long long))> = traits::sfinae> inline
void saveValue(T const & t)
{
std::stringstream ss; ss.precision( std::numeric_limits<long double>::max_digits10 );
ss << t;
@ -390,7 +388,7 @@ namespace cereal
@endcode
\ingroup Archives */
class JSONInputArchive : public InputArchive<JSONInputArchive>
class JSONInputArchive : public InputArchive<JSONInputArchive>, public traits::TextArchive
{
private:
typedef rapidjson::GenericReadStream ReadStream;
@ -562,6 +560,13 @@ namespace cereal
++itsIteratorStack.back();
}
//! Retrieves the current node name
/*! @return nullptr if no name exists */
const char * getNodeName() const
{
return itsIteratorStack.back().name();
}
//! Sets the name for the next node created with startNode
void setNextName( const char * name )
{
@ -569,9 +574,9 @@ namespace cereal
}
//! Loads a value from the current node - small signed overload
template<class T> inline
typename std::enable_if<std::is_signed<T>::value && sizeof(T) < sizeof(int64_t), void>::type
loadValue(T & val)
template <class T, traits::EnableIf<std::is_signed<T>::value,
sizeof(T) < sizeof(int64_t)> = traits::sfinae> inline
void loadValue(T & val)
{
search();
@ -580,10 +585,10 @@ namespace cereal
}
//! Loads a value from the current node - small unsigned overload
template<class T> inline
typename std::enable_if<(std::is_unsigned<T>::value && sizeof(T) < sizeof(uint64_t)) &&
!std::is_same<bool, T>::value, void>::type
loadValue(T & val)
template <class T, traits::EnableIf<std::is_unsigned<T>::value,
sizeof(T) < sizeof(uint64_t),
!std::is_same<bool, T>::value> = traits::sfinae> inline
void loadValue(T & val)
{
search();
@ -604,6 +609,46 @@ namespace cereal
//! Loads a value from the current node - string overload
void loadValue(std::string & val) { search(); val = itsIteratorStack.back().value().GetString(); ++itsIteratorStack.back(); }
// Special cases to handle various flavors of long, which tend to conflict with
// the int32_t or int64_t on various compiler/OS combinations. MSVC doesn't need any of this.
#ifndef _MSC_VER
private:
//! 32 bit signed long loading from current node
template <class T> inline
typename std::enable_if<sizeof(T) == sizeof(std::int32_t) && std::is_signed<T>::value, void>::type
loadLong(T & l){ loadValue( reinterpret_cast<std::int32_t&>( l ) ); }
//! non 32 bit signed long loading from current node
template <class T> inline
typename std::enable_if<sizeof(T) == sizeof(std::int64_t) && std::is_signed<T>::value, void>::type
loadLong(T & l){ loadValue( reinterpret_cast<std::int64_t&>( l ) ); }
//! 32 bit unsigned long loading from current node
template <class T> inline
typename std::enable_if<sizeof(T) == sizeof(std::uint32_t) && !std::is_signed<T>::value, void>::type
loadLong(T & lu){ loadValue( reinterpret_cast<std::uint32_t&>( lu ) ); }
//! non 32 bit unsigned long loading from current node
template <class T> inline
typename std::enable_if<sizeof(T) == sizeof(std::uint64_t) && !std::is_signed<T>::value, void>::type
loadLong(T & lu){ loadValue( reinterpret_cast<std::uint64_t&>( lu ) ); }
public:
//! Serialize a long if it would not be caught otherwise
template <class T> inline
typename std::enable_if<std::is_same<T, long>::value &&
!std::is_same<T, std::int32_t>::value &&
!std::is_same<T, std::int64_t>::value, void>::type
loadValue( T & t ){ loadLong(t); }
//! Serialize an unsigned long if it would not be caught otherwise
template <class T> inline
typename std::enable_if<std::is_same<T, unsigned long>::value &&
!std::is_same<T, std::uint32_t>::value &&
!std::is_same<T, std::uint64_t>::value, void>::type
loadValue( T & t ){ loadLong(t); }
#endif // _MSC_VER
private:
//! Convert a string to a long long
void stringToNumber( std::string const & str, long long & val ) { val = std::stoll( str ); }
@ -614,14 +659,13 @@ namespace cereal
public:
//! Loads a value from the current node - long double and long long overloads
template<class T> inline
typename std::enable_if<std::is_arithmetic<T>::value &&
!std::is_same<T, long>::value &&
!std::is_same<T, unsigned long>::value &&
!std::is_same<T, std::int64_t>::value &&
!std::is_same<T, std::uint64_t>::value &&
(sizeof(T) >= sizeof(long double) || sizeof(T) >= sizeof(long long)), void>::type
loadValue(T & val)
template <class T, traits::EnableIf<std::is_arithmetic<T>::value,
!std::is_same<T, long>::value,
!std::is_same<T, unsigned long>::value,
!std::is_same<T, std::int64_t>::value,
!std::is_same<T, std::uint64_t>::value,
(sizeof(T) >= sizeof(long double) || sizeof(T) >= sizeof(long long))> = traits::sfinae>
inline void loadValue(T & val)
{
std::string encoded;
loadValue( encoded );
@ -705,19 +749,19 @@ namespace cereal
that may be given data by the type about to be archived
Minimal types do not start or finish nodes */
template <class T> inline
typename std::enable_if<!std::is_arithmetic<T>::value &&
!traits::has_minimal_output_serialization<T, JSONOutputArchive>::value, void>::type
prologue( JSONOutputArchive & ar, T const & )
template <class T, traits::DisableIf<std::is_arithmetic<T>::value ||
traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, JSONOutputArchive>::value ||
traits::has_minimal_output_serialization<T, JSONOutputArchive>::value> = traits::sfinae>
inline void prologue( JSONOutputArchive & ar, T const & )
{
ar.startNode();
}
//! Prologue for all other types for JSON archives
template <class T> inline
typename std::enable_if<!std::is_arithmetic<T>::value &&
!traits::has_minimal_input_serialization<T, JSONOutputArchive>::value, void>::type
prologue( JSONInputArchive & ar, T const & )
template <class T, traits::DisableIf<std::is_arithmetic<T>::value ||
traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, JSONInputArchive>::value ||
traits::has_minimal_input_serialization<T, JSONInputArchive>::value> = traits::sfinae>
inline void prologue( JSONInputArchive & ar, T const & )
{
ar.startNode();
}
@ -727,49 +771,45 @@ namespace cereal
/*! Finishes the node created in the prologue
Minimal types do not start or finish nodes */
template <class T> inline
typename std::enable_if<!std::is_arithmetic<T>::value &&
!traits::has_minimal_output_serialization<T, JSONOutputArchive>::value, void>::type
epilogue( JSONOutputArchive & ar, T const & )
template <class T, traits::DisableIf<std::is_arithmetic<T>::value ||
traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, JSONOutputArchive>::value ||
traits::has_minimal_output_serialization<T, JSONOutputArchive>::value> = traits::sfinae>
inline void epilogue( JSONOutputArchive & ar, T const & )
{
ar.finishNode();
}
//! Epilogue for all other types other for JSON archives
template <class T> inline
typename std::enable_if<!std::is_arithmetic<T>::value &&
!traits::has_minimal_input_serialization<T, JSONOutputArchive>::value, void>::type
epilogue( JSONInputArchive & ar, T const & )
template <class T, traits::DisableIf<std::is_arithmetic<T>::value ||
traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, JSONInputArchive>::value ||
traits::has_minimal_input_serialization<T, JSONInputArchive>::value> = traits::sfinae>
inline void epilogue( JSONInputArchive & ar, T const & )
{
ar.finishNode();
}
// ######################################################################
//! Prologue for arithmetic types for JSON archives
template <class T> inline
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
prologue( JSONOutputArchive & ar, T const & )
template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
void prologue( JSONOutputArchive & ar, T const & )
{
ar.writeName();
}
//! Prologue for arithmetic types for JSON archives
template <class T> inline
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
prologue( JSONInputArchive &, T const & )
template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
void prologue( JSONInputArchive &, T const & )
{ }
// ######################################################################
//! Epilogue for arithmetic types for JSON archives
template <class T> inline
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
epilogue( JSONOutputArchive &, T const & )
template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
void epilogue( JSONOutputArchive &, T const & )
{ }
//! Epilogue for arithmetic types for JSON archives
template <class T> inline
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
epilogue( JSONInputArchive &, T const & )
template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
void epilogue( JSONInputArchive &, T const & )
{ }
// ######################################################################
@ -799,48 +839,45 @@ namespace cereal
// ######################################################################
// Common JSONArchive serialization functions
// ######################################################################
//! Serializing NVP types to JSON
template <class T> inline
void save( JSONOutputArchive & ar, NameValuePair<T> const & t )
void CEREAL_SAVE_FUNCTION_NAME( JSONOutputArchive & ar, NameValuePair<T> const & t )
{
ar.setNextName( t.name );
ar( t.value );
}
template <class T> inline
void load( JSONInputArchive & ar, NameValuePair<T> & t )
void CEREAL_LOAD_FUNCTION_NAME( JSONInputArchive & ar, NameValuePair<T> & t )
{
ar.setNextName( t.name );
ar( t.value );
}
//! Saving for arithmetic to JSON
template<class T> inline
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
save(JSONOutputArchive & ar, T const & t)
template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
void CEREAL_SAVE_FUNCTION_NAME(JSONOutputArchive & ar, T const & t)
{
ar.saveValue( t );
}
//! Loading arithmetic from JSON
template<class T> inline
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
load(JSONInputArchive & ar, T & t)
template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
void CEREAL_LOAD_FUNCTION_NAME(JSONInputArchive & ar, T & t)
{
ar.loadValue( t );
}
//! saving string to JSON
template<class CharT, class Traits, class Alloc> inline
void save(JSONOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
void CEREAL_SAVE_FUNCTION_NAME(JSONOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
{
ar.saveValue( str );
}
//! loading string from JSON
template<class CharT, class Traits, class Alloc> inline
void load(JSONInputArchive & ar, std::basic_string<CharT, Traits, Alloc> & str)
void CEREAL_LOAD_FUNCTION_NAME(JSONInputArchive & ar, std::basic_string<CharT, Traits, Alloc> & str)
{
ar.loadValue( str );
}
@ -848,14 +885,14 @@ namespace cereal
// ######################################################################
//! Saving SizeTags to JSON
template <class T> inline
void save( JSONOutputArchive &, SizeTag<T> const & )
void CEREAL_SAVE_FUNCTION_NAME( JSONOutputArchive &, SizeTag<T> const & )
{
// nothing to do here, we don't explicitly save the size
}
//! Loading SizeTags from JSON
template <class T> inline
void load( JSONInputArchive & ar, SizeTag<T> & st )
void CEREAL_LOAD_FUNCTION_NAME( JSONInputArchive & ar, SizeTag<T> & st )
{
ar.loadSize( st.size );
}
@ -865,4 +902,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_

View file

@ -175,7 +175,7 @@ namespace cereal
//! Saving for POD types to portable binary
template<class T> inline
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
save(PortableBinaryOutputArchive & ar, T const & t)
CEREAL_SAVE_FUNCTION_NAME(PortableBinaryOutputArchive & ar, T const & t)
{
static_assert( !std::is_floating_point<T>::value ||
(std::is_floating_point<T>::value && std::numeric_limits<T>::is_iec559),
@ -186,7 +186,7 @@ namespace cereal
//! Loading for POD types from portable binary
template<class T> inline
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
load(PortableBinaryInputArchive & ar, T & t)
CEREAL_LOAD_FUNCTION_NAME(PortableBinaryInputArchive & ar, T & t)
{
static_assert( !std::is_floating_point<T>::value ||
(std::is_floating_point<T>::value && std::numeric_limits<T>::is_iec559),
@ -197,7 +197,7 @@ namespace cereal
//! Serializing NVP types to portable binary
template <class Archive, class T> inline
CEREAL_ARCHIVE_RESTRICT(PortableBinaryInputArchive, PortableBinaryOutputArchive)
serialize( Archive & ar, NameValuePair<T> & t )
CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, NameValuePair<T> & t )
{
ar( t.value );
}
@ -205,14 +205,14 @@ namespace cereal
//! Serializing SizeTags to portable binary
template <class Archive, class T> inline
CEREAL_ARCHIVE_RESTRICT(PortableBinaryInputArchive, PortableBinaryOutputArchive)
serialize( Archive & ar, SizeTag<T> & t )
CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, SizeTag<T> & t )
{
ar( t.size );
}
//! Saving binary data to portable binary
template <class T> inline
void save(PortableBinaryOutputArchive & ar, BinaryData<T> const & bd)
void CEREAL_SAVE_FUNCTION_NAME(PortableBinaryOutputArchive & ar, BinaryData<T> const & bd)
{
typedef typename std::remove_pointer<T>::type TT;
static_assert( !std::is_floating_point<TT>::value ||
@ -224,7 +224,7 @@ namespace cereal
//! Loading binary data from portable binary
template <class T> inline
void load(PortableBinaryInputArchive & ar, BinaryData<T> & bd)
void CEREAL_LOAD_FUNCTION_NAME(PortableBinaryInputArchive & ar, BinaryData<T> & bd)
{
typedef typename std::remove_pointer<T>::type TT;
static_assert( !std::is_floating_point<TT>::value ||
@ -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_

View file

@ -56,6 +56,12 @@ namespace cereal
//! The name given to the root node in a cereal xml archive
static const char * CEREAL_XML_STRING = CEREAL_XML_STRING_VALUE;
//! Returns true if the character is whitespace
inline bool isWhitespace( char c )
{
return c == ' ' || c == '\t' || c == '\n' || c == '\r';
}
}
// ######################################################################
@ -87,7 +93,7 @@ namespace cereal
is accomplished through the cereal::SizeTag object, which will also add an attribute
to its parent field.
\ingroup Archives */
class XMLOutputArchive : public OutputArchive<XMLOutputArchive>
class XMLOutputArchive : public OutputArchive<XMLOutputArchive>, public traits::TextArchive
{
public:
/*! @name Common Functionality
@ -196,7 +202,7 @@ namespace cereal
const auto nameString = itsNodes.top().getValueName();
// allocate strings for all of the data in the XML object
auto namePtr = itsXML.allocate_string( nameString.data(), nameString.size() );
auto namePtr = itsXML.allocate_string( nameString.data(), nameString.length() + 1 );
// insert into the XML
auto node = itsXML.allocate_node( rapidxml::node_element, namePtr, nullptr, nameString.size() );
@ -226,8 +232,16 @@ namespace cereal
itsOS.clear(); itsOS.seekp( 0, std::ios::beg );
itsOS << value << std::ends;
const auto strValue = itsOS.str();
// if there is the first or the last character in string is whitespace then add xml:space attribute
// the last character has index length-2 because there is \0 character at end added with std::ends
if( !strValue.empty() && ( xml_detail::isWhitespace( strValue[0] ) || xml_detail::isWhitespace( strValue[strValue.length() - 2] ) ) )
{
itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "xml:space", "preserve" ) );
}
// allocate strings for all of the data in the XML object
auto dataPtr = itsXML.allocate_string( itsOS.str().c_str() );
auto dataPtr = itsXML.allocate_string( itsOS.str().c_str(), itsOS.str().length() + 1 );
// insert into the XML
itsNodes.top().node->append_node( itsXML.allocate_node( rapidxml::node_data, nullptr, dataPtr ) );
@ -256,7 +270,7 @@ namespace cereal
const auto nameString = util::demangledName<T>();
// allocate strings for all of the data in the XML object
auto namePtr = itsXML.allocate_string( nameString.data(), nameString.size() );
auto namePtr = itsXML.allocate_string( nameString.data(), nameString.length() + 1 );
itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", namePtr ) );
}
@ -348,7 +362,7 @@ namespace cereal
@endcode
\ingroup Archives */
class XMLInputArchive : public InputArchive<XMLInputArchive>
class XMLInputArchive : public InputArchive<XMLInputArchive>, public traits::TextArchive
{
public:
/*! @name Common Functionality
@ -367,7 +381,7 @@ namespace cereal
try
{
itsData.push_back('\0'); // rapidxml will do terrible things without the data being null terminated
itsXML.parse<rapidxml::parse_no_data_nodes | rapidxml::parse_declaration_node>( reinterpret_cast<char *>( itsData.data() ) );
itsXML.parse<rapidxml::parse_trim_whitespace | rapidxml::parse_no_data_nodes | rapidxml::parse_declaration_node>( reinterpret_cast<char *>( itsData.data() ) );
}
catch( rapidxml::parse_error const & )
{
@ -461,6 +475,13 @@ namespace cereal
itsNodes.top().name = nullptr;
}
//! Retrieves the current node name
//! will return @c nullptr if the node does not have a name
const char * getNodeName() const
{
return itsNodes.top().node->name();
}
//! Sets the name for the next node created with startNode
void setNextName( const char * name )
{
@ -468,51 +489,78 @@ namespace cereal
}
//! Loads a bool from the current top node
template <class T> inline
typename std::enable_if<std::is_unsigned<T>::value && std::is_same<T, bool>::value, void>::type
loadValue( T & value )
template <class T, traits::EnableIf<std::is_unsigned<T>::value,
std::is_same<T, bool>::value> = traits::sfinae> inline
void loadValue( T & value )
{
std::istringstream is( itsNodes.top().node->value() );
is.setf( std::ios::boolalpha );
is >> value;
}
//! Loads a char (signed or unsigned) from the current top node
template <class T, traits::EnableIf<std::is_integral<T>::value,
!std::is_same<T, bool>::value,
sizeof(T) == sizeof(char)> = traits::sfinae> inline
void loadValue( T & value )
{
value = *reinterpret_cast<T*>( itsNodes.top().node->value() );
}
//! Load an int8_t from the current top node (ensures we parse entire number)
void loadValue( int8_t & value )
{
int32_t val; loadValue( val ); value = val;
}
//! Load a uint8_t from the current top node (ensures we parse entire number)
void loadValue( uint8_t & value )
{
uint32_t val; loadValue( val ); value = val;
}
//! Loads a type best represented as an unsigned long from the current top node
template <class T> inline
typename std::enable_if<std::is_unsigned<T>::value && !std::is_same<T, bool>::value && sizeof(T) < sizeof(long long), void>::type
loadValue( T & value )
template <class T, traits::EnableIf<std::is_unsigned<T>::value,
!std::is_same<T, bool>::value,
!std::is_same<T, unsigned char>::value,
sizeof(T) < sizeof(long long)> = traits::sfinae> inline
void loadValue( T & value )
{
value = static_cast<T>( std::stoul( itsNodes.top().node->value() ) );
}
//! Loads a type best represented as an unsigned long long from the current top node
template <class T> inline
typename std::enable_if<std::is_unsigned<T>::value && !std::is_same<T, bool>::value && sizeof(T) >= sizeof(long long), void>::type
loadValue( T & value )
template <class T, traits::EnableIf<std::is_unsigned<T>::value,
!std::is_same<T, bool>::value,
sizeof(T) >= sizeof(long long)> = traits::sfinae> inline
void loadValue( T & value )
{
value = static_cast<T>( std::stoull( itsNodes.top().node->value() ) );
}
//! Loads a type best represented as an int from the current top node
template <class T> inline
typename std::enable_if<std::is_signed<T>::value && sizeof(T) <= sizeof(int), void>::type
loadValue( T & value )
template <class T, traits::EnableIf<std::is_signed<T>::value,
!std::is_same<T, char>::value,
sizeof(T) <= sizeof(int)> = traits::sfinae> inline
void loadValue( T & value )
{
value = static_cast<T>( std::stoi( itsNodes.top().node->value() ) );
}
//! Loads a type best represented as a long from the current top node
template <class T> inline
typename std::enable_if<std::is_signed<T>::value && (sizeof(T) > sizeof(int)) && (sizeof(T) <= sizeof(long)), void>::type
loadValue( T & value )
template <class T, traits::EnableIf<std::is_signed<T>::value,
(sizeof(T) > sizeof(int)),
sizeof(T) <= sizeof(long)> = traits::sfinae> inline
void loadValue( T & value )
{
value = static_cast<T>( std::stol( itsNodes.top().node->value() ) );
}
//! Loads a type best represented as a long long from the current top node
template <class T> inline
typename std::enable_if<std::is_signed<T>::value && (sizeof(T) > sizeof(long)) && (sizeof(T) <= sizeof(long long)), void>::type
loadValue( T & value )
template <class T, traits::EnableIf<std::is_signed<T>::value,
(sizeof(T) > sizeof(long)),
sizeof(T) <= sizeof(long long)> = traits::sfinae> inline
void loadValue( T & value )
{
value = static_cast<T>( std::stoll( itsNodes.top().node->value() ) );
}
@ -721,18 +769,18 @@ namespace cereal
that may be given data by the type about to be archived
Minimal types do not start or end nodes */
template <class T> inline
typename std::enable_if<!traits::has_minimal_output_serialization<T, XMLOutputArchive>::value, void>::type
prologue( XMLOutputArchive & ar, T const & )
template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, XMLOutputArchive>::value ||
traits::has_minimal_output_serialization<T, XMLOutputArchive>::value> = traits::sfinae> inline
void prologue( XMLOutputArchive & ar, T const & )
{
ar.startNode();
ar.insertType<T>();
}
//! Prologue for all other types for XML input archives (except minimal types)
template <class T> inline
typename std::enable_if<!traits::has_minimal_input_serialization<T, XMLInputArchive>::value, void>::type
prologue( XMLInputArchive & ar, T const & )
template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, XMLInputArchive>::value ||
traits::has_minimal_input_serialization<T, XMLInputArchive>::value> = traits::sfinae> inline
void prologue( XMLInputArchive & ar, T const & )
{
ar.startNode();
}
@ -742,17 +790,17 @@ namespace cereal
/*! Finishes the node created in the prologue
Minimal types do not start or end nodes */
template <class T> inline
typename std::enable_if<!traits::has_minimal_output_serialization<T, XMLOutputArchive>::value, void>::type
epilogue( XMLOutputArchive & ar, T const & )
template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, XMLOutputArchive>::value ||
traits::has_minimal_output_serialization<T, XMLOutputArchive>::value> = traits::sfinae> inline
void epilogue( XMLOutputArchive & ar, T const & )
{
ar.finishNode();
}
//! Epilogue for all other types other for XML output archives (except minimal types)
template <class T> inline
typename std::enable_if<!traits::has_minimal_input_serialization<T, XMLInputArchive>::value, void>::type
epilogue( XMLInputArchive & ar, T const & )
template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, XMLInputArchive>::value ||
traits::has_minimal_input_serialization<T, XMLInputArchive>::value> = traits::sfinae> inline
void epilogue( XMLInputArchive & ar, T const & )
{
ar.finishNode();
}
@ -763,7 +811,7 @@ namespace cereal
//! Saving NVP types to XML
template <class T> inline
void save( XMLOutputArchive & ar, NameValuePair<T> const & t )
void CEREAL_SAVE_FUNCTION_NAME( XMLOutputArchive & ar, NameValuePair<T> const & t )
{
ar.setNextName( t.name );
ar( t.value );
@ -771,7 +819,7 @@ namespace cereal
//! Loading NVP types from XML
template <class T> inline
void load( XMLInputArchive & ar, NameValuePair<T> & t )
void CEREAL_LOAD_FUNCTION_NAME( XMLInputArchive & ar, NameValuePair<T> & t )
{
ar.setNextName( t.name );
ar( t.value );
@ -780,29 +828,27 @@ namespace cereal
// ######################################################################
//! Saving SizeTags to XML
template <class T> inline
void save( XMLOutputArchive &, SizeTag<T> const & )
void CEREAL_SAVE_FUNCTION_NAME( XMLOutputArchive &, SizeTag<T> const & )
{ }
//! Loading SizeTags from XML
template <class T> inline
void load( XMLInputArchive & ar, SizeTag<T> & st )
void CEREAL_LOAD_FUNCTION_NAME( XMLInputArchive & ar, SizeTag<T> & st )
{
ar.loadSize( st.size );
}
// ######################################################################
//! Saving for POD types to xml
template<class T> inline
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
save(XMLOutputArchive & ar, T const & t)
template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
void CEREAL_SAVE_FUNCTION_NAME(XMLOutputArchive & ar, T const & t)
{
ar.saveValue( t );
}
//! Loading for POD types from xml
template<class T> inline
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
load(XMLInputArchive & ar, T & t)
template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
void CEREAL_LOAD_FUNCTION_NAME(XMLInputArchive & ar, T & t)
{
ar.loadValue( t );
}
@ -810,14 +856,14 @@ namespace cereal
// ######################################################################
//! saving string to xml
template<class CharT, class Traits, class Alloc> inline
void save(XMLOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
void CEREAL_SAVE_FUNCTION_NAME(XMLOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
{
ar.saveValue( str );
}
//! loading string from xml
template<class CharT, class Traits, class Alloc> inline
void load(XMLInputArchive & ar, std::basic_string<CharT, Traits, Alloc> & str)
void CEREAL_LOAD_FUNCTION_NAME(XMLInputArchive & ar, std::basic_string<CharT, Traits, Alloc> & str)
{
ar.loadValue( str );
}
@ -827,4 +873,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_

View file

@ -39,9 +39,10 @@
#include <cstdint>
#include <functional>
#include "./details/traits.hpp"
#include "./details/helpers.hpp"
#include "./types/base_class.hpp"
#include "macros.hpp"
#include "details/traits.hpp"
#include "details/helpers.hpp"
#include "types/base_class.hpp"
namespace cereal
{
@ -137,13 +138,14 @@ namespace cereal
support pointers to polymorphic data types. All archives that
come with cereal are already registered.
@ingroup Internal */
#define CEREAL_REGISTER_ARCHIVE(Archive) \
namespace cereal { namespace detail { \
template <class T> \
typename polymorphic_serialization_support<Archive, T>::type \
instantiate_polymorphic_binding( T*, Archive*, adl_tag ); \
} } // end namespaces
#define CEREAL_REGISTER_ARCHIVE(Archive) \
namespace cereal { namespace detail { \
template <class T, class BindingTag> \
typename polymorphic_serialization_support<Archive, T>::type \
instantiate_polymorphic_binding( T*, Archive*, BindingTag, adl_tag ); \
} } /* end namespaces */
// ######################################################################
//! Defines a class version for some type
/*! Versioning information is optional and adds some small amount of
overhead to serialization. This overhead will occur both in terms of
@ -167,7 +169,9 @@ namespace cereal
automatically.
Versioning cannot be mixed with non-versioned serialization functions.
Having both types will result result in a compile time error.
Having both types will result result in a compile time error. Data
serialized without versioning cannot be loaded by a serialization
function with added versioning support.
Example interface for versioning on a non-member serialize function:
@ -196,18 +200,20 @@ namespace cereal
namespace cereal { namespace detail { \
template <> struct Version<TYPE> \
{ \
static const std::uint32_t version = VERSION_NUMBER; \
static Version<TYPE> registerVersion() \
static const std::uint32_t version; \
static std::uint32_t registerVersion() \
{ \
::cereal::detail::StaticObject<Versions>::getInstance().mapping.emplace( \
std::type_index(typeid(TYPE)).hash_code(), VERSION_NUMBER ); \
return {}; \
return VERSION_NUMBER; \
} \
static void unused() { (void)version; } \
}; /* end Version */ \
static const auto CEREAL_CLASS_VERSION_REGISTER##TYPE##VERSION_NUMBER = \
const std::uint32_t Version<TYPE>::version = \
Version<TYPE>::registerVersion(); \
} } // end namespaces
// ######################################################################
//! The base output archive class
/*! This is the base output archive for all output archives. If you create
a custom archive class, it should derive from this, passing itself as
@ -357,100 +363,98 @@ namespace cereal
return *self;
}
//! Helper macro that expands the requirements for activating an overload
#define PROCESS_IF(name) \
traits::EnableIf<traits::has_##name<T, ArchiveType>::value, \
!traits::has_invalid_output_versioning<T, ArchiveType>::value, \
(traits::is_specialized_##name<T, ArchiveType>::value || \
traits::is_output_serializable<T, ArchiveType>::value)> = traits::sfinae
//! Member serialization
template <class T> inline
typename std::enable_if<traits::has_member_serialize<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
(traits::is_specialized_member_serialize<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
ArchiveType &>::type
processImpl(T const & t)
template <class T, PROCESS_IF(member_serialize)> inline
ArchiveType & processImpl(T const & t)
{
access::member_serialize(*self, const_cast<T &>(t));
return *self;
}
//! Non member serialization
template <class T> inline
typename std::enable_if<traits::has_non_member_serialize<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
(traits::is_specialized_non_member_serialize<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
ArchiveType &>::type
processImpl(T const & t)
template <class T, PROCESS_IF(non_member_serialize)> inline
ArchiveType & processImpl(T const & t)
{
serialize(*self, const_cast<T &>(t));
CEREAL_SERIALIZE_FUNCTION_NAME(*self, const_cast<T &>(t));
return *self;
}
//! Member split (save)
template <class T> inline
typename std::enable_if<traits::has_member_save<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
(traits::is_specialized_member_save<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
ArchiveType &>::type
processImpl(T const & t)
template <class T, PROCESS_IF(member_save)> inline
ArchiveType & processImpl(T const & t)
{
access::member_save(*self, t);
return *self;
}
//! Non member split (save)
template <class T> inline
typename std::enable_if<traits::has_non_member_save<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
(traits::is_specialized_non_member_save<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
ArchiveType &>::type
processImpl(T const & t)
template <class T, PROCESS_IF(non_member_save)> inline
ArchiveType & processImpl(T const & t)
{
save(*self, t);
CEREAL_SAVE_FUNCTION_NAME(*self, t);
return *self;
}
//! Member split (save_minimal)
template <class T> inline
typename std::enable_if<traits::has_member_save_minimal<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
(traits::is_specialized_member_save_minimal<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
ArchiveType &>::type
processImpl(T const & t)
template <class T, PROCESS_IF(member_save_minimal)> inline
ArchiveType & processImpl(T const & t)
{
self->process( access::member_save_minimal(*self, t) );
return *self;
}
//! Non member split (save_minimal)
template <class T> inline
typename std::enable_if<traits::has_non_member_save_minimal<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
(traits::is_specialized_non_member_save_minimal<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
ArchiveType &>::type
processImpl(T const & t)
template <class T, PROCESS_IF(non_member_save_minimal)> inline
ArchiveType & processImpl(T const & t)
{
self->process( save_minimal(*self, t) );
self->process( CEREAL_SAVE_MINIMAL_FUNCTION_NAME(*self, t) );
return *self;
}
//! Empty class specialization
template <class T> inline
typename std::enable_if<(Flags & AllowEmptyClassElision) &&
!traits::is_specialized<T, ArchiveType>::value &&
!traits::is_output_serializable<T, ArchiveType>::value && std::is_empty<T>::value, ArchiveType &>::type
processImpl(T const &)
template <class T, traits::EnableIf<(Flags & AllowEmptyClassElision),
!traits::is_specialized<T, ArchiveType>::value,
!traits::is_output_serializable<T, ArchiveType>::value,
std::is_empty<T>::value> = traits::sfinae> inline
ArchiveType & processImpl(T const &)
{
return *self;
}
//! No matching serialization
template <class T> inline
typename std::enable_if<traits::has_invalid_output_versioning<T, ArchiveType>::value ||
(!traits::is_specialized<T, ArchiveType>::value && !traits::is_output_serializable<T, ArchiveType>::value &&
(!(Flags & AllowEmptyClassElision) || ((Flags & AllowEmptyClassElision) && !std::is_empty<T>::value))),
ArchiveType &>::type
processImpl(T const &)
/*! Invalid if we have invalid output versioning or
we have no specialization, are not output serializable, and either
don't allow empty class ellision or allow it but are not serializing an empty class */
template <class T, traits::EnableIf<traits::has_invalid_output_versioning<T, ArchiveType>::value ||
(!traits::is_specialized<T, ArchiveType>::value &&
!traits::is_output_serializable<T, ArchiveType>::value &&
(!(Flags & AllowEmptyClassElision) || ((Flags & AllowEmptyClassElision) && !std::is_empty<T>::value)))> = traits::sfinae> inline
ArchiveType & processImpl(T const &)
{
static_assert(traits::is_output_serializable<T, ArchiveType>::value, "Trying to serialize an unserializable type with an output archive. \n\n "
static_assert(traits::detail::count_output_serializers<T, ArchiveType>::value != 0,
"cereal could not find any output serialization functions for the provided type and archive combination. \n\n "
"Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
"Use specialization (see access.hpp) if you need to disambiguate between serialize vs load/save functions. \n "
"In addition, you may not mix versioned with non-versioned serialization functions. \n "
"Serialize functions generally have the following signature: \n\n "
"template<class Archive> \n "
" void serialize(Archive & ar) \n "
" { \n "
" ar( member1, member2, member3 ); \n "
" } \n\n " );
static_assert(traits::detail::count_output_serializers<T, ArchiveType>::value < 2,
"cereal found more than one compatible output serialization function for the provided type and archive combination. \n\n "
"Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
"Use specialization (see access.hpp) if you need to disambiguate between serialize vs load/save functions. \n "
"Note that serialization functions can be inherited which may lead to the aforementioned ambiguities. \n "
"In addition, you may not mix versioned with non-versioned serialization functions. \n\n ");
return *self;
}
@ -461,92 +465,75 @@ namespace cereal
@tparam T The type of the class being serialized
@param version The version number associated with it */
template <class T> inline
void registerClassVersion( const std::uint32_t version )
std::uint32_t registerClassVersion()
{
static const auto hash = std::type_index(typeid(T)).hash_code();
const auto insertResult = itsVersionedTypes.insert( hash );
const auto version =
detail::StaticObject<detail::Versions>::getInstance().find( hash, detail::Version<T>::version );
if( insertResult.second ) // insertion took place, serialize the version number
process( make_nvp<ArchiveType>("cereal_class_version", version) );
return version;
}
//! Member serialization
/*! Versioning implementation */
template <class T> inline
typename std::enable_if<traits::has_member_versioned_serialize<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
(traits::is_specialized_member_serialize<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
ArchiveType &>::type
processImpl(T const & t)
template <class T, PROCESS_IF(member_versioned_serialize)> inline
ArchiveType & processImpl(T const & t)
{
registerClassVersion<T>( detail::Version<T>::version );
access::member_serialize(*self, const_cast<T &>(t), detail::Version<T>::version);
access::member_serialize(*self, const_cast<T &>(t), registerClassVersion<T>());
return *self;
}
//! Non member serialization
/*! Versioning implementation */
template <class T> inline
typename std::enable_if<traits::has_non_member_versioned_serialize<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
(traits::is_specialized_non_member_serialize<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
ArchiveType &>::type
processImpl(T const & t)
template <class T, PROCESS_IF(non_member_versioned_serialize)> inline
ArchiveType & processImpl(T const & t)
{
registerClassVersion<T>( detail::Version<T>::version );
serialize(*self, const_cast<T &>(t), detail::Version<T>::version);
CEREAL_SERIALIZE_FUNCTION_NAME(*self, const_cast<T &>(t), registerClassVersion<T>());
return *self;
}
//! Member split (save)
/*! Versioning implementation */
template <class T> inline
typename std::enable_if<traits::has_member_versioned_save<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
(traits::is_specialized_member_save<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
ArchiveType &>::type
processImpl(T const & t)
template <class T, PROCESS_IF(member_versioned_save)> inline
ArchiveType & processImpl(T const & t)
{
registerClassVersion<T>( detail::Version<T>::version );
access::member_save(*self, t, detail::Version<T>::version);
access::member_save(*self, t, registerClassVersion<T>());
return *self;
}
//! Non member split (save)
/*! Versioning implementation */
template <class T> inline
typename std::enable_if<traits::has_non_member_versioned_save<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
(traits::is_specialized_non_member_save<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
ArchiveType &>::type
processImpl(T const & t)
template <class T, PROCESS_IF(non_member_versioned_save)> inline
ArchiveType & processImpl(T const & t)
{
registerClassVersion<T>( detail::Version<T>::version );
save(*self, t, detail::Version<T>::version);
CEREAL_SAVE_FUNCTION_NAME(*self, t, registerClassVersion<T>());
return *self;
}
//! Member split (save_minimal)
/*! Versioning implementation */
template <class T> inline
typename std::enable_if<traits::has_member_versioned_save_minimal<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
(traits::is_specialized_member_save_minimal<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
ArchiveType &>::type
processImpl(T const & t)
template <class T, PROCESS_IF(member_versioned_save_minimal)> inline
ArchiveType & processImpl(T const & t)
{
registerClassVersion<T>( detail::Version<T>::version );
self->process( access::member_save_minimal(*self, t, detail::Version<T>::version) );
self->process( access::member_save_minimal(*self, t, registerClassVersion<T>()) );
return *self;
}
//! Non member split (save_minimal)
/*! Versioning implementation */
template <class T> inline
typename std::enable_if<traits::has_non_member_versioned_save_minimal<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
(traits::is_specialized_non_member_save_minimal<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
ArchiveType &>::type
processImpl(T const & t)
template <class T, PROCESS_IF(non_member_versioned_save_minimal)> inline
ArchiveType & processImpl(T const & t)
{
registerClassVersion<T>( detail::Version<T>::version );
self->process( save_minimal(*self, t, detail::Version<T>::version) );
self->process( CEREAL_SAVE_MINIMAL_FUNCTION_NAME(*self, t, registerClassVersion<T>()) );
return *self;
}
#undef PROCESS_IF
private:
ArchiveType * const self;
@ -737,103 +724,104 @@ namespace cereal
return *self;
}
//! Helper macro that expands the requirements for activating an overload
#define PROCESS_IF(name) \
traits::EnableIf<traits::has_##name<T, ArchiveType>::value, \
!traits::has_invalid_input_versioning<T, ArchiveType>::value, \
(traits::is_specialized_##name<T, ArchiveType>::value || \
traits::is_input_serializable<T, ArchiveType>::value)> = traits::sfinae
//! Member serialization
template <class T> inline
typename std::enable_if<traits::has_member_serialize<T, ArchiveType>::value &&
(traits::is_specialized_member_serialize<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
ArchiveType &>::type
processImpl(T & t)
template <class T, PROCESS_IF(member_serialize)> inline
ArchiveType & processImpl(T & t)
{
access::member_serialize(*self, t);
return *self;
}
//! Non member serialization
template <class T> inline
typename std::enable_if<traits::has_non_member_serialize<T, ArchiveType>::value &&
(traits::is_specialized_non_member_serialize<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
ArchiveType &>::type
processImpl(T & t)
template <class T, PROCESS_IF(non_member_serialize)> inline
ArchiveType & processImpl(T & t)
{
serialize(*self, t);
CEREAL_SERIALIZE_FUNCTION_NAME(*self, t);
return *self;
}
//! Member split (load)
template <class T> inline
typename std::enable_if<traits::has_member_load<T, ArchiveType>::value &&
(traits::is_specialized_member_load<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
ArchiveType &>::type
processImpl(T & t)
template <class T, PROCESS_IF(member_load)> inline
ArchiveType & processImpl(T & t)
{
access::member_load(*self, t);
return *self;
}
//! Non member split (load)
template <class T> inline
typename std::enable_if<traits::has_non_member_load<T, ArchiveType>::value &&
(traits::is_specialized_non_member_load<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
ArchiveType &>::type
processImpl(T & t)
template <class T, PROCESS_IF(non_member_load)> inline
ArchiveType & processImpl(T & t)
{
load(*self, t);
CEREAL_LOAD_FUNCTION_NAME(*self, t);
return *self;
}
//! Member split (load_minimal)
template <class T> inline
typename std::enable_if<traits::has_member_load_minimal<T, ArchiveType>::value &&
(traits::is_specialized_member_load_minimal<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
ArchiveType &>::type
processImpl(T & t)
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;
}
//! Non member split (load_minimal)
template <class T> inline
typename std::enable_if<traits::has_non_member_load_minimal<T, ArchiveType>::value &&
(traits::is_specialized_non_member_load_minimal<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
ArchiveType &>::type
processImpl(T & t)
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 );
load_minimal(*self, t, value);
CEREAL_LOAD_MINIMAL_FUNCTION_NAME(*self, t, value);
return *self;
}
//! Empty class specialization
template <class T> inline
typename std::enable_if<(Flags & AllowEmptyClassElision) &&
!traits::is_specialized<T, ArchiveType>::value &&
!traits::is_input_serializable<T, ArchiveType>::value && std::is_empty<T>::value, ArchiveType &>::type
processImpl(T const &)
template <class T, traits::EnableIf<(Flags & AllowEmptyClassElision),
!traits::is_specialized<T, ArchiveType>::value,
!traits::is_input_serializable<T, ArchiveType>::value,
std::is_empty<T>::value> = traits::sfinae> inline
ArchiveType & processImpl(T const &)
{
return *self;
}
//! No matching serialization
template <class T> inline
typename std::enable_if<!traits::is_specialized<T, ArchiveType>::value && !traits::is_input_serializable<T, ArchiveType>::value &&
(!(Flags & AllowEmptyClassElision) || ((Flags & AllowEmptyClassElision) && !std::is_empty<T>::value)),
ArchiveType &>::type
processImpl(T const &)
/*! Invalid if we have invalid input versioning or
we have no specialization, are not input serializable, and either
don't allow empty class ellision or allow it but are not serializing an empty class */
template <class T, traits::EnableIf<traits::has_invalid_input_versioning<T, ArchiveType>::value ||
(!traits::is_specialized<T, ArchiveType>::value &&
!traits::is_input_serializable<T, ArchiveType>::value &&
(!(Flags & AllowEmptyClassElision) || ((Flags & AllowEmptyClassElision) && !std::is_empty<T>::value)))> = traits::sfinae> inline
ArchiveType & processImpl(T const &)
{
static_assert(traits::is_output_serializable<T, ArchiveType>::value, "Trying to serialize an unserializable type with an output archive. \n\n "
static_assert(traits::detail::count_input_serializers<T, ArchiveType>::value != 0,
"cereal could not find any input serialization functions for the provided type and archive combination. \n\n "
"Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
"Use specialization (see access.hpp) if you need to disambiguate between serialize vs load/save functions. \n "
"In addition, you may not mix versioned with non-versioned serialization functions. \n "
"Serialize functions generally have the following signature: \n\n "
"template<class Archive> \n "
" void serialize(Archive & ar) \n "
" { \n "
" ar( member1, member2, member3 ); \n "
" } \n\n " );
static_assert(traits::detail::count_input_serializers<T, ArchiveType>::value < 2,
"cereal found more than one compatible input serialization function for the provided type and archive combination. \n\n "
"Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
"Use specialization (see access.hpp) if you need to disambiguate between serialize vs load/save functions. \n "
"Note that serialization functions can be inherited which may lead to the aforementioned ambiguities. \n "
"In addition, you may not mix versioned with non-versioned serialization functions. \n\n ");
return *self;
}
@ -864,11 +852,8 @@ namespace cereal
//! Member serialization
/*! Versioning implementation */
template <class T> inline
typename std::enable_if<traits::has_member_versioned_serialize<T, ArchiveType>::value &&
(traits::is_specialized_member_serialize<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
ArchiveType &>::type
processImpl(T & t)
template <class T, PROCESS_IF(member_versioned_serialize)> inline
ArchiveType & processImpl(T & t)
{
const auto version = loadClassVersion<T>();
access::member_serialize(*self, t, version);
@ -877,24 +862,18 @@ namespace cereal
//! Non member serialization
/*! Versioning implementation */
template <class T> inline
typename std::enable_if<traits::has_non_member_versioned_serialize<T, ArchiveType>::value &&
(traits::is_specialized_non_member_serialize<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
ArchiveType &>::type
processImpl(T & t)
template <class T, PROCESS_IF(non_member_versioned_serialize)> inline
ArchiveType & processImpl(T & t)
{
const auto version = loadClassVersion<T>();
serialize(*self, t, version);
CEREAL_SERIALIZE_FUNCTION_NAME(*self, t, version);
return *self;
}
//! Member split (load)
/*! Versioning implementation */
template <class T> inline
typename std::enable_if<traits::has_member_versioned_load<T, ArchiveType>::value &&
(traits::is_specialized_member_load<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
ArchiveType &>::type
processImpl(T & t)
template <class T, PROCESS_IF(member_versioned_load)> inline
ArchiveType & processImpl(T & t)
{
const auto version = loadClassVersion<T>();
access::member_load(*self, t, version);
@ -903,27 +882,22 @@ namespace cereal
//! Non member split (load)
/*! Versioning implementation */
template <class T> inline
typename std::enable_if<traits::has_non_member_versioned_load<T, ArchiveType>::value &&
(traits::is_specialized_non_member_load<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
ArchiveType &>::type
processImpl(T & t)
template <class T, PROCESS_IF(non_member_versioned_load)> inline
ArchiveType & processImpl(T & t)
{
const auto version = loadClassVersion<T>();
load(*self, t, version);
CEREAL_LOAD_FUNCTION_NAME(*self, t, version);
return *self;
}
//! Member split (load_minimal)
/*! Versioning implementation */
template <class T> inline
typename std::enable_if<traits::has_member_versioned_load_minimal<T, ArchiveType>::value &&
(traits::is_specialized_member_load_minimal<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
ArchiveType &>::type
processImpl(T & t)
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;
@ -931,19 +905,19 @@ namespace cereal
//! Non member split (load_minimal)
/*! Versioning implementation */
template <class T> inline
typename std::enable_if<traits::has_non_member_versioned_load_minimal<T, ArchiveType>::value &&
(traits::is_specialized_non_member_load_minimal<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
ArchiveType &>::type
processImpl(T & t)
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);
load_minimal(*self, t, value, version);
CEREAL_LOAD_MINIMAL_FUNCTION_NAME(*self, t, value, version);
return *self;
}
#undef PROCESS_IF
private:
ArchiveType * const self;
@ -962,6 +936,6 @@ namespace cereal
} // namespace cereal
// This include needs to come after things such as binary_data, make_nvp, etc
#include "./types/common.hpp"
#include "types/common.hpp"
#endif // CEREAL_CEREAL_HPP_

View file

@ -37,6 +37,7 @@
#include <unordered_map>
#include <stdexcept>
#include "../macros.hpp"
#include "../details/static_object.hpp"
namespace cereal
@ -46,15 +47,15 @@ namespace cereal
/*! @ingroup Utility */
struct Exception : public std::runtime_error
{
Exception( const std::string & what_ ) : std::runtime_error(what_) {}
Exception( const char * what_ ) : std::runtime_error(what_) {}
explicit Exception( const std::string & what_ ) : std::runtime_error(what_) {}
explicit Exception( const char * what_ ) : std::runtime_error(what_) {}
};
// ######################################################################
//! The size type used by cereal
/*! To ensure compatability between 32, 64, etc bit machines, we need to use
* a fixed size type instead of size_t, which may vary from machine to
* machine. */
a fixed size type instead of size_t, which may vary from machine to
machine. */
using size_type = uint64_t;
// forward decls
@ -64,7 +65,7 @@ namespace cereal
// ######################################################################
namespace detail
{
struct NameValuePairCore {};
struct NameValuePairCore {}; //!< Traits struct for NVPs
}
//! For holding name value pairs
@ -108,7 +109,7 @@ namespace cereal
@endcode
There is a slight amount of overhead to creating NameValuePairs, so there
is a third method which will elide the names when they are not needed by
is a third method which will elide the names when they are not used by
the Archive:
@code{.cpp}
@ -134,16 +135,14 @@ namespace cereal
class NameValuePair : detail::NameValuePairCore
{
private:
// If we get passed an RValue, we'll just make a local copy if it here
// otherwise, we store a reference. If we were passed an array, don't
// decay the type - keep it as an array, and then proceed as normal
// with the RValue business
using DT = typename std::conditional<std::is_array<typename std::remove_reference<T>::type>::value,
typename std::remove_cv<T>::type,
typename std::decay<T>::type>::type;
using Type = typename std::conditional<std::is_rvalue_reference<T>::value,
DT,
typename std::add_lvalue_reference<DT>::type>::type;
// If we get passed an array, keep the type as is, otherwise store
// a reference if we were passed an l value reference, else copy the value
using Type = typename std::conditional<std::is_array<typename std::remove_reference<T>::type>::value,
typename std::remove_cv<T>::type,
typename std::conditional<std::is_lvalue_reference<T>::value,
T,
typename std::decay<T>::type>::type>::type;
// prevent nested nvps
static_assert( !std::is_base_of<detail::NameValuePairCore, T>::value,
"Cannot pair a name to a NameValuePair" );
@ -155,9 +154,9 @@ namespace cereal
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
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
@internal */
NameValuePair( char const * n, T && v ) : name(n), value(const_cast<Type>(v)) {}
size() call.
@internal */
NameValuePair( char const * n, T && v ) : name(n), value(std::forward<T>(v)) {}
char const * name;
Type value;
@ -193,7 +192,7 @@ namespace cereal
/*! For use in inteneral generic typing functions which have an
Archive type declared
@internal */
#define _CEREAL_NVP(name, value) ::cereal::make_nvp<Archive>(name, value)
#define CEREAL_NVP_(name, value) ::cereal::make_nvp<Archive>(name, value)
// ######################################################################
//! A wrapper around data that can be serialized in a binary fashion
@ -211,9 +210,9 @@ namespace cereal
const void *,
void *>::type;
BinaryData( T && d, uint64_t s ) : data(d), size(s) {}
BinaryData( T && d, uint64_t s ) : data(std::forward<T>(d)), size(s) {}
PT data; //!< pointer to beginning of data
PT data; //!< pointer to beginning of data
uint64_t size; //!< size in bytes
};
@ -221,15 +220,18 @@ namespace cereal
namespace detail
{
// base classes for type checking
struct OutputArchiveBase {};
struct InputArchiveBase {};
/* The rtti virtual function only exists to enable an archive to
be used in a polymorphic fashion, if necessary. See the
archive adapters for an example of this */
class OutputArchiveBase { private: virtual void rtti(){} };
class InputArchiveBase { private: virtual void rtti(){} };
// forward decls for polymorphic support
template <class Archive, class T> struct polymorphic_serialization_support;
struct adl_tag;
// used during saving pointers
static const int32_t msb_32bit = 0x80000000;
static const int32_t msb_32bit = 0x80000000;
static const int32_t msb2_32bit = 0x40000000;
}
@ -246,15 +248,14 @@ namespace cereal
class SizeTag
{
private:
// If we get passed an RValue, we'll just make a local copy if it here
// otherwise, we store a reference
using DT = typename std::decay<T>::type;
using Type = typename std::conditional<std::is_rvalue_reference<T>::value,
DT,
typename std::add_lvalue_reference<DT>::type>::type;
// Store a reference if passed an lvalue reference, otherwise
// make a copy of the data
using Type = typename std::conditional<std::is_lvalue_reference<T>::value,
T,
typename std::decay<T>::type>::type;
public:
SizeTag( T && sz ) : size(const_cast<Type>(sz)) {}
SizeTag( T && sz ) : size(std::forward<T>(sz)) {}
Type size;
};
@ -283,28 +284,26 @@ namespace cereal
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;
std::is_lvalue_reference<Key>::value,
Key,
typename std::decay<Key>::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;
using ValueType = typename std::conditional<
std::is_lvalue_reference<Value>::value,
Value,
typename std::decay<Value>::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_)) {}
MapItem( Key && key_, Value && value_ ) : key(std::forward<Key>(key_)), value(std::forward<Value>(value_)) {}
KeyType key;
ValueType value;
//! Serialize the MapItem with the NVPs "key" and "value"
template <class Archive> inline
void serialize(Archive & archive)
void CEREAL_SERIALIZE_FUNCTION_NAME(Archive & archive)
{
archive( make_nvp<Archive>("key", key),
make_nvp<Archive>("value", value) );
@ -322,129 +321,33 @@ namespace cereal
namespace detail
{
// ######################################################################
//! Holds all registered version information
struct Versions
{
std::unordered_map<std::size_t, std::uint32_t> mapping;
}; // struct Versions
//! Tag for Version, which due to its anonymous namespace, becomes a different
//! type in each translation unit
/*! This allows CEREAL_CLASS_VERSION to be safely called in a header file */
namespace{ struct version_binding_tag {}; }
// ######################################################################
//! Version information class
/*! This is the base case for classes that have not been explicitly
registered */
template <class T> struct Version
template <class T, class BindingTag = version_binding_tag> struct Version
{
static const std::uint32_t version = 0;
// we don't need to explicitly register these types since they
// always get a version number of 0
};
#ifdef CEREAL_FUTURE_EXPERIMENTAL
// ######################################################################
//! A class that can store any type
/*! This is inspired by boost::any and is intended to be a very light-weight
replacement for internal use only.
This class is only here as a candidate for issue #46 (see github) and
should be considered unsupported until a future version of cereal.
*/
class Any
//! Holds all registered version information
struct Versions
{
private:
//! Convenience alias for decay
template <class T>
using ST = typename std::decay<T>::type;
std::unordered_map<std::size_t, std::uint32_t> mapping;
struct Base
{
virtual ~Base() {}
virtual std::unique_ptr<Base> clone() const = 0;
};
template <class T>
struct Derived : Base
{
template <class U>
Derived( U && data ) : value( std::forward<U>( data ) ) {}
std::unique_ptr<Base> clone() const
{
return std::unique_ptr<Base>( new Derived<T>( value ) );
}
T value;
};
public:
//! Construct from any type
template <class T> inline
Any( T && data ) :
itsPtr( new Derived<ST<T>>( std::forward<T>( data ) ) )
{ }
//! Convert to any type, if possible
/*! Attempts to perform the conversion if possible,
otherwise throws an exception.
@throw Exception if conversion is not possible (see get() for more info)
@tparam The requested type to convert to */
template <class T> inline
operator T()
{
return get<ST<T>>();
}
Any() : itsPtr() {}
Any( Any & other ) : itsPtr( other.clone() ) {}
Any( Any const & other ) : itsPtr( other.clone() ) {}
Any( Any && other ) : itsPtr( std::move( other.itsPtr ) ) {}
Any & operator=( Any const & other )
{
if( itsPtr == other.itsPtr ) return *this;
auto cloned = other.clone();
itsPtr = std::move( cloned );
return *this;
}
Any & operator=( Any && other )
{
if( itsPtr == other.itsPtr ) return *this;
itsPtr = std::move( other.itsPtr );
return *this;
}
protected:
//! Get the contained type as type T
/*! @tparam T The requested type to convert to
@return The type converted to T
@throw Exception if conversion is impossible */
template <class T>
ST<T> & get()
{
auto * derived = dynamic_cast<Derived<ST<T>> *>( itsPtr.get() );
if( !derived )
throw ::cereal::Exception( "Invalid conversion requested on ASDFA" );
return derived->value;
}
//! Clones the held data if it exists
std::unique_ptr<Base> clone() const
{
if( itsPtr ) return itsPtr->clone();
else return {};
}
private:
std::unique_ptr<Base> itsPtr;
}; // struct Any
#endif // CEREAL_FUTURE_EXPERIMENTAL
std::uint32_t find( std::size_t hash, std::uint32_t version )
{
const auto result = mapping.emplace( hash, version );
return result.first->second;
}
}; // struct Versions
} // namespace detail
} // namespace cereal

View file

@ -52,22 +52,23 @@
#include <map>
//! Binds a polymorhic type to all registered archives
/*! This binds a polymorphic type to all registered archives that
/*! This binds a polymorphic type to all compatible registered archives that
have been registered with CEREAL_REGISTER_ARCHIVE. This must be called
after all archives are registered (usually after the archives themselves
have been included). */
#define CEREAL_BIND_TO_ARCHIVES(T) \
namespace cereal { \
namespace detail { \
template<> \
struct init_binding<T> { \
static bind_to_archives<T> const & b; \
}; \
bind_to_archives<T> const & init_binding<T>::b = \
::cereal::detail::StaticObject< \
bind_to_archives<T> \
>::getInstance().bind(); \
}} // end namespaces
#define CEREAL_BIND_TO_ARCHIVES(T) \
namespace cereal { \
namespace detail { \
template<> \
struct init_binding<T> { \
static bind_to_archives<T> const & b; \
static void unused() { (void)b; } \
}; \
bind_to_archives<T> const & init_binding<T>::b = \
::cereal::detail::StaticObject< \
bind_to_archives<T> \
>::getInstance().bind(); \
}} /* end namespaces */
namespace cereal
{
@ -136,8 +137,8 @@ namespace cereal
};
// forward decls for archives from cereal.hpp
struct InputArchiveBase;
struct OutputArchiveBase;
class InputArchiveBase;
class OutputArchiveBase;
//! Creates a binding (map entry) between an input archive type and a polymorphic type
/*! Bindings are made when types are registered, assuming that at least one
@ -149,6 +150,13 @@ namespace cereal
//! Initialize the binding
InputBindingCreator()
{
auto & map = StaticObject<InputBindingMap<Archive>>::getInstance().map;
auto key = std::string(binding_name<T>::name());
auto lb = map.lower_bound(key);
if (lb != map.end() && lb->first == key)
return;
typename InputBindingMap<Archive>::Serializers serializers;
serializers.shared_ptr =
@ -157,7 +165,7 @@ namespace cereal
Archive & ar = *static_cast<Archive*>(arptr);
std::shared_ptr<T> ptr;
ar( _CEREAL_NVP("ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
ar( CEREAL_NVP_("ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
dptr = ptr;
};
@ -168,12 +176,12 @@ namespace cereal
Archive & ar = *static_cast<Archive*>(arptr);
std::unique_ptr<T> ptr;
ar( _CEREAL_NVP("ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
ar( CEREAL_NVP_("ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
dptr.reset(ptr.release());
};
StaticObject<InputBindingMap<Archive>>::getInstance().map.insert( { std::string(binding_name<T>::name()), serializers } );
map.insert( lb, { std::move(key), std::move(serializers) } );
}
};
@ -192,13 +200,13 @@ namespace cereal
std::uint32_t id = ar.registerPolymorphicType(name);
// Serialize the id
ar( _CEREAL_NVP("polymorphic_id", id) );
ar( CEREAL_NVP_("polymorphic_id", id) );
// If the msb of the id is 1, then the type name is new, and we should serialize it
if( id & detail::msb_32bit )
{
std::string namestring(name);
ar( _CEREAL_NVP("polymorphic_name", namestring) );
ar( CEREAL_NVP_("polymorphic_name", namestring) );
}
}
@ -250,7 +258,7 @@ namespace cereal
{
::cereal::memory_detail::EnableSharedStateHelper<T> state( static_cast<T *>(const_cast<void *>(dptr)) );
PolymorphicSharedPointerWrapper psptr( dptr );
ar( _CEREAL_NVP("ptr_wrapper", memory_detail::make_ptr_wrapper( psptr() ) ) );
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( psptr() ) ) );
}
//! Does the actual work of saving a polymorphic shared_ptr
@ -264,12 +272,19 @@ namespace cereal
static inline void savePolymorphicSharedPtr( Archive & ar, void const * dptr, std::false_type /* has_shared_from_this */ )
{
PolymorphicSharedPointerWrapper psptr( dptr );
ar( _CEREAL_NVP("ptr_wrapper", memory_detail::make_ptr_wrapper( psptr() ) ) );
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( psptr() ) ) );
}
//! Initialize the binding
OutputBindingCreator()
{
auto & map = StaticObject<OutputBindingMap<Archive>>::getInstance().map;
auto key = std::type_index(typeid(T));
auto lb = map.lower_bound(key);
if (lb != map.end() && lb->first == key)
return;
typename OutputBindingMap<Archive>::Serializers serializers;
serializers.shared_ptr =
@ -295,10 +310,10 @@ namespace cereal
std::unique_ptr<T const, EmptyDeleter<T const>> const ptr(static_cast<T const *>(dptr));
ar( _CEREAL_NVP("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
};
StaticObject<OutputBindingMap<Archive>>::getInstance().map.insert( {std::type_index(typeid(T)), serializers} );
map.insert( { std::move(key), std::move(serializers) } );
}
};
@ -306,6 +321,10 @@ namespace cereal
//! of instantiate_polymorphic_binding
struct adl_tag {};
//! Tag for init_binding, bind_to_archives and instantiate_polymorphic_binding. Due to the use of anonymous
//! namespace it becomes a different type in each translation unit.
namespace { struct polymorphic_binding_tag {}; }
//! Causes the static object bindings between an archive type and a serializable type T
template <class Archive, class T>
struct create_bindings
@ -338,14 +357,14 @@ namespace cereal
template <class Archive, class T>
struct polymorphic_serialization_support
{
#ifdef _MSC_VER
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
//! Creates the appropriate bindings depending on whether the archive supports
//! saving or loading
virtual void instantiate();
virtual CEREAL_DLL_EXPORT void instantiate() CEREAL_USED;
#else // NOT _MSC_VER
//! Creates the appropriate bindings depending on whether the archive supports
//! saving or loading
static void instantiate();
static CEREAL_DLL_EXPORT void instantiate() CEREAL_USED;
//! This typedef causes the compiler to instantiate this static function
typedef instantiate_function<instantiate> unused;
#endif // _MSC_VER
@ -353,11 +372,15 @@ namespace cereal
// instantiate implementation
template <class Archive, class T>
void polymorphic_serialization_support<Archive,T>::instantiate()
CEREAL_DLL_EXPORT void polymorphic_serialization_support<Archive,T>::instantiate()
{
create_bindings<Archive,T>::save( std::is_base_of<detail::OutputArchiveBase, Archive>() );
create_bindings<Archive,T>::save( std::integral_constant<bool,
std::is_base_of<detail::OutputArchiveBase, Archive>::value &&
traits::is_output_serializable<T, Archive>::value>{} );
create_bindings<Archive,T>::load( std::is_base_of<detail::InputArchiveBase, Archive>() );
create_bindings<Archive,T>::load( std::integral_constant<bool,
std::is_base_of<detail::InputArchiveBase, Archive>::value &&
traits::is_input_serializable<T, Archive>::value>{} );
}
//! Begins the binding process of a type to all registered archives
@ -365,13 +388,13 @@ namespace cereal
the CEREAL_REGISTER_ARCHIVE macro. Overload resolution will then force
several static objects to be made that allow us to bind together all
registered archive types with the parameter type T. */
template <class T>
template <class T, class Tag = polymorphic_binding_tag>
struct bind_to_archives
{
//! Binding for non abstract types
void bind(std::false_type) const
{
instantiate_polymorphic_binding((T*) 0, 0, adl_tag{});
instantiate_polymorphic_binding((T*) 0, 0, Tag{}, adl_tag{});
}
//! Binding for abstract types
@ -391,7 +414,7 @@ namespace cereal
};
//! Used to hide the static object used to bind T to registered archives
template <class T>
template <class T, class Tag = polymorphic_binding_tag>
struct init_binding;
//! Base case overload for instantiation
@ -406,8 +429,8 @@ namespace cereal
mechanisms even though they are never called.
See the documentation for the other functions to try and understand this */
template <class T>
void instantiate_polymorphic_binding( T*, int, adl_tag ) {}
template <class T, typename BindingTag>
void instantiate_polymorphic_binding( T*, int, BindingTag, adl_tag ) {}
} // namespace detail
} // namespace cereal

View file

@ -4,7 +4,6 @@
/*
Copyright (c) 2014, Randolph Voorhies, Shane Grant
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
@ -15,7 +14,6 @@
* Neither the name of cereal nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@ -30,7 +28,23 @@
#ifndef CEREAL_DETAILS_STATIC_OBJECT_HPP_
#define CEREAL_DETAILS_STATIC_OBJECT_HPP_
#include "../details/util.hpp"
//! Prevent link optimization from removing non-referenced static objects
/*! Especially for polymorphic support, we create static objects which
may not ever be explicitly referenced. Most linkers will detect this
and remove the code causing various unpleasant runtime errors. These
macros, adopted from Boost (see force_include.hpp) prevent this
(C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
Use, modification and distribution is subject to the Boost Software
License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt) */
#ifdef _MSC_VER
# define CEREAL_DLL_EXPORT __declspec(dllexport)
# define CEREAL_USED
#else // clang or gcc
# define CEREAL_DLL_EXPORT
# define CEREAL_USED __attribute__ ((__used__))
#endif
namespace cereal
{
@ -40,12 +54,11 @@ namespace cereal
/*! This class will create a single copy (singleton) of some
type and ensures that merely referencing this type will
cause it to be instantiated and initialized pre-execution.
For example, this is used heavily in the polymorphic pointer
serialization mechanisms to bind various archive types with
different polymorphic classes */
template <class T>
class StaticObject
class CEREAL_DLL_EXPORT StaticObject
{
private:
//! Forces instantiation at pre-execution time
@ -71,7 +84,7 @@ namespace cereal
};
template <class T> T & StaticObject<T>::instance = StaticObject<T>::create();
}
} // namespace detail
} // namespace cereal
#endif // CEREAL_DETAILS_STATIC_OBJECT_HPP_
#endif // CEREAL_DETAILS_STATIC_OBJECT_HPP_

File diff suppressed because it is too large Load diff

View file

@ -41,17 +41,13 @@ namespace cereal
//! Demangles the type encoded in a string
/*! @internal */
inline std::string demangle( std::string const & name )
{
return name;
}
{ return name; }
//! Gets the demangled name of a type
/*! @internal */
template <class T> inline
std::string demangledName()
{
return typeid( T ).name();
}
std::string demangledName()
{ return typeid( T ).name(); }
} // namespace util
} // namespace cereal
#else // clang or gcc
@ -79,7 +75,7 @@ namespace cereal
inline std::string demangle(std::string mangledName)
{
int status = 0;
char *demangledName = NULL;
char *demangledName = nullptr;
std::size_t len;
demangledName = abi::__cxa_demangle(mangledName.c_str(), 0, &len, &status);
@ -93,12 +89,9 @@ namespace cereal
//! Gets the demangled name of a type
/*! @internal */
template<class T> inline
std::string demangledName()
{ return demangle(typeid(T).name()); }
std::string demangledName()
{ return demangle(typeid(T).name()); }
}
} // namespace cereal
#endif
#endif // clang or gcc branch of _MSC_VER
#endif // CEREAL_DETAILS_UTIL_HPP_

View file

@ -410,7 +410,7 @@ private:
}
template <>
bool characterOk<char>( Ch )
bool characterOk<char>( char )
{
return true;
}

View file

@ -185,7 +185,7 @@ protected:
}
template <>
bool characterOk<char>( Ch )
bool characterOk<char>( char )
{
return true;
}

View file

@ -334,6 +334,14 @@ namespace rapidxml
}
return true;
}
template<class Ch>
inline bool preserve_space(xml_node<Ch>* node)
{
const Ch preserve_value[] = { Ch('p'), Ch('r'), Ch('e'), Ch('s'), Ch('e'), Ch('r'), Ch('v'), Ch('e') };
const xml_attribute<Ch>* space = node->first_attribute("xml:space");
return space && internal::compare(space->value(), space->value_size(), preserve_value, sizeof(preserve_value) / sizeof(Ch), true);
}
}
//! \endcond
@ -1566,7 +1574,7 @@ namespace rapidxml
// - replacing XML character entity references with proper characters (&apos; &amp; &quot; &lt; &gt; &#...;)
// - condensing whitespace sequences to single space character
template<class StopPred, class StopPredPure, int Flags>
static Ch *skip_and_expand_character_refs(Ch *&text)
static Ch *skip_and_expand_character_refs(Ch *&text, bool preserve_space)
{
// If entity translation, whitespace condense and whitespace trimming is disabled, use plain skip
if (Flags & parse_no_entity_translation &&
@ -1691,7 +1699,7 @@ namespace rapidxml
}
// If whitespace condensing is enabled
if (Flags & parse_normalize_whitespace)
if ((Flags & parse_normalize_whitespace) && !preserve_space)
{
// Test if condensing is needed
if (whitespace_pred::test(*src))
@ -1942,15 +1950,17 @@ namespace rapidxml
if (!(Flags & parse_trim_whitespace))
text = contents_start;
const bool preserve_space = internal::preserve_space(node);
// Skip until end of data
Ch *value_ = text, *end;
if (Flags & parse_normalize_whitespace)
end = skip_and_expand_character_refs<text_pred, text_pure_with_ws_pred, Flags>(text);
if ((Flags & parse_normalize_whitespace) && !preserve_space)
end = skip_and_expand_character_refs<text_pred, text_pure_with_ws_pred, Flags>(text, false);
else
end = skip_and_expand_character_refs<text_pred, text_pure_no_ws_pred, Flags>(text);
end = skip_and_expand_character_refs<text_pred, text_pure_no_ws_pred, Flags>(text, preserve_space);
// Trim trailing whitespace if flag is set; leading was already trimmed by whitespace skip after >
if (Flags & parse_trim_whitespace)
if ((Flags & parse_trim_whitespace) && !preserve_space)
{
if (Flags & parse_normalize_whitespace)
{
@ -2187,6 +2197,12 @@ namespace rapidxml
case Ch('<'):
if (text[1] == Ch('/'))
{
Ch *contents_end = 0;
if (internal::preserve_space(node))
{
contents_end = text;
}
// Node closing
text += 2; // Skip '</'
if (Flags & parse_validate_closing_tags)
@ -2207,6 +2223,12 @@ namespace rapidxml
if (*text != Ch('>'))
RAPIDXML_PARSE_ERROR("expected >", text);
++text; // Skip '>'
if (contents_end && contents_end != contents_start)
{
node->value(contents_start, contents_end - contents_start);
node->value()[node->value_size()] = Ch('\0');
}
return; // Node closed, finished parsing contents
}
else
@ -2275,9 +2297,9 @@ namespace rapidxml
Ch *value_ = text, *end;
const int AttFlags = Flags & ~parse_normalize_whitespace; // No whitespace normalization in attributes
if (quote == Ch('\''))
end = skip_and_expand_character_refs<attribute_value_pred<Ch('\'')>, attribute_value_pure_pred<Ch('\'')>, AttFlags>(text);
end = skip_and_expand_character_refs<attribute_value_pred<Ch('\'')>, attribute_value_pure_pred<Ch('\'')>, AttFlags>(text, false);
else
end = skip_and_expand_character_refs<attribute_value_pred<Ch('"')>, attribute_value_pure_pred<Ch('"')>, AttFlags>(text);
end = skip_and_expand_character_refs<attribute_value_pred<Ch('"')>, attribute_value_pure_pred<Ch('"')>, AttFlags>(text, false);
// Set attribute value
attribute->value(value_, end - value_);

View file

@ -0,0 +1,82 @@
/*! \file macros.hpp
\brief Preprocessor macros that can customise the cereal library
By default, cereal looks for serialization functions with very
specific names, that is: serialize, load, save, load_minimal,
or save_minimal.
This file allows an advanced user to change these names to conform
to some other style or preference. This is implemented using
preprocessor macros.
As a result of this, in internal cereal code you will see macros
used for these function names. In user code, you should name
the functions like you normally would and not use the macros
to improve readability.
\ingroup utility */
/*
Copyright (c) 2014, Randolph Voorhies, Shane Grant
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of cereal nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CEREAL_MACROS_HPP_
#define CEREAL_MACROS_HPP_
#ifndef CEREAL_SERIALIZE_FUNCTION_NAME
//! The serialization/deserialization function name to search for.
/*! You can define @c CEREAL_SERIALIZE_FUNCTION_NAME to be different assuming
you do so before this file is included. */
#define CEREAL_SERIALIZE_FUNCTION_NAME serialize
#endif // CEREAL_SERIALIZE_FUNCTION_NAME
#ifndef CEREAL_LOAD_FUNCTION_NAME
//! The deserialization (load) function name to search for.
/*! You can define @c CEREAL_LOAD_FUNCTION_NAME to be different assuming you do so
before this file is included. */
#define CEREAL_LOAD_FUNCTION_NAME load
#endif // CEREAL_LOAD_FUNCTION_NAME
#ifndef CEREAL_SAVE_FUNCTION_NAME
//! The serialization (save) function name to search for.
/*! You can define @c CEREAL_SAVE_FUNCTION_NAME to be different assuming you do so
before this file is included. */
#define CEREAL_SAVE_FUNCTION_NAME save
#endif // CEREAL_SAVE_FUNCTION_NAME
#ifndef CEREAL_LOAD_MINIMAL_FUNCTION_NAME
//! The deserialization (load_minimal) function name to search for.
/*! You can define @c CEREAL_LOAD_MINIMAL_FUNCTION_NAME to be different assuming you do so
before this file is included. */
#define CEREAL_LOAD_MINIMAL_FUNCTION_NAME load_minimal
#endif // CEREAL_LOAD_MINIMAL_FUNCTION_NAME
#ifndef CEREAL_SAVE_MINIMAL_FUNCTION_NAME
//! The serialization (save_minimal) function name to search for.
/*! You can define @c CEREAL_SAVE_MINIMAL_FUNCTION_NAME to be different assuming you do so
before this file is included. */
#define CEREAL_SAVE_MINIMAL_FUNCTION_NAME save_minimal
#endif // CEREAL_SAVE_MINIMAL_FUNCTION_NAME
#endif // CEREAL_MACROS_HPP_

View file

@ -40,7 +40,7 @@ namespace cereal
template <class Archive, class T, size_t N> inline
typename std::enable_if<traits::is_output_serializable<BinaryData<T>, Archive>::value
&& std::is_arithmetic<T>::value, void>::type
save( Archive & ar, std::array<T, N> const & array )
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::array<T, N> const & array )
{
ar( binary_data( array.data(), sizeof(array) ) );
}
@ -50,7 +50,7 @@ namespace cereal
template <class Archive, class T, size_t N> inline
typename std::enable_if<traits::is_input_serializable<BinaryData<T>, Archive>::value
&& std::is_arithmetic<T>::value, void>::type
load( Archive & ar, std::array<T, N> & array )
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::array<T, N> & array )
{
ar( binary_data( array.data(), sizeof(array) ) );
}
@ -59,7 +59,7 @@ namespace cereal
template <class Archive, class T, size_t N> inline
typename std::enable_if<!traits::is_output_serializable<BinaryData<T>, Archive>::value
|| !std::is_arithmetic<T>::value, void>::type
save( Archive & ar, std::array<T, N> const & array )
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::array<T, N> const & array )
{
for( auto const & i : array )
ar( i );
@ -69,7 +69,7 @@ namespace cereal
template <class Archive, class T, size_t N> inline
typename std::enable_if<!traits::is_input_serializable<BinaryData<T>, Archive>::value
|| !std::is_arithmetic<T>::value, void>::type
load( Archive & ar, std::array<T, N> & array )
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::array<T, N> & array )
{
for( auto & i : array )
ar( i );

View file

@ -30,6 +30,8 @@
#ifndef CEREAL_TYPES_BASE_CLASS_HPP_
#define CEREAL_TYPES_BASE_CLASS_HPP_
#include "../details/traits.hpp"
namespace cereal
{
//! Casts a derived class to its non-virtual base class in a way that safely supports abstract classes
@ -67,12 +69,12 @@ namespace cereal
};
@endcode */
template<class Base>
struct base_class
struct base_class : private traits::detail::BaseCastBase
{
template<class Derived>
base_class(Derived const * derived) :
base_ptr(const_cast<Base*>(static_cast<Base const *>(derived)))
{ }
{ static_assert( std::is_base_of<Base, Derived>::value, "Can only use base_class on a valid base class" ); }
Base * base_ptr;
};
@ -147,12 +149,12 @@ namespace cereal
}
@endcode */
template<class Base>
struct virtual_base_class
struct virtual_base_class : private traits::detail::BaseCastBase
{
template<class Derived>
virtual_base_class(Derived const * derived) :
base_ptr(const_cast<Base*>(static_cast<Base const *>(derived)))
{ }
{ static_assert( std::is_base_of<Base, Derived>::value, "Can only use base_class on a valid base class" ); }
Base * base_ptr;
};

View file

@ -49,57 +49,57 @@ namespace cereal
//! Serializing (save) for std::bitset
template <class Archive, size_t N> inline
void save( Archive & ar, std::bitset<N> const & bits )
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::bitset<N> const & bits )
{
try
{
auto const b = bits.to_ulong();
ar( _CEREAL_NVP("type", bitset_detail::type::ulong) );
ar( _CEREAL_NVP("data", b) );
ar( CEREAL_NVP_("type", bitset_detail::type::ulong) );
ar( CEREAL_NVP_("data", b) );
}
catch( std::overflow_error const & )
{
try
{
auto const b = bits.to_ullong();
ar( _CEREAL_NVP("type", bitset_detail::type::ullong) );
ar( _CEREAL_NVP("data", b) );
ar( CEREAL_NVP_("type", bitset_detail::type::ullong) );
ar( CEREAL_NVP_("data", b) );
}
catch( std::overflow_error const & )
{
ar( _CEREAL_NVP("type", bitset_detail::type::string) );
ar( _CEREAL_NVP("data", bits.to_string()) );
ar( CEREAL_NVP_("type", bitset_detail::type::string) );
ar( CEREAL_NVP_("data", bits.to_string()) );
}
}
}
//! Serializing (load) for std::bitset
template <class Archive, size_t N> inline
void load( Archive & ar, std::bitset<N> & bits )
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::bitset<N> & bits )
{
bitset_detail::type t;
ar( _CEREAL_NVP("type", t) );
ar( CEREAL_NVP_("type", t) );
switch( t )
{
case bitset_detail::type::ulong:
{
unsigned long b;
ar( _CEREAL_NVP("data", b) );
ar( CEREAL_NVP_("data", b) );
bits = std::bitset<N>( b );
break;
}
case bitset_detail::type::ullong:
{
unsigned long long b;
ar( _CEREAL_NVP("data", b) );
ar( CEREAL_NVP_("data", b) );
bits = std::bitset<N>( b );
break;
}
case bitset_detail::type::string:
{
std::string b;
ar( _CEREAL_NVP("data", b) );
ar( CEREAL_NVP_("data", b) );
bits = std::bitset<N>( b );
break;
}

View file

@ -47,7 +47,7 @@ namespace cereal
template<class T>
void operator()(T const & value) const
{
ar( _CEREAL_NVP("data", value) );
ar( CEREAL_NVP_("data", value) );
}
Archive & ar;
@ -69,7 +69,7 @@ namespace cereal
if(N == target)
{
H value;
ar( _CEREAL_NVP("data", value) );
ar( CEREAL_NVP_("data", value) );
variant = value;
}
else
@ -80,22 +80,22 @@ namespace cereal
//! Saving for boost::variant
template <class Archive, typename... VariantTypes> inline
void save( Archive & ar, boost::variant<VariantTypes...> const & variant )
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, boost::variant<VariantTypes...> const & variant )
{
int32_t which = variant.which();
ar( _CEREAL_NVP("which", which) );
ar( CEREAL_NVP_("which", which) );
variant_detail::variant_save_visitor<Archive> visitor(ar);
variant.apply_visitor(visitor);
}
//! Loading for boost::variant
template <class Archive, typename... VariantTypes> inline
void load( Archive & ar, boost::variant<VariantTypes...> & variant )
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, boost::variant<VariantTypes...> & variant )
{
typedef typename boost::variant<VariantTypes...>::types types;
int32_t which;
ar( _CEREAL_NVP("which", which) );
ar( CEREAL_NVP_("which", which) );
if(which >= boost::mpl::size<types>::value)
throw Exception("Invalid 'which' selector when deserializing boost::variant");

View file

@ -36,34 +36,34 @@ namespace cereal
{
//! Saving std::chrono::duration
template <class Archive, class R, class P> inline
void save( Archive & ar, std::chrono::duration<R, P> const & dur )
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::chrono::duration<R, P> const & dur )
{
ar( _CEREAL_NVP("count", dur.count()) );
ar( CEREAL_NVP_("count", dur.count()) );
}
//! Loading std::chrono::duration
template <class Archive, class R, class P> inline
void load( Archive & ar, std::chrono::duration<R, P> & dur )
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::chrono::duration<R, P> & dur )
{
R count;
ar( _CEREAL_NVP("count", count) );
ar( CEREAL_NVP_("count", count) );
dur = std::chrono::duration<R, P>{count};
}
//! Saving std::chrono::time_point
template <class Archive, class C, class D> inline
void save( Archive & ar, std::chrono::time_point<C, D> const & dur )
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::chrono::time_point<C, D> const & dur )
{
ar( _CEREAL_NVP("time_since_epoch", dur.time_since_epoch()) );
ar( CEREAL_NVP_("time_since_epoch", dur.time_since_epoch()) );
}
//! Loading std::chrono::time_point
template <class Archive, class C, class D> inline
void load( Archive & ar, std::chrono::time_point<C, D> & dur )
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::chrono::time_point<C, D> & dur )
{
D elapsed;
ar( _CEREAL_NVP("time_since_epoch", elapsed) );
ar( CEREAL_NVP_("time_since_epoch", elapsed) );
dur = std::chrono::time_point<C, D>{elapsed};
}

View file

@ -90,8 +90,9 @@ namespace cereal
//! Saving for enum types
template <class Archive, class T> inline
typename std::enable_if<common_detail::is_enum<T>::value, typename common_detail::is_enum<T>::base_type>::type
save_minimal( Archive const &, T const & t )
typename std::enable_if<common_detail::is_enum<T>::value,
typename common_detail::is_enum<T>::base_type>::type
CEREAL_SAVE_MINIMAL_FUNCTION_NAME( Archive const &, T const & t )
{
return static_cast<typename common_detail::is_enum<T>::base_type>(t);
}
@ -99,7 +100,8 @@ namespace cereal
//! Loading for enum types
template <class Archive, class T> inline
typename std::enable_if<common_detail::is_enum<T>::value, void>::type
load_minimal( Archive const &, T && t, typename common_detail::is_enum<T>::base_type const & value )
CEREAL_LOAD_MINIMAL_FUNCTION_NAME( Archive const &, T && t,
typename common_detail::is_enum<T>::base_type const & value )
{
t = reinterpret_cast<typename common_detail::is_enum<T>::type const &>( value );
}
@ -107,7 +109,7 @@ namespace cereal
//! Serialization for raw pointers
/*! This exists only to throw a static_assert to let users know we don't support raw pointers. */
template <class Archive, class T> inline
void serialize( Archive &, T * & )
void CEREAL_SERIALIZE_FUNCTION_NAME( Archive &, T * & )
{
static_assert(cereal::traits::detail::delay_static_assert<T>::value,
"Cereal does not support serializing raw pointers - please use a smart pointer");
@ -116,7 +118,7 @@ namespace cereal
//! Serialization for C style arrays
template <class Archive, class T> inline
typename std::enable_if<std::is_array<T>::value, void>::type
serialize(Archive & ar, T & array)
CEREAL_SERIALIZE_FUNCTION_NAME(Archive & ar, T & array)
{
common_detail::serializeArray( ar, array,
std::integral_constant<bool, traits::is_output_serializable<BinaryData<T>, Archive>::value &&

View file

@ -36,19 +36,19 @@ namespace cereal
{
//! Serializing (save) for std::complex
template <class Archive, class T> inline
void save( Archive & ar, std::complex<T> const & comp )
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::complex<T> const & comp )
{
ar( _CEREAL_NVP("real", comp.real()),
_CEREAL_NVP("imag", comp.imag()) );
ar( CEREAL_NVP_("real", comp.real()),
CEREAL_NVP_("imag", comp.imag()) );
}
//! Serializing (load) for std::complex
template <class Archive, class T> inline
void load( Archive & ar, std::complex<T> & bits )
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::complex<T> & bits )
{
T real, imag;
ar( _CEREAL_NVP("real", real),
_CEREAL_NVP("imag", imag) );
ar( CEREAL_NVP_("real", real),
CEREAL_NVP_("imag", imag) );
bits = {real, imag};
}
} // namespace cereal

View file

@ -37,7 +37,7 @@ namespace cereal
{
//! Saving for std::deque
template <class Archive, class T, class A> inline
void save( Archive & ar, std::deque<T, A> const & deque )
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::deque<T, A> const & deque )
{
ar( make_size_tag( static_cast<size_type>(deque.size()) ) );
@ -47,7 +47,7 @@ namespace cereal
//! Loading for std::deque
template <class Archive, class T, class A> inline
void load( Archive & ar, std::deque<T, A> & deque )
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::deque<T, A> & deque )
{
size_type size;
ar( make_size_tag( size ) );

View file

@ -37,7 +37,7 @@ namespace cereal
{
//! Saving for std::forward_list all other types
template <class Archive, class T, class A> inline
void save( Archive & ar, std::forward_list<T, A> const & forward_list )
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::forward_list<T, A> const & forward_list )
{
// write the size - note that this is slow because we need to traverse
// the entire list. there are ways we could avoid this but this was chosen
@ -53,7 +53,7 @@ namespace cereal
//! Loading for std::forward_list all other types from
template <class Archive, class T, class A>
void load( Archive & ar, std::forward_list<T, A> & forward_list )
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::forward_list<T, A> & forward_list )
{
size_type size;
ar( make_size_tag( size ) );

View file

@ -37,7 +37,7 @@ namespace cereal
{
//! Saving for std::list
template <class Archive, class T, class A> inline
void save( Archive & ar, std::list<T, A> const & list )
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::list<T, A> const & list )
{
ar( make_size_tag( static_cast<size_type>(list.size()) ) );
@ -47,7 +47,7 @@ namespace cereal
//! Loading for std::list
template <class Archive, class T, class A> inline
void load( Archive & ar, std::list<T, A> & list )
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::list<T, A> & list )
{
size_type size;
ar( make_size_tag( size ) );

View file

@ -76,14 +76,14 @@ namespace cereal
//! Saving for std::map
template <class Archive, class K, class T, class C, class A> inline
void save( Archive & ar, std::map<K, T, C, A> const & map )
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::map<K, T, C, A> const & map )
{
map_detail::save( ar, map );
}
//! Loading for std::map
template <class Archive, class K, class T, class C, class A> inline
void load( Archive & ar, std::map<K, T, C, A> & map )
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::map<K, T, C, A> & map )
{
map_detail::load( ar, map );
}
@ -91,7 +91,7 @@ namespace cereal
//! Saving for std::multimap
/*! @note serialization for this type is not guaranteed to preserve ordering */
template <class Archive, class K, class T, class C, class A> inline
void save( Archive & ar, std::multimap<K, T, C, A> const & multimap )
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::multimap<K, T, C, A> const & multimap )
{
map_detail::save( ar, multimap );
}
@ -99,7 +99,7 @@ namespace cereal
//! Loading for std::multimap
/*! @note serialization for this type is not guaranteed to preserve ordering */
template <class Archive, class K, class T, class C, class A> inline
void load( Archive & ar, std::multimap<K, T, C, A> & multimap )
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::multimap<K, T, C, A> & multimap )
{
map_detail::load( ar, multimap );
}

View file

@ -67,7 +67,7 @@ namespace cereal
construct( ptr )
{ }
inline void serialize( Archive & ar )
inline void CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar )
{
::cereal::detail::Construct<T, Archive>::load_andor_construct( ar, construct );
}
@ -152,7 +152,7 @@ namespace cereal
memory_detail::EnableSharedStateHelper<T> state( ptr );
// let the user perform their initialization
ar( _CEREAL_NVP("data", loadWrapper) );
ar( CEREAL_NVP_("data", loadWrapper) );
}
//! Performs loading and construction for a shared pointer that is NOT derived from
@ -167,59 +167,59 @@ namespace cereal
void loadAndConstructSharedPtr( Archive & ar, T * ptr, std::false_type /* has_shared_from_this */ )
{
memory_detail::LoadAndConstructLoadWrapper<Archive, T> loadWrapper( ptr );
ar( _CEREAL_NVP("data", loadWrapper) );
ar( CEREAL_NVP_("data", loadWrapper) );
}
} // end namespace memory_detail
//! Saving std::shared_ptr for non polymorphic types
template <class Archive, class T> inline
typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
save( Archive & ar, std::shared_ptr<T> const & ptr )
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::shared_ptr<T> const & ptr )
{
ar( _CEREAL_NVP("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
}
//! Loading std::shared_ptr, case when no user load and construct for non polymorphic types
template <class Archive, class T> inline
typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
load( Archive & ar, std::shared_ptr<T> & ptr )
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::shared_ptr<T> & ptr )
{
ar( _CEREAL_NVP("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
}
//! Saving std::weak_ptr for non polymorphic types
template <class Archive, class T> inline
typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
save( Archive & ar, std::weak_ptr<T> const & ptr )
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::weak_ptr<T> const & ptr )
{
auto const sptr = ptr.lock();
ar( _CEREAL_NVP("ptr_wrapper", memory_detail::make_ptr_wrapper( sptr )) );
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( sptr )) );
}
//! Loading std::weak_ptr for non polymorphic types
template <class Archive, class T> inline
typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
load( Archive & ar, std::weak_ptr<T> & ptr )
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::weak_ptr<T> & ptr )
{
std::shared_ptr<T> sptr;
ar( _CEREAL_NVP("ptr_wrapper", memory_detail::make_ptr_wrapper( sptr )) );
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( sptr )) );
ptr = sptr;
}
//! Saving std::unique_ptr for non polymorphic types
template <class Archive, class T, class D> inline
typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
save( Archive & ar, std::unique_ptr<T, D> const & ptr )
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::unique_ptr<T, D> const & ptr )
{
ar( _CEREAL_NVP("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
}
//! Loading std::unique_ptr, case when user provides load_and_construct for non polymorphic types
template <class Archive, class T, class D> inline
typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
load( Archive & ar, std::unique_ptr<T, D> & ptr )
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::unique_ptr<T, D> & ptr )
{
ar( _CEREAL_NVP("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
}
// ######################################################################
@ -228,16 +228,16 @@ namespace cereal
//! Saving std::shared_ptr (wrapper implementation)
/*! @internal */
template <class Archive, class T> inline
void save( Archive & ar, memory_detail::PtrWrapper<std::shared_ptr<T> const &> const & wrapper )
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::shared_ptr<T> const &> const & wrapper )
{
auto & ptr = wrapper.ptr;
uint32_t id = ar.registerSharedPointer( ptr.get() );
ar( _CEREAL_NVP("id", id) );
ar( CEREAL_NVP_("id", id) );
if( id & detail::msb_32bit )
{
ar( _CEREAL_NVP("data", *ptr) );
ar( CEREAL_NVP_("data", *ptr) );
}
}
@ -245,13 +245,13 @@ namespace cereal
/*! @internal */
template <class Archive, class T> inline
typename std::enable_if<traits::has_load_and_construct<T, Archive>::value, void>::type
load( Archive & ar, memory_detail::PtrWrapper<std::shared_ptr<T> &> & wrapper )
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::shared_ptr<T> &> & wrapper )
{
auto & ptr = wrapper.ptr;
uint32_t id;
ar( _CEREAL_NVP("id", id) );
ar( CEREAL_NVP_("id", id) );
if( id & detail::msb_32bit )
{
@ -292,19 +292,19 @@ namespace cereal
/*! @internal */
template <class Archive, class T> inline
typename std::enable_if<!traits::has_load_and_construct<T, Archive>::value, void>::type
load( Archive & ar, memory_detail::PtrWrapper<std::shared_ptr<T> &> & wrapper )
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::shared_ptr<T> &> & wrapper )
{
auto & ptr = wrapper.ptr;
uint32_t id;
ar( _CEREAL_NVP("id", id) );
ar( CEREAL_NVP_("id", id) );
if( id & detail::msb_32bit )
{
ptr.reset( detail::Construct<T, Archive>::load_andor_construct() );
ar.registerSharedPointer( id, ptr );
ar( _CEREAL_NVP("data", *ptr) );
ar( CEREAL_NVP_("data", *ptr) );
}
else
ptr = std::static_pointer_cast<T>(ar.getSharedPointer(id));
@ -313,7 +313,7 @@ namespace cereal
//! Saving std::unique_ptr (wrapper implementation)
/*! @internal */
template <class Archive, class T, class D> inline
void save( Archive & ar, memory_detail::PtrWrapper<std::unique_ptr<T, D> const &> const & wrapper )
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::unique_ptr<T, D> const &> const & wrapper )
{
auto & ptr = wrapper.ptr;
@ -322,11 +322,11 @@ namespace cereal
// 1 == not null
if( !ptr )
ar( _CEREAL_NVP("valid", uint8_t(0)) );
ar( CEREAL_NVP_("valid", uint8_t(0)) );
else
{
ar( _CEREAL_NVP("valid", uint8_t(1)) );
ar( _CEREAL_NVP("data", *ptr) );
ar( CEREAL_NVP_("valid", uint8_t(1)) );
ar( CEREAL_NVP_("data", *ptr) );
}
}
@ -334,10 +334,10 @@ namespace cereal
/*! @internal */
template <class Archive, class T, class D> inline
typename std::enable_if<traits::has_load_and_construct<T, Archive>::value, void>::type
load( Archive & ar, memory_detail::PtrWrapper<std::unique_ptr<T, D> &> & wrapper )
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::unique_ptr<T, D> &> & wrapper )
{
uint8_t isValid;
ar( _CEREAL_NVP("valid", isValid) );
ar( CEREAL_NVP_("valid", isValid) );
auto & ptr = wrapper.ptr;
@ -355,7 +355,7 @@ namespace cereal
memory_detail::LoadAndConstructLoadWrapper<Archive, T> loadWrapper( reinterpret_cast<T *>( stPtr.get() ) );
// Initialize storage
ar( _CEREAL_NVP("data", loadWrapper) );
ar( CEREAL_NVP_("data", loadWrapper) );
// Transfer ownership to correct unique_ptr type
ptr.reset( reinterpret_cast<T *>( stPtr.release() ) );
@ -368,17 +368,17 @@ namespace cereal
/*! @internal */
template <class Archive, class T, class D> inline
typename std::enable_if<!traits::has_load_and_construct<T, Archive>::value, void>::type
load( Archive & ar, memory_detail::PtrWrapper<std::unique_ptr<T, D> &> & wrapper )
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::unique_ptr<T, D> &> & wrapper )
{
uint8_t isValid;
ar( _CEREAL_NVP("valid", isValid) );
ar( CEREAL_NVP_("valid", isValid) );
auto & ptr = wrapper.ptr;
if( isValid )
{
ptr.reset( detail::Construct<T, Archive>::load_andor_construct() );
ar( *ptr );
ar( CEREAL_NVP_( "data", *ptr ) );
}
else
{

View file

@ -44,19 +44,39 @@
#define STATIC_CONSTEXPR static constexpr
#endif
//! Registers a polymorphic type with cereal
/*! Polymorphic types must be registered before pointers
to them can be serialized. This also assumes that
all relevent archives have also previously been
registered. Registration for archives is usually done
in the header file in which they are defined. This means
that type registration needs to happen after specific
archives to be used are included.
//! Registers a derived polymorphic type with cereal
/*! Polymorphic types must be registered before smart
pointers to them can be serialized. Note that base
classes do not need to be registered.
Registering a type lets cereal know how to properly
serialize it when a pointer to a base object is
serialize it when a smart pointer to a base object is
used in conjunction with a derived class.
This assumes that all relevant archives have also
previously been registered. Registration for archives
is usually done in the header file in which they are
defined. This means that type registration needs to
happen after specific archives to be used are included.
It is recommended that type registration be done in
the header file in which the type is declared.
Registration can also be placed in a source file,
but this may require the use of the
CEREAL_REGISTER_DYNAMIC_INIT macro (see below).
Registration may be called repeatedly for the same
type in different translation units to add support
for additional archives if they are not initially
available (included and registered).
When building serialization support as a DLL on
Windows, registration must happen in the header file.
On Linux and Mac things should still work properly
if placed in a source file, but see the above comments
on registering in source files.
Polymorphic support in cereal requires RTTI to be
enabled */
#define CEREAL_REGISTER_TYPE(T) \
@ -85,6 +105,57 @@
} } /* end namespaces */ \
CEREAL_BIND_TO_ARCHIVES(T)
//! Adds a way to force initialization of a translation unit containing
//! calls to CEREAL_REGISTER_TYPE
/*! In C++, dynamic initialization of non-local variables of a translation
unit may be deferred until "the first odr-use of any function or variable
defined in the same translation unit as the variable to be initialized."
Informally, odr-use means that your program takes the address of or binds
a reference directly to an object, which must have a definition.
Since polymorphic type support in cereal relies on the dynamic
initialization of certain global objects happening before
serialization is performed, it is important to ensure that something
from files that call CEREAL_REGISTER_TYPE is odr-used before serialization
occurs, otherwise the registration will never take place. This may often
be the case when serialization is built as a shared library external from
your main program.
This macro, with any name of your choosing, should be placed into the
source file that contains calls to CEREAL_REGISTER_TYPE.
Its counterpart, CEREAL_FORCE_DYNAMIC_INIT, should be placed in its
associated header file such that it is included in the translation units
(source files) in which you want the registration to appear.
@relates CEREAL_FORCE_DYNAMIC_INIT
*/
#define CEREAL_REGISTER_DYNAMIC_INIT(LibName) \
namespace cereal { \
namespace detail { \
void CEREAL_DLL_EXPORT dynamic_init_dummy_##LibName() {} \
} } /* end namespaces */
//! Forces dynamic initialization of polymorphic support in a
//! previously registered source file
/*! @sa CEREAL_REGISTER_DYNAMIC_INIT
See CEREAL_REGISTER_DYNAMIC_INIT for detailed explanation
of how this macro should be used. The name used should
match that for CEREAL_REGISTER_DYNAMIC_INIT. */
#define CEREAL_FORCE_DYNAMIC_INIT(LibName) \
namespace cereal { \
namespace detail { \
void dynamic_init_dummy_##LibName(); \
} /* end detail */ \
namespace { \
void dynamic_init_##LibName() \
{ \
::cereal::detail::dynamic_init_dummy_##LibName(); \
} \
} } /* end namespaces */
#ifdef _MSC_VER
#undef CONSTEXPR
#endif
@ -93,6 +164,14 @@ namespace cereal
{
namespace polymorphic_detail
{
//! Error message used for unregistered polymorphic types
/*! @internal */
#define UNREGISTERED_POLYMORPHIC_EXCEPTION(LoadSave, Name) \
throw cereal::Exception("Trying to " #LoadSave " an unregistered polymorphic type (" + Name + ").\n" \
"Make sure your type is registered with CEREAL_REGISTER_TYPE and that the archive " \
"you are using was included (and registered with CEREAL_REGISTER_ARCHIVE) prior to calling CEREAL_REGISTER_TYPE.\n" \
"If your type is already registered and you still see this error, you may need to use CEREAL_REGISTER_DYNAMIC_INIT.");
//! Get an input binding from the given archive by deserializing the type meta data
/*! @internal */
template<class Archive> inline
@ -110,7 +189,7 @@ namespace cereal
std::string name;
if(nameid & detail::msb_32bit)
{
ar( _CEREAL_NVP("polymorphic_name", name) );
ar( CEREAL_NVP_("polymorphic_name", name) );
ar.registerPolymorphicName(nameid, name);
}
else
@ -120,7 +199,7 @@ namespace cereal
auto binding = bindingMap.find(name);
if(binding == bindingMap.end())
throw cereal::Exception("Trying to load an unregistered polymorphic type (" + name + ")");
UNREGISTERED_POLYMORPHIC_EXCEPTION(load, name)
return binding->second;
}
@ -132,14 +211,14 @@ namespace cereal
default constructors, but on clang/gcc this will return false. So we also need to check for that here.
@internal */
template<class Archive, class T> inline
typename std::enable_if<(std::is_default_constructible<T>::value
typename std::enable_if<(traits::is_default_constructible<T>::value
|| traits::has_load_and_construct<T, Archive>::value)
&& !std::is_abstract<T>::value, bool>::type
serialize_wrapper(Archive & ar, std::shared_ptr<T> & ptr, std::uint32_t const nameid)
{
if(nameid & detail::msb2_32bit)
{
ar( _CEREAL_NVP("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
return true;
}
return false;
@ -150,14 +229,14 @@ namespace cereal
using the derived class serialize function
@internal */
template<class Archive, class T, class D> inline
typename std::enable_if<(std::is_default_constructible<T>::value
typename std::enable_if<(traits::is_default_constructible<T>::value
|| traits::has_load_and_construct<T, Archive>::value)
&& !std::is_abstract<T>::value, bool>::type
serialize_wrapper(Archive & ar, std::unique_ptr<T, D> & ptr, std::uint32_t const nameid)
{
if(nameid & detail::msb2_32bit)
{
ar( _CEREAL_NVP("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
return true;
}
return false;
@ -170,7 +249,7 @@ namespace cereal
this was a polymorphic type serialized by its proper pointer type
@internal */
template<class Archive, class T> inline
typename std::enable_if<(!std::is_default_constructible<T>::value
typename std::enable_if<(!traits::is_default_constructible<T>::value
&& !traits::has_load_and_construct<T, Archive>::value)
|| std::is_abstract<T>::value, bool>::type
serialize_wrapper(Archive &, std::shared_ptr<T> &, std::uint32_t const nameid)
@ -187,7 +266,7 @@ namespace cereal
this was a polymorphic type serialized by its proper pointer type
@internal */
template<class Archive, class T, class D> inline
typename std::enable_if<(!std::is_default_constructible<T>::value
typename std::enable_if<(!traits::is_default_constructible<T>::value
&& !traits::has_load_and_construct<T, Archive>::value)
|| std::is_abstract<T>::value, bool>::type
serialize_wrapper(Archive &, std::unique_ptr<T, D> &, std::uint32_t const nameid)
@ -204,12 +283,12 @@ namespace cereal
//! Saving std::shared_ptr for polymorphic types, abstract
template <class Archive, class T> inline
typename std::enable_if<std::is_polymorphic<T>::value && std::is_abstract<T>::value, void>::type
save( Archive & ar, std::shared_ptr<T> const & ptr )
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::shared_ptr<T> const & ptr )
{
if(!ptr)
{
// same behavior as nullptr in memory implementation
ar( _CEREAL_NVP("polymorphic_id", std::uint32_t(0)) );
ar( CEREAL_NVP_("polymorphic_id", std::uint32_t(0)) );
return;
}
@ -222,7 +301,7 @@ namespace cereal
auto binding = bindingMap.find(std::type_index(ptrinfo));
if(binding == bindingMap.end())
throw cereal::Exception("Trying to save an unregistered polymorphic type (" + cereal::util::demangle(ptrinfo.name()) + ")");
UNREGISTERED_POLYMORPHIC_EXCEPTION(save, cereal::util::demangle(ptrinfo.name()))
binding->second.shared_ptr(&ar, ptr.get());
}
@ -230,12 +309,12 @@ namespace cereal
//! Saving std::shared_ptr for polymorphic types, not abstract
template <class Archive, class T> inline
typename std::enable_if<std::is_polymorphic<T>::value && !std::is_abstract<T>::value, void>::type
save( Archive & ar, std::shared_ptr<T> const & ptr )
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::shared_ptr<T> const & ptr )
{
if(!ptr)
{
// same behavior as nullptr in memory implementation
ar( _CEREAL_NVP("polymorphic_id", std::uint32_t(0)) );
ar( CEREAL_NVP_("polymorphic_id", std::uint32_t(0)) );
return;
}
@ -246,9 +325,9 @@ namespace cereal
{
// The 2nd msb signals that the following pointer does not need to be
// cast with our polymorphic machinery
ar( _CEREAL_NVP("polymorphic_id", detail::msb2_32bit) );
ar( CEREAL_NVP_("polymorphic_id", detail::msb2_32bit) );
ar( _CEREAL_NVP("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
return;
}
@ -257,7 +336,7 @@ namespace cereal
auto binding = bindingMap.find(std::type_index(ptrinfo));
if(binding == bindingMap.end())
throw cereal::Exception("Trying to save an unregistered polymorphic type (" + cereal::util::demangle(ptrinfo.name()) + ")");
UNREGISTERED_POLYMORPHIC_EXCEPTION(save, cereal::util::demangle(ptrinfo.name()))
binding->second.shared_ptr(&ar, ptr.get());
}
@ -265,10 +344,10 @@ namespace cereal
//! Loading std::shared_ptr for polymorphic types
template <class Archive, class T> inline
typename std::enable_if<std::is_polymorphic<T>::value, void>::type
load( Archive & ar, std::shared_ptr<T> & ptr )
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::shared_ptr<T> & ptr )
{
std::uint32_t nameid;
ar( _CEREAL_NVP("polymorphic_id", nameid) );
ar( CEREAL_NVP_("polymorphic_id", nameid) );
// Check to see if we can skip all of this polymorphism business
if(polymorphic_detail::serialize_wrapper(ar, ptr, nameid))
@ -283,31 +362,31 @@ namespace cereal
//! Saving std::weak_ptr for polymorphic types
template <class Archive, class T> inline
typename std::enable_if<std::is_polymorphic<T>::value, void>::type
save( Archive & ar, std::weak_ptr<T> const & ptr )
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::weak_ptr<T> const & ptr )
{
auto const sptr = ptr.lock();
ar( _CEREAL_NVP("locked_ptr", sptr) );
ar( CEREAL_NVP_("locked_ptr", sptr) );
}
//! Loading std::weak_ptr for polymorphic types
template <class Archive, class T> inline
typename std::enable_if<std::is_polymorphic<T>::value, void>::type
load( Archive & ar, std::weak_ptr<T> & ptr )
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::weak_ptr<T> & ptr )
{
std::shared_ptr<T> sptr;
ar( _CEREAL_NVP("locked_ptr", sptr) );
ar( CEREAL_NVP_("locked_ptr", sptr) );
ptr = sptr;
}
//! Saving std::unique_ptr for polymorphic types that are abstract
template <class Archive, class T, class D> inline
typename std::enable_if<std::is_polymorphic<T>::value && std::is_abstract<T>::value, void>::type
save( Archive & ar, std::unique_ptr<T, D> const & ptr )
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::unique_ptr<T, D> const & ptr )
{
if(!ptr)
{
// same behavior as nullptr in memory implementation
ar( _CEREAL_NVP("polymorphic_id", std::uint32_t(0)) );
ar( CEREAL_NVP_("polymorphic_id", std::uint32_t(0)) );
return;
}
@ -320,7 +399,7 @@ namespace cereal
auto binding = bindingMap.find(std::type_index(ptrinfo));
if(binding == bindingMap.end())
throw cereal::Exception("Trying to save an unregistered polymorphic type (" + cereal::util::demangle(ptrinfo.name()) + ")");
UNREGISTERED_POLYMORPHIC_EXCEPTION(save, cereal::util::demangle(ptrinfo.name()))
binding->second.unique_ptr(&ar, ptr.get());
}
@ -328,12 +407,12 @@ namespace cereal
//! Saving std::unique_ptr for polymorphic types, not abstract
template <class Archive, class T, class D> inline
typename std::enable_if<std::is_polymorphic<T>::value && !std::is_abstract<T>::value, void>::type
save( Archive & ar, std::unique_ptr<T, D> const & ptr )
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::unique_ptr<T, D> const & ptr )
{
if(!ptr)
{
// same behavior as nullptr in memory implementation
ar( _CEREAL_NVP("polymorphic_id", std::uint32_t(0)) );
ar( CEREAL_NVP_("polymorphic_id", std::uint32_t(0)) );
return;
}
@ -344,9 +423,9 @@ namespace cereal
{
// The 2nd msb signals that the following pointer does not need to be
// cast with our polymorphic machinery
ar( _CEREAL_NVP("polymorphic_id", detail::msb2_32bit) );
ar( CEREAL_NVP_("polymorphic_id", detail::msb2_32bit) );
ar( _CEREAL_NVP("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
return;
}
@ -355,7 +434,7 @@ namespace cereal
auto binding = bindingMap.find(std::type_index(ptrinfo));
if(binding == bindingMap.end())
throw cereal::Exception("Trying to save an unregistered polymorphic type (" + cereal::util::demangle(ptrinfo.name()) + ")");
UNREGISTERED_POLYMORPHIC_EXCEPTION(save, cereal::util::demangle(ptrinfo.name()))
binding->second.unique_ptr(&ar, ptr.get());
}
@ -363,10 +442,10 @@ namespace cereal
//! Loading std::unique_ptr, case when user provides load_and_construct for polymorphic types
template <class Archive, class T, class D> inline
typename std::enable_if<std::is_polymorphic<T>::value, void>::type
load( Archive & ar, std::unique_ptr<T, D> & ptr )
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::unique_ptr<T, D> & ptr )
{
std::uint32_t nameid;
ar( _CEREAL_NVP("polymorphic_id", nameid) );
ar( CEREAL_NVP_("polymorphic_id", nameid) );
// Check to see if we can skip all of this polymorphism business
if(polymorphic_detail::serialize_wrapper(ar, ptr, nameid))
@ -377,5 +456,7 @@ namespace cereal
binding.unique_ptr(&ar, result);
ptr.reset(static_cast<T*>(result.release()));
}
#undef UNREGISTERED_POLYMORPHIC_EXCEPTION
} // namespace cereal
#endif // CEREAL_TYPES_POLYMORPHIC_HPP_

View file

@ -91,37 +91,37 @@ namespace cereal
//! Saving for std::queue
template <class Archive, class T, class C> inline
void save( Archive & ar, std::queue<T, C> const & queue )
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::queue<T, C> const & queue )
{
ar( _CEREAL_NVP("container", queue_detail::container( queue )) );
ar( CEREAL_NVP_("container", queue_detail::container( queue )) );
}
//! Loading for std::queue
template <class Archive, class T, class C> inline
void load( Archive & ar, std::queue<T, C> & queue )
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::queue<T, C> & queue )
{
C container;
ar( _CEREAL_NVP("container", container) );
ar( CEREAL_NVP_("container", container) );
queue = std::queue<T, C>( std::move( container ) );
}
//! Saving for std::priority_queue
template <class Archive, class T, class C, class Comp> inline
void save( Archive & ar, std::priority_queue<T, C, Comp> const & priority_queue )
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::priority_queue<T, C, Comp> const & priority_queue )
{
ar( _CEREAL_NVP("comparator", queue_detail::comparator( priority_queue )) );
ar( _CEREAL_NVP("container", queue_detail::container( priority_queue )) );
ar( CEREAL_NVP_("comparator", queue_detail::comparator( priority_queue )) );
ar( CEREAL_NVP_("container", queue_detail::container( priority_queue )) );
}
//! Loading for std::priority_queue
template <class Archive, class T, class C, class Comp> inline
void load( Archive & ar, std::priority_queue<T, C, Comp> & priority_queue )
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::priority_queue<T, C, Comp> & priority_queue )
{
Comp comparator;
ar( _CEREAL_NVP("comparator", comparator) );
ar( CEREAL_NVP_("comparator", comparator) );
C container;
ar( _CEREAL_NVP("container", container) );
ar( CEREAL_NVP_("container", container) );
priority_queue = std::priority_queue<T, C, Comp>( comparator, std::move( container ) );
}

View file

@ -73,28 +73,28 @@ namespace cereal
//! Saving for std::set
template <class Archive, class K, class C, class A> inline
void save( Archive & ar, std::set<K, C, A> const & set )
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::set<K, C, A> const & set )
{
set_detail::save( ar, set );
}
//! Loading for std::set
template <class Archive, class K, class C, class A> inline
void load( Archive & ar, std::set<K, C, A> & set )
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::set<K, C, A> & set )
{
set_detail::load( ar, set );
}
//! Saving for std::multiset
template <class Archive, class K, class C, class A> inline
void save( Archive & ar, std::multiset<K, C, A> const & multiset )
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::multiset<K, C, A> const & multiset )
{
set_detail::save( ar, multiset );
}
//! Loading for std::multiset
template <class Archive, class K, class C, class A> inline
void load( Archive & ar, std::multiset<K, C, A> & multiset )
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::multiset<K, C, A> & multiset )
{
set_detail::load( ar, multiset );
}

View file

@ -58,17 +58,17 @@ namespace cereal
//! Saving for std::stack
template <class Archive, class T, class C> inline
void save( Archive & ar, std::stack<T, C> const & stack )
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::stack<T, C> const & stack )
{
ar( _CEREAL_NVP("container", stack_detail::container( stack )) );
ar( CEREAL_NVP_("container", stack_detail::container( stack )) );
}
//! Loading for std::stack
template <class Archive, class T, class C> inline
void load( Archive & ar, std::stack<T, C> & stack )
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::stack<T, C> & stack )
{
C container;
ar( _CEREAL_NVP("container", container) );
ar( CEREAL_NVP_("container", container) );
stack = std::stack<T, C>( std::move( container ) );
}
} // namespace cereal

View file

@ -38,7 +38,7 @@ namespace cereal
//! Serialization for basic_string types, if binary data is supported
template<class Archive, class CharT, class Traits, class Alloc> inline
typename std::enable_if<traits::is_output_serializable<BinaryData<CharT>, Archive>::value, void>::type
save(Archive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
CEREAL_SAVE_FUNCTION_NAME(Archive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
{
// Save number of chars + the data
ar( make_size_tag( static_cast<size_type>(str.size()) ) );
@ -48,7 +48,7 @@ namespace cereal
//! Serialization for basic_string types, if binary data is supported
template<class Archive, class CharT, class Traits, class Alloc> inline
typename std::enable_if<traits::is_input_serializable<BinaryData<CharT>, Archive>::value, void>::type
load(Archive & ar, std::basic_string<CharT, Traits, Alloc> & str)
CEREAL_LOAD_FUNCTION_NAME(Archive & ar, std::basic_string<CharT, Traits, Alloc> & str)
{
size_type size;
ar( make_size_tag( size ) );

View file

@ -37,6 +37,56 @@ namespace cereal
{
namespace tuple_detail
{
//! Creates a c string from a sequence of characters
/*! The c string created will alwas be prefixed by "tuple_element"
Based on code from: http://stackoverflow/a/20973438/710791
@internal */
template<char...Cs>
struct char_seq_to_c_str
{
static const int size = 14;// Size of array for the word: tuple_element
typedef const char (&arr_type)[sizeof...(Cs) + size];
static const char str[sizeof...(Cs) + size];
};
// the word tuple_element plus a number
//! @internal
template<char...Cs>
const char char_seq_to_c_str<Cs...>::str[sizeof...(Cs) + size] =
{'t','u','p','l','e','_','e','l','e','m','e','n','t', Cs..., '\0'};
//! Converts a number into a sequence of characters
/*! @tparam Q The quotient of dividing the original number by 10
@tparam R The remainder of dividing the original number by 10
@tparam C The sequence built so far
@internal */
template <size_t Q, size_t R, char ... C>
struct to_string_impl
{
using type = typename to_string_impl<Q/1, Q%10, R+'0', C...>::type;
};
//! Base case with no quotient
/*! @internal */
template <size_t R, char ... C>
struct to_string_impl<0, R, C...>
{
using type = char_seq_to_c_str<R+'0', C...>;
};
//! Generates a c string for a given index of a tuple
/*! Example use:
@code{cpp}
tuple_element_name<3>::c_str();// returns "tuple_element3"
@endcode
@internal */
template<size_t T>
struct tuple_element_name
{
using type = typename to_string_impl<T/10, T%10>::type;
static const typename type::arr_type c_str(){ return type::str; };
};
// unwinds a tuple to save it
//! @internal
template <size_t Height>
@ -45,8 +95,9 @@ namespace cereal
template <class Archive, class ... Types> inline
static void apply( Archive & ar, std::tuple<Types...> & tuple )
{
ar( _CEREAL_NVP("tuple_element", std::get<Height - 1>( tuple )) );
serialize<Height - 1>::template apply( ar, tuple );
ar( CEREAL_NVP_(tuple_element_name<Height - 1>::c_str(),
std::get<Height - 1>( tuple )) );
}
};
@ -63,7 +114,7 @@ namespace cereal
//! Serializing for std::tuple
template <class Archive, class ... Types> inline
void serialize( Archive & ar, std::tuple<Types...> & tuple )
void CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, std::tuple<Types...> & tuple )
{
tuple_detail::serialize<std::tuple_size<std::tuple<Types...>>::value>::template apply( ar, tuple );
}

View file

@ -70,28 +70,28 @@ namespace cereal
//! Saving for std::unordered_map
template <class Archive, class K, class T, class H, class KE, class A> inline
void save( Archive & ar, std::unordered_map<K, T, H, KE, A> const & unordered_map )
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::unordered_map<K, T, H, KE, A> const & unordered_map )
{
unordered_map_detail::save( ar, unordered_map );
}
//! Loading for std::unordered_map
template <class Archive, class K, class T, class H, class KE, class A> inline
void load( Archive & ar, std::unordered_map<K, T, H, KE, A> & unordered_map )
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::unordered_map<K, T, H, KE, A> & unordered_map )
{
unordered_map_detail::load( ar, unordered_map );
}
//! Saving for std::unordered_multimap
template <class Archive, class K, class T, class H, class KE, class A> inline
void save( Archive & ar, std::unordered_multimap<K, T, H, KE, A> const & unordered_multimap )
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::unordered_multimap<K, T, H, KE, A> const & unordered_multimap )
{
unordered_map_detail::save( ar, unordered_multimap );
}
//! Loading for std::unordered_multimap
template <class Archive, class K, class T, class H, class KE, class A> inline
void load( Archive & ar, std::unordered_multimap<K, T, H, KE, A> & unordered_multimap )
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::unordered_multimap<K, T, H, KE, A> & unordered_multimap )
{
unordered_map_detail::load( ar, unordered_multimap );
}

View file

@ -69,28 +69,28 @@ namespace cereal
//! Saving for std::unordered_set
template <class Archive, class K, class H, class KE, class A> inline
void save( Archive & ar, std::unordered_set<K, H, KE, A> const & unordered_set )
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::unordered_set<K, H, KE, A> const & unordered_set )
{
unordered_set_detail::save( ar, unordered_set );
}
//! Loading for std::unordered_set
template <class Archive, class K, class H, class KE, class A> inline
void load( Archive & ar, std::unordered_set<K, H, KE, A> & unordered_set )
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::unordered_set<K, H, KE, A> & unordered_set )
{
unordered_set_detail::load( ar, unordered_set );
}
//! Saving for std::unordered_multiset
template <class Archive, class K, class H, class KE, class A> inline
void save( Archive & ar, std::unordered_multiset<K, H, KE, A> const & unordered_multiset )
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::unordered_multiset<K, H, KE, A> const & unordered_multiset )
{
unordered_set_detail::save( ar, unordered_multiset );
}
//! Loading for std::unordered_multiset
template <class Archive, class K, class H, class KE, class A> inline
void load( Archive & ar, std::unordered_multiset<K, H, KE, A> & unordered_multiset )
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::unordered_multiset<K, H, KE, A> & unordered_multiset )
{
unordered_set_detail::load( ar, unordered_multiset );
}

View file

@ -37,10 +37,10 @@ namespace cereal
{
//! Serializing for std::pair
template <class Archive, class T1, class T2> inline
void serialize( Archive & ar, std::pair<T1, T2> & pair )
void CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, std::pair<T1, T2> & pair )
{
ar( _CEREAL_NVP("first", pair.first),
_CEREAL_NVP("second", pair.second) );
ar( CEREAL_NVP_("first", pair.first),
CEREAL_NVP_("second", pair.second) );
}
} // namespace cereal

View file

@ -39,7 +39,7 @@ namespace cereal
template <class Archive, class T, class A> inline
typename std::enable_if<traits::is_output_serializable<BinaryData<T>, Archive>::value
&& std::is_arithmetic<T>::value && !std::is_same<T, bool>::value, void>::type
save( Archive & ar, std::vector<T, A> const & vector )
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::vector<T, A> const & vector )
{
ar( make_size_tag( static_cast<size_type>(vector.size()) ) ); // number of elements
ar( binary_data( vector.data(), vector.size() * sizeof(T) ) );
@ -49,7 +49,7 @@ namespace cereal
template <class Archive, class T, class A> inline
typename std::enable_if<traits::is_input_serializable<BinaryData<T>, Archive>::value
&& std::is_arithmetic<T>::value && !std::is_same<T, bool>::value, void>::type
load( Archive & ar, std::vector<T, A> & vector )
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::vector<T, A> & vector )
{
size_type vectorSize;
ar( make_size_tag( vectorSize ) );
@ -62,49 +62,49 @@ namespace cereal
template <class Archive, class T, class A> inline
typename std::enable_if<!traits::is_output_serializable<BinaryData<T>, Archive>::value
|| !std::is_arithmetic<T>::value, void>::type
save( Archive & ar, std::vector<T, A> const & vector )
CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::vector<T, A> const & vector )
{
ar( make_size_tag( static_cast<size_type>(vector.size()) ) ); // number of elements
for( auto it = vector.begin(), end = vector.end(); it != end; ++it )
ar( *it );
for(auto && v : vector)
ar( v );
}
//! Serialization for non-arithmetic vector types
template <class Archive, class T, class A> inline
typename std::enable_if<!traits::is_input_serializable<BinaryData<T>, Archive>::value
|| !std::is_arithmetic<T>::value, void>::type
load( Archive & ar, std::vector<T, A> & vector )
CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::vector<T, A> & vector )
{
size_type size;
ar( make_size_tag( size ) );
vector.resize( static_cast<std::size_t>( size ) );
for( auto it = vector.begin(), end = vector.end(); it != end; ++it )
ar( *it );
for(auto && v : vector)
ar( v );
}
//! Serialization for bool vector types
template <class Archive, class A> inline
void save( Archive & ar, std::vector<bool, A> const & vector )
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::vector<bool, A> const & vector )
{
ar( make_size_tag( static_cast<size_type>(vector.size()) ) ); // number of elements
for( auto it = vector.begin(), end = vector.end(); it != end; ++it )
ar( static_cast<bool>( *it ) );
for(auto && v : vector)
ar( static_cast<bool>(v) );
}
//! Serialization for bool vector types
template <class Archive, class A> inline
void load( Archive & ar, std::vector<bool, A> & vector )
void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::vector<bool, A> & vector )
{
size_type size;
ar( make_size_tag( size ) );
vector.resize( static_cast<std::size_t>( size ) );
for( auto it = vector.begin(), end = vector.end(); it != end; ++it )
for(auto && v : vector)
{
bool b;
ar( b );
*it = b;
v = b;
}
}
} // namespace cereal