LCOV - code coverage report
Current view: top level - cereal/types - base_class.hpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 10 10 100.0 %
Date: 2022-01-16 21:05:07 Functions: 10 10 100.0 %

          Line data    Source code
       1             : /*! \file base_class.hpp
       2             :     \brief Support for base classes (virtual and non-virtual)
       3             :     \ingroup OtherTypes */
       4             : /*
       5             :   Copyright (c) 2014, Randolph Voorhies, Shane Grant
       6             :   All rights reserved.
       7             : 
       8             :   Redistribution and use in source and binary forms, with or without
       9             :   modification, are permitted provided that the following conditions are met:
      10             :       * Redistributions of source code must retain the above copyright
      11             :         notice, this list of conditions and the following disclaimer.
      12             :       * Redistributions in binary form must reproduce the above copyright
      13             :         notice, this list of conditions and the following disclaimer in the
      14             :         documentation and/or other materials provided with the distribution.
      15             :       * Neither the name of the copyright holder nor the
      16             :         names of its contributors may be used to endorse or promote products
      17             :         derived from this software without specific prior written permission.
      18             : 
      19             :   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
      20             :   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
      21             :   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
      22             :   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
      23             :   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
      24             :   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
      25             :   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
      26             :   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      27             :   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
      28             :   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      29             : */
      30             : #ifndef CEREAL_TYPES_BASE_CLASS_HPP_
      31             : #define CEREAL_TYPES_BASE_CLASS_HPP_
      32             : 
      33             : #include "cereal/details/traits.hpp"
      34             : #include "cereal/details/polymorphic_impl_fwd.hpp"
      35             : 
      36             : namespace cereal
      37             : {
      38             :   namespace base_class_detail
      39             :   {
      40             :     //! Used to register polymorphic relations and avoid the need to include
      41             :     //! polymorphic.hpp when no polymorphism is used
      42             :     /*! @internal */
      43             :     template <class Base, class Derived, bool IsPolymorphic = std::is_polymorphic<Base>::value>
      44             :     struct RegisterPolymorphicBaseClass
      45             :     {
      46             :       static void bind()
      47             :       { }
      48             :     };
      49             : 
      50             :     //! Polymorphic version
      51             :     /*! @internal */
      52             :     template <class Base, class Derived>
      53             :     struct RegisterPolymorphicBaseClass<Base, Derived, true>
      54             :     {
      55        9600 :       static void bind()
      56        9600 :       { detail::RegisterPolymorphicCaster<Base, Derived>::bind(); }
      57             :     };
      58             :   }
      59             : 
      60             :   //! Casts a derived class to its non-virtual base class in a way that safely supports abstract classes
      61             :   /*! This should be used in cases when a derived type needs to serialize its base type. This is better than directly
      62             :       using static_cast, as it allows for serialization of pure virtual (abstract) base classes.
      63             : 
      64             :       This also automatically registers polymorphic relation between the base and derived class, assuming they
      65             :       are indeed polymorphic. Note this is not the same as polymorphic type registration. For more information
      66             :       see the documentation on polymorphism. If using a polymorphic class, be sure to include support for
      67             :       polymorphism (cereal/types/polymorphic.hpp).
      68             : 
      69             :       \sa virtual_base_class
      70             : 
      71             :       @code{.cpp}
      72             :       struct MyBase
      73             :       {
      74             :         int x;
      75             : 
      76             :         virtual void foo() = 0;
      77             : 
      78             :         template <class Archive>
      79             :         void serialize( Archive & ar )
      80             :         {
      81             :           ar( x );
      82             :         }
      83             :       };
      84             : 
      85             :       struct MyDerived : public MyBase //<-- Note non-virtual inheritance
      86             :       {
      87             :         int y;
      88             : 
      89             :         virtual void foo() {};
      90             : 
      91             :         template <class Archive>
      92             :         void serialize( Archive & ar )
      93             :         {
      94             :           ar( cereal::base_class<MyBase>(this) );
      95             :           ar( y );
      96             :         }
      97             :       };
      98             :       @endcode */
      99             :   template<class Base>
     100             :     struct base_class : private traits::detail::BaseCastBase
     101             :     {
     102             :       template<class Derived>
     103        6400 :         base_class(Derived const * derived) :
     104        6400 :           base_ptr(const_cast<Base*>(static_cast<Base const *>(derived)))
     105             :       {
     106             :         static_assert( std::is_base_of<Base, Derived>::value, "Can only use base_class on a valid base class" );
     107        6400 :         base_class_detail::RegisterPolymorphicBaseClass<Base, Derived>::bind();
     108        6400 :       }
     109             : 
     110             :         Base * base_ptr;
     111             :     };
     112             : 
     113             :   //! Casts a derived class to its virtual base class in a way that allows cereal to track inheritance
     114             :   /*! This should be used in cases when a derived type features virtual inheritance from some
     115             :       base type.  This allows cereal to track the inheritance and to avoid making duplicate copies
     116             :       during serialization.
     117             : 
     118             :       It is safe to use virtual_base_class in all circumstances for serializing base classes, even in cases
     119             :       where virtual inheritance does not take place, though it may be slightly faster to utilize
     120             :       cereal::base_class<> if you do not need to worry about virtual inheritance.
     121             : 
     122             :       This also automatically registers polymorphic relation between the base and derived class, assuming they
     123             :       are indeed polymorphic. Note this is not the same as polymorphic type registration. For more information
     124             :       see the documentation on polymorphism. If using a polymorphic class, be sure to include support for
     125             :       polymorphism (cereal/types/polymorphic.hpp).
     126             : 
     127             :       \sa base_class
     128             : 
     129             :       @code{.cpp}
     130             :       struct MyBase
     131             :       {
     132             :         int x;
     133             : 
     134             :         template <class Archive>
     135             :         void serialize( Archive & ar )
     136             :         {
     137             :           ar( x );
     138             :         }
     139             :       };
     140             : 
     141             :       struct MyLeft : virtual MyBase //<-- Note the virtual inheritance
     142             :       {
     143             :         int y;
     144             : 
     145             :         template <class Archive>
     146             :         void serialize( Archive & ar )
     147             :         {
     148             :           ar( cereal::virtual_base_class<MyBase>( this ) );
     149             :           ar( y );
     150             :         }
     151             :       };
     152             : 
     153             :       struct MyRight : virtual MyBase
     154             :       {
     155             :         int z;
     156             : 
     157             :         template <class Archive>
     158             :         void serialize( Archive & ar )
     159             :         {
     160             :           ar( cereal::virtual_base_clas<MyBase>( this ) );
     161             :           ar( z );
     162             :         }
     163             :       };
     164             : 
     165             :       // diamond virtual inheritance; contains one copy of each base class
     166             :       struct MyDerived : virtual MyLeft, virtual MyRight
     167             :       {
     168             :         int a;
     169             : 
     170             :         template <class Archive>
     171             :         void serialize( Archive & ar )
     172             :         {
     173             :           ar( cereal::virtual_base_class<MyLeft>( this ) );  // safely serialize data members in MyLeft
     174             :           ar( cereal::virtual_base_class<MyRight>( this ) ); // safely serialize data members in MyRight
     175             :           ar( a );
     176             : 
     177             :           // Because we used virtual_base_class, cereal will ensure that only one instance of MyBase is
     178             :           // serialized as we traverse the inheritance heirarchy. This means that there will be one copy
     179             :           // each of the variables x, y, z, and a
     180             : 
     181             :           // If we had chosen to use static_cast<> instead, cereal would perform no tracking and
     182             :           // assume that every base class should be serialized (in this case leading to a duplicate
     183             :           // serialization of MyBase due to diamond inheritance
     184             :       };
     185             :      }
     186             :      @endcode */
     187             :   template<class Base>
     188             :     struct virtual_base_class : private traits::detail::BaseCastBase
     189             :     {
     190             :       template<class Derived>
     191        3200 :         virtual_base_class(Derived const * derived) :
     192        3200 :           base_ptr(const_cast<Base*>(static_cast<Base const *>(derived)))
     193             :       {
     194             :         static_assert( std::is_base_of<Base, Derived>::value, "Can only use virtual_base_class on a valid base class" );
     195        3200 :         base_class_detail::RegisterPolymorphicBaseClass<Base, Derived>::bind();
     196        3200 :       }
     197             : 
     198             :         Base * base_ptr;
     199             :     };
     200             : 
     201             : } // namespace cereal
     202             : 
     203             : #endif // CEREAL_TYPES_BASE_CLASS_HPP_

Generated by: LCOV version 1.14