File: base_class.hpp

package info (click to toggle)
libcereal 1.3.2%2Bdfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 2,064 kB
  • sloc: cpp: 19,837; xml: 178; sh: 56; makefile: 13
file content (203 lines) | stat: -rw-r--r-- 7,571 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
/*! \file base_class.hpp
    \brief Support for base classes (virtual and non-virtual)
    \ingroup OtherTypes */
/*
  Copyright (c) 2014, Randolph Voorhies, Shane Grant
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:
      * Redistributions of source code must retain the above copyright
        notice, this list of conditions and the following disclaimer.
      * Redistributions in binary form must reproduce the above copyright
        notice, this list of conditions and the following disclaimer in the
        documentation and/or other materials provided with the distribution.
      * Neither the name of the copyright holder nor the
        names of its contributors may be used to endorse or promote products
        derived from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CEREAL_TYPES_BASE_CLASS_HPP_
#define CEREAL_TYPES_BASE_CLASS_HPP_

#include "cereal/details/traits.hpp"
#include "cereal/details/polymorphic_impl_fwd.hpp"

namespace cereal
{
  namespace base_class_detail
  {
    //! Used to register polymorphic relations and avoid the need to include
    //! polymorphic.hpp when no polymorphism is used
    /*! @internal */
    template <class Base, class Derived, bool IsPolymorphic = std::is_polymorphic<Base>::value>
    struct RegisterPolymorphicBaseClass
    {
      static void bind()
      { }
    };

    //! Polymorphic version
    /*! @internal */
    template <class Base, class Derived>
    struct RegisterPolymorphicBaseClass<Base, Derived, true>
    {
      static void bind()
      { detail::RegisterPolymorphicCaster<Base, Derived>::bind(); }
    };
  }

  //! Casts a derived class to its non-virtual base class in a way that safely supports abstract classes
  /*! This should be used in cases when a derived type needs to serialize its base type. This is better than directly
      using static_cast, as it allows for serialization of pure virtual (abstract) base classes.

      This also automatically registers polymorphic relation between the base and derived class, assuming they
      are indeed polymorphic. Note this is not the same as polymorphic type registration. For more information
      see the documentation on polymorphism. If using a polymorphic class, be sure to include support for
      polymorphism (cereal/types/polymorphic.hpp).

      \sa virtual_base_class

      @code{.cpp}
      struct MyBase
      {
        int x;

        virtual void foo() = 0;

        template <class Archive>
        void serialize( Archive & ar )
        {
          ar( x );
        }
      };

      struct MyDerived : public MyBase //<-- Note non-virtual inheritance
      {
        int y;

        virtual void foo() {};

        template <class Archive>
        void serialize( Archive & ar )
        {
          ar( cereal::base_class<MyBase>(this) );
          ar( y );
        }
      };
      @endcode */
  template<class Base>
    struct base_class : private traits::detail::BaseCastBase
    {
      template<class Derived>
        base_class(Derived const * derived) :
          base_ptr(const_cast<Base*>(static_cast<Base const *>(derived)))
      {
        static_assert( std::is_base_of<Base, Derived>::value, "Can only use base_class on a valid base class" );
        base_class_detail::RegisterPolymorphicBaseClass<Base, Derived>::bind();
      }

        Base * base_ptr;
    };

  //! Casts a derived class to its virtual base class in a way that allows cereal to track inheritance
  /*! This should be used in cases when a derived type features virtual inheritance from some
      base type.  This allows cereal to track the inheritance and to avoid making duplicate copies
      during serialization.

      It is safe to use virtual_base_class in all circumstances for serializing base classes, even in cases
      where virtual inheritance does not take place, though it may be slightly faster to utilize
      cereal::base_class<> if you do not need to worry about virtual inheritance.

      This also automatically registers polymorphic relation between the base and derived class, assuming they
      are indeed polymorphic. Note this is not the same as polymorphic type registration. For more information
      see the documentation on polymorphism. If using a polymorphic class, be sure to include support for
      polymorphism (cereal/types/polymorphic.hpp).

      \sa base_class

      @code{.cpp}
      struct MyBase
      {
        int x;

        template <class Archive>
        void serialize( Archive & ar )
        {
          ar( x );
        }
      };

      struct MyLeft : virtual MyBase //<-- Note the virtual inheritance
      {
        int y;

        template <class Archive>
        void serialize( Archive & ar )
        {
          ar( cereal::virtual_base_class<MyBase>( this ) );
          ar( y );
        }
      };

      struct MyRight : virtual MyBase
      {
        int z;

        template <class Archive>
        void serialize( Archive & ar )
        {
          ar( cereal::virtual_base_clas<MyBase>( this ) );
          ar( z );
        }
      };

      // diamond virtual inheritance; contains one copy of each base class
      struct MyDerived : virtual MyLeft, virtual MyRight
      {
        int a;

        template <class Archive>
        void serialize( Archive & ar )
        {
          ar( cereal::virtual_base_class<MyLeft>( this ) );  // safely serialize data members in MyLeft
          ar( cereal::virtual_base_class<MyRight>( this ) ); // safely serialize data members in MyRight
          ar( a );

          // Because we used virtual_base_class, cereal will ensure that only one instance of MyBase is
          // serialized as we traverse the inheritance heirarchy. This means that there will be one copy
          // each of the variables x, y, z, and a

          // If we had chosen to use static_cast<> instead, cereal would perform no tracking and
          // assume that every base class should be serialized (in this case leading to a duplicate
          // serialization of MyBase due to diamond inheritance
      };
     }
     @endcode */
  template<class Base>
    struct virtual_base_class : private traits::detail::BaseCastBase
    {
      template<class Derived>
        virtual_base_class(Derived const * derived) :
          base_ptr(const_cast<Base*>(static_cast<Base const *>(derived)))
      {
        static_assert( std::is_base_of<Base, Derived>::value, "Can only use virtual_base_class on a valid base class" );
        base_class_detail::RegisterPolymorphicBaseClass<Base, Derived>::bind();
      }

        Base * base_ptr;
    };

} // namespace cereal

#endif // CEREAL_TYPES_BASE_CLASS_HPP_