isotree 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/LICENSE.txt +2 -2
  4. data/README.md +22 -1
  5. data/ext/isotree/ext.cpp +26 -0
  6. data/ext/isotree/extconf.rb +3 -3
  7. data/lib/isotree.rb +1 -0
  8. data/lib/isotree/isolation_forest.rb +86 -1
  9. data/lib/isotree/version.rb +1 -1
  10. data/vendor/cereal/LICENSE +24 -0
  11. data/vendor/cereal/README.md +85 -0
  12. data/vendor/cereal/include/cereal/access.hpp +351 -0
  13. data/vendor/cereal/include/cereal/archives/adapters.hpp +163 -0
  14. data/vendor/cereal/include/cereal/archives/binary.hpp +169 -0
  15. data/vendor/cereal/include/cereal/archives/json.hpp +1019 -0
  16. data/vendor/cereal/include/cereal/archives/portable_binary.hpp +334 -0
  17. data/vendor/cereal/include/cereal/archives/xml.hpp +956 -0
  18. data/vendor/cereal/include/cereal/cereal.hpp +1089 -0
  19. data/vendor/cereal/include/cereal/details/helpers.hpp +422 -0
  20. data/vendor/cereal/include/cereal/details/polymorphic_impl.hpp +796 -0
  21. data/vendor/cereal/include/cereal/details/polymorphic_impl_fwd.hpp +65 -0
  22. data/vendor/cereal/include/cereal/details/static_object.hpp +127 -0
  23. data/vendor/cereal/include/cereal/details/traits.hpp +1411 -0
  24. data/vendor/cereal/include/cereal/details/util.hpp +84 -0
  25. data/vendor/cereal/include/cereal/external/base64.hpp +134 -0
  26. data/vendor/cereal/include/cereal/external/rapidjson/allocators.h +284 -0
  27. data/vendor/cereal/include/cereal/external/rapidjson/cursorstreamwrapper.h +78 -0
  28. data/vendor/cereal/include/cereal/external/rapidjson/document.h +2652 -0
  29. data/vendor/cereal/include/cereal/external/rapidjson/encodedstream.h +299 -0
  30. data/vendor/cereal/include/cereal/external/rapidjson/encodings.h +716 -0
  31. data/vendor/cereal/include/cereal/external/rapidjson/error/en.h +74 -0
  32. data/vendor/cereal/include/cereal/external/rapidjson/error/error.h +161 -0
  33. data/vendor/cereal/include/cereal/external/rapidjson/filereadstream.h +99 -0
  34. data/vendor/cereal/include/cereal/external/rapidjson/filewritestream.h +104 -0
  35. data/vendor/cereal/include/cereal/external/rapidjson/fwd.h +151 -0
  36. data/vendor/cereal/include/cereal/external/rapidjson/internal/biginteger.h +290 -0
  37. data/vendor/cereal/include/cereal/external/rapidjson/internal/diyfp.h +271 -0
  38. data/vendor/cereal/include/cereal/external/rapidjson/internal/dtoa.h +245 -0
  39. data/vendor/cereal/include/cereal/external/rapidjson/internal/ieee754.h +78 -0
  40. data/vendor/cereal/include/cereal/external/rapidjson/internal/itoa.h +308 -0
  41. data/vendor/cereal/include/cereal/external/rapidjson/internal/meta.h +186 -0
  42. data/vendor/cereal/include/cereal/external/rapidjson/internal/pow10.h +55 -0
  43. data/vendor/cereal/include/cereal/external/rapidjson/internal/regex.h +740 -0
  44. data/vendor/cereal/include/cereal/external/rapidjson/internal/stack.h +232 -0
  45. data/vendor/cereal/include/cereal/external/rapidjson/internal/strfunc.h +69 -0
  46. data/vendor/cereal/include/cereal/external/rapidjson/internal/strtod.h +290 -0
  47. data/vendor/cereal/include/cereal/external/rapidjson/internal/swap.h +46 -0
  48. data/vendor/cereal/include/cereal/external/rapidjson/istreamwrapper.h +128 -0
  49. data/vendor/cereal/include/cereal/external/rapidjson/memorybuffer.h +70 -0
  50. data/vendor/cereal/include/cereal/external/rapidjson/memorystream.h +71 -0
  51. data/vendor/cereal/include/cereal/external/rapidjson/msinttypes/inttypes.h +316 -0
  52. data/vendor/cereal/include/cereal/external/rapidjson/msinttypes/stdint.h +300 -0
  53. data/vendor/cereal/include/cereal/external/rapidjson/ostreamwrapper.h +81 -0
  54. data/vendor/cereal/include/cereal/external/rapidjson/pointer.h +1414 -0
  55. data/vendor/cereal/include/cereal/external/rapidjson/prettywriter.h +277 -0
  56. data/vendor/cereal/include/cereal/external/rapidjson/rapidjson.h +656 -0
  57. data/vendor/cereal/include/cereal/external/rapidjson/reader.h +2230 -0
  58. data/vendor/cereal/include/cereal/external/rapidjson/schema.h +2497 -0
  59. data/vendor/cereal/include/cereal/external/rapidjson/stream.h +223 -0
  60. data/vendor/cereal/include/cereal/external/rapidjson/stringbuffer.h +121 -0
  61. data/vendor/cereal/include/cereal/external/rapidjson/writer.h +709 -0
  62. data/vendor/cereal/include/cereal/external/rapidxml/license.txt +52 -0
  63. data/vendor/cereal/include/cereal/external/rapidxml/manual.html +406 -0
  64. data/vendor/cereal/include/cereal/external/rapidxml/rapidxml.hpp +2624 -0
  65. data/vendor/cereal/include/cereal/external/rapidxml/rapidxml_iterators.hpp +175 -0
  66. data/vendor/cereal/include/cereal/external/rapidxml/rapidxml_print.hpp +428 -0
  67. data/vendor/cereal/include/cereal/external/rapidxml/rapidxml_utils.hpp +123 -0
  68. data/vendor/cereal/include/cereal/macros.hpp +154 -0
  69. data/vendor/cereal/include/cereal/specialize.hpp +139 -0
  70. data/vendor/cereal/include/cereal/types/array.hpp +79 -0
  71. data/vendor/cereal/include/cereal/types/atomic.hpp +55 -0
  72. data/vendor/cereal/include/cereal/types/base_class.hpp +203 -0
  73. data/vendor/cereal/include/cereal/types/bitset.hpp +176 -0
  74. data/vendor/cereal/include/cereal/types/boost_variant.hpp +164 -0
  75. data/vendor/cereal/include/cereal/types/chrono.hpp +72 -0
  76. data/vendor/cereal/include/cereal/types/common.hpp +129 -0
  77. data/vendor/cereal/include/cereal/types/complex.hpp +56 -0
  78. data/vendor/cereal/include/cereal/types/concepts/pair_associative_container.hpp +73 -0
  79. data/vendor/cereal/include/cereal/types/deque.hpp +62 -0
  80. data/vendor/cereal/include/cereal/types/forward_list.hpp +68 -0
  81. data/vendor/cereal/include/cereal/types/functional.hpp +43 -0
  82. data/vendor/cereal/include/cereal/types/list.hpp +62 -0
  83. data/vendor/cereal/include/cereal/types/map.hpp +36 -0
  84. data/vendor/cereal/include/cereal/types/memory.hpp +425 -0
  85. data/vendor/cereal/include/cereal/types/optional.hpp +66 -0
  86. data/vendor/cereal/include/cereal/types/polymorphic.hpp +483 -0
  87. data/vendor/cereal/include/cereal/types/queue.hpp +132 -0
  88. data/vendor/cereal/include/cereal/types/set.hpp +103 -0
  89. data/vendor/cereal/include/cereal/types/stack.hpp +76 -0
  90. data/vendor/cereal/include/cereal/types/string.hpp +61 -0
  91. data/vendor/cereal/include/cereal/types/tuple.hpp +123 -0
  92. data/vendor/cereal/include/cereal/types/unordered_map.hpp +36 -0
  93. data/vendor/cereal/include/cereal/types/unordered_set.hpp +99 -0
  94. data/vendor/cereal/include/cereal/types/utility.hpp +47 -0
  95. data/vendor/cereal/include/cereal/types/valarray.hpp +89 -0
  96. data/vendor/cereal/include/cereal/types/variant.hpp +109 -0
  97. data/vendor/cereal/include/cereal/types/vector.hpp +112 -0
  98. data/vendor/cereal/include/cereal/version.hpp +52 -0
  99. data/vendor/isotree/LICENSE +1 -1
  100. data/vendor/isotree/README.md +2 -1
  101. data/vendor/isotree/src/RcppExports.cpp +44 -4
  102. data/vendor/isotree/src/Rwrapper.cpp +141 -51
  103. data/vendor/isotree/src/crit.cpp +1 -1
  104. data/vendor/isotree/src/dealloc.cpp +1 -1
  105. data/vendor/isotree/src/dist.cpp +6 -6
  106. data/vendor/isotree/src/extended.cpp +5 -5
  107. data/vendor/isotree/src/fit_model.cpp +30 -19
  108. data/vendor/isotree/src/helpers_iforest.cpp +26 -11
  109. data/vendor/isotree/src/impute.cpp +7 -7
  110. data/vendor/isotree/src/isoforest.cpp +7 -7
  111. data/vendor/isotree/src/isotree.hpp +27 -5
  112. data/vendor/isotree/src/merge_models.cpp +1 -1
  113. data/vendor/isotree/src/mult.cpp +1 -1
  114. data/vendor/isotree/src/predict.cpp +20 -16
  115. data/vendor/isotree/src/serialize.cpp +1 -1
  116. data/vendor/isotree/src/sql.cpp +545 -0
  117. data/vendor/isotree/src/utils.cpp +36 -44
  118. metadata +98 -92
@@ -0,0 +1,334 @@
1
+ /*! \file binary.hpp
2
+ \brief Binary input and output archives */
3
+ /*
4
+ Copyright (c) 2014, Randolph Voorhies, Shane Grant
5
+ All rights reserved.
6
+
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 cereal 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
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
22
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+ */
29
+ #ifndef CEREAL_ARCHIVES_PORTABLE_BINARY_HPP_
30
+ #define CEREAL_ARCHIVES_PORTABLE_BINARY_HPP_
31
+
32
+ #include "cereal/cereal.hpp"
33
+ #include <sstream>
34
+ #include <limits>
35
+
36
+ namespace cereal
37
+ {
38
+ namespace portable_binary_detail
39
+ {
40
+ //! Returns true if the current machine is little endian
41
+ /*! @ingroup Internal */
42
+ inline std::uint8_t is_little_endian()
43
+ {
44
+ static std::int32_t test = 1;
45
+ return *reinterpret_cast<std::int8_t*>( &test ) == 1;
46
+ }
47
+
48
+ //! Swaps the order of bytes for some chunk of memory
49
+ /*! @param data The data as a uint8_t pointer
50
+ @tparam DataSize The true size of the data
51
+ @ingroup Internal */
52
+ template <std::size_t DataSize>
53
+ inline void swap_bytes( std::uint8_t * data )
54
+ {
55
+ for( std::size_t i = 0, end = DataSize / 2; i < end; ++i )
56
+ std::swap( data[i], data[DataSize - i - 1] );
57
+ }
58
+ } // end namespace portable_binary_detail
59
+
60
+ // ######################################################################
61
+ //! An output archive designed to save data in a compact binary representation portable over different architectures
62
+ /*! This archive outputs data to a stream in an extremely compact binary
63
+ representation with as little extra metadata as possible.
64
+
65
+ This archive will record the endianness of the data as well as the desired in/out endianness
66
+ and assuming that the user takes care of ensuring serialized types are the same size
67
+ across machines, is portable over different architectures.
68
+
69
+ When using a binary archive and a file stream, you must use the
70
+ std::ios::binary format flag to avoid having your data altered
71
+ inadvertently.
72
+
73
+ \warning This archive has not been thoroughly tested across different architectures.
74
+ Please report any issues, optimizations, or feature requests at
75
+ <a href="www.github.com/USCiLab/cereal">the project github</a>.
76
+
77
+ \ingroup Archives */
78
+ class PortableBinaryOutputArchive : public OutputArchive<PortableBinaryOutputArchive, AllowEmptyClassElision>
79
+ {
80
+ public:
81
+ //! A class containing various advanced options for the PortableBinaryOutput archive
82
+ class Options
83
+ {
84
+ public:
85
+ //! Represents desired endianness
86
+ enum class Endianness : std::uint8_t
87
+ { big, little };
88
+
89
+ //! Default options, preserve system endianness
90
+ static Options Default(){ return Options(); }
91
+
92
+ //! Save as little endian
93
+ static Options LittleEndian(){ return Options( Endianness::little ); }
94
+
95
+ //! Save as big endian
96
+ static Options BigEndian(){ return Options( Endianness::big ); }
97
+
98
+ //! Specify specific options for the PortableBinaryOutputArchive
99
+ /*! @param outputEndian The desired endianness of saved (output) data */
100
+ explicit Options( Endianness outputEndian = getEndianness() ) :
101
+ itsOutputEndianness( outputEndian ) { }
102
+
103
+ private:
104
+ //! Gets the endianness of the system
105
+ inline static Endianness getEndianness()
106
+ { return portable_binary_detail::is_little_endian() ? Endianness::little : Endianness::big; }
107
+
108
+ //! Checks if Options is set for little endian
109
+ inline std::uint8_t is_little_endian() const
110
+ { return itsOutputEndianness == Endianness::little; }
111
+
112
+ friend class PortableBinaryOutputArchive;
113
+ Endianness itsOutputEndianness;
114
+ };
115
+
116
+ //! Construct, outputting to the provided stream
117
+ /*! @param stream The stream to output to. Should be opened with std::ios::binary flag.
118
+ @param options The PortableBinary specific options to use. See the Options struct
119
+ for the values of default parameters */
120
+ PortableBinaryOutputArchive(std::ostream & stream, Options const & options = Options::Default()) :
121
+ OutputArchive<PortableBinaryOutputArchive, AllowEmptyClassElision>(this),
122
+ itsStream(stream),
123
+ itsConvertEndianness( portable_binary_detail::is_little_endian() ^ options.is_little_endian() )
124
+ {
125
+ this->operator()( options.is_little_endian() );
126
+ }
127
+
128
+ ~PortableBinaryOutputArchive() CEREAL_NOEXCEPT = default;
129
+
130
+ //! Writes size bytes of data to the output stream
131
+ template <std::streamsize DataSize> inline
132
+ void saveBinary( const void * data, std::streamsize size )
133
+ {
134
+ std::streamsize writtenSize = 0;
135
+
136
+ if( itsConvertEndianness )
137
+ {
138
+ for( std::streamsize i = 0; i < size; i += DataSize )
139
+ for( std::streamsize j = 0; j < DataSize; ++j )
140
+ writtenSize += itsStream.rdbuf()->sputn( reinterpret_cast<const char*>( data ) + DataSize - j - 1 + i, 1 );
141
+ }
142
+ else
143
+ writtenSize = itsStream.rdbuf()->sputn( reinterpret_cast<const char*>( data ), size );
144
+
145
+ if(writtenSize != size)
146
+ throw Exception("Failed to write " + std::to_string(size) + " bytes to output stream! Wrote " + std::to_string(writtenSize));
147
+ }
148
+
149
+ private:
150
+ std::ostream & itsStream;
151
+ const uint8_t itsConvertEndianness; //!< If set to true, we will need to swap bytes upon saving
152
+ };
153
+
154
+ // ######################################################################
155
+ //! An input archive designed to load data saved using PortableBinaryOutputArchive
156
+ /*! This archive outputs data to a stream in an extremely compact binary
157
+ representation with as little extra metadata as possible.
158
+
159
+ This archive will load the endianness of the serialized data and
160
+ if necessary transform it to match that of the local machine. This comes
161
+ at a significant performance cost compared to non portable archives if
162
+ the transformation is necessary, and also causes a small performance hit
163
+ even if it is not necessary.
164
+
165
+ It is recommended to use portable archives only if you know that you will
166
+ be sending binary data to machines with different endianness.
167
+
168
+ The archive will do nothing to ensure types are the same size - that is
169
+ the responsibility of the user.
170
+
171
+ When using a binary archive and a file stream, you must use the
172
+ std::ios::binary format flag to avoid having your data altered
173
+ inadvertently.
174
+
175
+ \warning This archive has not been thoroughly tested across different architectures.
176
+ Please report any issues, optimizations, or feature requests at
177
+ <a href="www.github.com/USCiLab/cereal">the project github</a>.
178
+
179
+ \ingroup Archives */
180
+ class PortableBinaryInputArchive : public InputArchive<PortableBinaryInputArchive, AllowEmptyClassElision>
181
+ {
182
+ public:
183
+ //! A class containing various advanced options for the PortableBinaryInput archive
184
+ class Options
185
+ {
186
+ public:
187
+ //! Represents desired endianness
188
+ enum class Endianness : std::uint8_t
189
+ { big, little };
190
+
191
+ //! Default options, preserve system endianness
192
+ static Options Default(){ return Options(); }
193
+
194
+ //! Load into little endian
195
+ static Options LittleEndian(){ return Options( Endianness::little ); }
196
+
197
+ //! Load into big endian
198
+ static Options BigEndian(){ return Options( Endianness::big ); }
199
+
200
+ //! Specify specific options for the PortableBinaryInputArchive
201
+ /*! @param inputEndian The desired endianness of loaded (input) data */
202
+ explicit Options( Endianness inputEndian = getEndianness() ) :
203
+ itsInputEndianness( inputEndian ) { }
204
+
205
+ private:
206
+ //! Gets the endianness of the system
207
+ inline static Endianness getEndianness()
208
+ { return portable_binary_detail::is_little_endian() ? Endianness::little : Endianness::big; }
209
+
210
+ //! Checks if Options is set for little endian
211
+ inline std::uint8_t is_little_endian() const
212
+ { return itsInputEndianness == Endianness::little; }
213
+
214
+ friend class PortableBinaryInputArchive;
215
+ Endianness itsInputEndianness;
216
+ };
217
+
218
+ //! Construct, loading from the provided stream
219
+ /*! @param stream The stream to read from. Should be opened with std::ios::binary flag.
220
+ @param options The PortableBinary specific options to use. See the Options struct
221
+ for the values of default parameters */
222
+ PortableBinaryInputArchive(std::istream & stream, Options const & options = Options::Default()) :
223
+ InputArchive<PortableBinaryInputArchive, AllowEmptyClassElision>(this),
224
+ itsStream(stream),
225
+ itsConvertEndianness( false )
226
+ {
227
+ uint8_t streamLittleEndian;
228
+ this->operator()( streamLittleEndian );
229
+ itsConvertEndianness = options.is_little_endian() ^ streamLittleEndian;
230
+ }
231
+
232
+ ~PortableBinaryInputArchive() CEREAL_NOEXCEPT = default;
233
+
234
+ //! Reads size bytes of data from the input stream
235
+ /*! @param data The data to save
236
+ @param size The number of bytes in the data
237
+ @tparam DataSize T The size of the actual type of the data elements being loaded */
238
+ template <std::streamsize DataSize> inline
239
+ void loadBinary( void * const data, std::streamsize size )
240
+ {
241
+ // load data
242
+ auto const readSize = itsStream.rdbuf()->sgetn( reinterpret_cast<char*>( data ), size );
243
+
244
+ if(readSize != size)
245
+ throw Exception("Failed to read " + std::to_string(size) + " bytes from input stream! Read " + std::to_string(readSize));
246
+
247
+ // flip bits if needed
248
+ if( itsConvertEndianness )
249
+ {
250
+ std::uint8_t * ptr = reinterpret_cast<std::uint8_t*>( data );
251
+ for( std::streamsize i = 0; i < size; i += DataSize )
252
+ portable_binary_detail::swap_bytes<DataSize>( ptr + i );
253
+ }
254
+ }
255
+
256
+ private:
257
+ std::istream & itsStream;
258
+ uint8_t itsConvertEndianness; //!< If set to true, we will need to swap bytes upon loading
259
+ };
260
+
261
+ // ######################################################################
262
+ // Common BinaryArchive serialization functions
263
+
264
+ //! Saving for POD types to portable binary
265
+ template<class T> inline
266
+ typename std::enable_if<std::is_arithmetic<T>::value, void>::type
267
+ CEREAL_SAVE_FUNCTION_NAME(PortableBinaryOutputArchive & ar, T const & t)
268
+ {
269
+ static_assert( !std::is_floating_point<T>::value ||
270
+ (std::is_floating_point<T>::value && std::numeric_limits<T>::is_iec559),
271
+ "Portable binary only supports IEEE 754 standardized floating point" );
272
+ ar.template saveBinary<sizeof(T)>(std::addressof(t), sizeof(t));
273
+ }
274
+
275
+ //! Loading for POD types from portable binary
276
+ template<class T> inline
277
+ typename std::enable_if<std::is_arithmetic<T>::value, void>::type
278
+ CEREAL_LOAD_FUNCTION_NAME(PortableBinaryInputArchive & ar, T & t)
279
+ {
280
+ static_assert( !std::is_floating_point<T>::value ||
281
+ (std::is_floating_point<T>::value && std::numeric_limits<T>::is_iec559),
282
+ "Portable binary only supports IEEE 754 standardized floating point" );
283
+ ar.template loadBinary<sizeof(T)>(std::addressof(t), sizeof(t));
284
+ }
285
+
286
+ //! Serializing NVP types to portable binary
287
+ template <class Archive, class T> inline
288
+ CEREAL_ARCHIVE_RESTRICT(PortableBinaryInputArchive, PortableBinaryOutputArchive)
289
+ CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, NameValuePair<T> & t )
290
+ {
291
+ ar( t.value );
292
+ }
293
+
294
+ //! Serializing SizeTags to portable binary
295
+ template <class Archive, class T> inline
296
+ CEREAL_ARCHIVE_RESTRICT(PortableBinaryInputArchive, PortableBinaryOutputArchive)
297
+ CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar, SizeTag<T> & t )
298
+ {
299
+ ar( t.size );
300
+ }
301
+
302
+ //! Saving binary data to portable binary
303
+ template <class T> inline
304
+ void CEREAL_SAVE_FUNCTION_NAME(PortableBinaryOutputArchive & ar, BinaryData<T> const & bd)
305
+ {
306
+ typedef typename std::remove_pointer<T>::type TT;
307
+ static_assert( !std::is_floating_point<TT>::value ||
308
+ (std::is_floating_point<TT>::value && std::numeric_limits<TT>::is_iec559),
309
+ "Portable binary only supports IEEE 754 standardized floating point" );
310
+
311
+ ar.template saveBinary<sizeof(TT)>( bd.data, static_cast<std::streamsize>( bd.size ) );
312
+ }
313
+
314
+ //! Loading binary data from portable binary
315
+ template <class T> inline
316
+ void CEREAL_LOAD_FUNCTION_NAME(PortableBinaryInputArchive & ar, BinaryData<T> & bd)
317
+ {
318
+ typedef typename std::remove_pointer<T>::type TT;
319
+ static_assert( !std::is_floating_point<TT>::value ||
320
+ (std::is_floating_point<TT>::value && std::numeric_limits<TT>::is_iec559),
321
+ "Portable binary only supports IEEE 754 standardized floating point" );
322
+
323
+ ar.template loadBinary<sizeof(TT)>( bd.data, static_cast<std::streamsize>( bd.size ) );
324
+ }
325
+ } // namespace cereal
326
+
327
+ // register archives for polymorphic support
328
+ CEREAL_REGISTER_ARCHIVE(cereal::PortableBinaryOutputArchive)
329
+ CEREAL_REGISTER_ARCHIVE(cereal::PortableBinaryInputArchive)
330
+
331
+ // tie input and output archives together
332
+ CEREAL_SETUP_ARCHIVE_TRAITS(cereal::PortableBinaryInputArchive, cereal::PortableBinaryOutputArchive)
333
+
334
+ #endif // CEREAL_ARCHIVES_PORTABLE_BINARY_HPP_
@@ -0,0 +1,956 @@
1
+ /*! \file xml.hpp
2
+ \brief XML input and output archives */
3
+ /*
4
+ Copyright (c) 2014, Randolph Voorhies, Shane Grant
5
+ All rights reserved.
6
+
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 cereal 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
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
22
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+ */
29
+ #ifndef CEREAL_ARCHIVES_XML_HPP_
30
+ #define CEREAL_ARCHIVES_XML_HPP_
31
+ #include "cereal/cereal.hpp"
32
+ #include "cereal/details/util.hpp"
33
+
34
+ #include "cereal/external/rapidxml/rapidxml.hpp"
35
+ #include "cereal/external/rapidxml/rapidxml_print.hpp"
36
+ #include "cereal/external/base64.hpp"
37
+
38
+ #include <sstream>
39
+ #include <stack>
40
+ #include <vector>
41
+ #include <limits>
42
+ #include <string>
43
+ #include <cstring>
44
+ #include <cmath>
45
+
46
+ namespace cereal
47
+ {
48
+ namespace xml_detail
49
+ {
50
+ #ifndef CEREAL_XML_STRING_VALUE
51
+ //! The default name for the root node in a cereal xml archive.
52
+ /*! You can define CEREAL_XML_STRING_VALUE to be different assuming you do so
53
+ before this file is included. */
54
+ #define CEREAL_XML_STRING_VALUE "cereal"
55
+ #endif // CEREAL_XML_STRING_VALUE
56
+
57
+ //! The name given to the root node in a cereal xml archive
58
+ static const char * CEREAL_XML_STRING = CEREAL_XML_STRING_VALUE;
59
+
60
+ //! Returns true if the character is whitespace
61
+ inline bool isWhitespace( char c )
62
+ {
63
+ return c == ' ' || c == '\t' || c == '\n' || c == '\r';
64
+ }
65
+ }
66
+
67
+ // ######################################################################
68
+ //! An output archive designed to save data to XML
69
+ /*! This archive uses RapidXML to build an in memory XML tree of the
70
+ data it serializes before outputting it to its stream upon destruction.
71
+ This archive should be used in an RAII fashion, letting
72
+ the automatic destruction of the object cause the flush to its stream.
73
+
74
+ XML archives provides a human readable output but at decreased
75
+ performance (both in time and space) compared to binary archives.
76
+
77
+ XML benefits greatly from name-value pairs, which if present, will
78
+ name the nodes in the output. If these are not present, each level
79
+ of the output tree will be given an automatically generated delimited name.
80
+
81
+ The precision of the output archive controls the number of decimals output
82
+ for floating point numbers and should be sufficiently large (i.e. at least 20)
83
+ if there is a desire to have binary equality between the numbers output and
84
+ those read in. In general you should expect a loss of precision when going
85
+ from floating point to text and back.
86
+
87
+ XML archives can optionally print the type of everything they serialize, which
88
+ adds an attribute to each node.
89
+
90
+ XML archives do not output the size information for any dynamically sized structure
91
+ and instead infer it from the number of children for a node. This means that data
92
+ can be hand edited for dynamic sized structures and will still be readable. This
93
+ is accomplished through the cereal::SizeTag object, which will also add an attribute
94
+ to its parent field.
95
+ \ingroup Archives */
96
+ class XMLOutputArchive : public OutputArchive<XMLOutputArchive>, public traits::TextArchive
97
+ {
98
+ public:
99
+ /*! @name Common Functionality
100
+ Common use cases for directly interacting with an XMLOutputArchive */
101
+ //! @{
102
+
103
+ //! A class containing various advanced options for the XML archive
104
+ /*! Options can either be directly passed to the constructor, or chained using the
105
+ modifier functions for an interface analogous to named parameters */
106
+ class Options
107
+ {
108
+ public:
109
+ //! Default options
110
+ static Options Default(){ return Options(); }
111
+
112
+ //! Specify specific options for the XMLOutputArchive
113
+ /*! @param precision_ The precision used for floating point numbers
114
+ @param indent_ Whether to indent each line of XML
115
+ @param outputType_ Whether to output the type of each serialized object as an attribute
116
+ @param sizeAttributes_ Whether dynamically sized containers output the size=dynamic attribute */
117
+ explicit Options( int precision_ = std::numeric_limits<double>::max_digits10,
118
+ bool indent_ = true,
119
+ bool outputType_ = false,
120
+ bool sizeAttributes_ = true ) :
121
+ itsPrecision( precision_ ),
122
+ itsIndent( indent_ ),
123
+ itsOutputType( outputType_ ),
124
+ itsSizeAttributes( sizeAttributes_ )
125
+ { }
126
+
127
+ /*! @name Option Modifiers
128
+ An interface for setting option settings analogous to named parameters.
129
+
130
+ @code{cpp}
131
+ cereal::XMLOutputArchive ar( myStream,
132
+ cereal::XMLOutputArchive::Options()
133
+ .indent(true)
134
+ .sizeAttributes(false) );
135
+ @endcode
136
+ */
137
+ //! @{
138
+
139
+ //! Sets the precision used for floaing point numbers
140
+ Options & precision( int value ){ itsPrecision = value; return * this; }
141
+ //! Whether to indent each line of XML
142
+ Options & indent( bool enable ){ itsIndent = enable; return *this; }
143
+ //! Whether to output the type of each serialized object as an attribute
144
+ Options & outputType( bool enable ){ itsOutputType = enable; return *this; }
145
+ //! Whether dynamically sized containers (e.g. vector) output the size=dynamic attribute
146
+ Options & sizeAttributes( bool enable ){ itsSizeAttributes = enable; return *this; }
147
+
148
+ //! @}
149
+
150
+ private:
151
+ friend class XMLOutputArchive;
152
+ int itsPrecision;
153
+ bool itsIndent;
154
+ bool itsOutputType;
155
+ bool itsSizeAttributes;
156
+ };
157
+
158
+ //! Construct, outputting to the provided stream upon destruction
159
+ /*! @param stream The stream to output to. Note that XML is only guaranteed to flush
160
+ its output to the stream upon destruction.
161
+ @param options The XML specific options to use. See the Options struct
162
+ for the values of default parameters */
163
+ XMLOutputArchive( std::ostream & stream, Options const & options = Options::Default() ) :
164
+ OutputArchive<XMLOutputArchive>(this),
165
+ itsStream(stream),
166
+ itsOutputType( options.itsOutputType ),
167
+ itsIndent( options.itsIndent ),
168
+ itsSizeAttributes(options.itsSizeAttributes)
169
+ {
170
+ // rapidxml will delete all allocations when xml_document is cleared
171
+ auto node = itsXML.allocate_node( rapidxml::node_declaration );
172
+ node->append_attribute( itsXML.allocate_attribute( "version", "1.0" ) );
173
+ node->append_attribute( itsXML.allocate_attribute( "encoding", "utf-8" ) );
174
+ itsXML.append_node( node );
175
+
176
+ // allocate root node
177
+ auto root = itsXML.allocate_node( rapidxml::node_element, xml_detail::CEREAL_XML_STRING );
178
+ itsXML.append_node( root );
179
+ itsNodes.emplace( root );
180
+
181
+ // set attributes on the streams
182
+ itsStream << std::boolalpha;
183
+ itsStream.precision( options.itsPrecision );
184
+ itsOS << std::boolalpha;
185
+ itsOS.precision( options.itsPrecision );
186
+ }
187
+
188
+ //! Destructor, flushes the XML
189
+ ~XMLOutputArchive() CEREAL_NOEXCEPT
190
+ {
191
+ const int flags = itsIndent ? 0x0 : rapidxml::print_no_indenting;
192
+ rapidxml::print( itsStream, itsXML, flags );
193
+ itsXML.clear();
194
+ }
195
+
196
+ //! Saves some binary data, encoded as a base64 string, with an optional name
197
+ /*! This can be called directly by users and it will automatically create a child node for
198
+ the current XML node, populate it with a base64 encoded string, and optionally name
199
+ it. The node will be finished after it has been populated. */
200
+ void saveBinaryValue( const void * data, size_t size, const char * name = nullptr )
201
+ {
202
+ itsNodes.top().name = name;
203
+
204
+ startNode();
205
+
206
+ auto base64string = base64::encode( reinterpret_cast<const unsigned char *>( data ), size );
207
+ saveValue( base64string );
208
+
209
+ if( itsOutputType )
210
+ itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", "cereal binary data" ) );
211
+
212
+ finishNode();
213
+ }
214
+
215
+ //! @}
216
+ /*! @name Internal Functionality
217
+ Functionality designed for use by those requiring control over the inner mechanisms of
218
+ the XMLOutputArchive */
219
+ //! @{
220
+
221
+ //! Creates a new node that is a child of the node at the top of the stack
222
+ /*! Nodes will be given a name that has either been pre-set by a name value pair,
223
+ or generated based upon a counter unique to the parent node. If you want to
224
+ give a node a specific name, use setNextName prior to calling startNode.
225
+
226
+ The node will then be pushed onto the node stack. */
227
+ void startNode()
228
+ {
229
+ // generate a name for this new node
230
+ const auto nameString = itsNodes.top().getValueName();
231
+
232
+ // allocate strings for all of the data in the XML object
233
+ auto namePtr = itsXML.allocate_string( nameString.data(), nameString.length() + 1 );
234
+
235
+ // insert into the XML
236
+ auto node = itsXML.allocate_node( rapidxml::node_element, namePtr, nullptr, nameString.size() );
237
+ itsNodes.top().node->append_node( node );
238
+ itsNodes.emplace( node );
239
+ }
240
+
241
+ //! Designates the most recently added node as finished
242
+ void finishNode()
243
+ {
244
+ itsNodes.pop();
245
+ }
246
+
247
+ //! Sets the name for the next node created with startNode
248
+ void setNextName( const char * name )
249
+ {
250
+ itsNodes.top().name = name;
251
+ }
252
+
253
+ //! Saves some data, encoded as a string, into the current top level node
254
+ /*! The data will be be named with the most recent name if one exists,
255
+ otherwise it will be given some default delimited value that depends upon
256
+ the parent node */
257
+ template <class T> inline
258
+ void saveValue( T const & value )
259
+ {
260
+ itsOS.clear(); itsOS.seekp( 0, std::ios::beg );
261
+ itsOS << value << std::ends;
262
+
263
+ auto strValue = itsOS.str();
264
+
265
+ // itsOS.str() may contain data from previous calls after the first '\0' that was just inserted
266
+ // and this data is counted in the length call. We make sure to remove that section so that the
267
+ // whitespace validation is done properly
268
+ strValue.resize(std::strlen(strValue.c_str()));
269
+
270
+ // If the first or last character is a whitespace, add xml:space attribute
271
+ const auto len = strValue.length();
272
+ if ( len > 0 && ( xml_detail::isWhitespace( strValue[0] ) || xml_detail::isWhitespace( strValue[len - 1] ) ) )
273
+ {
274
+ itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "xml:space", "preserve" ) );
275
+ }
276
+
277
+ // allocate strings for all of the data in the XML object
278
+ auto dataPtr = itsXML.allocate_string(strValue.c_str(), strValue.length() + 1 );
279
+
280
+ // insert into the XML
281
+ itsNodes.top().node->append_node( itsXML.allocate_node( rapidxml::node_data, nullptr, dataPtr ) );
282
+ }
283
+
284
+ //! Overload for uint8_t prevents them from being serialized as characters
285
+ void saveValue( uint8_t const & value )
286
+ {
287
+ saveValue( static_cast<uint32_t>( value ) );
288
+ }
289
+
290
+ //! Overload for int8_t prevents them from being serialized as characters
291
+ void saveValue( int8_t const & value )
292
+ {
293
+ saveValue( static_cast<int32_t>( value ) );
294
+ }
295
+
296
+ //! Causes the type to be appended as an attribute to the most recently made node if output type is set to true
297
+ template <class T> inline
298
+ void insertType()
299
+ {
300
+ if( !itsOutputType )
301
+ return;
302
+
303
+ // generate a name for this new node
304
+ const auto nameString = util::demangledName<T>();
305
+
306
+ // allocate strings for all of the data in the XML object
307
+ auto namePtr = itsXML.allocate_string( nameString.data(), nameString.length() + 1 );
308
+
309
+ itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", namePtr ) );
310
+ }
311
+
312
+ //! Appends an attribute to the current top level node
313
+ void appendAttribute( const char * name, const char * value )
314
+ {
315
+ auto namePtr = itsXML.allocate_string( name );
316
+ auto valuePtr = itsXML.allocate_string( value );
317
+ itsNodes.top().node->append_attribute( itsXML.allocate_attribute( namePtr, valuePtr ) );
318
+ }
319
+
320
+ bool hasSizeAttributes() const { return itsSizeAttributes; }
321
+
322
+ protected:
323
+ //! A struct that contains metadata about a node
324
+ struct NodeInfo
325
+ {
326
+ NodeInfo( rapidxml::xml_node<> * n = nullptr,
327
+ const char * nm = nullptr ) :
328
+ node( n ),
329
+ counter( 0 ),
330
+ name( nm )
331
+ { }
332
+
333
+ rapidxml::xml_node<> * node; //!< A pointer to this node
334
+ size_t counter; //!< The counter for naming child nodes
335
+ const char * name; //!< The name for the next child node
336
+
337
+ //! Gets the name for the next child node created from this node
338
+ /*! The name will be automatically generated using the counter if
339
+ a name has not been previously set. If a name has been previously
340
+ set, that name will be returned only once */
341
+ std::string getValueName()
342
+ {
343
+ if( name )
344
+ {
345
+ auto n = name;
346
+ name = nullptr;
347
+ return {n};
348
+ }
349
+ else
350
+ return "value" + std::to_string( counter++ ) + "\0";
351
+ }
352
+ }; // NodeInfo
353
+
354
+ //! @}
355
+
356
+ private:
357
+ std::ostream & itsStream; //!< The output stream
358
+ rapidxml::xml_document<> itsXML; //!< The XML document
359
+ std::stack<NodeInfo> itsNodes; //!< A stack of nodes added to the document
360
+ std::ostringstream itsOS; //!< Used to format strings internally
361
+ bool itsOutputType; //!< Controls whether type information is printed
362
+ bool itsIndent; //!< Controls whether indenting is used
363
+ bool itsSizeAttributes; //!< Controls whether lists have a size attribute
364
+ }; // XMLOutputArchive
365
+
366
+ // ######################################################################
367
+ //! An output archive designed to load data from XML
368
+ /*! This archive uses RapidXML to build an in memory XML tree of the
369
+ data in the stream it is given before loading any types serialized.
370
+
371
+ As with the output XML archive, the preferred way to use this archive is in
372
+ an RAII fashion, ensuring its destruction after all data has been read.
373
+
374
+ Input XML should have been produced by the XMLOutputArchive. Data can
375
+ only be added to dynamically sized containers - the input archive will
376
+ determine their size by looking at the number of child nodes. Data that
377
+ did not originate from an XMLOutputArchive is not officially supported,
378
+ but may be possible to use if properly formatted.
379
+
380
+ The XMLInputArchive does not require that nodes are loaded in the same
381
+ order they were saved by XMLOutputArchive. Using name value pairs (NVPs),
382
+ it is possible to load in an out of order fashion or otherwise skip/select
383
+ specific nodes to load.
384
+
385
+ The default behavior of the input archive is to read sequentially starting
386
+ with the first node and exploring its children. When a given NVP does
387
+ not match the read in name for a node, the archive will search for that
388
+ node at the current level and load it if it exists. After loading an out of
389
+ order node, the archive will then proceed back to loading sequentially from
390
+ its new position.
391
+
392
+ Consider this simple example where loading of some data is skipped:
393
+
394
+ @code{cpp}
395
+ // imagine the input file has someData(1-9) saved in order at the top level node
396
+ ar( someData1, someData2, someData3 ); // XML loads in the order it sees in the file
397
+ ar( cereal::make_nvp( "hello", someData6 ) ); // NVP given does not
398
+ // match expected NVP name, so we search
399
+ // for the given NVP and load that value
400
+ ar( someData7, someData8, someData9 ); // with no NVP given, loading resumes at its
401
+ // current location, proceeding sequentially
402
+ @endcode
403
+
404
+ \ingroup Archives */
405
+ class XMLInputArchive : public InputArchive<XMLInputArchive>, public traits::TextArchive
406
+ {
407
+ public:
408
+ /*! @name Common Functionality
409
+ Common use cases for directly interacting with an XMLInputArchive */
410
+ //! @{
411
+
412
+ //! Construct, reading in from the provided stream
413
+ /*! Reads in an entire XML document from some stream and parses it as soon
414
+ as serialization starts
415
+
416
+ @param stream The stream to read from. Can be a stringstream or a file. */
417
+ XMLInputArchive( std::istream & stream ) :
418
+ InputArchive<XMLInputArchive>( this ),
419
+ itsData( std::istreambuf_iterator<char>( stream ), std::istreambuf_iterator<char>() )
420
+ {
421
+ try
422
+ {
423
+ itsData.push_back('\0'); // rapidxml will do terrible things without the data being null terminated
424
+ itsXML.parse<rapidxml::parse_trim_whitespace | rapidxml::parse_no_data_nodes | rapidxml::parse_declaration_node>( reinterpret_cast<char *>( itsData.data() ) );
425
+ }
426
+ catch( rapidxml::parse_error const & )
427
+ {
428
+ //std::cerr << "-----Original-----" << std::endl;
429
+ //stream.seekg(0);
430
+ //std::cout << std::string( std::istreambuf_iterator<char>( stream ), std::istreambuf_iterator<char>() ) << std::endl;
431
+
432
+ //std::cerr << "-----Error-----" << std::endl;
433
+ //std::cerr << e.what() << std::endl;
434
+ //std::cerr << e.where<char>() << std::endl;
435
+ throw Exception("XML Parsing failed - likely due to invalid characters or invalid naming");
436
+ }
437
+
438
+ // Parse the root
439
+ auto root = itsXML.first_node( xml_detail::CEREAL_XML_STRING );
440
+ if( root == nullptr )
441
+ throw Exception("Could not detect cereal root node - likely due to empty or invalid input");
442
+ else
443
+ itsNodes.emplace( root );
444
+ }
445
+
446
+ ~XMLInputArchive() CEREAL_NOEXCEPT = default;
447
+
448
+ //! Loads some binary data, encoded as a base64 string, optionally specified by some name
449
+ /*! This will automatically start and finish a node to load the data, and can be called directly by
450
+ users.
451
+
452
+ Note that this follows the same ordering rules specified in the class description in regards
453
+ to loading in/out of order */
454
+ void loadBinaryValue( void * data, size_t size, const char * name = nullptr )
455
+ {
456
+ setNextName( name );
457
+ startNode();
458
+
459
+ std::string encoded;
460
+ loadValue( encoded );
461
+
462
+ auto decoded = base64::decode( encoded );
463
+
464
+ if( size != decoded.size() )
465
+ throw Exception("Decoded binary data size does not match specified size");
466
+
467
+ std::memcpy( data, decoded.data(), decoded.size() );
468
+
469
+ finishNode();
470
+ }
471
+
472
+ //! @}
473
+ /*! @name Internal Functionality
474
+ Functionality designed for use by those requiring control over the inner mechanisms of
475
+ the XMLInputArchive */
476
+ //! @{
477
+
478
+ //! Prepares to start reading the next node
479
+ /*! This places the next node to be parsed onto the nodes stack.
480
+
481
+ By default our strategy is to start with the document root node and then
482
+ recursively iterate through all children in the order they show up in the document.
483
+ We don't need to know NVPs do to this; we'll just blindly load in the order things appear in.
484
+
485
+ We check to see if the specified NVP matches what the next automatically loaded node is. If they
486
+ match, we just continue as normal, going in order. If they don't match, we attempt to find a node
487
+ named after the NVP that is being loaded. If that NVP does not exist, we throw an exception. */
488
+ void startNode()
489
+ {
490
+ auto next = itsNodes.top().child; // By default we would move to the next child node
491
+ auto const expectedName = itsNodes.top().name; // this is the expected name from the NVP, if provided
492
+
493
+ // If we were given an NVP name, look for it in the current level of the document.
494
+ // We only need to do this if either we have exhausted the siblings of the current level or
495
+ // the NVP name does not match the name of the node we would normally read next
496
+ if( expectedName && ( next == nullptr || std::strcmp( next->name(), expectedName ) != 0 ) )
497
+ {
498
+ next = itsNodes.top().search( expectedName );
499
+
500
+ if( next == nullptr )
501
+ throw Exception("XML Parsing failed - provided NVP (" + std::string(expectedName) + ") not found");
502
+ }
503
+
504
+ itsNodes.emplace( next );
505
+ }
506
+
507
+ //! Finishes reading the current node
508
+ void finishNode()
509
+ {
510
+ // remove current
511
+ itsNodes.pop();
512
+
513
+ // advance parent
514
+ itsNodes.top().advance();
515
+
516
+ // Reset name
517
+ itsNodes.top().name = nullptr;
518
+ }
519
+
520
+ //! Retrieves the current node name
521
+ //! will return @c nullptr if the node does not have a name
522
+ const char * getNodeName() const
523
+ {
524
+ return itsNodes.top().getChildName();
525
+ }
526
+
527
+ //! Sets the name for the next node created with startNode
528
+ void setNextName( const char * name )
529
+ {
530
+ itsNodes.top().name = name;
531
+ }
532
+
533
+ //! Loads a bool from the current top node
534
+ template <class T, traits::EnableIf<std::is_unsigned<T>::value,
535
+ std::is_same<T, bool>::value> = traits::sfinae> inline
536
+ void loadValue( T & value )
537
+ {
538
+ std::istringstream is( itsNodes.top().node->value() );
539
+ is.setf( std::ios::boolalpha );
540
+ is >> value;
541
+ }
542
+
543
+ //! Loads a char (signed or unsigned) from the current top node
544
+ template <class T, traits::EnableIf<std::is_integral<T>::value,
545
+ !std::is_same<T, bool>::value,
546
+ sizeof(T) == sizeof(char)> = traits::sfinae> inline
547
+ void loadValue( T & value )
548
+ {
549
+ value = *reinterpret_cast<T*>( itsNodes.top().node->value() );
550
+ }
551
+
552
+ //! Load an int8_t from the current top node (ensures we parse entire number)
553
+ void loadValue( int8_t & value )
554
+ {
555
+ int32_t val; loadValue( val ); value = static_cast<int8_t>( val );
556
+ }
557
+
558
+ //! Load a uint8_t from the current top node (ensures we parse entire number)
559
+ void loadValue( uint8_t & value )
560
+ {
561
+ uint32_t val; loadValue( val ); value = static_cast<uint8_t>( val );
562
+ }
563
+
564
+ //! Loads a type best represented as an unsigned long from the current top node
565
+ template <class T, traits::EnableIf<std::is_unsigned<T>::value,
566
+ !std::is_same<T, bool>::value,
567
+ !std::is_same<T, char>::value,
568
+ !std::is_same<T, unsigned char>::value,
569
+ sizeof(T) < sizeof(long long)> = traits::sfinae> inline
570
+ void loadValue( T & value )
571
+ {
572
+ value = static_cast<T>( std::stoul( itsNodes.top().node->value() ) );
573
+ }
574
+
575
+ //! Loads a type best represented as an unsigned long long from the current top node
576
+ template <class T, traits::EnableIf<std::is_unsigned<T>::value,
577
+ !std::is_same<T, bool>::value,
578
+ sizeof(T) >= sizeof(long long)> = traits::sfinae> inline
579
+ void loadValue( T & value )
580
+ {
581
+ value = static_cast<T>( std::stoull( itsNodes.top().node->value() ) );
582
+ }
583
+
584
+ //! Loads a type best represented as an int from the current top node
585
+ template <class T, traits::EnableIf<std::is_signed<T>::value,
586
+ !std::is_same<T, char>::value,
587
+ sizeof(T) <= sizeof(int)> = traits::sfinae> inline
588
+ void loadValue( T & value )
589
+ {
590
+ value = static_cast<T>( std::stoi( itsNodes.top().node->value() ) );
591
+ }
592
+
593
+ //! Loads a type best represented as a long from the current top node
594
+ template <class T, traits::EnableIf<std::is_signed<T>::value,
595
+ (sizeof(T) > sizeof(int)),
596
+ sizeof(T) <= sizeof(long)> = traits::sfinae> inline
597
+ void loadValue( T & value )
598
+ {
599
+ value = static_cast<T>( std::stol( itsNodes.top().node->value() ) );
600
+ }
601
+
602
+ //! Loads a type best represented as a long long from the current top node
603
+ template <class T, traits::EnableIf<std::is_signed<T>::value,
604
+ (sizeof(T) > sizeof(long)),
605
+ sizeof(T) <= sizeof(long long)> = traits::sfinae> inline
606
+ void loadValue( T & value )
607
+ {
608
+ value = static_cast<T>( std::stoll( itsNodes.top().node->value() ) );
609
+ }
610
+
611
+ //! Loads a type best represented as a float from the current top node
612
+ void loadValue( float & value )
613
+ {
614
+ try
615
+ {
616
+ value = std::stof( itsNodes.top().node->value() );
617
+ }
618
+ catch( std::out_of_range const & )
619
+ {
620
+ // special case for denormalized values
621
+ std::istringstream is( itsNodes.top().node->value() );
622
+ is >> value;
623
+ if( std::fpclassify( value ) != FP_SUBNORMAL )
624
+ throw;
625
+ }
626
+ }
627
+
628
+ //! Loads a type best represented as a double from the current top node
629
+ void loadValue( double & value )
630
+ {
631
+ try
632
+ {
633
+ value = std::stod( itsNodes.top().node->value() );
634
+ }
635
+ catch( std::out_of_range const & )
636
+ {
637
+ // special case for denormalized values
638
+ std::istringstream is( itsNodes.top().node->value() );
639
+ is >> value;
640
+ if( std::fpclassify( value ) != FP_SUBNORMAL )
641
+ throw;
642
+ }
643
+ }
644
+
645
+ //! Loads a type best represented as a long double from the current top node
646
+ void loadValue( long double & value )
647
+ {
648
+ try
649
+ {
650
+ value = std::stold( itsNodes.top().node->value() );
651
+ }
652
+ catch( std::out_of_range const & )
653
+ {
654
+ // special case for denormalized values
655
+ std::istringstream is( itsNodes.top().node->value() );
656
+ is >> value;
657
+ if( std::fpclassify( value ) != FP_SUBNORMAL )
658
+ throw;
659
+ }
660
+ }
661
+
662
+ //! Loads a string from the current node from the current top node
663
+ template<class CharT, class Traits, class Alloc> inline
664
+ void loadValue( std::basic_string<CharT, Traits, Alloc> & str )
665
+ {
666
+ std::basic_istringstream<CharT, Traits> is( itsNodes.top().node->value() );
667
+
668
+ str.assign( std::istreambuf_iterator<CharT, Traits>( is ),
669
+ std::istreambuf_iterator<CharT, Traits>() );
670
+ }
671
+
672
+ //! Loads the size of the current top node
673
+ template <class T> inline
674
+ void loadSize( T & value )
675
+ {
676
+ value = getNumChildren( itsNodes.top().node );
677
+ }
678
+
679
+ protected:
680
+ //! Gets the number of children (usually interpreted as size) for the specified node
681
+ static size_t getNumChildren( rapidxml::xml_node<> * node )
682
+ {
683
+ size_t size = 0;
684
+ node = node->first_node(); // get first child
685
+
686
+ while( node != nullptr )
687
+ {
688
+ ++size;
689
+ node = node->next_sibling();
690
+ }
691
+
692
+ return size;
693
+ }
694
+
695
+ //! A struct that contains metadata about a node
696
+ /*! Keeps track of some top level node, its number of
697
+ remaining children, and the current active child node */
698
+ struct NodeInfo
699
+ {
700
+ NodeInfo( rapidxml::xml_node<> * n = nullptr ) :
701
+ node( n ),
702
+ child( n->first_node() ),
703
+ size( XMLInputArchive::getNumChildren( n ) ),
704
+ name( nullptr )
705
+ { }
706
+
707
+ //! Advances to the next sibling node of the child
708
+ /*! If this is the last sibling child will be null after calling */
709
+ void advance()
710
+ {
711
+ if( size > 0 )
712
+ {
713
+ --size;
714
+ child = child->next_sibling();
715
+ }
716
+ }
717
+
718
+ //! Searches for a child with the given name in this node
719
+ /*! @param searchName The name to search for (must be null terminated)
720
+ @return The node if found, nullptr otherwise */
721
+ rapidxml::xml_node<> * search( const char * searchName )
722
+ {
723
+ if( searchName )
724
+ {
725
+ size_t new_size = XMLInputArchive::getNumChildren( node );
726
+ const size_t name_size = rapidxml::internal::measure( searchName );
727
+
728
+ for( auto new_child = node->first_node(); new_child != nullptr; new_child = new_child->next_sibling() )
729
+ {
730
+ if( rapidxml::internal::compare( new_child->name(), new_child->name_size(), searchName, name_size, true ) )
731
+ {
732
+ size = new_size;
733
+ child = new_child;
734
+
735
+ return new_child;
736
+ }
737
+ --new_size;
738
+ }
739
+ }
740
+
741
+ return nullptr;
742
+ }
743
+
744
+ //! Returns the actual name of the next child node, if it exists
745
+ const char * getChildName() const
746
+ {
747
+ return child ? child->name() : nullptr;
748
+ }
749
+
750
+ rapidxml::xml_node<> * node; //!< A pointer to this node
751
+ rapidxml::xml_node<> * child; //!< A pointer to its current child
752
+ size_t size; //!< The remaining number of children for this node
753
+ const char * name; //!< The NVP name for next child node
754
+ }; // NodeInfo
755
+
756
+ //! @}
757
+
758
+ private:
759
+ std::vector<char> itsData; //!< The raw data loaded
760
+ rapidxml::xml_document<> itsXML; //!< The XML document
761
+ std::stack<NodeInfo> itsNodes; //!< A stack of nodes read from the document
762
+ };
763
+
764
+ // ######################################################################
765
+ // XMLArchive prologue and epilogue functions
766
+ // ######################################################################
767
+
768
+ // ######################################################################
769
+ //! Prologue for NVPs for XML output archives
770
+ /*! NVPs do not start or finish nodes - they just set up the names */
771
+ template <class T> inline
772
+ void prologue( XMLOutputArchive &, NameValuePair<T> const & )
773
+ { }
774
+
775
+ //! Prologue for NVPs for XML input archives
776
+ template <class T> inline
777
+ void prologue( XMLInputArchive &, NameValuePair<T> const & )
778
+ { }
779
+
780
+ // ######################################################################
781
+ //! Epilogue for NVPs for XML output archives
782
+ /*! NVPs do not start or finish nodes - they just set up the names */
783
+ template <class T> inline
784
+ void epilogue( XMLOutputArchive &, NameValuePair<T> const & )
785
+ { }
786
+
787
+ //! Epilogue for NVPs for XML input archives
788
+ template <class T> inline
789
+ void epilogue( XMLInputArchive &, NameValuePair<T> const & )
790
+ { }
791
+
792
+ // ######################################################################
793
+ //! Prologue for deferred data for XML archives
794
+ /*! Do nothing for the defer wrapper */
795
+ template <class T> inline
796
+ void prologue( XMLOutputArchive &, DeferredData<T> const & )
797
+ { }
798
+
799
+ //! Prologue for deferred data for XML archives
800
+ template <class T> inline
801
+ void prologue( XMLInputArchive &, DeferredData<T> const & )
802
+ { }
803
+
804
+ // ######################################################################
805
+ //! Epilogue for deferred for XML archives
806
+ /*! NVPs do not start or finish nodes - they just set up the names */
807
+ template <class T> inline
808
+ void epilogue( XMLOutputArchive &, DeferredData<T> const & )
809
+ { }
810
+
811
+ //! Epilogue for deferred for XML archives
812
+ /*! Do nothing for the defer wrapper */
813
+ template <class T> inline
814
+ void epilogue( XMLInputArchive &, DeferredData<T> const & )
815
+ { }
816
+
817
+ // ######################################################################
818
+ //! Prologue for SizeTags for XML output archives
819
+ /*! SizeTags do not start or finish nodes */
820
+ template <class T> inline
821
+ void prologue( XMLOutputArchive & ar, SizeTag<T> const & )
822
+ {
823
+ if (ar.hasSizeAttributes())
824
+ {
825
+ ar.appendAttribute("size", "dynamic");
826
+ }
827
+ }
828
+
829
+ template <class T> inline
830
+ void prologue( XMLInputArchive &, SizeTag<T> const & )
831
+ { }
832
+
833
+ //! Epilogue for SizeTags for XML output archives
834
+ /*! SizeTags do not start or finish nodes */
835
+ template <class T> inline
836
+ void epilogue( XMLOutputArchive &, SizeTag<T> const & )
837
+ { }
838
+
839
+ template <class T> inline
840
+ void epilogue( XMLInputArchive &, SizeTag<T> const & )
841
+ { }
842
+
843
+ // ######################################################################
844
+ //! Prologue for all other types for XML output archives (except minimal types)
845
+ /*! Starts a new node, named either automatically or by some NVP,
846
+ that may be given data by the type about to be archived
847
+
848
+ Minimal types do not start or end nodes */
849
+ template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, XMLOutputArchive>::value ||
850
+ traits::has_minimal_output_serialization<T, XMLOutputArchive>::value> = traits::sfinae> inline
851
+ void prologue( XMLOutputArchive & ar, T const & )
852
+ {
853
+ ar.startNode();
854
+ ar.insertType<T>();
855
+ }
856
+
857
+ //! Prologue for all other types for XML input archives (except minimal types)
858
+ template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, XMLInputArchive>::value ||
859
+ traits::has_minimal_input_serialization<T, XMLInputArchive>::value> = traits::sfinae> inline
860
+ void prologue( XMLInputArchive & ar, T const & )
861
+ {
862
+ ar.startNode();
863
+ }
864
+
865
+ // ######################################################################
866
+ //! Epilogue for all other types other for XML output archives (except minimal types)
867
+ /*! Finishes the node created in the prologue
868
+
869
+ Minimal types do not start or end nodes */
870
+ template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, XMLOutputArchive>::value ||
871
+ traits::has_minimal_output_serialization<T, XMLOutputArchive>::value> = traits::sfinae> inline
872
+ void epilogue( XMLOutputArchive & ar, T const & )
873
+ {
874
+ ar.finishNode();
875
+ }
876
+
877
+ //! Epilogue for all other types other for XML output archives (except minimal types)
878
+ template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, XMLInputArchive>::value ||
879
+ traits::has_minimal_input_serialization<T, XMLInputArchive>::value> = traits::sfinae> inline
880
+ void epilogue( XMLInputArchive & ar, T const & )
881
+ {
882
+ ar.finishNode();
883
+ }
884
+
885
+ // ######################################################################
886
+ // Common XMLArchive serialization functions
887
+ // ######################################################################
888
+
889
+ //! Saving NVP types to XML
890
+ template <class T> inline
891
+ void CEREAL_SAVE_FUNCTION_NAME( XMLOutputArchive & ar, NameValuePair<T> const & t )
892
+ {
893
+ ar.setNextName( t.name );
894
+ ar( t.value );
895
+ }
896
+
897
+ //! Loading NVP types from XML
898
+ template <class T> inline
899
+ void CEREAL_LOAD_FUNCTION_NAME( XMLInputArchive & ar, NameValuePair<T> & t )
900
+ {
901
+ ar.setNextName( t.name );
902
+ ar( t.value );
903
+ }
904
+
905
+ // ######################################################################
906
+ //! Saving SizeTags to XML
907
+ template <class T> inline
908
+ void CEREAL_SAVE_FUNCTION_NAME( XMLOutputArchive &, SizeTag<T> const & )
909
+ { }
910
+
911
+ //! Loading SizeTags from XML
912
+ template <class T> inline
913
+ void CEREAL_LOAD_FUNCTION_NAME( XMLInputArchive & ar, SizeTag<T> & st )
914
+ {
915
+ ar.loadSize( st.size );
916
+ }
917
+
918
+ // ######################################################################
919
+ //! Saving for POD types to xml
920
+ template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
921
+ void CEREAL_SAVE_FUNCTION_NAME(XMLOutputArchive & ar, T const & t)
922
+ {
923
+ ar.saveValue( t );
924
+ }
925
+
926
+ //! Loading for POD types from xml
927
+ template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
928
+ void CEREAL_LOAD_FUNCTION_NAME(XMLInputArchive & ar, T & t)
929
+ {
930
+ ar.loadValue( t );
931
+ }
932
+
933
+ // ######################################################################
934
+ //! saving string to xml
935
+ template<class CharT, class Traits, class Alloc> inline
936
+ void CEREAL_SAVE_FUNCTION_NAME(XMLOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
937
+ {
938
+ ar.saveValue( str );
939
+ }
940
+
941
+ //! loading string from xml
942
+ template<class CharT, class Traits, class Alloc> inline
943
+ void CEREAL_LOAD_FUNCTION_NAME(XMLInputArchive & ar, std::basic_string<CharT, Traits, Alloc> & str)
944
+ {
945
+ ar.loadValue( str );
946
+ }
947
+ } // namespace cereal
948
+
949
+ // register archives for polymorphic support
950
+ CEREAL_REGISTER_ARCHIVE(cereal::XMLOutputArchive)
951
+ CEREAL_REGISTER_ARCHIVE(cereal::XMLInputArchive)
952
+
953
+ // tie input and output archives together
954
+ CEREAL_SETUP_ARCHIVE_TRAITS(cereal::XMLInputArchive, cereal::XMLOutputArchive)
955
+
956
+ #endif // CEREAL_ARCHIVES_XML_HPP_