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