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
7a956470 sago007 2016-02-14 17:09 41
   See /boost/serialization/export.hpp and /boost/archive/detail/register_archive.hpp for their
7a956470 sago007 2016-02-14 17:09 42
   implementation.
7a956470 sago007 2016-02-14 17:09 43
*/
7a956470 sago007 2016-02-14 17:09 44
#ifndef CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_
7a956470 sago007 2016-02-14 17:09 45
#define CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_
7a956470 sago007 2016-02-14 17:09 46
7a956470 sago007 2016-02-14 17:09 47
#include <cereal/details/static_object.hpp>
7a956470 sago007 2016-02-14 17:09 48
#include <cereal/types/memory.hpp>
7a956470 sago007 2016-02-14 17:09 49
#include <cereal/types/string.hpp>
7a956470 sago007 2016-02-14 17:09 50
#include <functional>
7a956470 sago007 2016-02-14 17:09 51
#include <typeindex>
7a956470 sago007 2016-02-14 17:09 52
#include <map>
7a956470 sago007 2016-02-14 17:09 53
7a956470 sago007 2016-02-14 17:09 54
//! Binds a polymorhic type to all registered archives
7a956470 sago007 2016-02-14 17:09 55
/*! This binds a polymorphic type to all compatible registered archives that
7a956470 sago007 2016-02-14 17:09 56
    have been registered with CEREAL_REGISTER_ARCHIVE.  This must be called
7a956470 sago007 2016-02-14 17:09 57
    after all archives are registered (usually after the archives themselves
7a956470 sago007 2016-02-14 17:09 58
    have been included). */
7a956470 sago007 2016-02-14 17:09 59
#define CEREAL_BIND_TO_ARCHIVES(T)                   \
7a956470 sago007 2016-02-14 17:09 60
    namespace cereal {                               \
7a956470 sago007 2016-02-14 17:09 61
    namespace detail {                               \
7a956470 sago007 2016-02-14 17:09 62
    template<>                                       \
7a956470 sago007 2016-02-14 17:09 63
    struct init_binding<T> {                         \
7a956470 sago007 2016-02-14 17:09 64
        static bind_to_archives<T> const & b;        \
7a956470 sago007 2016-02-14 17:09 65
        static void unused() { (void)b; }            \
7a956470 sago007 2016-02-14 17:09 66
    };                                               \
7a956470 sago007 2016-02-14 17:09 67
    bind_to_archives<T> const & init_binding<T>::b = \
7a956470 sago007 2016-02-14 17:09 68
        ::cereal::detail::StaticObject<              \
7a956470 sago007 2016-02-14 17:09 69
            bind_to_archives<T>                      \
7a956470 sago007 2016-02-14 17:09 70
        >::getInstance().bind();                     \
7a956470 sago007 2016-02-14 17:09 71
    }} /* end namespaces */
7a956470 sago007 2016-02-14 17:09 72
7a956470 sago007 2016-02-14 17:09 73
namespace cereal
7a956470 sago007 2016-02-14 17:09 74
{
7a956470 sago007 2016-02-14 17:09 75
  namespace detail
7a956470 sago007 2016-02-14 17:09 76
  {
7a956470 sago007 2016-02-14 17:09 77
    //! Binds a compile time type with a user defined string
7a956470 sago007 2016-02-14 17:09 78
    template <class T>
7a956470 sago007 2016-02-14 17:09 79
    struct binding_name {};
7a956470 sago007 2016-02-14 17:09 80
7a956470 sago007 2016-02-14 17:09 81
    //! A structure holding a map from type_indices to output serializer functions
7a956470 sago007 2016-02-14 17:09 82
    /*! A static object of this map should be created for each registered archive
7a956470 sago007 2016-02-14 17:09 83
        type, containing entries for every registered type that describe how to
7a956470 sago007 2016-02-14 17:09 84
        properly cast the type to its real type in polymorphic scenarios for
7a956470 sago007 2016-02-14 17:09 85
        shared_ptr, weak_ptr, and unique_ptr. */
7a956470 sago007 2016-02-14 17:09 86
    template <class Archive>
7a956470 sago007 2016-02-14 17:09 87
    struct OutputBindingMap
7a956470 sago007 2016-02-14 17:09 88
    {
7a956470 sago007 2016-02-14 17:09 89
      //! A serializer function
7a956470 sago007 2016-02-14 17:09 90
      /*! Serializer functions return nothing and take an archive as
7a956470 sago007 2016-02-14 17:09 91
          their first parameter (will be cast properly inside the function,
7a956470 sago007 2016-02-14 17:09 92
          and a pointer to actual data (contents of smart_ptr's get() function)
7a956470 sago007 2016-02-14 17:09 93
          as their second parameter */
7a956470 sago007 2016-02-14 17:09 94
      typedef std::function<void(void*, void const *)> Serializer;
7a956470 sago007 2016-02-14 17:09 95
7a956470 sago007 2016-02-14 17:09 96
      //! Struct containing the serializer functions for all pointer types
7a956470 sago007 2016-02-14 17:09 97
      struct Serializers
7a956470 sago007 2016-02-14 17:09 98
      {
7a956470 sago007 2016-02-14 17:09 99
        Serializer shared_ptr, //!< Serializer function for shared/weak pointers
7a956470 sago007 2016-02-14 17:09 100
                   unique_ptr; //!< Serializer function for unique pointers
7a956470 sago007 2016-02-14 17:09 101
      };
7a956470 sago007 2016-02-14 17:09 102
7a956470 sago007 2016-02-14 17:09 103
      //! A map of serializers for pointers of all registered types
7a956470 sago007 2016-02-14 17:09 104
      std::map<std::type_index, Serializers> map;
7a956470 sago007 2016-02-14 17:09 105
    };
7a956470 sago007 2016-02-14 17:09 106
7a956470 sago007 2016-02-14 17:09 107
    //! An empty noop deleter
7a956470 sago007 2016-02-14 17:09 108
    template<class T> struct EmptyDeleter { void operator()(T *) const {} };
7a956470 sago007 2016-02-14 17:09 109
7a956470 sago007 2016-02-14 17:09 110
    //! A structure holding a map from type name strings to input serializer functions
7a956470 sago007 2016-02-14 17:09 111
    /*! A static object of this map should be created for each registered archive
7a956470 sago007 2016-02-14 17:09 112
        type, containing entries for every registered type that describe how to
7a956470 sago007 2016-02-14 17:09 113
        properly cast the type to its real type in polymorphic scenarios for
7a956470 sago007 2016-02-14 17:09 114
        shared_ptr, weak_ptr, and unique_ptr. */
7a956470 sago007 2016-02-14 17:09 115
    template <class Archive>
7a956470 sago007 2016-02-14 17:09 116
    struct InputBindingMap
7a956470 sago007 2016-02-14 17:09 117
    {
7a956470 sago007 2016-02-14 17:09 118
      //! Shared ptr serializer function
7a956470 sago007 2016-02-14 17:09 119
      /*! Serializer functions return nothing and take an archive as
7a956470 sago007 2016-02-14 17:09 120
          their first parameter (will be cast properly inside the function,
7a956470 sago007 2016-02-14 17:09 121
          and a shared_ptr (or unique_ptr for the unique case) of any base
7a956470 sago007 2016-02-14 17:09 122
          type.  Internally it will properly be loaded and cast to the
7a956470 sago007 2016-02-14 17:09 123
          correct type. */
7a956470 sago007 2016-02-14 17:09 124
      typedef std::function<void(void*, std::shared_ptr<void> & )> SharedSerializer;
7a956470 sago007 2016-02-14 17:09 125
      //! Unique ptr serializer function
7a956470 sago007 2016-02-14 17:09 126
      typedef std::function<void(void*, std::unique_ptr<void, EmptyDeleter<void>> & )> UniqueSerializer;
7a956470 sago007 2016-02-14 17:09 127
7a956470 sago007 2016-02-14 17:09 128
      //! Struct containing the serializer functions for all pointer types
7a956470 sago007 2016-02-14 17:09 129
      struct Serializers
7a956470 sago007 2016-02-14 17:09 130
      {
7a956470 sago007 2016-02-14 17:09 131
        SharedSerializer shared_ptr; //!< Serializer function for shared/weak pointers
7a956470 sago007 2016-02-14 17:09 132
        UniqueSerializer unique_ptr; //!< Serializer function for unique pointers
7a956470 sago007 2016-02-14 17:09 133
      };
7a956470 sago007 2016-02-14 17:09 134
7a956470 sago007 2016-02-14 17:09 135
      //! A map of serializers for pointers of all registered types
7a956470 sago007 2016-02-14 17:09 136
      std::map<std::string, Serializers> map;
7a956470 sago007 2016-02-14 17:09 137
    };
7a956470 sago007 2016-02-14 17:09 138
7a956470 sago007 2016-02-14 17:09 139
    // forward decls for archives from cereal.hpp
7a956470 sago007 2016-02-14 17:09 140
    class InputArchiveBase;
7a956470 sago007 2016-02-14 17:09 141
    class OutputArchiveBase;
7a956470 sago007 2016-02-14 17:09 142
7a956470 sago007 2016-02-14 17:09 143
    //! Creates a binding (map entry) between an input archive type and a polymorphic type
7a956470 sago007 2016-02-14 17:09 144
    /*! Bindings are made when types are registered, assuming that at least one
7a956470 sago007 2016-02-14 17:09 145
        archive has already been registered.  When this struct is created,
7a956470 sago007 2016-02-14 17:09 146
        it will insert (at run time) an entry into a map that properly handles
7a956470 sago007 2016-02-14 17:09 147
        casting for serializing polymorphic objects */
7a956470 sago007 2016-02-14 17:09 148
    template <class Archive, class T> struct InputBindingCreator
7a956470 sago007 2016-02-14 17:09 149
    {
7a956470 sago007 2016-02-14 17:09 150
      //! Initialize the binding
7a956470 sago007 2016-02-14 17:09 151
      InputBindingCreator()
7a956470 sago007 2016-02-14 17:09 152
      {
7a956470 sago007 2016-02-14 17:09 153
        auto & map = StaticObject<InputBindingMap<Archive>>::getInstance().map;
7a956470 sago007 2016-02-14 17:09 154
        auto key = std::string(binding_name<T>::name());
7a956470 sago007 2016-02-14 17:09 155
        auto lb = map.lower_bound(key);
7a956470 sago007 2016-02-14 17:09 156
7a956470 sago007 2016-02-14 17:09 157
        if (lb != map.end() && lb->first == key)
7a956470 sago007 2016-02-14 17:09 158
          return;
7a956470 sago007 2016-02-14 17:09 159
7a956470 sago007 2016-02-14 17:09 160
        typename InputBindingMap<Archive>::Serializers serializers;
7a956470 sago007 2016-02-14 17:09 161
7a956470 sago007 2016-02-14 17:09 162
        serializers.shared_ptr =
7a956470 sago007 2016-02-14 17:09 163
          [](void * arptr, std::shared_ptr<void> & dptr)
7a956470 sago007 2016-02-14 17:09 164
          {
7a956470 sago007 2016-02-14 17:09 165
            Archive & ar = *static_cast<Archive*>(arptr);
7a956470 sago007 2016-02-14 17:09 166
            std::shared_ptr<T> ptr;
7a956470 sago007 2016-02-14 17:09 167
7a956470 sago007 2016-02-14 17:09 168
            ar( CEREAL_NVP_("ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
7a956470 sago007 2016-02-14 17:09 169
7a956470 sago007 2016-02-14 17:09 170
            dptr = ptr;
7a956470 sago007 2016-02-14 17:09 171
          };
7a956470 sago007 2016-02-14 17:09 172
7a956470 sago007 2016-02-14 17:09 173
        serializers.unique_ptr =
7a956470 sago007 2016-02-14 17:09 174
          [](void * arptr, std::unique_ptr<void, EmptyDeleter<void>> & dptr)
7a956470 sago007 2016-02-14 17:09 175
          {
7a956470 sago007 2016-02-14 17:09 176
            Archive & ar = *static_cast<Archive*>(arptr);
7a956470 sago007 2016-02-14 17:09 177
            std::unique_ptr<T> ptr;
7a956470 sago007 2016-02-14 17:09 178
7a956470 sago007 2016-02-14 17:09 179
            ar( CEREAL_NVP_("ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
7a956470 sago007 2016-02-14 17:09 180
7a956470 sago007 2016-02-14 17:09 181
            dptr.reset(ptr.release());
7a956470 sago007 2016-02-14 17:09 182
          };
7a956470 sago007 2016-02-14 17:09 183
7a956470 sago007 2016-02-14 17:09 184
        map.insert( lb, { std::move(key), std::move(serializers) } );
7a956470 sago007 2016-02-14 17:09 185
      }
7a956470 sago007 2016-02-14 17:09 186
    };
7a956470 sago007 2016-02-14 17:09 187
7a956470 sago007 2016-02-14 17:09 188
    //! Creates a binding (map entry) between an output archive type and a polymorphic type
7a956470 sago007 2016-02-14 17:09 189
    /*! Bindings are made when types are registered, assuming that at least one
7a956470 sago007 2016-02-14 17:09 190
        archive has already been registered.  When this struct is created,
7a956470 sago007 2016-02-14 17:09 191
        it will insert (at run time) an entry into a map that properly handles
7a956470 sago007 2016-02-14 17:09 192
        casting for serializing polymorphic objects */
7a956470 sago007 2016-02-14 17:09 193
    template <class Archive, class T> struct OutputBindingCreator
7a956470 sago007 2016-02-14 17:09 194
    {
7a956470 sago007 2016-02-14 17:09 195
      //! Writes appropriate metadata to the archive for this polymorphic type
7a956470 sago007 2016-02-14 17:09 196
      static void writeMetadata(Archive & ar)
7a956470 sago007 2016-02-14 17:09 197
      {
7a956470 sago007 2016-02-14 17:09 198
        // Register the polymorphic type name with the archive, and get the id
7a956470 sago007 2016-02-14 17:09 199
        char const * name = binding_name<T>::name();
7a956470 sago007 2016-02-14 17:09 200
        std::uint32_t id = ar.registerPolymorphicType(name);
7a956470 sago007 2016-02-14 17:09 201
7a956470 sago007 2016-02-14 17:09 202
        // Serialize the id
7a956470 sago007 2016-02-14 17:09 203
        ar( CEREAL_NVP_("polymorphic_id", id) );
7a956470 sago007 2016-02-14 17:09 204
7a956470 sago007 2016-02-14 17:09 205
        // 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 206
        if( id & detail::msb_32bit )
7a956470 sago007 2016-02-14 17:09 207
        {
7a956470 sago007 2016-02-14 17:09 208
          std::string namestring(name);
7a956470 sago007 2016-02-14 17:09 209
          ar( CEREAL_NVP_("polymorphic_name", namestring) );
7a956470 sago007 2016-02-14 17:09 210
        }
7a956470 sago007 2016-02-14 17:09 211
      }
7a956470 sago007 2016-02-14 17:09 212
7a956470 sago007 2016-02-14 17:09 213
      //! Holds a properly typed shared_ptr to the polymorphic type
7a956470 sago007 2016-02-14 17:09 214
      class PolymorphicSharedPointerWrapper
7a956470 sago007 2016-02-14 17:09 215
      {
7a956470 sago007 2016-02-14 17:09 216
        public:
7a956470 sago007 2016-02-14 17:09 217
          /*! Wrap a raw polymorphic pointer in a shared_ptr to its true type
7a956470 sago007 2016-02-14 17:09 218
7a956470 sago007 2016-02-14 17:09 219
              The wrapped pointer will not be responsible for ownership of the held pointer
7a956470 sago007 2016-02-14 17:09 220
              so it will not attempt to destroy it; instead the refcount of the wrapped
7a956470 sago007 2016-02-14 17:09 221
              pointer will be tied to a fake 'ownership pointer' that will do nothing
7a956470 sago007 2016-02-14 17:09 222
              when it ultimately goes out of scope.
7a956470 sago007 2016-02-14 17:09 223
7a956470 sago007 2016-02-14 17:09 224
              The main reason for doing this, other than not to destroy the true object
7a956470 sago007 2016-02-14 17:09 225
              with our wrapper pointer, is to avoid meddling with the internal reference
7a956470 sago007 2016-02-14 17:09 226
              count in a polymorphic type that inherits from std::enable_shared_from_this.
7a956470 sago007 2016-02-14 17:09 227
7a956470 sago007 2016-02-14 17:09 228
              @param dptr A void pointer to the contents of the shared_ptr to serialize */
7a956470 sago007 2016-02-14 17:09 229
          PolymorphicSharedPointerWrapper( void const * dptr ) : refCount()
7a956470 sago007 2016-02-14 17:09 230
          {
7a956470 sago007 2016-02-14 17:09 231
            #ifdef _LIBCPP_VERSION
7a956470 sago007 2016-02-14 17:09 232
            // libc++ needs this hacky workaround, see http://llvm.org/bugs/show_bug.cgi?id=18843
7a956470 sago007 2016-02-14 17:09 233
            wrappedPtr = std::shared_ptr<T const>(
7a956470 sago007 2016-02-14 17:09 234
                std::const_pointer_cast<T const>(
7a956470 sago007 2016-02-14 17:09 235
                  std::shared_ptr<T>( refCount, static_cast<T *>(const_cast<void *>(dptr) ))));
7a956470 sago007 2016-02-14 17:09 236
            #else // NOT _LIBCPP_VERSION
7a956470 sago007 2016-02-14 17:09 237
            wrappedPtr = std::shared_ptr<T const>( refCount, static_cast<T const *>(dptr) );
7a956470 sago007 2016-02-14 17:09 238
            #endif // _LIBCPP_VERSION
7a956470 sago007 2016-02-14 17:09 239
          }
7a956470 sago007 2016-02-14 17:09 240
7a956470 sago007 2016-02-14 17:09 241
          //! Get the wrapped shared_ptr */
7a956470 sago007 2016-02-14 17:09 242
          inline std::shared_ptr<T const> const & operator()() const { return wrappedPtr; }
7a956470 sago007 2016-02-14 17:09 243
7a956470 sago007 2016-02-14 17:09 244
        private:
7a956470 sago007 2016-02-14 17:09 245
          std::shared_ptr<void> refCount;      //!< The ownership pointer
7a956470 sago007 2016-02-14 17:09 246
          std::shared_ptr<T const> wrappedPtr; //!< The wrapped pointer
7a956470 sago007 2016-02-14 17:09 247
      };
7a956470 sago007 2016-02-14 17:09 248
7a956470 sago007 2016-02-14 17:09 249
      //! Does the actual work of saving a polymorphic shared_ptr
7a956470 sago007 2016-02-14 17:09 250
      /*! This function will properly create a shared_ptr from the void * that is passed in
7a956470 sago007 2016-02-14 17:09 251
          before passing it to the archive for serialization.
7a956470 sago007 2016-02-14 17:09 252
7a956470 sago007 2016-02-14 17:09 253
          In addition, this will also preserve the state of any internal enable_shared_from_this mechanisms
7a956470 sago007 2016-02-14 17:09 254
7a956470 sago007 2016-02-14 17:09 255
          @param ar The archive to serialize to
7a956470 sago007 2016-02-14 17:09 256
          @param dptr Pointer to the actual data held by the shared_ptr */
7a956470 sago007 2016-02-14 17:09 257
      static inline void savePolymorphicSharedPtr( Archive & ar, void const * dptr, std::true_type /* has_shared_from_this */ )
7a956470 sago007 2016-02-14 17:09 258
      {
7a956470 sago007 2016-02-14 17:09 259
        ::cereal::memory_detail::EnableSharedStateHelper<T> state( static_cast<T *>(const_cast<void *>(dptr)) );
7a956470 sago007 2016-02-14 17:09 260
        PolymorphicSharedPointerWrapper psptr( dptr );
7a956470 sago007 2016-02-14 17:09 261
        ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( psptr() ) ) );
7a956470 sago007 2016-02-14 17:09 262
      }
7a956470 sago007 2016-02-14 17:09 263
7a956470 sago007 2016-02-14 17:09 264
      //! Does the actual work of saving a polymorphic shared_ptr
7a956470 sago007 2016-02-14 17:09 265
      /*! This function will properly create a shared_ptr from the void * that is passed in
7a956470 sago007 2016-02-14 17:09 266
          before passing it to the archive for serialization.
7a956470 sago007 2016-02-14 17:09 267
7a956470 sago007 2016-02-14 17:09 268
          This version is for types that do not inherit from std::enable_shared_from_this.
7a956470 sago007 2016-02-14 17:09 269
7a956470 sago007 2016-02-14 17:09 270
          @param ar The archive to serialize to
7a956470 sago007 2016-02-14 17:09 271
          @param dptr Pointer to the actual data held by the shared_ptr */
7a956470 sago007 2016-02-14 17:09 272
      static inline void savePolymorphicSharedPtr( Archive & ar, void const * dptr, std::false_type /* has_shared_from_this */ )
7a956470 sago007 2016-02-14 17:09 273
      {
7a956470 sago007 2016-02-14 17:09 274
        PolymorphicSharedPointerWrapper psptr( dptr );
7a956470 sago007 2016-02-14 17:09 275
        ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( psptr() ) ) );
7a956470 sago007 2016-02-14 17:09 276
      }
7a956470 sago007 2016-02-14 17:09 277
7a956470 sago007 2016-02-14 17:09 278
      //! Initialize the binding
7a956470 sago007 2016-02-14 17:09 279
      OutputBindingCreator()
7a956470 sago007 2016-02-14 17:09 280
      {
7a956470 sago007 2016-02-14 17:09 281
        auto & map = StaticObject<OutputBindingMap<Archive>>::getInstance().map;
7a956470 sago007 2016-02-14 17:09 282
        auto key = std::type_index(typeid(T));
7a956470 sago007 2016-02-14 17:09 283
        auto lb = map.lower_bound(key);
7a956470 sago007 2016-02-14 17:09 284
7a956470 sago007 2016-02-14 17:09 285
        if (lb != map.end() && lb->first == key)
7a956470 sago007 2016-02-14 17:09 286
          return;
7a956470 sago007 2016-02-14 17:09 287
7a956470 sago007 2016-02-14 17:09 288
        typename OutputBindingMap<Archive>::Serializers serializers;
7a956470 sago007 2016-02-14 17:09 289
7a956470 sago007 2016-02-14 17:09 290
        serializers.shared_ptr =
7a956470 sago007 2016-02-14 17:09 291
          [&](void * arptr, void const * dptr)
7a956470 sago007 2016-02-14 17:09 292
          {
7a956470 sago007 2016-02-14 17:09 293
            Archive & ar = *static_cast<Archive*>(arptr);
7a956470 sago007 2016-02-14 17:09 294
7a956470 sago007 2016-02-14 17:09 295
            writeMetadata(ar);
7a956470 sago007 2016-02-14 17:09 296
7a956470 sago007 2016-02-14 17:09 297
            #ifdef _MSC_VER
7a956470 sago007 2016-02-14 17:09 298
            savePolymorphicSharedPtr( ar, dptr, ::cereal::traits::has_shared_from_this<T>::type() ); // MSVC doesn't like typename here
7a956470 sago007 2016-02-14 17:09 299
            #else // not _MSC_VER
7a956470 sago007 2016-02-14 17:09 300
            savePolymorphicSharedPtr( ar, dptr, typename ::cereal::traits::has_shared_from_this<T>::type() );
7a956470 sago007 2016-02-14 17:09 301
            #endif // _MSC_VER
7a956470 sago007 2016-02-14 17:09 302
          };
7a956470 sago007 2016-02-14 17:09 303
7a956470 sago007 2016-02-14 17:09 304
        serializers.unique_ptr =
7a956470 sago007 2016-02-14 17:09 305
          [&](void * arptr, void const * dptr)
7a956470 sago007 2016-02-14 17:09 306
          {
7a956470 sago007 2016-02-14 17:09 307
            Archive & ar = *static_cast<Archive*>(arptr);
7a956470 sago007 2016-02-14 17:09 308
7a956470 sago007 2016-02-14 17:09 309
            writeMetadata(ar);
7a956470 sago007 2016-02-14 17:09 310
7a956470 sago007 2016-02-14 17:09 311
            std::unique_ptr<T const, EmptyDeleter<T const>> const ptr(static_cast<T const *>(dptr));
7a956470 sago007 2016-02-14 17:09 312
7a956470 sago007 2016-02-14 17:09 313
            ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
7a956470 sago007 2016-02-14 17:09 314
          };
7a956470 sago007 2016-02-14 17:09 315
7a956470 sago007 2016-02-14 17:09 316
        map.insert( { std::move(key), std::move(serializers) } );
7a956470 sago007 2016-02-14 17:09 317
      }
7a956470 sago007 2016-02-14 17:09 318
    };
7a956470 sago007 2016-02-14 17:09 319
7a956470 sago007 2016-02-14 17:09 320
    //! Used to help out argument dependent lookup for finding potential overloads
7a956470 sago007 2016-02-14 17:09 321
    //! of instantiate_polymorphic_binding
7a956470 sago007 2016-02-14 17:09 322
    struct adl_tag {};
7a956470 sago007 2016-02-14 17:09 323
7a956470 sago007 2016-02-14 17:09 324
    //! Tag for init_binding, bind_to_archives and instantiate_polymorphic_binding. Due to the use of anonymous
7a956470 sago007 2016-02-14 17:09 325
    //! namespace it becomes a different type in each translation unit.
7a956470 sago007 2016-02-14 17:09 326
    namespace { struct polymorphic_binding_tag {}; }
7a956470 sago007 2016-02-14 17:09 327
7a956470 sago007 2016-02-14 17:09 328
    //! Causes the static object bindings between an archive type and a serializable type T
7a956470 sago007 2016-02-14 17:09 329
    template <class Archive, class T>
7a956470 sago007 2016-02-14 17:09 330
    struct create_bindings
7a956470 sago007 2016-02-14 17:09 331
    {
7a956470 sago007 2016-02-14 17:09 332
      static const InputBindingCreator<Archive, T> &
7a956470 sago007 2016-02-14 17:09 333
      load(std::true_type)
7a956470 sago007 2016-02-14 17:09 334
      {
7a956470 sago007 2016-02-14 17:09 335
        return cereal::detail::StaticObject<InputBindingCreator<Archive, T>>::getInstance();
7a956470 sago007 2016-02-14 17:09 336
      }
7a956470 sago007 2016-02-14 17:09 337
7a956470 sago007 2016-02-14 17:09 338
      static const OutputBindingCreator<Archive, T> &
7a956470 sago007 2016-02-14 17:09 339
      save(std::true_type)
7a956470 sago007 2016-02-14 17:09 340
      {
7a956470 sago007 2016-02-14 17:09 341
        return cereal::detail::StaticObject<OutputBindingCreator<Archive, T>>::getInstance();
7a956470 sago007 2016-02-14 17:09 342
      }
7a956470 sago007 2016-02-14 17:09 343
7a956470 sago007 2016-02-14 17:09 344
      inline static void load(std::false_type) {}
7a956470 sago007 2016-02-14 17:09 345
      inline static void save(std::false_type) {}
7a956470 sago007 2016-02-14 17:09 346
    };
7a956470 sago007 2016-02-14 17:09 347
7a956470 sago007 2016-02-14 17:09 348
    //! When specialized, causes the compiler to instantiate its parameter
7a956470 sago007 2016-02-14 17:09 349
    template <void(*)()>
7a956470 sago007 2016-02-14 17:09 350
    struct instantiate_function {};
7a956470 sago007 2016-02-14 17:09 351
7a956470 sago007 2016-02-14 17:09 352
    /*! This struct is used as the return type of instantiate_polymorphic_binding
7a956470 sago007 2016-02-14 17:09 353
        for specific Archive types.  When the compiler looks for overloads of
7a956470 sago007 2016-02-14 17:09 354
        instantiate_polymorphic_binding, it will be forced to instantiate this
7a956470 sago007 2016-02-14 17:09 355
        struct during overload resolution, even though it will not be part of a valid
7a956470 sago007 2016-02-14 17:09 356
        overload */
7a956470 sago007 2016-02-14 17:09 357
    template <class Archive, class T>
7a956470 sago007 2016-02-14 17:09 358
    struct polymorphic_serialization_support
7a956470 sago007 2016-02-14 17:09 359
    {
7a956470 sago007 2016-02-14 17:09 360
      #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
7a956470 sago007 2016-02-14 17:09 361
      //! Creates the appropriate bindings depending on whether the archive supports
7a956470 sago007 2016-02-14 17:09 362
      //! saving or loading
7a956470 sago007 2016-02-14 17:09 363
      virtual CEREAL_DLL_EXPORT void instantiate() CEREAL_USED;
7a956470 sago007 2016-02-14 17:09 364
      #else // NOT _MSC_VER
7a956470 sago007 2016-02-14 17:09 365
      //! Creates the appropriate bindings depending on whether the archive supports
7a956470 sago007 2016-02-14 17:09 366
      //! saving or loading
7a956470 sago007 2016-02-14 17:09 367
      static CEREAL_DLL_EXPORT void instantiate() CEREAL_USED;
7a956470 sago007 2016-02-14 17:09 368
      //! This typedef causes the compiler to instantiate this static function
7a956470 sago007 2016-02-14 17:09 369
      typedef instantiate_function<instantiate> unused;
7a956470 sago007 2016-02-14 17:09 370
      #endif // _MSC_VER
7a956470 sago007 2016-02-14 17:09 371
    };
7a956470 sago007 2016-02-14 17:09 372
7a956470 sago007 2016-02-14 17:09 373
    // instantiate implementation
7a956470 sago007 2016-02-14 17:09 374
    template <class Archive, class T>
7a956470 sago007 2016-02-14 17:09 375
    CEREAL_DLL_EXPORT void polymorphic_serialization_support<Archive,T>::instantiate()
7a956470 sago007 2016-02-14 17:09 376
    {
7a956470 sago007 2016-02-14 17:09 377
      create_bindings<Archive,T>::save( std::integral_constant<bool,
7a956470 sago007 2016-02-14 17:09 378
                                          std::is_base_of<detail::OutputArchiveBase, Archive>::value &&
7a956470 sago007 2016-02-14 17:09 379
                                          traits::is_output_serializable<T, Archive>::value>{} );
7a956470 sago007 2016-02-14 17:09 380
7a956470 sago007 2016-02-14 17:09 381
      create_bindings<Archive,T>::load( std::integral_constant<bool,
7a956470 sago007 2016-02-14 17:09 382
                                          std::is_base_of<detail::InputArchiveBase, Archive>::value &&
7a956470 sago007 2016-02-14 17:09 383
                                          traits::is_input_serializable<T, Archive>::value>{} );
7a956470 sago007 2016-02-14 17:09 384
    }
7a956470 sago007 2016-02-14 17:09 385
7a956470 sago007 2016-02-14 17:09 386
    //! Begins the binding process of a type to all registered archives
7a956470 sago007 2016-02-14 17:09 387
    /*! Archives need to be registered prior to this struct being instantiated via
7a956470 sago007 2016-02-14 17:09 388
        the CEREAL_REGISTER_ARCHIVE macro.  Overload resolution will then force
7a956470 sago007 2016-02-14 17:09 389
        several static objects to be made that allow us to bind together all
7a956470 sago007 2016-02-14 17:09 390
        registered archive types with the parameter type T. */
7a956470 sago007 2016-02-14 17:09 391
    template <class T, class Tag = polymorphic_binding_tag>
7a956470 sago007 2016-02-14 17:09 392
    struct bind_to_archives
7a956470 sago007 2016-02-14 17:09 393
    {
7a956470 sago007 2016-02-14 17:09 394
      //! Binding for non abstract types
7a956470 sago007 2016-02-14 17:09 395
      void bind(std::false_type) const
7a956470 sago007 2016-02-14 17:09 396
	    {
7a956470 sago007 2016-02-14 17:09 397
		    instantiate_polymorphic_binding((T*) 0, 0, Tag{}, adl_tag{});
7a956470 sago007 2016-02-14 17:09 398
      }
7a956470 sago007 2016-02-14 17:09 399
7a956470 sago007 2016-02-14 17:09 400
      //! Binding for abstract types
7a956470 sago007 2016-02-14 17:09 401
      void bind(std::true_type) const
7a956470 sago007 2016-02-14 17:09 402
      { }
7a956470 sago007 2016-02-14 17:09 403
7a956470 sago007 2016-02-14 17:09 404
      //! Binds the type T to all registered archives
7a956470 sago007 2016-02-14 17:09 405
      /*! If T is abstract, we will not serialize it and thus
7a956470 sago007 2016-02-14 17:09 406
          do not need to make a binding */
7a956470 sago007 2016-02-14 17:09 407
      bind_to_archives const & bind() const
7a956470 sago007 2016-02-14 17:09 408
      {
7a956470 sago007 2016-02-14 17:09 409
        static_assert( std::is_polymorphic<T>::value,
7a956470 sago007 2016-02-14 17:09 410
                       "Attempting to register non polymorphic type" );
7a956470 sago007 2016-02-14 17:09 411
        bind( std::is_abstract<T>() );
7a956470 sago007 2016-02-14 17:09 412
        return *this;
7a956470 sago007 2016-02-14 17:09 413
      }
7a956470 sago007 2016-02-14 17:09 414
    };
7a956470 sago007 2016-02-14 17:09 415
7a956470 sago007 2016-02-14 17:09 416
    //! Used to hide the static object used to bind T to registered archives
7a956470 sago007 2016-02-14 17:09 417
    template <class T, class Tag = polymorphic_binding_tag>
7a956470 sago007 2016-02-14 17:09 418
    struct init_binding;
7a956470 sago007 2016-02-14 17:09 419
7a956470 sago007 2016-02-14 17:09 420
    //! Base case overload for instantiation
7a956470 sago007 2016-02-14 17:09 421
    /*! This will end up always being the best overload due to the second
7a956470 sago007 2016-02-14 17:09 422
        parameter always being passed as an int.  All other overloads will
7a956470 sago007 2016-02-14 17:09 423
        accept pointers to archive types and have lower precedence than int.
7a956470 sago007 2016-02-14 17:09 424
7a956470 sago007 2016-02-14 17:09 425
        Since the compiler needs to check all possible overloads, the
7a956470 sago007 2016-02-14 17:09 426
        other overloads created via CEREAL_REGISTER_ARCHIVE, which will have
7a956470 sago007 2016-02-14 17:09 427
        lower precedence due to requring a conversion from int to (Archive*),
7a956470 sago007 2016-02-14 17:09 428
        will cause their return types to be instantiated through the static object
7a956470 sago007 2016-02-14 17:09 429
        mechanisms even though they are never called.
7a956470 sago007 2016-02-14 17:09 430
7a956470 sago007 2016-02-14 17:09 431
        See the documentation for the other functions to try and understand this */
7a956470 sago007 2016-02-14 17:09 432
    template <class T, typename BindingTag>
7a956470 sago007 2016-02-14 17:09 433
    void instantiate_polymorphic_binding( T*, int, BindingTag, adl_tag ) {}
7a956470 sago007 2016-02-14 17:09 434
  } // namespace detail
7a956470 sago007 2016-02-14 17:09 435
} // namespace cereal
7a956470 sago007 2016-02-14 17:09 436
7a956470 sago007 2016-02-14 17:09 437
#endif // CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_
1970-01-01 00:00 438