adapters.hpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /*! \file adapters.hpp
  2. \brief Archive adapters that provide additional functionality
  3. on top of an existing archive */
  4. /*
  5. Copyright (c) 2014, Randolph Voorhies, Shane Grant
  6. All rights reserved.
  7. Redistribution and use in source and binary forms, with or without
  8. modification, are permitted provided that the following conditions are met:
  9. * Redistributions of source code must retain the above copyright
  10. notice, this list of conditions and the following disclaimer.
  11. * Redistributions in binary form must reproduce the above copyright
  12. notice, this list of conditions and the following disclaimer in the
  13. documentation and/or other materials provided with the distribution.
  14. * Neither the name of the copyright holder nor the
  15. names of its contributors may be used to endorse or promote products
  16. derived from this software without specific prior written permission.
  17. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  18. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  19. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  20. DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
  21. DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  22. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  23. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  24. ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  26. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. */
  28. #ifndef CEREAL_ARCHIVES_ADAPTERS_HPP_
  29. #define CEREAL_ARCHIVES_ADAPTERS_HPP_
  30. #include "cereal/details/helpers.hpp"
  31. #include <utility>
  32. namespace cereal
  33. {
  34. #ifdef CEREAL_FUTURE_EXPERIMENTAL
  35. // Forward declaration for friend access
  36. template <class U, class A> U & get_user_data( A & );
  37. //! Wraps an archive and gives access to user data
  38. /*! This adapter is useful if you require access to
  39. either raw pointers or references within your
  40. serialization functions.
  41. While cereal does not directly support serialization
  42. raw pointers or references, it is sometimes the case
  43. that you may want to supply something such as a raw
  44. pointer or global reference to some constructor.
  45. In this situation this adapter would likely be used
  46. with the construct class to allow for non-default
  47. constructors.
  48. @note This feature is experimental and may be altered or removed in a future release. See issue #46.
  49. @code{.cpp}
  50. struct MyUserData
  51. {
  52. int * myRawPointer;
  53. std::reference_wrapper<MyOtherType> myReference;
  54. };
  55. struct MyClass
  56. {
  57. // Note the raw pointer parameter
  58. MyClass( int xx, int * rawP );
  59. int x;
  60. template <class Archive>
  61. void serialize( Archive & ar )
  62. { ar( x ); }
  63. template <class Archive>
  64. static void load_and_construct( Archive & ar, cereal::construct<MyClass> & construct )
  65. {
  66. int xx;
  67. ar( xx );
  68. // note the need to use get_user_data to retrieve user data from the archive
  69. construct( xx, cereal::get_user_data<MyUserData>( ar ).myRawPointer );
  70. }
  71. };
  72. int main()
  73. {
  74. {
  75. MyUserData md;
  76. md.myRawPointer = &something;
  77. md.myReference = someInstanceOfType;
  78. std::ifstream is( "data.xml" );
  79. cereal::UserDataAdapter<MyUserData, cereal::XMLInputArchive> ar( md, is );
  80. std::unique_ptr<MyClass> sc;
  81. ar( sc ); // use as normal
  82. }
  83. return 0;
  84. }
  85. @endcode
  86. @relates get_user_data
  87. @tparam UserData The type to give the archive access to
  88. @tparam Archive The archive to wrap */
  89. template <class UserData, class Archive>
  90. class UserDataAdapter : public Archive
  91. {
  92. public:
  93. //! Construct the archive with some user data struct
  94. /*! This will forward all arguments (other than the user
  95. data) to the wrapped archive type. The UserDataAdapter
  96. can then be used identically to the wrapped archive type
  97. @tparam Args The arguments to pass to the constructor of
  98. the archive. */
  99. template <class ... Args>
  100. UserDataAdapter( UserData & ud, Args && ... args ) :
  101. Archive( std::forward<Args>( args )... ),
  102. userdata( ud )
  103. { }
  104. private:
  105. //! Overload the rtti function to enable dynamic_cast
  106. void rtti() {}
  107. friend UserData & get_user_data<UserData>( Archive & ar );
  108. UserData & userdata; //!< The actual user data
  109. };
  110. //! Retrieves user data from an archive wrapped by UserDataAdapter
  111. /*! This will attempt to retrieve the user data associated with
  112. some archive wrapped by UserDataAdapter. If this is used on
  113. an archive that is not wrapped, a run-time exception will occur.
  114. @note This feature is experimental and may be altered or removed in a future release. See issue #46.
  115. @note The correct use of this function cannot be enforced at compile
  116. time.
  117. @relates UserDataAdapter
  118. @tparam UserData The data struct contained in the archive
  119. @tparam Archive The archive, which should be wrapped by UserDataAdapter
  120. @param ar The archive
  121. @throws Exception if the archive this is used upon is not wrapped with
  122. UserDataAdapter. */
  123. template <class UserData, class Archive>
  124. UserData & get_user_data( Archive & ar )
  125. {
  126. try
  127. {
  128. return dynamic_cast<UserDataAdapter<UserData, Archive> &>( ar ).userdata;
  129. }
  130. catch( std::bad_cast const & )
  131. {
  132. throw ::cereal::Exception("Attempting to get user data from archive not wrapped in UserDataAdapter");
  133. }
  134. }
  135. #endif // CEREAL_FUTURE_EXPERIMENTAL
  136. } // namespace cereal
  137. #endif // CEREAL_ARCHIVES_ADAPTERS_HPP_