git repos / blockattack-game

blame: source/code/Libs/include/cereal/details/polymorphic_impl.hpp

normal view · raw

7a956470 sago007 2016-02-14 17:09 1
/*! \file polymorphic_impl.hpp
7a956470 sago007 2016-02-14 17:09 2
    \brief Internal polymorphism support
7a956470 sago007 2016-02-14 17:09 3
    \ingroup Internal */
7a956470 sago007 2016-02-14 17:09 4
/*
7a956470 sago007 2016-02-14 17:09 5
  Copyright (c) 2014, Randolph Voorhies, Shane Grant
7a956470 sago007 2016-02-14 17:09 6
  All rights reserved.
7a956470 sago007 2016-02-14 17:09 7
7a956470 sago007 2016-02-14 17:09 8
  Redistribution and use in source and binary forms, with or without
7a956470 sago007 2016-02-14 17:09 9
  modification, are permitted provided that the following conditions are met:
7a956470 sago007 2016-02-14 17:09 10
      * Redistributions of source code must retain the above copyright
7a956470 sago007 2016-02-14 17:09 11
        notice, this list of conditions and the following disclaimer.
7a956470 sago007 2016-02-14 17:09 12
      * Redistributions in binary form must reproduce the above copyright
7a956470 sago007 2016-02-14 17:09 13
        notice, this list of conditions and the following disclaimer in the
7a956470 sago007 2016-02-14 17:09 14
        documentation and/or other materials provided with the distribution.
7a956470 sago007 2016-02-14 17:09 15
      * Neither the name of cereal nor the
7a956470 sago007 2016-02-14 17:09 16
        names of its contributors may be used to endorse or promote products
7a956470 sago007 2016-02-14 17:09 17
        derived from this software without specific prior written permission.
7a956470 sago007 2016-02-14 17:09 18
7a956470 sago007 2016-02-14 17:09 19
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7a956470 sago007 2016-02-14 17:09 20
  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
7a956470 sago007 2016-02-14 17:09 21
  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
7a956470 sago007 2016-02-14 17:09 22
  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
7a956470 sago007 2016-02-14 17:09 23
  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
7a956470 sago007 2016-02-14 17:09 24
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
7a956470 sago007 2016-02-14 17:09 25
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
7a956470 sago007 2016-02-14 17:09 26
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
7a956470 sago007 2016-02-14 17:09 27
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
7a956470 sago007 2016-02-14 17:09 28
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
7a956470 sago007 2016-02-14 17:09 29
*/
7a956470 sago007 2016-02-14 17:09 30
7a956470 sago007 2016-02-14 17:09 31
/* This code is heavily inspired by the boost serialization implementation by the following authors
7a956470 sago007 2016-02-14 17:09 32
7a956470 sago007 2016-02-14 17:09 33
   (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
7a956470 sago007 2016-02-14 17:09 34
   Use, modification and distribution is subject to the Boost Software
7a956470 sago007 2016-02-14 17:09 35
   License, Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt)
7a956470 sago007 2016-02-14 17:09 36
7a956470 sago007 2016-02-14 17:09 37
    See http://www.boost.org for updates, documentation, and revision history.
7a956470 sago007 2016-02-14 17:09 38
7a956470 sago007 2016-02-14 17:09 39
   (C) Copyright 2006 David Abrahams - http://www.boost.org.
7a956470 sago007 2016-02-14 17:09 40
6c5f2c01 sago007 2017-03-15 17:56 41
   See /boost/serialization/export.hpp, /boost/archive/detail/register_archive.hpp,
6c5f2c01 sago007 2017-03-15 17:56 42
   and /boost/serialization/void_cast.hpp for their implementation. Additional details
6c5f2c01 sago007 2017-03-15 17:56 43
   found in other files split across serialization and archive.
7a956470 sago007 2016-02-14 17:09 44
*/
7a956470 sago007 2016-02-14 17:09 45
#ifndef CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_
7a956470 sago007 2016-02-14 17:09 46
#define CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_
7a956470 sago007 2016-02-14 17:09 47
6c5f2c01 sago007 2017-03-15 17:56 48
#include "cereal/details/polymorphic_impl_fwd.hpp"
6c5f2c01 sago007 2017-03-15 17:56 49
#include "cereal/details/static_object.hpp"
6c5f2c01 sago007 2017-03-15 17:56 50
#include "cereal/types/memory.hpp"
6c5f2c01 sago007 2017-03-15 17:56 51
#include "cereal/types/string.hpp"
7a956470 sago007 2016-02-14 17:09 52
#include <functional>
7a956470 sago007 2016-02-14 17:09 53
#include <typeindex>
7a956470 sago007 2016-02-14 17:09 54
#include <map>
6c5f2c01 sago007 2017-03-15 17:56 55
#include <limits>
6c5f2c01 sago007 2017-03-15 17:56 56
#include <set>
6c5f2c01 sago007 2017-03-15 17:56 57
#include <stack>
7a956470 sago007 2016-02-14 17:09 58
7a956470 sago007 2016-02-14 17:09 59
//! Binds a polymorhic type to all registered archives
7a956470 sago007 2016-02-14 17:09 60
/*! This binds a polymorphic type to all compatible registered archives that
7a956470 sago007 2016-02-14 17:09 61
    have been registered with CEREAL_REGISTER_ARCHIVE.  This must be called
7a956470 sago007 2016-02-14 17:09 62
    after all archives are registered (usually after the archives themselves
7a956470 sago007 2016-02-14 17:09 63
    have been included). */
6c5f2c01 sago007 2017-03-15 17:56 64
#define CEREAL_BIND_TO_ARCHIVES(...)                                     \
6c5f2c01 sago007 2017-03-15 17:56 65
    namespace cereal {                                                   \
6c5f2c01 sago007 2017-03-15 17:56 66
    namespace detail {                                                   \
6c5f2c01 sago007 2017-03-15 17:56 67
    template<>                                                           \
6c5f2c01 sago007 2017-03-15 17:56 68
    struct init_binding<__VA_ARGS__> {                                   \
6c5f2c01 sago007 2017-03-15 17:56 69
        static bind_to_archives<__VA_ARGS__> const & b;                  \
6c5f2c01 sago007 2017-03-15 17:56 70
        static void unused() { (void)b; }                                \
6c5f2c01 sago007 2017-03-15 17:56 71
    };                                                                   \
6c5f2c01 sago007 2017-03-15 17:56 72
    bind_to_archives<__VA_ARGS__> const & init_binding<__VA_ARGS__>::b = \
6c5f2c01 sago007 2017-03-15 17:56 73
        ::cereal::detail::StaticObject<                                  \
6c5f2c01 sago007 2017-03-15 17:56 74
            bind_to_archives<__VA_ARGS__>                                \
6c5f2c01 sago007 2017-03-15 17:56 75
        >::getInstance().bind();                                         \
7a956470 sago007 2016-02-14 17:09 76
    }} /* end namespaces */
7a956470 sago007 2016-02-14 17:09 77
7a956470 sago007 2016-02-14 17:09 78
namespace cereal
7a956470 sago007 2016-02-14 17:09 79
{
6c5f2c01 sago007 2017-03-15 17:56 80
  /* Polymorphic casting support */
6c5f2c01 sago007 2017-03-15 17:56 81
  namespace detail
6c5f2c01 sago007 2017-03-15 17:56 82
  {
6c5f2c01 sago007 2017-03-15 17:56 83
    //! Base type for polymorphic void casting
6c5f2c01 sago007 2017-03-15 17:56 84
    /*! Contains functions for casting between registered base and derived types.
6c5f2c01 sago007 2017-03-15 17:56 85
6c5f2c01 sago007 2017-03-15 17:56 86
        This is necessary so that cereal can properly cast between polymorphic types
6c5f2c01 sago007 2017-03-15 17:56 87
        even though void pointers are used, which normally have no type information.
6c5f2c01 sago007 2017-03-15 17:56 88
        Runtime type information is used instead to index a compile-time made mapping
6c5f2c01 sago007 2017-03-15 17:56 89
        that can perform the proper cast. In the case of multiple levels of inheritance,
6c5f2c01 sago007 2017-03-15 17:56 90
        cereal will attempt to find the shortest path by using registered relationships to
6c5f2c01 sago007 2017-03-15 17:56 91
        perform the cast.
6c5f2c01 sago007 2017-03-15 17:56 92
6c5f2c01 sago007 2017-03-15 17:56 93
        This class will be allocated as a StaticObject and only referenced by pointer,
6c5f2c01 sago007 2017-03-15 17:56 94
        allowing a templated derived version of it to define strongly typed functions
6c5f2c01 sago007 2017-03-15 17:56 95
        that cast between registered base and derived types. */
6c5f2c01 sago007 2017-03-15 17:56 96
    struct PolymorphicCaster
6c5f2c01 sago007 2017-03-15 17:56 97
    {
6c5f2c01 sago007 2017-03-15 17:56 98
      PolymorphicCaster() = default;
6c5f2c01 sago007 2017-03-15 17:56 99
      PolymorphicCaster( const PolymorphicCaster & ) = default;
6c5f2c01 sago007 2017-03-15 17:56 100
      PolymorphicCaster & operator=( const PolymorphicCaster & ) = default;
6c5f2c01 sago007 2017-03-15 17:56 101
      PolymorphicCaster( PolymorphicCaster && ) CEREAL_NOEXCEPT {}
6c5f2c01 sago007 2017-03-15 17:56 102
      PolymorphicCaster & operator=( PolymorphicCaster && ) CEREAL_NOEXCEPT { return *this; }
6c5f2c01 sago007 2017-03-15 17:56 103
      virtual ~PolymorphicCaster() CEREAL_NOEXCEPT = default;
6c5f2c01 sago007 2017-03-15 17:56 104
6c5f2c01 sago007 2017-03-15 17:56 105
      //! Downcasts to the proper derived type
6c5f2c01 sago007 2017-03-15 17:56 106
      virtual void const * downcast( void const * const ptr ) const = 0;
6c5f2c01 sago007 2017-03-15 17:56 107
      //! Upcast to proper base type
6c5f2c01 sago007 2017-03-15 17:56 108
      virtual void * upcast( void * const ptr ) const = 0;
6c5f2c01 sago007 2017-03-15 17:56 109
      //! Upcast to proper base type, shared_ptr version
6c5f2c01 sago007 2017-03-15 17:56 110
      virtual std::shared_ptr<void> upcast( std::shared_ptr<void> const & ptr ) const = 0;
6c5f2c01 sago007 2017-03-15 17:56 111
    };
6c5f2c01 sago007 2017-03-15 17:56 112
6c5f2c01 sago007 2017-03-15 17:56 113
    //! Holds registered mappings between base and derived types for casting
6c5f2c01 sago007 2017-03-15 17:56 114
    /*! This will be allocated as a StaticObject and holds a map containing
6c5f2c01 sago007 2017-03-15 17:56 115
        all registered mappings between base and derived types. */
6c5f2c01 sago007 2017-03-15 17:56 116
    struct PolymorphicCasters
6c5f2c01 sago007 2017-03-15 17:56 117
    {
6c5f2c01 sago007 2017-03-15 17:56 118
      //! Maps from base type index to a map from derived type index to caster
6c5f2c01 sago007 2017-03-15 17:56 119
      std::map<std::type_index, std::map<std::type_index, std::vector<PolymorphicCaster const*>>> map;
6c5f2c01 sago007 2017-03-15 17:56 120
6c5f2c01 sago007 2017-03-15 17:56 121
      std::multimap<std::type_index, std::type_index> reverseMap;
6c5f2c01 sago007 2017-03-15 17:56 122
6c5f2c01 sago007 2017-03-15 17:56 123
      //! Error message used for unregistered polymorphic casts
6c5f2c01 sago007 2017-03-15 17:56 124
      #define UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(LoadSave)                                                                                                                \
6c5f2c01 sago007 2017-03-15 17:56 125
        throw cereal::Exception("Trying to " #LoadSave " a registered polymorphic type with an unregistered polymorphic cast.\n"                                               \
6c5f2c01 sago007 2017-03-15 17:56 126
                                "Could not find a path to a base class (" + util::demangle(baseInfo.name()) + ") for type: " + ::cereal::util::demangledName<Derived>() + "\n" \
6c5f2c01 sago007 2017-03-15 17:56 127
                                "Make sure you either serialize the base class at some point via cereal::base_class or cereal::virtual_base_class.\n"                          \
6c5f2c01 sago007 2017-03-15 17:56 128
                                "Alternatively, manually register the association with CEREAL_REGISTER_POLYMORPHIC_RELATION.");
6c5f2c01 sago007 2017-03-15 17:56 129
6c5f2c01 sago007 2017-03-15 17:56 130
      //! Checks if the mapping object that can perform the upcast or downcast
6c5f2c01 sago007 2017-03-15 17:56 131
      /*! Uses the type index from the base and derived class to find the matching
6c5f2c01 sago007 2017-03-15 17:56 132
          registered caster. If no matching caster exists, returns false. */
6c5f2c01 sago007 2017-03-15 17:56 133
      static bool exists( std::type_index const & baseIndex, std::type_index const & derivedIndex )
6c5f2c01 sago007 2017-03-15 17:56 134
      {
6c5f2c01 sago007 2017-03-15 17:56 135
        // First phase of lookup - match base type index
6c5f2c01 sago007 2017-03-15 17:56 136
        auto const & baseMap = StaticObject<PolymorphicCasters>::getInstance().map;
6c5f2c01 sago007 2017-03-15 17:56 137
        auto baseIter = baseMap.find( baseIndex );
6c5f2c01 sago007 2017-03-15 17:56 138
        if (baseIter == baseMap.end())
6c5f2c01 sago007 2017-03-15 17:56 139
          return false;
6c5f2c01 sago007 2017-03-15 17:56 140
6c5f2c01 sago007 2017-03-15 17:56 141
        // Second phase - find a match from base to derived
6c5f2c01 sago007 2017-03-15 17:56 142
        auto & derivedMap = baseIter->second;
6c5f2c01 sago007 2017-03-15 17:56 143
        auto derivedIter = derivedMap.find( derivedIndex );
6c5f2c01 sago007 2017-03-15 17:56 144
        if (derivedIter == derivedMap.end())
6c5f2c01 sago007 2017-03-15 17:56 145
          return false;
6c5f2c01 sago007 2017-03-15 17:56 146
6c5f2c01 sago007 2017-03-15 17:56 147
        return true;
6c5f2c01 sago007 2017-03-15 17:56 148
      }
6c5f2c01 sago007 2017-03-15 17:56 149
6c5f2c01 sago007 2017-03-15 17:56 150
      //! Gets the mapping object that can perform the upcast or downcast
6c5f2c01 sago007 2017-03-15 17:56 151
      /*! Uses the type index from the base and derived class to find the matching
6c5f2c01 sago007 2017-03-15 17:56 152
          registered caster. If no matching caster exists, calls the exception function.
6c5f2c01 sago007 2017-03-15 17:56 153
6c5f2c01 sago007 2017-03-15 17:56 154
          The returned PolymorphicCaster is capable of upcasting or downcasting between the two types. */
6c5f2c01 sago007 2017-03-15 17:56 155
      template <class F> inline
6c5f2c01 sago007 2017-03-15 17:56 156
      static std::vector<PolymorphicCaster const *> const & lookup( std::type_index const & baseIndex, std::type_index const & derivedIndex, F && exceptionFunc )
6c5f2c01 sago007 2017-03-15 17:56 157
      {
6c5f2c01 sago007 2017-03-15 17:56 158
        // First phase of lookup - match base type index
6c5f2c01 sago007 2017-03-15 17:56 159
        auto const & baseMap = StaticObject<PolymorphicCasters>::getInstance().map;
6c5f2c01 sago007 2017-03-15 17:56 160
        auto baseIter = baseMap.find( baseIndex );
6c5f2c01 sago007 2017-03-15 17:56 161
        if( baseIter == baseMap.end() )
6c5f2c01 sago007 2017-03-15 17:56 162
          exceptionFunc();
6c5f2c01 sago007 2017-03-15 17:56 163
6c5f2c01 sago007 2017-03-15 17:56 164
        // Second phase - find a match from base to derived
6c5f2c01 sago007 2017-03-15 17:56 165
        auto & derivedMap = baseIter->second;
6c5f2c01 sago007 2017-03-15 17:56 166
        auto derivedIter = derivedMap.find( derivedIndex );
6c5f2c01 sago007 2017-03-15 17:56 167
        if( derivedIter == derivedMap.end() )
6c5f2c01 sago007 2017-03-15 17:56 168
          exceptionFunc();
6c5f2c01 sago007 2017-03-15 17:56 169
6c5f2c01 sago007 2017-03-15 17:56 170
        return derivedIter->second;
6c5f2c01 sago007 2017-03-15 17:56 171
      }
6c5f2c01 sago007 2017-03-15 17:56 172
6c5f2c01 sago007 2017-03-15 17:56 173
      //! Performs a downcast to the derived type using a registered mapping
6c5f2c01 sago007 2017-03-15 17:56 174
      template <class Derived> inline
6c5f2c01 sago007 2017-03-15 17:56 175
      static const Derived * downcast( const void * dptr, std::type_info const & baseInfo )
6c5f2c01 sago007 2017-03-15 17:56 176
      {
6c5f2c01 sago007 2017-03-15 17:56 177
        auto const & mapping = lookup( baseInfo, typeid(Derived), [&](){ UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(save) } );
6c5f2c01 sago007 2017-03-15 17:56 178
6c5f2c01 sago007 2017-03-15 17:56 179
        for( auto const * map : mapping )
6c5f2c01 sago007 2017-03-15 17:56 180
          dptr = map->downcast( dptr );
6c5f2c01 sago007 2017-03-15 17:56 181
6c5f2c01 sago007 2017-03-15 17:56 182
        return static_cast<Derived const *>( dptr );
6c5f2c01 sago007 2017-03-15 17:56 183
      }
6c5f2c01 sago007 2017-03-15 17:56 184
6c5f2c01 sago007 2017-03-15 17:56 185
      //! Performs an upcast to the registered base type using the given a derived type
6c5f2c01 sago007 2017-03-15 17:56 186
      /*! The return is untyped because the final casting to the base type must happen in the polymorphic
6c5f2c01 sago007 2017-03-15 17:56 187
          serialization function, where the type is known at compile time */
6c5f2c01 sago007 2017-03-15 17:56 188
      template <class Derived> inline
6c5f2c01 sago007 2017-03-15 17:56 189
      static void * upcast( Derived * const dptr, std::type_info const & baseInfo )
6c5f2c01 sago007 2017-03-15 17:56 190
      {
6c5f2c01 sago007 2017-03-15 17:56 191
        auto const & mapping = lookup( baseInfo, typeid(Derived), [&](){ UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(load) } );
6c5f2c01 sago007 2017-03-15 17:56 192
6c5f2c01 sago007 2017-03-15 17:56 193
        void * uptr = dptr;
6c5f2c01 sago007 2017-03-15 17:56 194
        for( auto mIter = mapping.rbegin(), mEnd = mapping.rend(); mIter != mEnd; ++mIter )
6c5f2c01 sago007 2017-03-15 17:56 195
          uptr = (*mIter)->upcast( uptr );
6c5f2c01 sago007 2017-03-15 17:56 196
6c5f2c01 sago007 2017-03-15 17:56 197
        return uptr;
6c5f2c01 sago007 2017-03-15 17:56 198
      }
6c5f2c01 sago007 2017-03-15 17:56 199
6c5f2c01 sago007 2017-03-15 17:56 200
      //! Upcasts for shared pointers
6c5f2c01 sago007 2017-03-15 17:56 201
      template <class Derived> inline
6c5f2c01 sago007 2017-03-15 17:56 202
      static std::shared_ptr<void> upcast( std::shared_ptr<Derived> const & dptr, std::type_info const & baseInfo )
6c5f2c01 sago007 2017-03-15 17:56 203
      {
6c5f2c01 sago007 2017-03-15 17:56 204
        auto const & mapping = lookup( baseInfo, typeid(Derived), [&](){ UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(load) } );
6c5f2c01 sago007 2017-03-15 17:56 205
6c5f2c01 sago007 2017-03-15 17:56 206
        std::shared_ptr<void> uptr = dptr;
6c5f2c01 sago007 2017-03-15 17:56 207
        for( auto mIter = mapping.rbegin(), mEnd = mapping.rend(); mIter != mEnd; ++mIter )
6c5f2c01 sago007 2017-03-15 17:56 208
          uptr = (*mIter)->upcast( uptr );
6c5f2c01 sago007 2017-03-15 17:56 209
6c5f2c01 sago007 2017-03-15 17:56 210
        return uptr;
6c5f2c01 sago007 2017-03-15 17:56 211
      }
6c5f2c01 sago007 2017-03-15 17:56 212
6c5f2c01 sago007 2017-03-15 17:56 213
      #undef UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION
6c5f2c01 sago007 2017-03-15 17:56 214
    };
6c5f2c01 sago007 2017-03-15 17:56 215
6c5f2c01 sago007 2017-03-15 17:56 216
    //! Strongly typed derivation of PolymorphicCaster
6c5f2c01 sago007 2017-03-15 17:56 217
    template <class Base, class Derived>
6c5f2c01 sago007 2017-03-15 17:56 218
    struct PolymorphicVirtualCaster : PolymorphicCaster
6c5f2c01 sago007 2017-03-15 17:56 219
    {
6c5f2c01 sago007 2017-03-15 17:56 220
      //! Inserts an entry in the polymorphic casting map for this pairing
6c5f2c01 sago007 2017-03-15 17:56 221
      /*! Creates an explicit mapping between Base and Derived in both upwards and
6c5f2c01 sago007 2017-03-15 17:56 222
          downwards directions, allowing void pointers to either to be properly cast
6c5f2c01 sago007 2017-03-15 17:56 223
          assuming dynamic type information is available */
6c5f2c01 sago007 2017-03-15 17:56 224
      PolymorphicVirtualCaster()
6c5f2c01 sago007 2017-03-15 17:56 225
      {
6c5f2c01 sago007 2017-03-15 17:56 226
        const auto baseKey = std::type_index(typeid(Base));
6c5f2c01 sago007 2017-03-15 17:56 227
        const auto derivedKey = std::type_index(typeid(Derived));
6c5f2c01 sago007 2017-03-15 17:56 228
6c5f2c01 sago007 2017-03-15 17:56 229
        // First insert the relation Base->Derived
6c5f2c01 sago007 2017-03-15 17:56 230
        const auto lock = StaticObject<PolymorphicCasters>::lock();
6c5f2c01 sago007 2017-03-15 17:56 231
        auto & baseMap = StaticObject<PolymorphicCasters>::getInstance().map;
6c5f2c01 sago007 2017-03-15 17:56 232
        auto lb = baseMap.lower_bound(baseKey);
6c5f2c01 sago007 2017-03-15 17:56 233
6c5f2c01 sago007 2017-03-15 17:56 234
        {
6c5f2c01 sago007 2017-03-15 17:56 235
          auto & derivedMap = baseMap.insert( lb, {baseKey, {}} )->second;
6c5f2c01 sago007 2017-03-15 17:56 236
          auto lbd = derivedMap.lower_bound(derivedKey);
6c5f2c01 sago007 2017-03-15 17:56 237
          auto & derivedVec = derivedMap.insert( lbd, { std::move(derivedKey), {}} )->second;
6c5f2c01 sago007 2017-03-15 17:56 238
          derivedVec.push_back( this );
6c5f2c01 sago007 2017-03-15 17:56 239
        }
6c5f2c01 sago007 2017-03-15 17:56 240
6c5f2c01 sago007 2017-03-15 17:56 241
        // Insert reverse relation Derived->Base
6c5f2c01 sago007 2017-03-15 17:56 242
        auto & reverseMap = StaticObject<PolymorphicCasters>::getInstance().reverseMap;
6c5f2c01 sago007 2017-03-15 17:56 243
        reverseMap.insert( {derivedKey, baseKey} );
6c5f2c01 sago007 2017-03-15 17:56 244
6c5f2c01 sago007 2017-03-15 17:56 245
        // Find all chainable unregistered relations
6c5f2c01 sago007 2017-03-15 17:56 246
        /* The strategy here is to process only the nodes in the class hierarchy graph that have been
6c5f2c01 sago007 2017-03-15 17:56 247
           affected by the new insertion. The aglorithm iteratively processes a node an ensures that it
6c5f2c01 sago007 2017-03-15 17:56 248
           is updated with all new shortest length paths. It then rocesses the parents of the active node,
6c5f2c01 sago007 2017-03-15 17:56 249
           with the knowledge that all children have already been processed.
6c5f2c01 sago007 2017-03-15 17:56 250
6c5f2c01 sago007 2017-03-15 17:56 251
           Note that for the following, we'll use the nomenclature of parent and child to not confuse with
6c5f2c01 sago007 2017-03-15 17:56 252
           the inserted base derived relationship */
6c5f2c01 sago007 2017-03-15 17:56 253
        {
6c5f2c01 sago007 2017-03-15 17:56 254
          // Checks whether there is a path from parent->child and returns a <dist, path> pair
6c5f2c01 sago007 2017-03-15 17:56 255
          // dist is set to MAX if the path does not exist
6c5f2c01 sago007 2017-03-15 17:56 256
          auto checkRelation = [](std::type_index const & parentInfo, std::type_index const & childInfo) ->
6c5f2c01 sago007 2017-03-15 17:56 257
            std::pair<size_t, std::vector<PolymorphicCaster const *>>
6c5f2c01 sago007 2017-03-15 17:56 258
          {
6c5f2c01 sago007 2017-03-15 17:56 259
            if( PolymorphicCasters::exists( parentInfo, childInfo ) )
6c5f2c01 sago007 2017-03-15 17:56 260
            {
6c5f2c01 sago007 2017-03-15 17:56 261
              auto const & path = PolymorphicCasters::lookup( parentInfo, childInfo, [](){} );
6c5f2c01 sago007 2017-03-15 17:56 262
              return {path.size(), path};
6c5f2c01 sago007 2017-03-15 17:56 263
            }
6c5f2c01 sago007 2017-03-15 17:56 264
            else
6c5f2c01 sago007 2017-03-15 17:56 265
              return {std::numeric_limits<size_t>::max(), {}};
6c5f2c01 sago007 2017-03-15 17:56 266
          };
6c5f2c01 sago007 2017-03-15 17:56 267
6c5f2c01 sago007 2017-03-15 17:56 268
          std::stack<std::type_index> parentStack;      // Holds the parent nodes to be processed
6c5f2c01 sago007 2017-03-15 17:56 269
          std::set<std::type_index>   dirtySet;         // Marks child nodes that have been changed
6c5f2c01 sago007 2017-03-15 17:56 270
          std::set<std::type_index>   processedParents; // Marks parent nodes that have been processed
6c5f2c01 sago007 2017-03-15 17:56 271
6c5f2c01 sago007 2017-03-15 17:56 272
          // Begin processing the base key and mark derived as dirty
6c5f2c01 sago007 2017-03-15 17:56 273
          parentStack.push( baseKey );
6c5f2c01 sago007 2017-03-15 17:56 274
          dirtySet.insert( derivedKey );
6c5f2c01 sago007 2017-03-15 17:56 275
6c5f2c01 sago007 2017-03-15 17:56 276
          while( !parentStack.empty() )
6c5f2c01 sago007 2017-03-15 17:56 277
          {
6c5f2c01 sago007 2017-03-15 17:56 278
            using Relations = std::multimap<std::type_index, std::pair<std::type_index, std::vector<PolymorphicCaster const *>>>;
6c5f2c01 sago007 2017-03-15 17:56 279
            Relations unregisteredRelations; // Defer insertions until after main loop to prevent iterator invalidation
6c5f2c01 sago007 2017-03-15 17:56 280
6c5f2c01 sago007 2017-03-15 17:56 281
            const auto parent = parentStack.top();
6c5f2c01 sago007 2017-03-15 17:56 282
            parentStack.pop();
6c5f2c01 sago007 2017-03-15 17:56 283
6c5f2c01 sago007 2017-03-15 17:56 284
            // Update paths to all children marked dirty
6c5f2c01 sago007 2017-03-15 17:56 285
            for( auto const & childPair : baseMap[parent] )
6c5f2c01 sago007 2017-03-15 17:56 286
            {
6c5f2c01 sago007 2017-03-15 17:56 287
              const auto child = childPair.first;
6c5f2c01 sago007 2017-03-15 17:56 288
              if( dirtySet.count( child ) && baseMap.count( child ) )
6c5f2c01 sago007 2017-03-15 17:56 289
              {
6c5f2c01 sago007 2017-03-15 17:56 290
                auto parentChildPath = checkRelation( parent, child );
6c5f2c01 sago007 2017-03-15 17:56 291
6c5f2c01 sago007 2017-03-15 17:56 292
                // Search all paths from the child to its own children (finalChild),
6c5f2c01 sago007 2017-03-15 17:56 293
                // looking for a shorter parth from parent to finalChild
6c5f2c01 sago007 2017-03-15 17:56 294
                for( auto const & finalChildPair : baseMap[child] )
6c5f2c01 sago007 2017-03-15 17:56 295
                {
6c5f2c01 sago007 2017-03-15 17:56 296
                  const auto finalChild = finalChildPair.first;
6c5f2c01 sago007 2017-03-15 17:56 297
6c5f2c01 sago007 2017-03-15 17:56 298
                  auto parentFinalChildPath = checkRelation( parent, finalChild );
6c5f2c01 sago007 2017-03-15 17:56 299
                  auto childFinalChildPath  = checkRelation( child, finalChild );
6c5f2c01 sago007 2017-03-15 17:56 300
6c5f2c01 sago007 2017-03-15 17:56 301
                  const size_t newLength = 1u + parentChildPath.first;
6c5f2c01 sago007 2017-03-15 17:56 302
6c5f2c01 sago007 2017-03-15 17:56 303
                  if( newLength < parentFinalChildPath.first )
6c5f2c01 sago007 2017-03-15 17:56 304
                  {
6c5f2c01 sago007 2017-03-15 17:56 305
                    std::vector<PolymorphicCaster const *> path = parentChildPath.second;
6c5f2c01 sago007 2017-03-15 17:56 306
                    path.insert( path.end(), childFinalChildPath.second.begin(), childFinalChildPath.second.end() );
6c5f2c01 sago007 2017-03-15 17:56 307
6c5f2c01 sago007 2017-03-15 17:56 308
                    // Check to see if we have a previous uncommitted path in unregisteredRelations
6c5f2c01 sago007 2017-03-15 17:56 309
                    // that is shorter. If so, ignore this path
6c5f2c01 sago007 2017-03-15 17:56 310
                    auto hintRange = unregisteredRelations.equal_range( parent );
6c5f2c01 sago007 2017-03-15 17:56 311
                    auto hint = hintRange.first;
6c5f2c01 sago007 2017-03-15 17:56 312
                    for( ; hint != hintRange.second; ++hint )
6c5f2c01 sago007 2017-03-15 17:56 313
                      if( hint->second.first == finalChild )
6c5f2c01 sago007 2017-03-15 17:56 314
                        break;
6c5f2c01 sago007 2017-03-15 17:56 315
6c5f2c01 sago007 2017-03-15 17:56 316
                    const bool uncommittedExists = hint != unregisteredRelations.end();
6c5f2c01 sago007 2017-03-15 17:56 317
                    if( uncommittedExists && (hint->second.second.size() <= newLength) )
6c5f2c01 sago007 2017-03-15 17:56 318
                      continue;
6c5f2c01 sago007 2017-03-15 17:56 319
6c5f2c01 sago007 2017-03-15 17:56 320
                    auto newPath = std::pair<std::type_index, std::vector<PolymorphicCaster const *>>{finalChild, std::move(path)};
6c5f2c01 sago007 2017-03-15 17:56 321
6c5f2c01 sago007 2017-03-15 17:56 322
                    // Insert the new path if it doesn't exist, otherwise this will just lookup where to do the
6c5f2c01 sago007 2017-03-15 17:56 323
                    // replacement
6c5f2c01 sago007 2017-03-15 17:56 324
                    #ifdef CEREAL_OLDER_GCC
6c5f2c01 sago007 2017-03-15 17:56 325
                    auto old = unregisteredRelations.insert( hint, std::make_pair(parent, newPath) );
6c5f2c01 sago007 2017-03-15 17:56 326
                    #else // NOT CEREAL_OLDER_GCC
6c5f2c01 sago007 2017-03-15 17:56 327
                    auto old = unregisteredRelations.emplace_hint( hint, parent, newPath );
6c5f2c01 sago007 2017-03-15 17:56 328
                    #endif // NOT CEREAL_OLDER_GCC
6c5f2c01 sago007 2017-03-15 17:56 329
6c5f2c01 sago007 2017-03-15 17:56 330
                    // If there was an uncommitted path, we need to perform a replacement
6c5f2c01 sago007 2017-03-15 17:56 331
                    if( uncommittedExists )
6c5f2c01 sago007 2017-03-15 17:56 332
                      old->second = newPath;
6c5f2c01 sago007 2017-03-15 17:56 333
                  }
6c5f2c01 sago007 2017-03-15 17:56 334
                } // end loop over child's children
6c5f2c01 sago007 2017-03-15 17:56 335
              } // end if dirty and child has children
6c5f2c01 sago007 2017-03-15 17:56 336
            } // end loop over children
6c5f2c01 sago007 2017-03-15 17:56 337
6c5f2c01 sago007 2017-03-15 17:56 338
            // Insert chained relations
6c5f2c01 sago007 2017-03-15 17:56 339
            for( auto const & it : unregisteredRelations )
6c5f2c01 sago007 2017-03-15 17:56 340
            {
6c5f2c01 sago007 2017-03-15 17:56 341
              auto & derivedMap = baseMap.find( it.first )->second;
6c5f2c01 sago007 2017-03-15 17:56 342
              derivedMap[it.second.first] = it.second.second;
6c5f2c01 sago007 2017-03-15 17:56 343
              reverseMap.insert( {it.second.first, it.first} );
6c5f2c01 sago007 2017-03-15 17:56 344
            }
6c5f2c01 sago007 2017-03-15 17:56 345
6c5f2c01 sago007 2017-03-15 17:56 346
            // Mark current parent as modified
6c5f2c01 sago007 2017-03-15 17:56 347
            dirtySet.insert( parent );
6c5f2c01 sago007 2017-03-15 17:56 348
6c5f2c01 sago007 2017-03-15 17:56 349
            // Insert all parents of the current parent node that haven't yet been processed
6c5f2c01 sago007 2017-03-15 17:56 350
            auto parentRange = reverseMap.equal_range( parent );
6c5f2c01 sago007 2017-03-15 17:56 351
            for( auto pIter = parentRange.first; pIter != parentRange.second; ++pIter )
6c5f2c01 sago007 2017-03-15 17:56 352
            {
6c5f2c01 sago007 2017-03-15 17:56 353
              const auto pParent = pIter->second;
6c5f2c01 sago007 2017-03-15 17:56 354
              if( !processedParents.count( pParent ) )
6c5f2c01 sago007 2017-03-15 17:56 355
              {
6c5f2c01 sago007 2017-03-15 17:56 356
                parentStack.push( pParent );
6c5f2c01 sago007 2017-03-15 17:56 357
                processedParents.insert( pParent );
6c5f2c01 sago007 2017-03-15 17:56 358
              }
6c5f2c01 sago007 2017-03-15 17:56 359
            }
6c5f2c01 sago007 2017-03-15 17:56 360
          } // end loop over parent stack
6c5f2c01 sago007 2017-03-15 17:56 361
        } // end chainable relations
6c5f2c01 sago007 2017-03-15 17:56 362
      } // end PolymorphicVirtualCaster()
6c5f2c01 sago007 2017-03-15 17:56 363
6c5f2c01 sago007 2017-03-15 17:56 364
      //! Performs the proper downcast with the templated types
6c5f2c01 sago007 2017-03-15 17:56 365
      void const * downcast( void const * const ptr ) const override
6c5f2c01 sago007 2017-03-15 17:56 366
      {
6c5f2c01 sago007 2017-03-15 17:56 367
        return dynamic_cast<Derived const*>( static_cast<Base const*>( ptr ) );
6c5f2c01 sago007 2017-03-15 17:56 368
      }
6c5f2c01 sago007 2017-03-15 17:56 369
6c5f2c01 sago007 2017-03-15 17:56 370
      //! Performs the proper upcast with the templated types
6c5f2c01 sago007 2017-03-15 17:56 371
      void * upcast( void * const ptr ) const override
6c5f2c01 sago007 2017-03-15 17:56 372
      {
6c5f2c01 sago007 2017-03-15 17:56 373
        return dynamic_cast<Base*>( static_cast<Derived*>( ptr ) );
6c5f2c01 sago007 2017-03-15 17:56 374
      }
6c5f2c01 sago007 2017-03-15 17:56 375
6c5f2c01 sago007 2017-03-15 17:56 376
      //! Performs the proper upcast with the templated types (shared_ptr version)
6c5f2c01 sago007 2017-03-15 17:56 377
      std::shared_ptr<void> upcast( std::shared_ptr<void> const & ptr ) const override
6c5f2c01 sago007 2017-03-15 17:56 378
      {
6c5f2c01 sago007 2017-03-15 17:56 379
        return std::dynamic_pointer_cast<Base>( std::static_pointer_cast<Derived>( ptr ) );
6c5f2c01 sago007 2017-03-15 17:56 380
      }
6c5f2c01 sago007 2017-03-15 17:56 381
    };
6c5f2c01 sago007 2017-03-15 17:56 382
6c5f2c01 sago007 2017-03-15 17:56 383
    //! Registers a polymorphic casting relation between a Base and Derived type
6c5f2c01 sago007 2017-03-15 17:56 384
    /*! Registering a relation allows cereal to properly cast between the two types
6c5f2c01 sago007 2017-03-15 17:56 385
        given runtime type information and void pointers.
6c5f2c01 sago007 2017-03-15 17:56 386
6c5f2c01 sago007 2017-03-15 17:56 387
        Registration happens automatically via cereal::base_class and cereal::virtual_base_class
6c5f2c01 sago007 2017-03-15 17:56 388
        instantiations. For cases where neither is called, see the CEREAL_REGISTER_POLYMORPHIC_RELATION
6c5f2c01 sago007 2017-03-15 17:56 389
        macro */
6c5f2c01 sago007 2017-03-15 17:56 390
    template <class Base, class Derived>
6c5f2c01 sago007 2017-03-15 17:56 391
    struct RegisterPolymorphicCaster
6c5f2c01 sago007 2017-03-15 17:56 392
    {
6c5f2c01 sago007 2017-03-15 17:56 393
      static PolymorphicCaster const * bind( std::true_type /* is_polymorphic<Base> */)
6c5f2c01 sago007 2017-03-15 17:56 394
      {
6c5f2c01 sago007 2017-03-15 17:56 395
        return &StaticObject<PolymorphicVirtualCaster<Base, Derived>>::getInstance();
6c5f2c01 sago007 2017-03-15 17:56 396
      }
6c5f2c01 sago007 2017-03-15 17:56 397
6c5f2c01 sago007 2017-03-15 17:56 398
      static PolymorphicCaster const * bind( std::false_type /* is_polymorphic<Base> */ )
6c5f2c01 sago007 2017-03-15 17:56 399
      { return nullptr; }
6c5f2c01 sago007 2017-03-15 17:56 400
6c5f2c01 sago007 2017-03-15 17:56 401
      //! Performs registration (binding) between Base and Derived
6c5f2c01 sago007 2017-03-15 17:56 402
      /*! If the type is not polymorphic, nothing will happen */
6c5f2c01 sago007 2017-03-15 17:56 403
      static PolymorphicCaster const * bind()
6c5f2c01 sago007 2017-03-15 17:56 404
      { return bind( typename std::is_polymorphic<Base>::type() ); }
6c5f2c01 sago007 2017-03-15 17:56 405
    };
6c5f2c01 sago007 2017-03-15 17:56 406
  }
6c5f2c01 sago007 2017-03-15 17:56 407
6c5f2c01 sago007 2017-03-15 17:56 408
  /* General polymorphism support */
7a956470 sago007 2016-02-14 17:09 409
  namespace detail
7a956470 sago007 2016-02-14 17:09 410
  {
7a956470 sago007 2016-02-14 17:09 411
    //! Binds a compile time type with a user defined string
7a956470 sago007 2016-02-14 17:09 412
    template <class T>
7a956470 sago007 2016-02-14 17:09 413
    struct binding_name {};
7a956470 sago007 2016-02-14 17:09 414
7a956470 sago007 2016-02-14 17:09 415
    //! A structure holding a map from type_indices to output serializer functions
7a956470 sago007 2016-02-14 17:09 416
    /*! A static object of this map should be created for each registered archive
7a956470 sago007 2016-02-14 17:09 417
        type, containing entries for every registered type that describe how to
7a956470 sago007 2016-02-14 17:09 418
        properly cast the type to its real type in polymorphic scenarios for
7a956470 sago007 2016-02-14 17:09 419
        shared_ptr, weak_ptr, and unique_ptr. */
7a956470 sago007 2016-02-14 17:09 420
    template <class Archive>
7a956470 sago007 2016-02-14 17:09 421
    struct OutputBindingMap
7a956470 sago007 2016-02-14 17:09 422
    {
7a956470 sago007 2016-02-14 17:09 423
      //! A serializer function
7a956470 sago007 2016-02-14 17:09 424
      /*! Serializer functions return nothing and take an archive as
7a956470 sago007 2016-02-14 17:09 425
          their first parameter (will be cast properly inside the function,
6c5f2c01 sago007 2017-03-15 17:56 426
          a pointer to actual data (contents of smart_ptr's get() function)
6c5f2c01 sago007 2017-03-15 17:56 427
          as their second parameter, and the type info of the owning smart_ptr
6c5f2c01 sago007 2017-03-15 17:56 428
          as their final parameter */
6c5f2c01 sago007 2017-03-15 17:56 429
      typedef std::function<void(void*, void const *, std::type_info const &)> Serializer;
7a956470 sago007 2016-02-14 17:09 430
7a956470 sago007 2016-02-14 17:09 431
      //! Struct containing the serializer functions for all pointer types
7a956470 sago007 2016-02-14 17:09 432
      struct Serializers
7a956470 sago007 2016-02-14 17:09 433
      {
7a956470 sago007 2016-02-14 17:09 434
        Serializer shared_ptr, //!< Serializer function for shared/weak pointers
7a956470 sago007 2016-02-14 17:09 435
                   unique_ptr; //!< Serializer function for unique pointers
7a956470 sago007 2016-02-14 17:09 436
      };
7a956470 sago007 2016-02-14 17:09 437
7a956470 sago007 2016-02-14 17:09 438
      //! A map of serializers for pointers of all registered types
7a956470 sago007 2016-02-14 17:09 439
      std::map<std::type_index, Serializers> map;
7a956470 sago007 2016-02-14 17:09 440
    };
7a956470 sago007 2016-02-14 17:09 441
7a956470 sago007 2016-02-14 17:09 442
    //! An empty noop deleter
7a956470 sago007 2016-02-14 17:09 443
    template<class T> struct EmptyDeleter { void operator()(T *) const {} };
7a956470 sago007 2016-02-14 17:09 444
7a956470 sago007 2016-02-14 17:09 445
    //! A structure holding a map from type name strings to input serializer functions
7a956470 sago007 2016-02-14 17:09 446
    /*! A static object of this map should be created for each registered archive
7a956470 sago007 2016-02-14 17:09 447
        type, containing entries for every registered type that describe how to
7a956470 sago007 2016-02-14 17:09 448
        properly cast the type to its real type in polymorphic scenarios for
7a956470 sago007 2016-02-14 17:09 449
        shared_ptr, weak_ptr, and unique_ptr. */
7a956470 sago007 2016-02-14 17:09 450
    template <class Archive>
7a956470 sago007 2016-02-14 17:09 451
    struct InputBindingMap
7a956470 sago007 2016-02-14 17:09 452
    {
7a956470 sago007 2016-02-14 17:09 453
      //! Shared ptr serializer function
7a956470 sago007 2016-02-14 17:09 454
      /*! Serializer functions return nothing and take an archive as
7a956470 sago007 2016-02-14 17:09 455
          their first parameter (will be cast properly inside the function,
6c5f2c01 sago007 2017-03-15 17:56 456
          a shared_ptr (or unique_ptr for the unique case) of any base
6c5f2c01 sago007 2017-03-15 17:56 457
          type, and the type id of said base type as the third parameter.
6c5f2c01 sago007 2017-03-15 17:56 458
          Internally it will properly be loaded and cast to the correct type. */
6c5f2c01 sago007 2017-03-15 17:56 459
      typedef std::function<void(void*, std::shared_ptr<void> &, std::type_info const &)> SharedSerializer;
7a956470 sago007 2016-02-14 17:09 460
      //! Unique ptr serializer function
6c5f2c01 sago007 2017-03-15 17:56 461
      typedef std::function<void(void*, std::unique_ptr<void, EmptyDeleter<void>> &, std::type_info const &)> UniqueSerializer;
7a956470 sago007 2016-02-14 17:09 462
7a956470 sago007 2016-02-14 17:09 463
      //! Struct containing the serializer functions for all pointer types
7a956470 sago007 2016-02-14 17:09 464
      struct Serializers
7a956470 sago007 2016-02-14 17:09 465
      {
7a956470 sago007 2016-02-14 17:09 466
        SharedSerializer shared_ptr; //!< Serializer function for shared/weak pointers
7a956470 sago007 2016-02-14 17:09 467
        UniqueSerializer unique_ptr; //!< Serializer function for unique pointers
7a956470 sago007 2016-02-14 17:09 468
      };
7a956470 sago007 2016-02-14 17:09 469
7a956470 sago007 2016-02-14 17:09 470
      //! A map of serializers for pointers of all registered types
7a956470 sago007 2016-02-14 17:09 471
      std::map<std::string, Serializers> map;
7a956470 sago007 2016-02-14 17:09 472
    };
7a956470 sago007 2016-02-14 17:09 473
7a956470 sago007 2016-02-14 17:09 474
    // forward decls for archives from cereal.hpp
7a956470 sago007 2016-02-14 17:09 475
    class InputArchiveBase;
7a956470 sago007 2016-02-14 17:09 476
    class OutputArchiveBase;
7a956470 sago007 2016-02-14 17:09 477
7a956470 sago007 2016-02-14 17:09 478
    //! Creates a binding (map entry) between an input archive type and a polymorphic type
7a956470 sago007 2016-02-14 17:09 479
    /*! Bindings are made when types are registered, assuming that at least one
7a956470 sago007 2016-02-14 17:09 480
        archive has already been registered.  When this struct is created,
7a956470 sago007 2016-02-14 17:09 481
        it will insert (at run time) an entry into a map that properly handles
7a956470 sago007 2016-02-14 17:09 482
        casting for serializing polymorphic objects */
7a956470 sago007 2016-02-14 17:09 483
    template <class Archive, class T> struct InputBindingCreator
7a956470 sago007 2016-02-14 17:09 484
    {
7a956470 sago007 2016-02-14 17:09 485
      //! Initialize the binding
7a956470 sago007 2016-02-14 17:09 486
      InputBindingCreator()
7a956470 sago007 2016-02-14 17:09 487
      {
7a956470 sago007 2016-02-14 17:09 488
        auto & map = StaticObject<InputBindingMap<Archive>>::getInstance().map;
6c5f2c01 sago007 2017-03-15 17:56 489
        auto lock = StaticObject<InputBindingMap<Archive>>::lock();
7a956470 sago007 2016-02-14 17:09 490
        auto key = std::string(binding_name<T>::name());
7a956470 sago007 2016-02-14 17:09 491
        auto lb = map.lower_bound(key);
7a956470 sago007 2016-02-14 17:09 492
7a956470 sago007 2016-02-14 17:09 493
        if (lb != map.end() && lb->first == key)
7a956470 sago007 2016-02-14 17:09 494
          return;
7a956470 sago007 2016-02-14 17:09 495
7a956470 sago007 2016-02-14 17:09 496
        typename InputBindingMap<Archive>::Serializers serializers;
7a956470 sago007 2016-02-14 17:09 497
7a956470 sago007 2016-02-14 17:09 498
        serializers.shared_ptr =
6c5f2c01 sago007 2017-03-15 17:56 499
          [](void * arptr, std::shared_ptr<void> & dptr, std::type_info const & baseInfo)
7a956470 sago007 2016-02-14 17:09 500
          {
7a956470 sago007 2016-02-14 17:09 501
            Archive & ar = *static_cast<Archive*>(arptr);
7a956470 sago007 2016-02-14 17:09 502
            std::shared_ptr<T> ptr;
7a956470 sago007 2016-02-14 17:09 503
7a956470 sago007 2016-02-14 17:09 504
            ar( CEREAL_NVP_("ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
7a956470 sago007 2016-02-14 17:09 505
6c5f2c01 sago007 2017-03-15 17:56 506
            dptr = PolymorphicCasters::template upcast<T>( ptr, baseInfo );
7a956470 sago007 2016-02-14 17:09 507
          };
7a956470 sago007 2016-02-14 17:09 508
7a956470 sago007 2016-02-14 17:09 509
        serializers.unique_ptr =
6c5f2c01 sago007 2017-03-15 17:56 510
          [](void * arptr, std::unique_ptr<void, EmptyDeleter<void>> & dptr, std::type_info const & baseInfo)
7a956470 sago007 2016-02-14 17:09 511
          {
7a956470 sago007 2016-02-14 17:09 512
            Archive & ar = *static_cast<Archive*>(arptr);
7a956470 sago007 2016-02-14 17:09 513
            std::unique_ptr<T> ptr;
7a956470 sago007 2016-02-14 17:09 514
7a956470 sago007 2016-02-14 17:09 515
            ar( CEREAL_NVP_("ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
7a956470 sago007 2016-02-14 17:09 516
6c5f2c01 sago007 2017-03-15 17:56 517
            dptr.reset( PolymorphicCasters::template upcast<T>( ptr.release(), baseInfo ));
7a956470 sago007 2016-02-14 17:09 518
          };
7a956470 sago007 2016-02-14 17:09 519
7a956470 sago007 2016-02-14 17:09 520
        map.insert( lb, { std::move(key), std::move(serializers) } );
7a956470 sago007 2016-02-14 17:09 521
      }
7a956470 sago007 2016-02-14 17:09 522
    };
7a956470 sago007 2016-02-14 17:09 523
7a956470 sago007 2016-02-14 17:09 524
    //! Creates a binding (map entry) between an output archive type and a polymorphic type
7a956470 sago007 2016-02-14 17:09 525
    /*! Bindings are made when types are registered, assuming that at least one
7a956470 sago007 2016-02-14 17:09 526
        archive has already been registered.  When this struct is created,
7a956470 sago007 2016-02-14 17:09 527
        it will insert (at run time) an entry into a map that properly handles
7a956470 sago007 2016-02-14 17:09 528
        casting for serializing polymorphic objects */
7a956470 sago007 2016-02-14 17:09 529
    template <class Archive, class T> struct OutputBindingCreator
7a956470 sago007 2016-02-14 17:09 530
    {
7a956470 sago007 2016-02-14 17:09 531
      //! Writes appropriate metadata to the archive for this polymorphic type
7a956470 sago007 2016-02-14 17:09 532
      static void writeMetadata(Archive & ar)
7a956470 sago007 2016-02-14 17:09 533
      {
7a956470 sago007 2016-02-14 17:09 534
        // Register the polymorphic type name with the archive, and get the id
7a956470 sago007 2016-02-14 17:09 535
        char const * name = binding_name<T>::name();
7a956470 sago007 2016-02-14 17:09 536
        std::uint32_t id = ar.registerPolymorphicType(name);
7a956470 sago007 2016-02-14 17:09 537
7a956470 sago007 2016-02-14 17:09 538
        // Serialize the id
7a956470 sago007 2016-02-14 17:09 539
        ar( CEREAL_NVP_("polymorphic_id", id) );
7a956470 sago007 2016-02-14 17:09 540
7a956470 sago007 2016-02-14 17:09 541
        // If the msb of the id is 1, then the type name is new, and we should serialize it
7a956470 sago007 2016-02-14 17:09 542
        if( id & detail::msb_32bit )
7a956470 sago007 2016-02-14 17:09 543
        {
7a956470 sago007 2016-02-14 17:09 544
          std::string namestring(name);
7a956470 sago007 2016-02-14 17:09 545
          ar( CEREAL_NVP_("polymorphic_name", namestring) );
7a956470 sago007 2016-02-14 17:09 546
        }
7a956470 sago007 2016-02-14 17:09 547
      }
7a956470 sago007 2016-02-14 17:09 548
7a956470 sago007 2016-02-14 17:09 549
      //! Holds a properly typed shared_ptr to the polymorphic type
7a956470 sago007 2016-02-14 17:09 550
      class PolymorphicSharedPointerWrapper
7a956470 sago007 2016-02-14 17:09 551
      {
7a956470 sago007 2016-02-14 17:09 552
        public:
7a956470 sago007 2016-02-14 17:09 553
          /*! Wrap a raw polymorphic pointer in a shared_ptr to its true type
7a956470 sago007 2016-02-14 17:09 554
7a956470 sago007 2016-02-14 17:09 555
              The wrapped pointer will not be responsible for ownership of the held pointer
7a956470 sago007 2016-02-14 17:09 556
              so it will not attempt to destroy it; instead the refcount of the wrapped
7a956470 sago007 2016-02-14 17:09 557
              pointer will be tied to a fake 'ownership pointer' that will do nothing
7a956470 sago007 2016-02-14 17:09 558
              when it ultimately goes out of scope.
7a956470 sago007 2016-02-14 17:09 559
7a956470 sago007 2016-02-14 17:09 560
              The main reason for doing this, other than not to destroy the true object
7a956470 sago007 2016-02-14 17:09 561
              with our wrapper pointer, is to avoid meddling with the internal reference
7a956470 sago007 2016-02-14 17:09 562
              count in a polymorphic type that inherits from std::enable_shared_from_this.
7a956470 sago007 2016-02-14 17:09 563
7a956470 sago007 2016-02-14 17:09 564
              @param dptr A void pointer to the contents of the shared_ptr to serialize */
6c5f2c01 sago007 2017-03-15 17:56 565
          PolymorphicSharedPointerWrapper( T const * dptr ) : refCount(), wrappedPtr( refCount, dptr )
6c5f2c01 sago007 2017-03-15 17:56 566
          { }
7a956470 sago007 2016-02-14 17:09 567
7a956470 sago007 2016-02-14 17:09 568
          //! Get the wrapped shared_ptr */
7a956470 sago007 2016-02-14 17:09 569
          inline std::shared_ptr<T const> const & operator()() const { return wrappedPtr; }
7a956470 sago007 2016-02-14 17:09 570
7a956470 sago007 2016-02-14 17:09 571
        private:
7a956470 sago007 2016-02-14 17:09 572
          std::shared_ptr<void> refCount;      //!< The ownership pointer
7a956470 sago007 2016-02-14 17:09 573
          std::shared_ptr<T const> wrappedPtr; //!< The wrapped pointer
7a956470 sago007 2016-02-14 17:09 574
      };
7a956470 sago007 2016-02-14 17:09 575
7a956470 sago007 2016-02-14 17:09 576
      //! Does the actual work of saving a polymorphic shared_ptr
7a956470 sago007 2016-02-14 17:09 577
      /*! This function will properly create a shared_ptr from the void * that is passed in
7a956470 sago007 2016-02-14 17:09 578
          before passing it to the archive for serialization.
7a956470 sago007 2016-02-14 17:09 579
7a956470 sago007 2016-02-14 17:09 580
          In addition, this will also preserve the state of any internal enable_shared_from_this mechanisms
7a956470 sago007 2016-02-14 17:09 581
7a956470 sago007 2016-02-14 17:09 582
          @param ar The archive to serialize to
7a956470 sago007 2016-02-14 17:09 583
          @param dptr Pointer to the actual data held by the shared_ptr */
6c5f2c01 sago007 2017-03-15 17:56 584
      static inline void savePolymorphicSharedPtr( Archive & ar, T const * dptr, std::true_type /* has_shared_from_this */ )
7a956470 sago007 2016-02-14 17:09 585
      {
6c5f2c01 sago007 2017-03-15 17:56 586
        ::cereal::memory_detail::EnableSharedStateHelper<T> state( const_cast<T *>(dptr) );
7a956470 sago007 2016-02-14 17:09 587
        PolymorphicSharedPointerWrapper psptr( dptr );
7a956470 sago007 2016-02-14 17:09 588
        ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( psptr() ) ) );
7a956470 sago007 2016-02-14 17:09 589
      }
7a956470 sago007 2016-02-14 17:09 590
7a956470 sago007 2016-02-14 17:09 591
      //! Does the actual work of saving a polymorphic shared_ptr
7a956470 sago007 2016-02-14 17:09 592
      /*! This function will properly create a shared_ptr from the void * that is passed in
7a956470 sago007 2016-02-14 17:09 593
          before passing it to the archive for serialization.
7a956470 sago007 2016-02-14 17:09 594
7a956470 sago007 2016-02-14 17:09 595
          This version is for types that do not inherit from std::enable_shared_from_this.
7a956470 sago007 2016-02-14 17:09 596
7a956470 sago007 2016-02-14 17:09 597
          @param ar The archive to serialize to
7a956470 sago007 2016-02-14 17:09 598
          @param dptr Pointer to the actual data held by the shared_ptr */
6c5f2c01 sago007 2017-03-15 17:56 599
      static inline void savePolymorphicSharedPtr( Archive & ar, T const * dptr, std::false_type /* has_shared_from_this */ )
7a956470 sago007 2016-02-14 17:09 600
      {
7a956470 sago007 2016-02-14 17:09 601
        PolymorphicSharedPointerWrapper psptr( dptr );
7a956470 sago007 2016-02-14 17:09 602
        ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( psptr() ) ) );
7a956470 sago007 2016-02-14 17:09 603
      }
7a956470 sago007 2016-02-14 17:09 604
7a956470 sago007 2016-02-14 17:09 605
      //! Initialize the binding
7a956470 sago007 2016-02-14 17:09 606
      OutputBindingCreator()
7a956470 sago007 2016-02-14 17:09 607
      {
7a956470 sago007 2016-02-14 17:09 608
        auto & map = StaticObject<OutputBindingMap<Archive>>::getInstance().map;
7a956470 sago007 2016-02-14 17:09 609
        auto key = std::type_index(typeid(T));
7a956470 sago007 2016-02-14 17:09 610
        auto lb = map.lower_bound(key);
7a956470 sago007 2016-02-14 17:09 611
7a956470 sago007 2016-02-14 17:09 612
        if (lb != map.end() && lb->first == key)
7a956470 sago007 2016-02-14 17:09 613
          return;
7a956470 sago007 2016-02-14 17:09 614
7a956470 sago007 2016-02-14 17:09 615
        typename OutputBindingMap<Archive>::Serializers serializers;
7a956470 sago007 2016-02-14 17:09 616
7a956470 sago007 2016-02-14 17:09 617
        serializers.shared_ptr =
6c5f2c01 sago007 2017-03-15 17:56 618
          [&](void * arptr, void const * dptr, std::type_info const & baseInfo)
7a956470 sago007 2016-02-14 17:09 619
          {
7a956470 sago007 2016-02-14 17:09 620
            Archive & ar = *static_cast<Archive*>(arptr);
7a956470 sago007 2016-02-14 17:09 621
            writeMetadata(ar);
7a956470 sago007 2016-02-14 17:09 622
6c5f2c01 sago007 2017-03-15 17:56 623
            auto ptr = PolymorphicCasters::template downcast<T>( dptr, baseInfo );
6c5f2c01 sago007 2017-03-15 17:56 624
7a956470 sago007 2016-02-14 17:09 625
            #ifdef _MSC_VER
6c5f2c01 sago007 2017-03-15 17:56 626
            savePolymorphicSharedPtr( ar, ptr, ::cereal::traits::has_shared_from_this<T>::type() ); // MSVC doesn't like typename here
7a956470 sago007 2016-02-14 17:09 627
            #else // not _MSC_VER
6c5f2c01 sago007 2017-03-15 17:56 628
            savePolymorphicSharedPtr( ar, ptr, typename ::cereal::traits::has_shared_from_this<T>::type() );
7a956470 sago007 2016-02-14 17:09 629
            #endif // _MSC_VER
7a956470 sago007 2016-02-14 17:09 630
          };
7a956470 sago007 2016-02-14 17:09 631
7a956470 sago007 2016-02-14 17:09 632
        serializers.unique_ptr =
6c5f2c01 sago007 2017-03-15 17:56 633
          [&](void * arptr, void const * dptr, std::type_info const & baseInfo)
7a956470 sago007 2016-02-14 17:09 634
          {
7a956470 sago007 2016-02-14 17:09 635
            Archive & ar = *static_cast<Archive*>(arptr);
7a956470 sago007 2016-02-14 17:09 636
            writeMetadata(ar);
7a956470 sago007 2016-02-14 17:09 637
6c5f2c01 sago007 2017-03-15 17:56 638
            std::unique_ptr<T const, EmptyDeleter<T const>> const ptr( PolymorphicCasters::template downcast<T>( dptr, baseInfo ) );
7a956470 sago007 2016-02-14 17:09 639
7a956470 sago007 2016-02-14 17:09 640
            ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
7a956470 sago007 2016-02-14 17:09 641
          };
7a956470 sago007 2016-02-14 17:09 642
7a956470 sago007 2016-02-14 17:09 643
        map.insert( { std::move(key), std::move(serializers) } );
7a956470 sago007 2016-02-14 17:09 644
      }
7a956470 sago007 2016-02-14 17:09 645
    };
7a956470 sago007 2016-02-14 17:09 646
7a956470 sago007 2016-02-14 17:09 647
    //! Used to help out argument dependent lookup for finding potential overloads
7a956470 sago007 2016-02-14 17:09 648
    //! of instantiate_polymorphic_binding
7a956470 sago007 2016-02-14 17:09 649
    struct adl_tag {};
7a956470 sago007 2016-02-14 17:09 650
7a956470 sago007 2016-02-14 17:09 651
    //! Tag for init_binding, bind_to_archives and instantiate_polymorphic_binding. Due to the use of anonymous
7a956470 sago007 2016-02-14 17:09 652
    //! namespace it becomes a different type in each translation unit.
7a956470 sago007 2016-02-14 17:09 653
    namespace { struct polymorphic_binding_tag {}; }
7a956470 sago007 2016-02-14 17:09 654
7a956470 sago007 2016-02-14 17:09 655
    //! Causes the static object bindings between an archive type and a serializable type T
7a956470 sago007 2016-02-14 17:09 656
    template <class Archive, class T>
7a956470 sago007 2016-02-14 17:09 657
    struct create_bindings
7a956470 sago007 2016-02-14 17:09 658
    {
7a956470 sago007 2016-02-14 17:09 659
      static const InputBindingCreator<Archive, T> &
7a956470 sago007 2016-02-14 17:09 660
      load(std::true_type)
7a956470 sago007 2016-02-14 17:09 661
      {
7a956470 sago007 2016-02-14 17:09 662
        return cereal::detail::StaticObject<InputBindingCreator<Archive, T>>::getInstance();
7a956470 sago007 2016-02-14 17:09 663
      }
7a956470 sago007 2016-02-14 17:09 664
7a956470 sago007 2016-02-14 17:09 665
      static const OutputBindingCreator<Archive, T> &
7a956470 sago007 2016-02-14 17:09 666
      save(std::true_type)
7a956470 sago007 2016-02-14 17:09 667
      {
7a956470 sago007 2016-02-14 17:09 668
        return cereal::detail::StaticObject<OutputBindingCreator<Archive, T>>::getInstance();
7a956470 sago007 2016-02-14 17:09 669
      }
7a956470 sago007 2016-02-14 17:09 670
7a956470 sago007 2016-02-14 17:09 671
      inline static void load(std::false_type) {}
7a956470 sago007 2016-02-14 17:09 672
      inline static void save(std::false_type) {}
7a956470 sago007 2016-02-14 17:09 673
    };
7a956470 sago007 2016-02-14 17:09 674
7a956470 sago007 2016-02-14 17:09 675
    //! When specialized, causes the compiler to instantiate its parameter
7a956470 sago007 2016-02-14 17:09 676
    template <void(*)()>
7a956470 sago007 2016-02-14 17:09 677
    struct instantiate_function {};
7a956470 sago007 2016-02-14 17:09 678
7a956470 sago007 2016-02-14 17:09 679
    /*! This struct is used as the return type of instantiate_polymorphic_binding
7a956470 sago007 2016-02-14 17:09 680
        for specific Archive types.  When the compiler looks for overloads of
7a956470 sago007 2016-02-14 17:09 681
        instantiate_polymorphic_binding, it will be forced to instantiate this
7a956470 sago007 2016-02-14 17:09 682
        struct during overload resolution, even though it will not be part of a valid
7a956470 sago007 2016-02-14 17:09 683
        overload */
7a956470 sago007 2016-02-14 17:09 684
    template <class Archive, class T>
7a956470 sago007 2016-02-14 17:09 685
    struct polymorphic_serialization_support
7a956470 sago007 2016-02-14 17:09 686
    {
7a956470 sago007 2016-02-14 17:09 687
      #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
7a956470 sago007 2016-02-14 17:09 688
      //! Creates the appropriate bindings depending on whether the archive supports
7a956470 sago007 2016-02-14 17:09 689
      //! saving or loading
7a956470 sago007 2016-02-14 17:09 690
      virtual CEREAL_DLL_EXPORT void instantiate() CEREAL_USED;
7a956470 sago007 2016-02-14 17:09 691
      #else // NOT _MSC_VER
7a956470 sago007 2016-02-14 17:09 692
      //! Creates the appropriate bindings depending on whether the archive supports
7a956470 sago007 2016-02-14 17:09 693
      //! saving or loading
7a956470 sago007 2016-02-14 17:09 694
      static CEREAL_DLL_EXPORT void instantiate() CEREAL_USED;
7a956470 sago007 2016-02-14 17:09 695
      //! This typedef causes the compiler to instantiate this static function
7a956470 sago007 2016-02-14 17:09 696
      typedef instantiate_function<instantiate> unused;
7a956470 sago007 2016-02-14 17:09 697
      #endif // _MSC_VER
7a956470 sago007 2016-02-14 17:09 698
    };
7a956470 sago007 2016-02-14 17:09 699
7a956470 sago007 2016-02-14 17:09 700
    // instantiate implementation
7a956470 sago007 2016-02-14 17:09 701
    template <class Archive, class T>
7a956470 sago007 2016-02-14 17:09 702
    CEREAL_DLL_EXPORT void polymorphic_serialization_support<Archive,T>::instantiate()
7a956470 sago007 2016-02-14 17:09 703
    {
7a956470 sago007 2016-02-14 17:09 704
      create_bindings<Archive,T>::save( std::integral_constant<bool,
7a956470 sago007 2016-02-14 17:09 705
                                          std::is_base_of<detail::OutputArchiveBase, Archive>::value &&
7a956470 sago007 2016-02-14 17:09 706
                                          traits::is_output_serializable<T, Archive>::value>{} );
7a956470 sago007 2016-02-14 17:09 707
7a956470 sago007 2016-02-14 17:09 708
      create_bindings<Archive,T>::load( std::integral_constant<bool,
7a956470 sago007 2016-02-14 17:09 709
                                          std::is_base_of<detail::InputArchiveBase, Archive>::value &&
7a956470 sago007 2016-02-14 17:09 710
                                          traits::is_input_serializable<T, Archive>::value>{} );
7a956470 sago007 2016-02-14 17:09 711
    }
7a956470 sago007 2016-02-14 17:09 712
7a956470 sago007 2016-02-14 17:09 713
    //! Begins the binding process of a type to all registered archives
7a956470 sago007 2016-02-14 17:09 714
    /*! Archives need to be registered prior to this struct being instantiated via
7a956470 sago007 2016-02-14 17:09 715
        the CEREAL_REGISTER_ARCHIVE macro.  Overload resolution will then force
7a956470 sago007 2016-02-14 17:09 716
        several static objects to be made that allow us to bind together all
7a956470 sago007 2016-02-14 17:09 717
        registered archive types with the parameter type T. */
7a956470 sago007 2016-02-14 17:09 718
    template <class T, class Tag = polymorphic_binding_tag>
7a956470 sago007 2016-02-14 17:09 719
    struct bind_to_archives
7a956470 sago007 2016-02-14 17:09 720
    {
7a956470 sago007 2016-02-14 17:09 721
      //! Binding for non abstract types
7a956470 sago007 2016-02-14 17:09 722
      void bind(std::false_type) const
6c5f2c01 sago007 2017-03-15 17:56 723
      {
6c5f2c01 sago007 2017-03-15 17:56 724
        instantiate_polymorphic_binding(static_cast<T*>(nullptr), 0, Tag{}, adl_tag{});
7a956470 sago007 2016-02-14 17:09 725
      }
7a956470 sago007 2016-02-14 17:09 726
7a956470 sago007 2016-02-14 17:09 727
      //! Binding for abstract types
7a956470 sago007 2016-02-14 17:09 728
      void bind(std::true_type) const
7a956470 sago007 2016-02-14 17:09 729
      { }
7a956470 sago007 2016-02-14 17:09 730
7a956470 sago007 2016-02-14 17:09 731
      //! Binds the type T to all registered archives
7a956470 sago007 2016-02-14 17:09 732
      /*! If T is abstract, we will not serialize it and thus
7a956470 sago007 2016-02-14 17:09 733
          do not need to make a binding */
7a956470 sago007 2016-02-14 17:09 734
      bind_to_archives const & bind() const
7a956470 sago007 2016-02-14 17:09 735
      {
7a956470 sago007 2016-02-14 17:09 736
        static_assert( std::is_polymorphic<T>::value,
7a956470 sago007 2016-02-14 17:09 737
                       "Attempting to register non polymorphic type" );
7a956470 sago007 2016-02-14 17:09 738
        bind( std::is_abstract<T>() );
7a956470 sago007 2016-02-14 17:09 739
        return *this;
7a956470 sago007 2016-02-14 17:09 740
      }
7a956470 sago007 2016-02-14 17:09 741
    };
7a956470 sago007 2016-02-14 17:09 742
7a956470 sago007 2016-02-14 17:09 743
    //! Used to hide the static object used to bind T to registered archives
7a956470 sago007 2016-02-14 17:09 744
    template <class T, class Tag = polymorphic_binding_tag>
7a956470 sago007 2016-02-14 17:09 745
    struct init_binding;
7a956470 sago007 2016-02-14 17:09 746
7a956470 sago007 2016-02-14 17:09 747
    //! Base case overload for instantiation
7a956470 sago007 2016-02-14 17:09 748
    /*! This will end up always being the best overload due to the second
7a956470 sago007 2016-02-14 17:09 749
        parameter always being passed as an int.  All other overloads will
7a956470 sago007 2016-02-14 17:09 750
        accept pointers to archive types and have lower precedence than int.
7a956470 sago007 2016-02-14 17:09 751
7a956470 sago007 2016-02-14 17:09 752
        Since the compiler needs to check all possible overloads, the
7a956470 sago007 2016-02-14 17:09 753
        other overloads created via CEREAL_REGISTER_ARCHIVE, which will have
7a956470 sago007 2016-02-14 17:09 754
        lower precedence due to requring a conversion from int to (Archive*),
7a956470 sago007 2016-02-14 17:09 755
        will cause their return types to be instantiated through the static object
7a956470 sago007 2016-02-14 17:09 756
        mechanisms even though they are never called.
7a956470 sago007 2016-02-14 17:09 757
7a956470 sago007 2016-02-14 17:09 758
        See the documentation for the other functions to try and understand this */
7a956470 sago007 2016-02-14 17:09 759
    template <class T, typename BindingTag>
7a956470 sago007 2016-02-14 17:09 760
    void instantiate_polymorphic_binding( T*, int, BindingTag, adl_tag ) {}
7a956470 sago007 2016-02-14 17:09 761
  } // namespace detail
7a956470 sago007 2016-02-14 17:09 762
} // namespace cereal
7a956470 sago007 2016-02-14 17:09 763
7a956470 sago007 2016-02-14 17:09 764
#endif // CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_
1970-01-01 00:00 765