helpers.hpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. /*! \file helpers.hpp
  2. \brief Internal helper functionality
  3. \ingroup Internal */
  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_DETAILS_HELPERS_HPP_
  29. #define CEREAL_DETAILS_HELPERS_HPP_
  30. #include <type_traits>
  31. #include <cstdint>
  32. #include <utility>
  33. #include <memory>
  34. #include <unordered_map>
  35. #include <stdexcept>
  36. #include "cereal/macros.hpp"
  37. #include "cereal/details/static_object.hpp"
  38. namespace cereal
  39. {
  40. // ######################################################################
  41. //! An exception class thrown when things go wrong at runtime
  42. /*! @ingroup Utility */
  43. struct Exception : public std::runtime_error
  44. {
  45. explicit Exception( const std::string & what_ ) : std::runtime_error(what_) {}
  46. explicit Exception( const char * what_ ) : std::runtime_error(what_) {}
  47. };
  48. // ######################################################################
  49. //! The size type used by cereal
  50. /*! To ensure compatability between 32, 64, etc bit machines, we need to use
  51. a fixed size type instead of size_t, which may vary from machine to
  52. machine.
  53. The default value for CEREAL_SIZE_TYPE is specified in cereal/macros.hpp */
  54. using size_type = CEREAL_SIZE_TYPE;
  55. // forward decls
  56. class BinaryOutputArchive;
  57. class BinaryInputArchive;
  58. // ######################################################################
  59. namespace detail
  60. {
  61. struct NameValuePairCore {}; //!< Traits struct for NVPs
  62. struct DeferredDataCore {}; //!< Traits struct for DeferredData
  63. }
  64. // ######################################################################
  65. //! For holding name value pairs
  66. /*! This pairs a name (some string) with some value such that an archive
  67. can potentially take advantage of the pairing.
  68. In serialization functions, NameValuePairs are usually created like so:
  69. @code{.cpp}
  70. struct MyStruct
  71. {
  72. int a, b, c, d, e;
  73. template<class Archive>
  74. void serialize(Archive & archive)
  75. {
  76. archive( CEREAL_NVP(a),
  77. CEREAL_NVP(b),
  78. CEREAL_NVP(c),
  79. CEREAL_NVP(d),
  80. CEREAL_NVP(e) );
  81. }
  82. };
  83. @endcode
  84. Alternatively, you can give you data members custom names like so:
  85. @code{.cpp}
  86. struct MyStruct
  87. {
  88. int a, b, my_embarrassing_variable_name, d, e;
  89. template<class Archive>
  90. void serialize(Archive & archive)
  91. {
  92. archive( CEREAL_NVP(a),
  93. CEREAL_NVP(b),
  94. cereal::make_nvp("var", my_embarrassing_variable_name) );
  95. CEREAL_NVP(d),
  96. CEREAL_NVP(e) );
  97. }
  98. };
  99. @endcode
  100. There is a slight amount of overhead to creating NameValuePairs, so there
  101. is a third method which will elide the names when they are not used by
  102. the Archive:
  103. @code{.cpp}
  104. struct MyStruct
  105. {
  106. int a, b;
  107. template<class Archive>
  108. void serialize(Archive & archive)
  109. {
  110. archive( cereal::make_nvp<Archive>(a),
  111. cereal::make_nvp<Archive>(b) );
  112. }
  113. };
  114. @endcode
  115. This third method is generally only used when providing generic type
  116. support. Users writing their own serialize functions will normally
  117. explicitly control whether they want to use NVPs or not.
  118. @internal */
  119. template <class T>
  120. class NameValuePair : detail::NameValuePairCore
  121. {
  122. private:
  123. // If we get passed an array, keep the type as is, otherwise store
  124. // a reference if we were passed an l value reference, else copy the value
  125. using Type = typename std::conditional<std::is_array<typename std::remove_reference<T>::type>::value,
  126. typename std::remove_cv<T>::type,
  127. typename std::conditional<std::is_lvalue_reference<T>::value,
  128. T,
  129. typename std::decay<T>::type>::type>::type;
  130. // prevent nested nvps
  131. static_assert( !std::is_base_of<detail::NameValuePairCore, T>::value,
  132. "Cannot pair a name to a NameValuePair" );
  133. NameValuePair & operator=( NameValuePair const & ) = delete;
  134. public:
  135. //! Constructs a new NameValuePair
  136. /*! @param n The name of the pair
  137. @param v The value to pair. Ideally this should be an l-value reference so that
  138. the value can be both loaded and saved to. If you pass an r-value reference,
  139. the NameValuePair will store a copy of it instead of a reference. Thus you should
  140. only pass r-values in cases where this makes sense, such as the result of some
  141. size() call.
  142. @internal */
  143. NameValuePair( char const * n, T && v ) : name(n), value(std::forward<T>(v)) {}
  144. char const * name;
  145. Type value;
  146. };
  147. //! A specialization of make_nvp<> that simply forwards the value for binary archives
  148. /*! @relates NameValuePair
  149. @internal */
  150. template<class Archive, class T> inline
  151. typename
  152. std::enable_if<std::is_same<Archive, ::cereal::BinaryInputArchive>::value ||
  153. std::is_same<Archive, ::cereal::BinaryOutputArchive>::value,
  154. T && >::type
  155. make_nvp( const char *, T && value )
  156. {
  157. return std::forward<T>(value);
  158. }
  159. //! A specialization of make_nvp<> that actually creates an nvp for non-binary archives
  160. /*! @relates NameValuePair
  161. @internal */
  162. template<class Archive, class T> inline
  163. typename
  164. std::enable_if<!std::is_same<Archive, ::cereal::BinaryInputArchive>::value &&
  165. !std::is_same<Archive, ::cereal::BinaryOutputArchive>::value,
  166. NameValuePair<T> >::type
  167. make_nvp( const char * name, T && value)
  168. {
  169. return {name, std::forward<T>(value)};
  170. }
  171. //! Convenience for creating a templated NVP
  172. /*! For use in internal generic typing functions which have an
  173. Archive type declared
  174. @internal */
  175. #define CEREAL_NVP_(name, value) ::cereal::make_nvp<Archive>(name, value)
  176. // ######################################################################
  177. //! A wrapper around data that can be serialized in a binary fashion
  178. /*! This class is used to demarcate data that can safely be serialized
  179. as a binary chunk of data. Individual archives can then choose how
  180. best represent this during serialization.
  181. @internal */
  182. template <class T>
  183. struct BinaryData
  184. {
  185. //! Internally store the pointer as a void *, keeping const if created with
  186. //! a const pointer
  187. using PT = typename std::conditional<std::is_const<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value,
  188. const void *,
  189. void *>::type;
  190. BinaryData( T && d, uint64_t s ) : data(std::forward<T>(d)), size(s) {}
  191. PT data; //!< pointer to beginning of data
  192. uint64_t size; //!< size in bytes
  193. };
  194. // ######################################################################
  195. //! A wrapper around data that should be serialized after all non-deferred data
  196. /*! This class is used to demarcate data that can only be safely serialized after
  197. any data not wrapped in this class.
  198. @internal */
  199. template <class T>
  200. class DeferredData : detail::DeferredDataCore
  201. {
  202. private:
  203. // If we get passed an array, keep the type as is, otherwise store
  204. // a reference if we were passed an l value reference, else copy the value
  205. using Type = typename std::conditional<std::is_array<typename std::remove_reference<T>::type>::value,
  206. typename std::remove_cv<T>::type,
  207. typename std::conditional<std::is_lvalue_reference<T>::value,
  208. T,
  209. typename std::decay<T>::type>::type>::type;
  210. // prevent nested nvps
  211. static_assert( !std::is_base_of<detail::DeferredDataCore, T>::value,
  212. "Cannot defer DeferredData" );
  213. DeferredData & operator=( DeferredData const & ) = delete;
  214. public:
  215. //! Constructs a new NameValuePair
  216. /*! @param v The value to defer. Ideally this should be an l-value reference so that
  217. the value can be both loaded and saved to. If you pass an r-value reference,
  218. the DeferredData will store a copy of it instead of a reference. Thus you should
  219. only pass r-values in cases where this makes sense, such as the result of some
  220. size() call.
  221. @internal */
  222. DeferredData( T && v ) : value(std::forward<T>(v)) {}
  223. Type value;
  224. };
  225. // ######################################################################
  226. namespace detail
  227. {
  228. // base classes for type checking
  229. /* The rtti virtual function only exists to enable an archive to
  230. be used in a polymorphic fashion, if necessary. See the
  231. archive adapters for an example of this */
  232. class OutputArchiveBase
  233. {
  234. public:
  235. OutputArchiveBase() = default;
  236. OutputArchiveBase( OutputArchiveBase && ) CEREAL_NOEXCEPT {}
  237. OutputArchiveBase & operator=( OutputArchiveBase && ) CEREAL_NOEXCEPT { return *this; }
  238. virtual ~OutputArchiveBase() CEREAL_NOEXCEPT = default;
  239. private:
  240. virtual void rtti() {}
  241. };
  242. class InputArchiveBase
  243. {
  244. public:
  245. InputArchiveBase() = default;
  246. InputArchiveBase( InputArchiveBase && ) CEREAL_NOEXCEPT {}
  247. InputArchiveBase & operator=( InputArchiveBase && ) CEREAL_NOEXCEPT { return *this; }
  248. virtual ~InputArchiveBase() CEREAL_NOEXCEPT = default;
  249. private:
  250. virtual void rtti() {}
  251. };
  252. // forward decls for polymorphic support
  253. template <class Archive, class T> struct polymorphic_serialization_support;
  254. struct adl_tag;
  255. // used during saving pointers
  256. static const uint32_t msb_32bit = 0x80000000;
  257. static const int32_t msb2_32bit = 0x40000000;
  258. }
  259. // ######################################################################
  260. //! A wrapper around size metadata
  261. /*! This class provides a way for archives to have more flexibility over how
  262. they choose to serialize size metadata for containers. For some archive
  263. types, the size may be implicitly encoded in the output (e.g. JSON) and
  264. not need an explicit entry. Specializing serialize or load/save for
  265. your archive and SizeTags allows you to choose what happens.
  266. @internal */
  267. template <class T>
  268. class SizeTag
  269. {
  270. private:
  271. // Store a reference if passed an lvalue reference, otherwise
  272. // make a copy of the data
  273. using Type = typename std::conditional<std::is_lvalue_reference<T>::value,
  274. T,
  275. typename std::decay<T>::type>::type;
  276. SizeTag & operator=( SizeTag const & ) = delete;
  277. public:
  278. SizeTag( T && sz ) : size(std::forward<T>(sz)) {}
  279. Type size;
  280. };
  281. // ######################################################################
  282. //! A wrapper around a key and value for serializing data into maps.
  283. /*! This class just provides a grouping of keys and values into a struct for
  284. human readable archives. For example, XML archives will use this wrapper
  285. to write maps like so:
  286. @code{.xml}
  287. <mymap>
  288. <item0>
  289. <key>MyFirstKey</key>
  290. <value>MyFirstValue</value>
  291. </item0>
  292. <item1>
  293. <key>MySecondKey</key>
  294. <value>MySecondValue</value>
  295. </item1>
  296. </mymap>
  297. @endcode
  298. \sa make_map_item
  299. @internal */
  300. template <class Key, class Value>
  301. struct MapItem
  302. {
  303. using KeyType = typename std::conditional<
  304. std::is_lvalue_reference<Key>::value,
  305. Key,
  306. typename std::decay<Key>::type>::type;
  307. using ValueType = typename std::conditional<
  308. std::is_lvalue_reference<Value>::value,
  309. Value,
  310. typename std::decay<Value>::type>::type;
  311. //! Construct a MapItem from a key and a value
  312. /*! @internal */
  313. MapItem( Key && key_, Value && value_ ) : key(std::forward<Key>(key_)), value(std::forward<Value>(value_)) {}
  314. MapItem & operator=( MapItem const & ) = delete;
  315. KeyType key;
  316. ValueType value;
  317. //! Serialize the MapItem with the NVPs "key" and "value"
  318. template <class Archive> inline
  319. void CEREAL_SERIALIZE_FUNCTION_NAME(Archive & archive)
  320. {
  321. archive( make_nvp<Archive>("key", key),
  322. make_nvp<Archive>("value", value) );
  323. }
  324. };
  325. //! Create a MapItem so that human readable archives will group keys and values together
  326. /*! @internal
  327. @relates MapItem */
  328. template <class KeyType, class ValueType> inline
  329. MapItem<KeyType, ValueType> make_map_item(KeyType && key, ValueType && value)
  330. {
  331. return {std::forward<KeyType>(key), std::forward<ValueType>(value)};
  332. }
  333. namespace detail
  334. {
  335. //! Tag for Version, which due to its anonymous namespace, becomes a different
  336. //! type in each translation unit
  337. /*! This allows CEREAL_CLASS_VERSION to be safely called in a header file */
  338. namespace{ struct version_binding_tag {}; }
  339. // ######################################################################
  340. //! Version information class
  341. /*! This is the base case for classes that have not been explicitly
  342. registered */
  343. template <class T, class BindingTag = version_binding_tag> struct Version
  344. {
  345. static const std::uint32_t version = 0;
  346. // we don't need to explicitly register these types since they
  347. // always get a version number of 0
  348. };
  349. //! Holds all registered version information
  350. struct Versions
  351. {
  352. std::unordered_map<std::size_t, std::uint32_t> mapping;
  353. std::uint32_t find( std::size_t hash, std::uint32_t version )
  354. {
  355. const auto result = mapping.emplace( hash, version );
  356. return result.first->second;
  357. }
  358. }; // struct Versions
  359. } // namespace detail
  360. } // namespace cereal
  361. #endif // CEREAL_DETAILS_HELPERS_HPP_