Uploading attachment code

This commit is contained in:
noam
2022-06-29 21:50:10 +03:00
parent feefcbcd6b
commit 7e8e141c53
133 changed files with 40692 additions and 62 deletions

381
external/cereal/details/helpers.hpp vendored Normal file
View File

@@ -0,0 +1,381 @@
/*! \file helpers.hpp
\brief Internal helper functionality
\ingroup Internal */
/*
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_DETAILS_HELPERS_HPP_
#define CEREAL_DETAILS_HELPERS_HPP_
#include <type_traits>
#include <cstdint>
#include <utility>
#include <memory>
#include <unordered_map>
#include <stdexcept>
#include <cereal/macros.hpp>
#include <cereal/details/static_object.hpp>
namespace cereal
{
// ######################################################################
//! An exception class thrown when things go wrong at runtime
/*! @ingroup Utility */
struct Exception : public std::runtime_error
{
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. */
using size_type = uint64_t;
// forward decls
class BinaryOutputArchive;
class BinaryInputArchive;
// ######################################################################
namespace detail
{
struct NameValuePairCore {}; //!< Traits struct for NVPs
}
//! For holding name value pairs
/*! This pairs a name (some string) with some value such that an archive
can potentially take advantage of the pairing.
In serialization functions, NameValuePairs are usually created like so:
@code{.cpp}
struct MyStruct
{
int a, b, c, d, e;
template<class Archive>
void serialize(Archive & archive)
{
archive( CEREAL_NVP(a),
CEREAL_NVP(b),
CEREAL_NVP(c),
CEREAL_NVP(d),
CEREAL_NVP(e) );
}
};
@endcode
Alternatively, you can give you data members custom names like so:
@code{.cpp}
struct MyStruct
{
int a, b, my_embarrassing_variable_name, d, e;
template<class Archive>
void serialize(Archive & archive)
{
archive( CEREAL_NVP(a),
CEREAL_NVP(b),
cereal::make_nvp("var", my_embarrassing_variable_name) );
CEREAL_NVP(d),
CEREAL_NVP(e) );
}
};
@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 used by
the Archive:
@code{.cpp}
struct MyStruct
{
int a, b;
template<class Archive>
void serialize(Archive & archive)
{
archive( cereal::make_nvp<Archive>(a),
cereal::make_nvp<Archive>(b) );
}
};
@endcode
This third method is generally only used when providing generic type
support. Users writing their own serialize functions will normally
explicitly control whether they want to use NVPs or not.
@internal */
template <class T>
class NameValuePair : detail::NameValuePairCore
{
private:
// 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" );
NameValuePair & operator=( NameValuePair const & ) = delete;
public:
//! Constructs a new NameValuePair
/*! @param n The name of the pair
@param v The value to pair. Ideally this should be an l-value reference so that
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.
@internal */
NameValuePair( char const * n, T && v ) : name(n), value(std::forward<T>(v)) {}
char const * name;
Type value;
};
//! A specialization of make_nvp<> that simply forwards the value for binary archives
/*! @relates NameValuePair
@internal */
template<class Archive, class T> inline
typename
std::enable_if<std::is_same<Archive, ::cereal::BinaryInputArchive>::value ||
std::is_same<Archive, ::cereal::BinaryOutputArchive>::value,
T && >::type
make_nvp( const char *, T && value )
{
return std::forward<T>(value);
}
//! A specialization of make_nvp<> that actually creates an nvp for non-binary archives
/*! @relates NameValuePair
@internal */
template<class Archive, class T> inline
typename
std::enable_if<!std::is_same<Archive, ::cereal::BinaryInputArchive>::value &&
!std::is_same<Archive, ::cereal::BinaryOutputArchive>::value,
NameValuePair<T> >::type
make_nvp( const char * name, T && value)
{
return {name, std::forward<T>(value)};
}
//! Convenience for creating a templated NVP
/*! For use in internal generic typing functions which have an
Archive type declared
@internal */
#define CEREAL_NVP_(name, value) ::cereal::make_nvp<Archive>(name, value)
// ######################################################################
//! A wrapper around data that can be serialized in a binary fashion
/*! This class is used to demarcate data that can safely be serialized
as a binary chunk of data. Individual archives can then choose how
best represent this during serialization.
@internal */
template <class T>
struct BinaryData
{
//! Internally store the pointer as a void *, keeping const if created with
//! a const pointer
using PT = typename std::conditional<std::is_const<typename std::remove_pointer<T>::type>::value,
const void *,
void *>::type;
BinaryData( T && d, uint64_t s ) : data(std::forward<T>(d)), size(s) {}
PT data; //!< pointer to beginning of data
uint64_t size; //!< size in bytes
};
// ######################################################################
namespace detail
{
// base classes for type checking
/* 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
{
public:
OutputArchiveBase() = default;
OutputArchiveBase( OutputArchiveBase && ) CEREAL_NOEXCEPT {}
OutputArchiveBase & operator=( OutputArchiveBase && ) CEREAL_NOEXCEPT { return *this; }
virtual ~OutputArchiveBase() CEREAL_NOEXCEPT = default;
private:
virtual void rtti() {}
};
class InputArchiveBase
{
public:
InputArchiveBase() = default;
InputArchiveBase( InputArchiveBase && ) CEREAL_NOEXCEPT {}
InputArchiveBase & operator=( InputArchiveBase && ) CEREAL_NOEXCEPT { return *this; }
virtual ~InputArchiveBase() CEREAL_NOEXCEPT = default;
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 msb2_32bit = 0x40000000;
}
// ######################################################################
//! A wrapper around size metadata
/*! This class provides a way for archives to have more flexibility over how
they choose to serialize size metadata for containers. For some archive
types, the size may be implicitly encoded in the output (e.g. JSON) and
not need an explicit entry. Specializing serialize or load/save for
your archive and SizeTags allows you to choose what happens.
@internal */
template <class T>
class SizeTag
{
private:
// 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;
SizeTag & operator=( SizeTag const & ) = delete;
public:
SizeTag( T && sz ) : size(std::forward<T>(sz)) {}
Type size;
};
// ######################################################################
//! A wrapper around a key and value for serializing data into maps.
/*! This class just provides a grouping of keys and values into a struct for
human readable archives. For example, XML archives will use this wrapper
to write maps like so:
@code{.xml}
<mymap>
<item0>
<key>MyFirstKey</key>
<value>MyFirstValue</value>
</item0>
<item1>
<key>MySecondKey</key>
<value>MySecondValue</value>
</item1>
</mymap>
@endcode
\sa make_map_item
@internal */
template <class Key, class Value>
struct MapItem
{
using KeyType = typename std::conditional<
std::is_lvalue_reference<Key>::value,
Key,
typename std::decay<Key>::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(std::forward<Key>(key_)), value(std::forward<Value>(value_)) {}
MapItem & operator=( MapItem const & ) = delete;
KeyType key;
ValueType value;
//! Serialize the MapItem with the NVPs "key" and "value"
template <class Archive> inline
void CEREAL_SERIALIZE_FUNCTION_NAME(Archive & archive)
{
archive( make_nvp<Archive>("key", key),
make_nvp<Archive>("value", value) );
}
};
//! Create a MapItem so that human readable archives will group keys and values together
/*! @internal
@relates MapItem */
template <class KeyType, class ValueType> inline
MapItem<KeyType, ValueType> make_map_item(KeyType && key, ValueType && value)
{
return {std::forward<KeyType>(key), std::forward<ValueType>(value)};
}
namespace detail
{
//! 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, 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
};
//! Holds all registered version information
struct Versions
{
std::unordered_map<std::size_t, std::uint32_t> mapping;
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
#endif // CEREAL_DETAILS_HELPERS_HPP_

View File

@@ -0,0 +1,688 @@
/*! \file polymorphic_impl.hpp
\brief Internal polymorphism support
\ingroup Internal */
/*
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.
*/
/* This code is heavily inspired by the boost serialization implementation by the following authors
(C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
Use, modification and distribution is subject to the Boost Software
License, Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt)
See http://www.boost.org for updates, documentation, and revision history.
(C) Copyright 2006 David Abrahams - http://www.boost.org.
See /boost/serialization/export.hpp, /boost/archive/detail/register_archive.hpp,
and /boost/serialization/void_cast.hpp for their implementation. Additional details
found in other files split across serialization and archive.
*/
#ifndef CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_
#define CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_
#include <cereal/details/polymorphic_impl_fwd.hpp>
#include <cereal/details/static_object.hpp>
#include <cereal/types/memory.hpp>
#include <cereal/types/string.hpp>
#include <functional>
#include <typeindex>
#include <map>
//! Binds a polymorhic type to all registered archives
/*! 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(...) \
namespace cereal { \
namespace detail { \
template<> \
struct init_binding<__VA_ARGS__> { \
static bind_to_archives<__VA_ARGS__> const & b; \
static void unused() { (void)b; } \
}; \
bind_to_archives<__VA_ARGS__> const & init_binding<__VA_ARGS__>::b = \
::cereal::detail::StaticObject< \
bind_to_archives<__VA_ARGS__> \
>::getInstance().bind(); \
}} /* end namespaces */
namespace cereal
{
/* Polymorphic casting support */
namespace detail
{
//! Base type for polymorphic void casting
/*! Contains functions for casting between registered base and derived types.
This is necessary so that cereal can properly cast between polymorphic types
even though void pointers are used, which normally have no type information.
Runtime type information is used instead to index a compile-time made mapping
that can perform the proper cast. In the case of multiple levels of inheritance,
cereal will attempt to find the shortest path by using registered relationships to
perform the cast.
This class will be allocated as a StaticObject and only referenced by pointer,
allowing a templated derived version of it to define strongly typed functions
that cast between registered base and derived types. */
struct PolymorphicCaster
{
PolymorphicCaster() = default;
PolymorphicCaster( const PolymorphicCaster & ) = default;
PolymorphicCaster & operator=( const PolymorphicCaster & ) = default;
PolymorphicCaster( PolymorphicCaster && ) CEREAL_NOEXCEPT {}
PolymorphicCaster & operator=( PolymorphicCaster && ) CEREAL_NOEXCEPT { return *this; }
virtual ~PolymorphicCaster() CEREAL_NOEXCEPT = default;
//! Downcasts to the proper derived type
virtual void const * downcast( void const * const ptr ) const = 0;
//! Upcast to proper base type
virtual void * upcast( void * const ptr ) const = 0;
//! Upcast to proper base type, shared_ptr version
virtual std::shared_ptr<void> upcast( std::shared_ptr<void> const & ptr ) const = 0;
};
//! Holds registered mappings between base and derived types for casting
/*! This will be allocated as a StaticObject and holds a map containing
all registered mappings between base and derived types. */
struct PolymorphicCasters
{
//! Maps from base type index to a map from derived type index to caster
std::map<std::type_index, std::map<std::type_index, std::vector<PolymorphicCaster const*>>> map;
//! Error message used for unregistered polymorphic casts
#define UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(LoadSave) \
throw cereal::Exception("Trying to " #LoadSave " a registered polymorphic type with an unregistered polymorphic cast.\n" \
"Could not find a path to a base class (" + util::demangle(baseInfo.name()) + ") for type: " + ::cereal::util::demangledName<Derived>() + "\n" \
"Make sure you either serialize the base class at some point via cereal::base_class or cereal::virtual_base_class.\n" \
"Alternatively, manually register the association with CEREAL_REGISTER_POLYMORPHIC_RELATION.");
//! Checks if the mapping object that can perform the upcast or downcast
/*! Uses the type index from the base and derived class to find the matching
registered caster. If no matching caster exists, returns false. */
static bool exists( std::type_index const & baseIndex, std::type_index const & derivedIndex )
{
// First phase of lookup - match base type index
auto const & baseMap = StaticObject<PolymorphicCasters>::getInstance().map;
auto baseIter = baseMap.find( baseIndex );
if (baseIter == baseMap.end())
return false;
// Second phase - find a match from base to derived
auto & derivedMap = baseIter->second;
auto derivedIter = derivedMap.find( derivedIndex );
if (derivedIter == derivedMap.end())
return false;
return true;
}
//! Gets the mapping object that can perform the upcast or downcast
/*! Uses the type index from the base and derived class to find the matching
registered caster. If no matching caster exists, calls the exception function.
The returned PolymorphicCaster is capable of upcasting or downcasting between the two types. */
template <class F> inline
static std::vector<PolymorphicCaster const *> const & lookup( std::type_index const & baseIndex, std::type_index const & derivedIndex, F && exceptionFunc )
{
// First phase of lookup - match base type index
auto const & baseMap = StaticObject<PolymorphicCasters>::getInstance().map;
auto baseIter = baseMap.find( baseIndex );
if( baseIter == baseMap.end() )
exceptionFunc();
// Second phase - find a match from base to derived
auto & derivedMap = baseIter->second;
auto derivedIter = derivedMap.find( derivedIndex );
if( derivedIter == derivedMap.end() )
exceptionFunc();
return derivedIter->second;
}
//! Performs a downcast to the derived type using a registered mapping
template <class Derived> inline
static const Derived * downcast( const void * dptr, std::type_info const & baseInfo )
{
auto const & mapping = lookup( baseInfo, typeid(Derived), [&](){ UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(save) } );
for( auto const * map : mapping )
dptr = map->downcast( dptr );
return static_cast<Derived const *>( dptr );
}
//! Performs an upcast to the registered base type using the given a derived type
/*! The return is untyped because the final casting to the base type must happen in the polymorphic
serialization function, where the type is known at compile time */
template <class Derived> inline
static void * upcast( Derived * const dptr, std::type_info const & baseInfo )
{
auto const & mapping = lookup( baseInfo, typeid(Derived), [&](){ UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(load) } );
void * uptr = dptr;
for( auto const * map : mapping )
uptr = map->upcast( uptr );
return uptr;
}
//! Upcasts for shared pointers
template <class Derived> inline
static std::shared_ptr<void> upcast( std::shared_ptr<Derived> const & dptr, std::type_info const & baseInfo )
{
auto const & mapping = lookup( baseInfo, typeid(Derived), [&](){ UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(load) } );
std::shared_ptr<void> uptr = dptr;
for( auto const * map : mapping )
uptr = map->upcast( uptr );
return uptr;
}
#undef UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION
};
//! Strongly typed derivation of PolymorphicCaster
template <class Base, class Derived>
struct PolymorphicVirtualCaster : PolymorphicCaster
{
//! Inserts an entry in the polymorphic casting map for this pairing
/*! Creates an explicit mapping between Base and Derived in both upwards and
downwards directions, allowing void pointers to either to be properly cast
assuming dynamic type information is available */
PolymorphicVirtualCaster()
{
const auto lock = StaticObject<PolymorphicCasters>::lock();
auto & baseMap = StaticObject<PolymorphicCasters>::getInstance().map;
auto baseKey = std::type_index(typeid(Base));
auto lb = baseMap.lower_bound(baseKey);
{
auto & derivedMap = baseMap.insert( lb, {baseKey, {}} )->second;
auto derivedKey = std::type_index(typeid(Derived));
auto lbd = derivedMap.lower_bound(derivedKey);
auto & derivedVec = derivedMap.insert( lbd, { std::move(derivedKey), {}} )->second;
derivedVec.push_back( this );
}
// Find all chainable unregistered relations
std::map<std::type_index, std::pair<std::type_index, std::vector<PolymorphicCaster const *>>> unregisteredRelations;
{
auto checkRelation = [](std::type_index const & baseInfo, std::type_index const & derivedInfo)
{
const bool exists = PolymorphicCasters::exists( baseInfo, derivedInfo );
return std::make_pair( exists, exists ? PolymorphicCasters::lookup( baseInfo, derivedInfo, [](){} ) :
std::vector<PolymorphicCaster const *>{} );
};
for( auto baseIt : baseMap )
for( auto derivedIt : baseIt.second )
{
for( auto otherBaseIt : baseMap )
{
if( baseIt.first == otherBaseIt.first ) // only interested in chained relations
continue;
// Check if there exists a mapping otherBase -> base -> derived that is shorter than
// any existing otherBase -> derived direct mapping
auto otherBaseItToDerived = checkRelation( otherBaseIt.first, derivedIt.first );
auto baseToDerived = checkRelation( baseIt.first, derivedIt.first );
auto otherBaseToBase = checkRelation( otherBaseIt.first, baseIt.first );
const size_t newLength = otherBaseToBase.second.size() + baseToDerived.second.size();
const bool isShorterOrFirstPath = !otherBaseItToDerived.first || (newLength < derivedIt.second.size());
if( isShorterOrFirstPath &&
baseToDerived.first &&
otherBaseToBase.first )
{
std::vector<PolymorphicCaster const *> path = otherBaseToBase.second;
path.insert( path.end(), baseToDerived.second.begin(), baseToDerived.second.end() );
#ifdef CEREAL_OLDER_GCC
unregisteredRelations.insert( std::make_pair(otherBaseIt.first,
std::pair<std::type_index, std::vector<PolymorphicCaster const *>>{derivedIt.first, std::move(path)}) );
#else // NOT CEREAL_OLDER_GCC
unregisteredRelations.emplace( otherBaseIt.first,
std::pair<std::type_index, std::vector<PolymorphicCaster const *>>{derivedIt.first, std::move(path)} );
#endif // NOT CEREAL_OLDER_GCC
}
} // end otherBaseIt
} // end derivedIt
} // end chain lookup
// Insert chained relations
for( auto it : unregisteredRelations )
{
auto & derivedMap = baseMap.find( it.first )->second;
derivedMap[it.second.first] = it.second.second;
}
}
//! Performs the proper downcast with the templated types
void const * downcast( void const * const ptr ) const override
{
return dynamic_cast<Derived const*>( static_cast<Base const*>( ptr ) );
}
//! Performs the proper upcast with the templated types
void * upcast( void * const ptr ) const override
{
return dynamic_cast<Base*>( static_cast<Derived*>( ptr ) );
}
//! Performs the proper upcast with the templated types (shared_ptr version)
std::shared_ptr<void> upcast( std::shared_ptr<void> const & ptr ) const override
{
return std::dynamic_pointer_cast<Base>( std::static_pointer_cast<Derived>( ptr ) );
}
};
//! Registers a polymorphic casting relation between a Base and Derived type
/*! Registering a relation allows cereal to properly cast between the two types
given runtime type information and void pointers.
Registration happens automatically via cereal::base_class and cereal::virtual_base_class
instantiations. For cases where neither is called, see the CEREAL_REGISTER_POLYMORPHIC_RELATION
macro */
template <class Base, class Derived>
struct RegisterPolymorphicCaster
{
static PolymorphicCaster const * bind( std::true_type /* is_polymorphic<Base> */)
{
return &StaticObject<PolymorphicVirtualCaster<Base, Derived>>::getInstance();
}
static PolymorphicCaster const * bind( std::false_type /* is_polymorphic<Base> */ )
{ return nullptr; }
//! Performs registration (binding) between Base and Derived
/*! If the type is not polymorphic, nothing will happen */
static PolymorphicCaster const * bind()
{ return bind( typename std::is_polymorphic<Base>::type() ); }
};
}
/* General polymorphism support */
namespace detail
{
//! Binds a compile time type with a user defined string
template <class T>
struct binding_name {};
//! A structure holding a map from type_indices to output serializer functions
/*! A static object of this map should be created for each registered archive
type, containing entries for every registered type that describe how to
properly cast the type to its real type in polymorphic scenarios for
shared_ptr, weak_ptr, and unique_ptr. */
template <class Archive>
struct OutputBindingMap
{
//! A serializer function
/*! Serializer functions return nothing and take an archive as
their first parameter (will be cast properly inside the function,
a pointer to actual data (contents of smart_ptr's get() function)
as their second parameter, and the type info of the owning smart_ptr
as their final parameter */
typedef std::function<void(void*, void const *, std::type_info const &)> Serializer;
//! Struct containing the serializer functions for all pointer types
struct Serializers
{
Serializer shared_ptr, //!< Serializer function for shared/weak pointers
unique_ptr; //!< Serializer function for unique pointers
};
//! A map of serializers for pointers of all registered types
std::map<std::type_index, Serializers> map;
};
//! An empty noop deleter
template<class T> struct EmptyDeleter { void operator()(T *) const {} };
//! A structure holding a map from type name strings to input serializer functions
/*! A static object of this map should be created for each registered archive
type, containing entries for every registered type that describe how to
properly cast the type to its real type in polymorphic scenarios for
shared_ptr, weak_ptr, and unique_ptr. */
template <class Archive>
struct InputBindingMap
{
//! Shared ptr serializer function
/*! Serializer functions return nothing and take an archive as
their first parameter (will be cast properly inside the function,
a shared_ptr (or unique_ptr for the unique case) of any base
type, and the type id of said base type as the third parameter.
Internally it will properly be loaded and cast to the correct type. */
typedef std::function<void(void*, std::shared_ptr<void> &, std::type_info const &)> SharedSerializer;
//! Unique ptr serializer function
typedef std::function<void(void*, std::unique_ptr<void, EmptyDeleter<void>> &, std::type_info const &)> UniqueSerializer;
//! Struct containing the serializer functions for all pointer types
struct Serializers
{
SharedSerializer shared_ptr; //!< Serializer function for shared/weak pointers
UniqueSerializer unique_ptr; //!< Serializer function for unique pointers
};
//! A map of serializers for pointers of all registered types
std::map<std::string, Serializers> map;
};
// forward decls for archives from cereal.hpp
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
archive has already been registered. When this struct is created,
it will insert (at run time) an entry into a map that properly handles
casting for serializing polymorphic objects */
template <class Archive, class T> struct InputBindingCreator
{
//! Initialize the binding
InputBindingCreator()
{
auto & map = StaticObject<InputBindingMap<Archive>>::getInstance().map;
auto lock = StaticObject<InputBindingMap<Archive>>::lock();
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 =
[](void * arptr, std::shared_ptr<void> & dptr, std::type_info const & baseInfo)
{
Archive & ar = *static_cast<Archive*>(arptr);
std::shared_ptr<T> ptr;
ar( CEREAL_NVP_("ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
dptr = PolymorphicCasters::template upcast<T>( ptr, baseInfo );
};
serializers.unique_ptr =
[](void * arptr, std::unique_ptr<void, EmptyDeleter<void>> & dptr, std::type_info const & baseInfo)
{
Archive & ar = *static_cast<Archive*>(arptr);
std::unique_ptr<T> ptr;
ar( CEREAL_NVP_("ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
dptr.reset( PolymorphicCasters::template upcast<T>( ptr.release(), baseInfo ));
};
map.insert( lb, { std::move(key), std::move(serializers) } );
}
};
//! Creates a binding (map entry) between an output archive type and a polymorphic type
/*! Bindings are made when types are registered, assuming that at least one
archive has already been registered. When this struct is created,
it will insert (at run time) an entry into a map that properly handles
casting for serializing polymorphic objects */
template <class Archive, class T> struct OutputBindingCreator
{
//! Writes appropriate metadata to the archive for this polymorphic type
static void writeMetadata(Archive & ar)
{
// Register the polymorphic type name with the archive, and get the id
char const * name = binding_name<T>::name();
std::uint32_t id = ar.registerPolymorphicType(name);
// Serialize the 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) );
}
}
//! Holds a properly typed shared_ptr to the polymorphic type
class PolymorphicSharedPointerWrapper
{
public:
/*! Wrap a raw polymorphic pointer in a shared_ptr to its true type
The wrapped pointer will not be responsible for ownership of the held pointer
so it will not attempt to destroy it; instead the refcount of the wrapped
pointer will be tied to a fake 'ownership pointer' that will do nothing
when it ultimately goes out of scope.
The main reason for doing this, other than not to destroy the true object
with our wrapper pointer, is to avoid meddling with the internal reference
count in a polymorphic type that inherits from std::enable_shared_from_this.
@param dptr A void pointer to the contents of the shared_ptr to serialize */
PolymorphicSharedPointerWrapper( T const * dptr ) : refCount(), wrappedPtr( refCount, dptr )
{ }
//! Get the wrapped shared_ptr */
inline std::shared_ptr<T const> const & operator()() const { return wrappedPtr; }
private:
std::shared_ptr<void> refCount; //!< The ownership pointer
std::shared_ptr<T const> wrappedPtr; //!< The wrapped pointer
};
//! Does the actual work of saving a polymorphic shared_ptr
/*! This function will properly create a shared_ptr from the void * that is passed in
before passing it to the archive for serialization.
In addition, this will also preserve the state of any internal enable_shared_from_this mechanisms
@param ar The archive to serialize to
@param dptr Pointer to the actual data held by the shared_ptr */
static inline void savePolymorphicSharedPtr( Archive & ar, T const * dptr, std::true_type /* has_shared_from_this */ )
{
::cereal::memory_detail::EnableSharedStateHelper<T> state( const_cast<T *>(dptr) );
PolymorphicSharedPointerWrapper psptr( dptr );
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( psptr() ) ) );
}
//! Does the actual work of saving a polymorphic shared_ptr
/*! This function will properly create a shared_ptr from the void * that is passed in
before passing it to the archive for serialization.
This version is for types that do not inherit from std::enable_shared_from_this.
@param ar The archive to serialize to
@param dptr Pointer to the actual data held by the shared_ptr */
static inline void savePolymorphicSharedPtr( Archive & ar, T const * dptr, std::false_type /* has_shared_from_this */ )
{
PolymorphicSharedPointerWrapper psptr( dptr );
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 =
[&](void * arptr, void const * dptr, std::type_info const & baseInfo)
{
Archive & ar = *static_cast<Archive*>(arptr);
writeMetadata(ar);
auto ptr = PolymorphicCasters::template downcast<T>( dptr, baseInfo );
#ifdef _MSC_VER
savePolymorphicSharedPtr( ar, ptr, ::cereal::traits::has_shared_from_this<T>::type() ); // MSVC doesn't like typename here
#else // not _MSC_VER
savePolymorphicSharedPtr( ar, ptr, typename ::cereal::traits::has_shared_from_this<T>::type() );
#endif // _MSC_VER
};
serializers.unique_ptr =
[&](void * arptr, void const * dptr, std::type_info const & baseInfo)
{
Archive & ar = *static_cast<Archive*>(arptr);
writeMetadata(ar);
std::unique_ptr<T const, EmptyDeleter<T const>> const ptr( PolymorphicCasters::template downcast<T>( dptr, baseInfo ) );
ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
};
map.insert( { std::move(key), std::move(serializers) } );
}
};
//! Used to help out argument dependent lookup for finding potential overloads
//! 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
{
static const InputBindingCreator<Archive, T> &
load(std::true_type)
{
return cereal::detail::StaticObject<InputBindingCreator<Archive, T>>::getInstance();
}
static const OutputBindingCreator<Archive, T> &
save(std::true_type)
{
return cereal::detail::StaticObject<OutputBindingCreator<Archive, T>>::getInstance();
}
inline static void load(std::false_type) {}
inline static void save(std::false_type) {}
};
//! When specialized, causes the compiler to instantiate its parameter
template <void(*)()>
struct instantiate_function {};
/*! This struct is used as the return type of instantiate_polymorphic_binding
for specific Archive types. When the compiler looks for overloads of
instantiate_polymorphic_binding, it will be forced to instantiate this
struct during overload resolution, even though it will not be part of a valid
overload */
template <class Archive, class T>
struct polymorphic_serialization_support
{
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
//! Creates the appropriate bindings depending on whether the archive supports
//! saving or loading
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 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
};
// instantiate implementation
template <class Archive, class T>
CEREAL_DLL_EXPORT void polymorphic_serialization_support<Archive,T>::instantiate()
{
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::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
/*! Archives need to be registered prior to this struct being instantiated via
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, 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, Tag{}, adl_tag{});
}
//! Binding for abstract types
void bind(std::true_type) const
{ }
//! Binds the type T to all registered archives
/*! If T is abstract, we will not serialize it and thus
do not need to make a binding */
bind_to_archives const & bind() const
{
static_assert( std::is_polymorphic<T>::value,
"Attempting to register non polymorphic type" );
bind( std::is_abstract<T>() );
return *this;
}
};
//! Used to hide the static object used to bind T to registered archives
template <class T, class Tag = polymorphic_binding_tag>
struct init_binding;
//! Base case overload for instantiation
/*! This will end up always being the best overload due to the second
parameter always being passed as an int. All other overloads will
accept pointers to archive types and have lower precedence than int.
Since the compiler needs to check all possible overloads, the
other overloads created via CEREAL_REGISTER_ARCHIVE, which will have
lower precedence due to requring a conversion from int to (Archive*),
will cause their return types to be instantiated through the static object
mechanisms even though they are never called.
See the documentation for the other functions to try and understand this */
template <class T, typename BindingTag>
void instantiate_polymorphic_binding( T*, int, BindingTag, adl_tag ) {}
} // namespace detail
} // namespace cereal
#endif // CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_

View File

@@ -0,0 +1,65 @@
/*! \file polymorphic_impl_fwd.hpp
\brief Internal polymorphism support forward declarations
\ingroup Internal */
/*
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.
*/
/* This code is heavily inspired by the boost serialization implementation by the following authors
(C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
Use, modification and distribution is subject to the Boost Software
License, Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt)
See http://www.boost.org for updates, documentation, and revision history.
(C) Copyright 2006 David Abrahams - http://www.boost.org.
See /boost/serialization/export.hpp and /boost/archive/detail/register_archive.hpp for their
implementation.
*/
#ifndef CEREAL_DETAILS_POLYMORPHIC_IMPL_FWD_HPP_
#define CEREAL_DETAILS_POLYMORPHIC_IMPL_FWD_HPP_
namespace cereal
{
namespace detail
{
//! Forward declaration, see polymorphic_impl.hpp for more information
template <class Base, class Derived>
struct RegisterPolymorphicCaster;
//! Forward declaration, see polymorphic_impl.hpp for more information
struct PolymorphicCasters;
//! Forward declaration, see polymorphic_impl.hpp for more information
template <class Base, class Derived>
struct PolymorphicRelation;
} // namespace detail
} // namespace cereal
#endif // CEREAL_DETAILS_POLYMORPHIC_IMPL_FWD_HPP_

View File

@@ -0,0 +1,132 @@
/*! \file static_object.hpp
\brief Internal polymorphism static object support
\ingroup Internal */
/*
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_DETAILS_STATIC_OBJECT_HPP_
#define CEREAL_DETAILS_STATIC_OBJECT_HPP_
#include <cereal/macros.hpp>
#if CEREAL_THREAD_SAFE
#include <mutex>
#endif
//! 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
{
namespace detail
{
//! A static, pre-execution object
/*! 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 CEREAL_DLL_EXPORT StaticObject
{
private:
//! Forces instantiation at pre-execution time
static void instantiate( T const & ) {}
static T & create()
{
static T t;
instantiate(instance);
return t;
}
StaticObject( StaticObject const & /*other*/ ) {}
public:
static T & getInstance()
{
return create();
}
//! A class that acts like std::lock_guard
class LockGuard
{
#if CEREAL_THREAD_SAFE
public:
LockGuard(std::mutex & m) : lock(m) {}
private:
std::unique_lock<std::mutex> lock;
#else
public:
~LockGuard() CEREAL_NOEXCEPT {} // prevents variable not used
#endif
};
//! Attempts to lock this static object for the current scope
/*! @note This function is a no-op if cereal is not compiled with
thread safety enabled (CEREAL_THREAD_SAFE = 1).
This function returns an object that holds a lock for
this StaticObject that will release its lock upon destruction. This
call will block until the lock is available. */
static LockGuard lock()
{
#if CEREAL_THREAD_SAFE
return LockGuard{instanceMutex};
#else
return LockGuard{};
#endif
}
private:
static T & instance;
#if CEREAL_THREAD_SAFE
static std::mutex instanceMutex;
#endif
};
template <class T> T & StaticObject<T>::instance = StaticObject<T>::create();
#if CEREAL_THREAD_SAFE
template <class T> std::mutex StaticObject<T>::instanceMutex;
#endif
} // namespace detail
} // namespace cereal
#endif // CEREAL_DETAILS_STATIC_OBJECT_HPP_

1389
external/cereal/details/traits.hpp vendored Normal file

File diff suppressed because it is too large Load Diff

84
external/cereal/details/util.hpp vendored Normal file
View File

@@ -0,0 +1,84 @@
/*! \file util.hpp
\brief Internal misc utilities
\ingroup Internal */
/*
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_DETAILS_UTIL_HPP_
#define CEREAL_DETAILS_UTIL_HPP_
#include <typeinfo>
#include <string>
#ifdef _MSC_VER
namespace cereal
{
namespace util
{
//! Demangles the type encoded in a string
/*! @internal */
inline std::string demangle( std::string const & name )
{ return name; }
//! Gets the demangled name of a type
/*! @internal */
template <class T> inline
std::string demangledName()
{ return typeid( T ).name(); }
} // namespace util
} // namespace cereal
#else // clang or gcc
#include <cxxabi.h>
#include <cstdlib>
namespace cereal
{
namespace util
{
//! Demangles the type encoded in a string
/*! @internal */
inline std::string demangle(std::string mangledName)
{
int status = 0;
char *demangledName = nullptr;
std::size_t len;
demangledName = abi::__cxa_demangle(mangledName.c_str(), 0, &len, &status);
std::string retName(demangledName);
free(demangledName);
return retName;
}
//! Gets the demangled name of a type
/*! @internal */
template<class T> inline
std::string demangledName()
{ return demangle(typeid(T).name()); }
}
} // namespace cereal
#endif // clang or gcc branch of _MSC_VER
#endif // CEREAL_DETAILS_UTIL_HPP_