isotree 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -1
  3. data/LICENSE.txt +2 -2
  4. data/README.md +32 -14
  5. data/ext/isotree/ext.cpp +144 -31
  6. data/ext/isotree/extconf.rb +7 -7
  7. data/lib/isotree/isolation_forest.rb +110 -30
  8. data/lib/isotree/version.rb +1 -1
  9. data/vendor/isotree/LICENSE +1 -1
  10. data/vendor/isotree/README.md +165 -27
  11. data/vendor/isotree/include/isotree.hpp +2111 -0
  12. data/vendor/isotree/include/isotree_oop.hpp +394 -0
  13. data/vendor/isotree/inst/COPYRIGHTS +62 -0
  14. data/vendor/isotree/src/RcppExports.cpp +525 -52
  15. data/vendor/isotree/src/Rwrapper.cpp +1931 -268
  16. data/vendor/isotree/src/c_interface.cpp +953 -0
  17. data/vendor/isotree/src/crit.hpp +4232 -0
  18. data/vendor/isotree/src/dist.hpp +1886 -0
  19. data/vendor/isotree/src/exp_depth_table.hpp +134 -0
  20. data/vendor/isotree/src/extended.hpp +1444 -0
  21. data/vendor/isotree/src/external_facing_generic.hpp +399 -0
  22. data/vendor/isotree/src/fit_model.hpp +2401 -0
  23. data/vendor/isotree/src/{dealloc.cpp → headers_joined.hpp} +38 -22
  24. data/vendor/isotree/src/helpers_iforest.hpp +813 -0
  25. data/vendor/isotree/src/{impute.cpp → impute.hpp} +353 -122
  26. data/vendor/isotree/src/indexer.cpp +515 -0
  27. data/vendor/isotree/src/instantiate_template_headers.cpp +118 -0
  28. data/vendor/isotree/src/instantiate_template_headers.hpp +240 -0
  29. data/vendor/isotree/src/isoforest.hpp +1659 -0
  30. data/vendor/isotree/src/isotree.hpp +1804 -392
  31. data/vendor/isotree/src/isotree_exportable.hpp +99 -0
  32. data/vendor/isotree/src/merge_models.cpp +159 -16
  33. data/vendor/isotree/src/mult.hpp +1321 -0
  34. data/vendor/isotree/src/oop_interface.cpp +842 -0
  35. data/vendor/isotree/src/oop_interface.hpp +278 -0
  36. data/vendor/isotree/src/other_helpers.hpp +219 -0
  37. data/vendor/isotree/src/predict.hpp +1932 -0
  38. data/vendor/isotree/src/python_helpers.hpp +134 -0
  39. data/vendor/isotree/src/ref_indexer.hpp +154 -0
  40. data/vendor/isotree/src/robinmap/LICENSE +21 -0
  41. data/vendor/isotree/src/robinmap/README.md +483 -0
  42. data/vendor/isotree/src/robinmap/include/tsl/robin_growth_policy.h +406 -0
  43. data/vendor/isotree/src/robinmap/include/tsl/robin_hash.h +1620 -0
  44. data/vendor/isotree/src/robinmap/include/tsl/robin_map.h +807 -0
  45. data/vendor/isotree/src/robinmap/include/tsl/robin_set.h +660 -0
  46. data/vendor/isotree/src/serialize.cpp +4300 -139
  47. data/vendor/isotree/src/sql.cpp +141 -59
  48. data/vendor/isotree/src/subset_models.cpp +174 -0
  49. data/vendor/isotree/src/utils.hpp +3808 -0
  50. data/vendor/isotree/src/xoshiro.hpp +467 -0
  51. data/vendor/isotree/src/ziggurat.hpp +405 -0
  52. metadata +38 -104
  53. data/vendor/cereal/LICENSE +0 -24
  54. data/vendor/cereal/README.md +0 -85
  55. data/vendor/cereal/include/cereal/access.hpp +0 -351
  56. data/vendor/cereal/include/cereal/archives/adapters.hpp +0 -163
  57. data/vendor/cereal/include/cereal/archives/binary.hpp +0 -169
  58. data/vendor/cereal/include/cereal/archives/json.hpp +0 -1019
  59. data/vendor/cereal/include/cereal/archives/portable_binary.hpp +0 -334
  60. data/vendor/cereal/include/cereal/archives/xml.hpp +0 -956
  61. data/vendor/cereal/include/cereal/cereal.hpp +0 -1089
  62. data/vendor/cereal/include/cereal/details/helpers.hpp +0 -422
  63. data/vendor/cereal/include/cereal/details/polymorphic_impl.hpp +0 -796
  64. data/vendor/cereal/include/cereal/details/polymorphic_impl_fwd.hpp +0 -65
  65. data/vendor/cereal/include/cereal/details/static_object.hpp +0 -127
  66. data/vendor/cereal/include/cereal/details/traits.hpp +0 -1411
  67. data/vendor/cereal/include/cereal/details/util.hpp +0 -84
  68. data/vendor/cereal/include/cereal/external/base64.hpp +0 -134
  69. data/vendor/cereal/include/cereal/external/rapidjson/allocators.h +0 -284
  70. data/vendor/cereal/include/cereal/external/rapidjson/cursorstreamwrapper.h +0 -78
  71. data/vendor/cereal/include/cereal/external/rapidjson/document.h +0 -2652
  72. data/vendor/cereal/include/cereal/external/rapidjson/encodedstream.h +0 -299
  73. data/vendor/cereal/include/cereal/external/rapidjson/encodings.h +0 -716
  74. data/vendor/cereal/include/cereal/external/rapidjson/error/en.h +0 -74
  75. data/vendor/cereal/include/cereal/external/rapidjson/error/error.h +0 -161
  76. data/vendor/cereal/include/cereal/external/rapidjson/filereadstream.h +0 -99
  77. data/vendor/cereal/include/cereal/external/rapidjson/filewritestream.h +0 -104
  78. data/vendor/cereal/include/cereal/external/rapidjson/fwd.h +0 -151
  79. data/vendor/cereal/include/cereal/external/rapidjson/internal/biginteger.h +0 -290
  80. data/vendor/cereal/include/cereal/external/rapidjson/internal/diyfp.h +0 -271
  81. data/vendor/cereal/include/cereal/external/rapidjson/internal/dtoa.h +0 -245
  82. data/vendor/cereal/include/cereal/external/rapidjson/internal/ieee754.h +0 -78
  83. data/vendor/cereal/include/cereal/external/rapidjson/internal/itoa.h +0 -308
  84. data/vendor/cereal/include/cereal/external/rapidjson/internal/meta.h +0 -186
  85. data/vendor/cereal/include/cereal/external/rapidjson/internal/pow10.h +0 -55
  86. data/vendor/cereal/include/cereal/external/rapidjson/internal/regex.h +0 -740
  87. data/vendor/cereal/include/cereal/external/rapidjson/internal/stack.h +0 -232
  88. data/vendor/cereal/include/cereal/external/rapidjson/internal/strfunc.h +0 -69
  89. data/vendor/cereal/include/cereal/external/rapidjson/internal/strtod.h +0 -290
  90. data/vendor/cereal/include/cereal/external/rapidjson/internal/swap.h +0 -46
  91. data/vendor/cereal/include/cereal/external/rapidjson/istreamwrapper.h +0 -128
  92. data/vendor/cereal/include/cereal/external/rapidjson/memorybuffer.h +0 -70
  93. data/vendor/cereal/include/cereal/external/rapidjson/memorystream.h +0 -71
  94. data/vendor/cereal/include/cereal/external/rapidjson/msinttypes/inttypes.h +0 -316
  95. data/vendor/cereal/include/cereal/external/rapidjson/msinttypes/stdint.h +0 -300
  96. data/vendor/cereal/include/cereal/external/rapidjson/ostreamwrapper.h +0 -81
  97. data/vendor/cereal/include/cereal/external/rapidjson/pointer.h +0 -1414
  98. data/vendor/cereal/include/cereal/external/rapidjson/prettywriter.h +0 -277
  99. data/vendor/cereal/include/cereal/external/rapidjson/rapidjson.h +0 -656
  100. data/vendor/cereal/include/cereal/external/rapidjson/reader.h +0 -2230
  101. data/vendor/cereal/include/cereal/external/rapidjson/schema.h +0 -2497
  102. data/vendor/cereal/include/cereal/external/rapidjson/stream.h +0 -223
  103. data/vendor/cereal/include/cereal/external/rapidjson/stringbuffer.h +0 -121
  104. data/vendor/cereal/include/cereal/external/rapidjson/writer.h +0 -709
  105. data/vendor/cereal/include/cereal/external/rapidxml/license.txt +0 -52
  106. data/vendor/cereal/include/cereal/external/rapidxml/manual.html +0 -406
  107. data/vendor/cereal/include/cereal/external/rapidxml/rapidxml.hpp +0 -2624
  108. data/vendor/cereal/include/cereal/external/rapidxml/rapidxml_iterators.hpp +0 -175
  109. data/vendor/cereal/include/cereal/external/rapidxml/rapidxml_print.hpp +0 -428
  110. data/vendor/cereal/include/cereal/external/rapidxml/rapidxml_utils.hpp +0 -123
  111. data/vendor/cereal/include/cereal/macros.hpp +0 -154
  112. data/vendor/cereal/include/cereal/specialize.hpp +0 -139
  113. data/vendor/cereal/include/cereal/types/array.hpp +0 -79
  114. data/vendor/cereal/include/cereal/types/atomic.hpp +0 -55
  115. data/vendor/cereal/include/cereal/types/base_class.hpp +0 -203
  116. data/vendor/cereal/include/cereal/types/bitset.hpp +0 -176
  117. data/vendor/cereal/include/cereal/types/boost_variant.hpp +0 -164
  118. data/vendor/cereal/include/cereal/types/chrono.hpp +0 -72
  119. data/vendor/cereal/include/cereal/types/common.hpp +0 -129
  120. data/vendor/cereal/include/cereal/types/complex.hpp +0 -56
  121. data/vendor/cereal/include/cereal/types/concepts/pair_associative_container.hpp +0 -73
  122. data/vendor/cereal/include/cereal/types/deque.hpp +0 -62
  123. data/vendor/cereal/include/cereal/types/forward_list.hpp +0 -68
  124. data/vendor/cereal/include/cereal/types/functional.hpp +0 -43
  125. data/vendor/cereal/include/cereal/types/list.hpp +0 -62
  126. data/vendor/cereal/include/cereal/types/map.hpp +0 -36
  127. data/vendor/cereal/include/cereal/types/memory.hpp +0 -425
  128. data/vendor/cereal/include/cereal/types/optional.hpp +0 -66
  129. data/vendor/cereal/include/cereal/types/polymorphic.hpp +0 -483
  130. data/vendor/cereal/include/cereal/types/queue.hpp +0 -132
  131. data/vendor/cereal/include/cereal/types/set.hpp +0 -103
  132. data/vendor/cereal/include/cereal/types/stack.hpp +0 -76
  133. data/vendor/cereal/include/cereal/types/string.hpp +0 -61
  134. data/vendor/cereal/include/cereal/types/tuple.hpp +0 -123
  135. data/vendor/cereal/include/cereal/types/unordered_map.hpp +0 -36
  136. data/vendor/cereal/include/cereal/types/unordered_set.hpp +0 -99
  137. data/vendor/cereal/include/cereal/types/utility.hpp +0 -47
  138. data/vendor/cereal/include/cereal/types/valarray.hpp +0 -89
  139. data/vendor/cereal/include/cereal/types/variant.hpp +0 -109
  140. data/vendor/cereal/include/cereal/types/vector.hpp +0 -112
  141. data/vendor/cereal/include/cereal/version.hpp +0 -52
  142. data/vendor/isotree/src/Makevars +0 -4
  143. data/vendor/isotree/src/crit.cpp +0 -912
  144. data/vendor/isotree/src/dist.cpp +0 -749
  145. data/vendor/isotree/src/extended.cpp +0 -790
  146. data/vendor/isotree/src/fit_model.cpp +0 -1090
  147. data/vendor/isotree/src/helpers_iforest.cpp +0 -324
  148. data/vendor/isotree/src/isoforest.cpp +0 -771
  149. data/vendor/isotree/src/mult.cpp +0 -607
  150. data/vendor/isotree/src/predict.cpp +0 -853
  151. data/vendor/isotree/src/utils.cpp +0 -1566
@@ -1,796 +0,0 @@
1
- /*! \file polymorphic_impl.hpp
2
- \brief Internal polymorphism support
3
- \ingroup Internal */
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 cereal 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 RANDOLPH VOORHIES OR SHANE GRANT 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
-
31
- /* This code is heavily inspired by the boost serialization implementation by the following authors
32
-
33
- (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
34
- Use, modification and distribution is subject to the Boost Software
35
- License, Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt)
36
-
37
- See http://www.boost.org for updates, documentation, and revision history.
38
-
39
- (C) Copyright 2006 David Abrahams - http://www.boost.org.
40
-
41
- See /boost/serialization/export.hpp, /boost/archive/detail/register_archive.hpp,
42
- and /boost/serialization/void_cast.hpp for their implementation. Additional details
43
- found in other files split across serialization and archive.
44
- */
45
- #ifndef CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_
46
- #define CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_
47
-
48
- #include "cereal/details/polymorphic_impl_fwd.hpp"
49
- #include "cereal/details/static_object.hpp"
50
- #include "cereal/types/memory.hpp"
51
- #include "cereal/types/string.hpp"
52
- #include <functional>
53
- #include <typeindex>
54
- #include <map>
55
- #include <limits>
56
- #include <set>
57
- #include <stack>
58
-
59
- //! Helper macro to omit unused warning
60
- #if defined(__GNUC__)
61
- // GCC / clang don't want the function
62
- #define CEREAL_BIND_TO_ARCHIVES_UNUSED_FUNCTION
63
- #else
64
- #define CEREAL_BIND_TO_ARCHIVES_UNUSED_FUNCTION static void unused() { (void)b; }
65
- #endif
66
-
67
- //! Binds a polymorhic type to all registered archives
68
- /*! This binds a polymorphic type to all compatible registered archives that
69
- have been registered with CEREAL_REGISTER_ARCHIVE. This must be called
70
- after all archives are registered (usually after the archives themselves
71
- have been included). */
72
- #define CEREAL_BIND_TO_ARCHIVES(...) \
73
- namespace cereal { \
74
- namespace detail { \
75
- template<> \
76
- struct init_binding<__VA_ARGS__> { \
77
- static bind_to_archives<__VA_ARGS__> const & b; \
78
- CEREAL_BIND_TO_ARCHIVES_UNUSED_FUNCTION \
79
- }; \
80
- bind_to_archives<__VA_ARGS__> const & init_binding<__VA_ARGS__>::b = \
81
- ::cereal::detail::StaticObject< \
82
- bind_to_archives<__VA_ARGS__> \
83
- >::getInstance().bind(); \
84
- }} /* end namespaces */
85
-
86
- namespace cereal
87
- {
88
- /* Polymorphic casting support */
89
- namespace detail
90
- {
91
- //! Base type for polymorphic void casting
92
- /*! Contains functions for casting between registered base and derived types.
93
-
94
- This is necessary so that cereal can properly cast between polymorphic types
95
- even though void pointers are used, which normally have no type information.
96
- Runtime type information is used instead to index a compile-time made mapping
97
- that can perform the proper cast. In the case of multiple levels of inheritance,
98
- cereal will attempt to find the shortest path by using registered relationships to
99
- perform the cast.
100
-
101
- This class will be allocated as a StaticObject and only referenced by pointer,
102
- allowing a templated derived version of it to define strongly typed functions
103
- that cast between registered base and derived types. */
104
- struct PolymorphicCaster
105
- {
106
- PolymorphicCaster() = default;
107
- PolymorphicCaster( const PolymorphicCaster & ) = default;
108
- PolymorphicCaster & operator=( const PolymorphicCaster & ) = default;
109
- PolymorphicCaster( PolymorphicCaster && ) CEREAL_NOEXCEPT {}
110
- PolymorphicCaster & operator=( PolymorphicCaster && ) CEREAL_NOEXCEPT { return *this; }
111
- virtual ~PolymorphicCaster() CEREAL_NOEXCEPT = default;
112
-
113
- //! Downcasts to the proper derived type
114
- virtual void const * downcast( void const * const ptr ) const = 0;
115
- //! Upcast to proper base type
116
- virtual void * upcast( void * const ptr ) const = 0;
117
- //! Upcast to proper base type, shared_ptr version
118
- virtual std::shared_ptr<void> upcast( std::shared_ptr<void> const & ptr ) const = 0;
119
- };
120
-
121
- //! Holds registered mappings between base and derived types for casting
122
- /*! This will be allocated as a StaticObject and holds a map containing
123
- all registered mappings between base and derived types. */
124
- struct PolymorphicCasters
125
- {
126
- //! Maps from a derived type index to a set of chainable casters
127
- using DerivedCasterMap = std::unordered_map<std::type_index, std::vector<PolymorphicCaster const *>>;
128
- //! Maps from base type index to a map from derived type index to caster
129
- std::unordered_map<std::type_index, DerivedCasterMap> map;
130
-
131
- std::multimap<std::type_index, std::type_index> reverseMap;
132
-
133
- //! Error message used for unregistered polymorphic casts
134
- #define UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(LoadSave) \
135
- throw cereal::Exception("Trying to " #LoadSave " a registered polymorphic type with an unregistered polymorphic cast.\n" \
136
- "Could not find a path to a base class (" + util::demangle(baseInfo.name()) + ") for type: " + ::cereal::util::demangledName<Derived>() + "\n" \
137
- "Make sure you either serialize the base class at some point via cereal::base_class or cereal::virtual_base_class.\n" \
138
- "Alternatively, manually register the association with CEREAL_REGISTER_POLYMORPHIC_RELATION.");
139
-
140
- //! Checks if the mapping object that can perform the upcast or downcast exists, and returns it if so
141
- /*! Uses the type index from the base and derived class to find the matching
142
- registered caster. If no matching caster exists, the bool in the pair will be false and the vector
143
- reference should not be used. */
144
- static std::pair<bool, std::vector<PolymorphicCaster const *> const &>
145
- lookup_if_exists( std::type_index const & baseIndex, std::type_index const & derivedIndex )
146
- {
147
- // First phase of lookup - match base type index
148
- auto const & baseMap = StaticObject<PolymorphicCasters>::getInstance().map;
149
- auto baseIter = baseMap.find( baseIndex );
150
- if (baseIter == baseMap.end())
151
- return {false, {}};
152
-
153
- // Second phase - find a match from base to derived
154
- auto const & derivedMap = baseIter->second;
155
- auto derivedIter = derivedMap.find( derivedIndex );
156
- if (derivedIter == derivedMap.end())
157
- return {false, {}};
158
-
159
- return {true, derivedIter->second};
160
- }
161
-
162
- //! Gets the mapping object that can perform the upcast or downcast
163
- /*! Uses the type index from the base and derived class to find the matching
164
- registered caster. If no matching caster exists, calls the exception function.
165
-
166
- The returned PolymorphicCaster is capable of upcasting or downcasting between the two types. */
167
- template <class F> inline
168
- static std::vector<PolymorphicCaster const *> const & lookup( std::type_index const & baseIndex, std::type_index const & derivedIndex, F && exceptionFunc )
169
- {
170
- // First phase of lookup - match base type index
171
- auto const & baseMap = StaticObject<PolymorphicCasters>::getInstance().map;
172
- auto baseIter = baseMap.find( baseIndex );
173
- if( baseIter == baseMap.end() )
174
- exceptionFunc();
175
-
176
- // Second phase - find a match from base to derived
177
- auto const & derivedMap = baseIter->second;
178
- auto derivedIter = derivedMap.find( derivedIndex );
179
- if( derivedIter == derivedMap.end() )
180
- exceptionFunc();
181
-
182
- return derivedIter->second;
183
- }
184
-
185
- //! Performs a downcast to the derived type using a registered mapping
186
- template <class Derived> inline
187
- static const Derived * downcast( const void * dptr, std::type_info const & baseInfo )
188
- {
189
- auto const & mapping = lookup( baseInfo, typeid(Derived), [&](){ UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(save) } );
190
-
191
- for( auto const * dmap : mapping )
192
- dptr = dmap->downcast( dptr );
193
-
194
- return static_cast<Derived const *>( dptr );
195
- }
196
-
197
- //! Performs an upcast to the registered base type using the given a derived type
198
- /*! The return is untyped because the final casting to the base type must happen in the polymorphic
199
- serialization function, where the type is known at compile time */
200
- template <class Derived> inline
201
- static void * upcast( Derived * const dptr, std::type_info const & baseInfo )
202
- {
203
- auto const & mapping = lookup( baseInfo, typeid(Derived), [&](){ UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(load) } );
204
-
205
- void * uptr = dptr;
206
- for( auto mIter = mapping.rbegin(), mEnd = mapping.rend(); mIter != mEnd; ++mIter )
207
- uptr = (*mIter)->upcast( uptr );
208
-
209
- return uptr;
210
- }
211
-
212
- //! Upcasts for shared pointers
213
- template <class Derived> inline
214
- static std::shared_ptr<void> upcast( std::shared_ptr<Derived> const & dptr, std::type_info const & baseInfo )
215
- {
216
- auto const & mapping = lookup( baseInfo, typeid(Derived), [&](){ UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(load) } );
217
-
218
- std::shared_ptr<void> uptr = dptr;
219
- for( auto mIter = mapping.rbegin(), mEnd = mapping.rend(); mIter != mEnd; ++mIter )
220
- uptr = (*mIter)->upcast( uptr );
221
-
222
- return uptr;
223
- }
224
-
225
- #undef UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION
226
- };
227
-
228
- #ifdef CEREAL_OLDER_GCC
229
- #define CEREAL_EMPLACE_MAP(map, key, value) \
230
- map.insert( std::make_pair(std::move(key), std::move(value)) );
231
- #else // NOT CEREAL_OLDER_GCC
232
- #define CEREAL_EMPLACE_MAP(map, key, value) \
233
- map.emplace( key, value );
234
- #endif // NOT_CEREAL_OLDER_GCC
235
-
236
- //! Strongly typed derivation of PolymorphicCaster
237
- template <class Base, class Derived>
238
- struct PolymorphicVirtualCaster : PolymorphicCaster
239
- {
240
- //! Inserts an entry in the polymorphic casting map for this pairing
241
- /*! Creates an explicit mapping between Base and Derived in both upwards and
242
- downwards directions, allowing void pointers to either to be properly cast
243
- assuming dynamic type information is available */
244
- PolymorphicVirtualCaster()
245
- {
246
- const auto baseKey = std::type_index(typeid(Base));
247
- const auto derivedKey = std::type_index(typeid(Derived));
248
-
249
- // First insert the relation Base->Derived
250
- const auto lock = StaticObject<PolymorphicCasters>::lock();
251
- auto & baseMap = StaticObject<PolymorphicCasters>::getInstance().map;
252
-
253
- {
254
- auto & derivedMap = baseMap.insert( {baseKey, PolymorphicCasters::DerivedCasterMap{}} ).first->second;
255
- auto & derivedVec = derivedMap.insert( {derivedKey, {}} ).first->second;
256
- derivedVec.push_back( this );
257
- }
258
-
259
- // Insert reverse relation Derived->Base
260
- auto & reverseMap = StaticObject<PolymorphicCasters>::getInstance().reverseMap;
261
- CEREAL_EMPLACE_MAP(reverseMap, derivedKey, baseKey);
262
-
263
- // Find all chainable unregistered relations
264
- /* The strategy here is to process only the nodes in the class hierarchy graph that have been
265
- affected by the new insertion. The aglorithm iteratively processes a node an ensures that it
266
- is updated with all new shortest length paths. It then rocesses the parents of the active node,
267
- with the knowledge that all children have already been processed.
268
-
269
- Note that for the following, we'll use the nomenclature of parent and child to not confuse with
270
- the inserted base derived relationship */
271
- {
272
- // Checks whether there is a path from parent->child and returns a <dist, path> pair
273
- // dist is set to MAX if the path does not exist
274
- auto checkRelation = [](std::type_index const & parentInfo, std::type_index const & childInfo) ->
275
- std::pair<size_t, std::vector<PolymorphicCaster const *> const &>
276
- {
277
- auto result = PolymorphicCasters::lookup_if_exists( parentInfo, childInfo );
278
- if( result.first )
279
- {
280
- auto const & path = result.second;
281
- return {path.size(), path};
282
- }
283
- else
284
- return {(std::numeric_limits<size_t>::max)(), {}};
285
- };
286
-
287
- std::stack<std::type_index> parentStack; // Holds the parent nodes to be processed
288
- std::vector<std::type_index> dirtySet; // Marks child nodes that have been changed
289
- std::unordered_set<std::type_index> processedParents; // Marks parent nodes that have been processed
290
-
291
- // Checks if a child has been marked dirty
292
- auto isDirty = [&](std::type_index const & c)
293
- {
294
- auto const dirtySetSize = dirtySet.size();
295
- for( size_t i = 0; i < dirtySetSize; ++i )
296
- if( dirtySet[i] == c )
297
- return true;
298
-
299
- return false;
300
- };
301
-
302
- // Begin processing the base key and mark derived as dirty
303
- parentStack.push( baseKey );
304
- dirtySet.emplace_back( derivedKey );
305
-
306
- while( !parentStack.empty() )
307
- {
308
- using Relations = std::unordered_multimap<std::type_index, std::pair<std::type_index, std::vector<PolymorphicCaster const *>>>;
309
- Relations unregisteredRelations; // Defer insertions until after main loop to prevent iterator invalidation
310
-
311
- const auto parent = parentStack.top();
312
- parentStack.pop();
313
-
314
- // Update paths to all children marked dirty
315
- for( auto const & childPair : baseMap[parent] )
316
- {
317
- const auto child = childPair.first;
318
- if( isDirty( child ) && baseMap.count( child ) )
319
- {
320
- auto parentChildPath = checkRelation( parent, child );
321
-
322
- // Search all paths from the child to its own children (finalChild),
323
- // looking for a shorter parth from parent to finalChild
324
- for( auto const & finalChildPair : baseMap[child] )
325
- {
326
- const auto finalChild = finalChildPair.first;
327
-
328
- auto parentFinalChildPath = checkRelation( parent, finalChild );
329
- auto childFinalChildPath = checkRelation( child, finalChild );
330
-
331
- const size_t newLength = 1u + parentChildPath.first;
332
-
333
- if( newLength < parentFinalChildPath.first )
334
- {
335
- std::vector<PolymorphicCaster const *> path = parentChildPath.second;
336
- path.insert( path.end(), childFinalChildPath.second.begin(), childFinalChildPath.second.end() );
337
-
338
- // Check to see if we have a previous uncommitted path in unregisteredRelations
339
- // that is shorter. If so, ignore this path
340
- auto hintRange = unregisteredRelations.equal_range( parent );
341
- auto hint = hintRange.first;
342
- for( ; hint != hintRange.second; ++hint )
343
- if( hint->second.first == finalChild )
344
- break;
345
-
346
- const bool uncommittedExists = hint != unregisteredRelations.end();
347
- if( uncommittedExists && (hint->second.second.size() <= newLength) )
348
- continue;
349
-
350
- auto newPath = std::pair<std::type_index, std::vector<PolymorphicCaster const *>>{finalChild, std::move(path)};
351
-
352
- // Insert the new path if it doesn't exist, otherwise this will just lookup where to do the
353
- // replacement
354
- #ifdef CEREAL_OLDER_GCC
355
- auto old = unregisteredRelations.insert( hint, std::make_pair(parent, newPath) );
356
- #else // NOT CEREAL_OLDER_GCC
357
- auto old = unregisteredRelations.emplace_hint( hint, parent, newPath );
358
- #endif // NOT CEREAL_OLDER_GCC
359
-
360
- // If there was an uncommitted path, we need to perform a replacement
361
- if( uncommittedExists )
362
- old->second = newPath;
363
- }
364
- } // end loop over child's children
365
- } // end if dirty and child has children
366
- } // end loop over children
367
-
368
- // Insert chained relations
369
- for( auto const & it : unregisteredRelations )
370
- {
371
- auto & derivedMap = baseMap.find( it.first )->second;
372
- derivedMap[it.second.first] = it.second.second;
373
- CEREAL_EMPLACE_MAP(reverseMap, it.second.first, it.first );
374
- }
375
-
376
- // Mark current parent as modified
377
- dirtySet.emplace_back( parent );
378
-
379
- // Insert all parents of the current parent node that haven't yet been processed
380
- auto parentRange = reverseMap.equal_range( parent );
381
- for( auto pIter = parentRange.first; pIter != parentRange.second; ++pIter )
382
- {
383
- const auto pParent = pIter->second;
384
- if( !processedParents.count( pParent ) )
385
- {
386
- parentStack.push( pParent );
387
- processedParents.insert( pParent );
388
- }
389
- }
390
- } // end loop over parent stack
391
- } // end chainable relations
392
- } // end PolymorphicVirtualCaster()
393
-
394
- #undef CEREAL_EMPLACE_MAP
395
-
396
- //! Performs the proper downcast with the templated types
397
- void const * downcast( void const * const ptr ) const override
398
- {
399
- return dynamic_cast<Derived const*>( static_cast<Base const*>( ptr ) );
400
- }
401
-
402
- //! Performs the proper upcast with the templated types
403
- void * upcast( void * const ptr ) const override
404
- {
405
- return dynamic_cast<Base*>( static_cast<Derived*>( ptr ) );
406
- }
407
-
408
- //! Performs the proper upcast with the templated types (shared_ptr version)
409
- std::shared_ptr<void> upcast( std::shared_ptr<void> const & ptr ) const override
410
- {
411
- return std::dynamic_pointer_cast<Base>( std::static_pointer_cast<Derived>( ptr ) );
412
- }
413
- };
414
-
415
- //! Registers a polymorphic casting relation between a Base and Derived type
416
- /*! Registering a relation allows cereal to properly cast between the two types
417
- given runtime type information and void pointers.
418
-
419
- Registration happens automatically via cereal::base_class and cereal::virtual_base_class
420
- instantiations. For cases where neither is called, see the CEREAL_REGISTER_POLYMORPHIC_RELATION
421
- macro */
422
- template <class Base, class Derived>
423
- struct RegisterPolymorphicCaster
424
- {
425
- static PolymorphicCaster const * bind( std::true_type /* is_polymorphic<Base> */)
426
- {
427
- return &StaticObject<PolymorphicVirtualCaster<Base, Derived>>::getInstance();
428
- }
429
-
430
- static PolymorphicCaster const * bind( std::false_type /* is_polymorphic<Base> */ )
431
- { return nullptr; }
432
-
433
- //! Performs registration (binding) between Base and Derived
434
- /*! If the type is not polymorphic, nothing will happen */
435
- static PolymorphicCaster const * bind()
436
- { return bind( typename std::is_polymorphic<Base>::type() ); }
437
- };
438
- }
439
-
440
- /* General polymorphism support */
441
- namespace detail
442
- {
443
- //! Binds a compile time type with a user defined string
444
- template <class T>
445
- struct binding_name {};
446
-
447
- //! A structure holding a map from type_indices to output serializer functions
448
- /*! A static object of this map should be created for each registered archive
449
- type, containing entries for every registered type that describe how to
450
- properly cast the type to its real type in polymorphic scenarios for
451
- shared_ptr, weak_ptr, and unique_ptr. */
452
- template <class Archive>
453
- struct OutputBindingMap
454
- {
455
- //! A serializer function
456
- /*! Serializer functions return nothing and take an archive as
457
- their first parameter (will be cast properly inside the function,
458
- a pointer to actual data (contents of smart_ptr's get() function)
459
- as their second parameter, and the type info of the owning smart_ptr
460
- as their final parameter */
461
- typedef std::function<void(void*, void const *, std::type_info const &)> Serializer;
462
-
463
- //! Struct containing the serializer functions for all pointer types
464
- struct Serializers
465
- {
466
- Serializer shared_ptr, //!< Serializer function for shared/weak pointers
467
- unique_ptr; //!< Serializer function for unique pointers
468
- };
469
-
470
- //! A map of serializers for pointers of all registered types
471
- std::map<std::type_index, Serializers> map;
472
- };
473
-
474
- //! An empty noop deleter
475
- template<class T> struct EmptyDeleter { void operator()(T *) const {} };
476
-
477
- //! A structure holding a map from type name strings to input serializer functions
478
- /*! A static object of this map should be created for each registered archive
479
- type, containing entries for every registered type that describe how to
480
- properly cast the type to its real type in polymorphic scenarios for
481
- shared_ptr, weak_ptr, and unique_ptr. */
482
- template <class Archive>
483
- struct InputBindingMap
484
- {
485
- //! Shared ptr serializer function
486
- /*! Serializer functions return nothing and take an archive as
487
- their first parameter (will be cast properly inside the function,
488
- a shared_ptr (or unique_ptr for the unique case) of any base
489
- type, and the type id of said base type as the third parameter.
490
- Internally it will properly be loaded and cast to the correct type. */
491
- typedef std::function<void(void*, std::shared_ptr<void> &, std::type_info const &)> SharedSerializer;
492
- //! Unique ptr serializer function
493
- typedef std::function<void(void*, std::unique_ptr<void, EmptyDeleter<void>> &, std::type_info const &)> UniqueSerializer;
494
-
495
- //! Struct containing the serializer functions for all pointer types
496
- struct Serializers
497
- {
498
- SharedSerializer shared_ptr; //!< Serializer function for shared/weak pointers
499
- UniqueSerializer unique_ptr; //!< Serializer function for unique pointers
500
- };
501
-
502
- //! A map of serializers for pointers of all registered types
503
- std::map<std::string, Serializers> map;
504
- };
505
-
506
- // forward decls for archives from cereal.hpp
507
- class InputArchiveBase;
508
- class OutputArchiveBase;
509
-
510
- //! Creates a binding (map entry) between an input archive type and a polymorphic type
511
- /*! Bindings are made when types are registered, assuming that at least one
512
- archive has already been registered. When this struct is created,
513
- it will insert (at run time) an entry into a map that properly handles
514
- casting for serializing polymorphic objects */
515
- template <class Archive, class T> struct InputBindingCreator
516
- {
517
- //! Initialize the binding
518
- InputBindingCreator()
519
- {
520
- auto & map = StaticObject<InputBindingMap<Archive>>::getInstance().map;
521
- auto lock = StaticObject<InputBindingMap<Archive>>::lock();
522
- auto key = std::string(binding_name<T>::name());
523
- auto lb = map.lower_bound(key);
524
-
525
- if (lb != map.end() && lb->first == key)
526
- return;
527
-
528
- typename InputBindingMap<Archive>::Serializers serializers;
529
-
530
- serializers.shared_ptr =
531
- [](void * arptr, std::shared_ptr<void> & dptr, std::type_info const & baseInfo)
532
- {
533
- Archive & ar = *static_cast<Archive*>(arptr);
534
- std::shared_ptr<T> ptr;
535
-
536
- ar( CEREAL_NVP_("ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
537
-
538
- dptr = PolymorphicCasters::template upcast<T>( ptr, baseInfo );
539
- };
540
-
541
- serializers.unique_ptr =
542
- [](void * arptr, std::unique_ptr<void, EmptyDeleter<void>> & dptr, std::type_info const & baseInfo)
543
- {
544
- Archive & ar = *static_cast<Archive*>(arptr);
545
- std::unique_ptr<T> ptr;
546
-
547
- ar( CEREAL_NVP_("ptr_wrapper", ::cereal::memory_detail::make_ptr_wrapper(ptr)) );
548
-
549
- dptr.reset( PolymorphicCasters::template upcast<T>( ptr.release(), baseInfo ));
550
- };
551
-
552
- map.insert( lb, { std::move(key), std::move(serializers) } );
553
- }
554
- };
555
-
556
- //! Creates a binding (map entry) between an output archive type and a polymorphic type
557
- /*! Bindings are made when types are registered, assuming that at least one
558
- archive has already been registered. When this struct is created,
559
- it will insert (at run time) an entry into a map that properly handles
560
- casting for serializing polymorphic objects */
561
- template <class Archive, class T> struct OutputBindingCreator
562
- {
563
- //! Writes appropriate metadata to the archive for this polymorphic type
564
- static void writeMetadata(Archive & ar)
565
- {
566
- // Register the polymorphic type name with the archive, and get the id
567
- char const * name = binding_name<T>::name();
568
- std::uint32_t id = ar.registerPolymorphicType(name);
569
-
570
- // Serialize the id
571
- ar( CEREAL_NVP_("polymorphic_id", id) );
572
-
573
- // If the msb of the id is 1, then the type name is new, and we should serialize it
574
- if( id & detail::msb_32bit )
575
- {
576
- std::string namestring(name);
577
- ar( CEREAL_NVP_("polymorphic_name", namestring) );
578
- }
579
- }
580
-
581
- //! Holds a properly typed shared_ptr to the polymorphic type
582
- class PolymorphicSharedPointerWrapper
583
- {
584
- public:
585
- /*! Wrap a raw polymorphic pointer in a shared_ptr to its true type
586
-
587
- The wrapped pointer will not be responsible for ownership of the held pointer
588
- so it will not attempt to destroy it; instead the refcount of the wrapped
589
- pointer will be tied to a fake 'ownership pointer' that will do nothing
590
- when it ultimately goes out of scope.
591
-
592
- The main reason for doing this, other than not to destroy the true object
593
- with our wrapper pointer, is to avoid meddling with the internal reference
594
- count in a polymorphic type that inherits from std::enable_shared_from_this.
595
-
596
- @param dptr A void pointer to the contents of the shared_ptr to serialize */
597
- PolymorphicSharedPointerWrapper( T const * dptr ) : refCount(), wrappedPtr( refCount, dptr )
598
- { }
599
-
600
- //! Get the wrapped shared_ptr */
601
- inline std::shared_ptr<T const> const & operator()() const { return wrappedPtr; }
602
-
603
- private:
604
- std::shared_ptr<void> refCount; //!< The ownership pointer
605
- std::shared_ptr<T const> wrappedPtr; //!< The wrapped pointer
606
- };
607
-
608
- //! Does the actual work of saving a polymorphic shared_ptr
609
- /*! This function will properly create a shared_ptr from the void * that is passed in
610
- before passing it to the archive for serialization.
611
-
612
- In addition, this will also preserve the state of any internal enable_shared_from_this mechanisms
613
-
614
- @param ar The archive to serialize to
615
- @param dptr Pointer to the actual data held by the shared_ptr */
616
- static inline void savePolymorphicSharedPtr( Archive & ar, T const * dptr, std::true_type /* has_shared_from_this */ )
617
- {
618
- ::cereal::memory_detail::EnableSharedStateHelper<T> state( const_cast<T *>(dptr) );
619
- PolymorphicSharedPointerWrapper psptr( dptr );
620
- ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( psptr() ) ) );
621
- }
622
-
623
- //! Does the actual work of saving a polymorphic shared_ptr
624
- /*! This function will properly create a shared_ptr from the void * that is passed in
625
- before passing it to the archive for serialization.
626
-
627
- This version is for types that do not inherit from std::enable_shared_from_this.
628
-
629
- @param ar The archive to serialize to
630
- @param dptr Pointer to the actual data held by the shared_ptr */
631
- static inline void savePolymorphicSharedPtr( Archive & ar, T const * dptr, std::false_type /* has_shared_from_this */ )
632
- {
633
- PolymorphicSharedPointerWrapper psptr( dptr );
634
- ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( psptr() ) ) );
635
- }
636
-
637
- //! Initialize the binding
638
- OutputBindingCreator()
639
- {
640
- auto & map = StaticObject<OutputBindingMap<Archive>>::getInstance().map;
641
- auto key = std::type_index(typeid(T));
642
- auto lb = map.lower_bound(key);
643
-
644
- if (lb != map.end() && lb->first == key)
645
- return;
646
-
647
- typename OutputBindingMap<Archive>::Serializers serializers;
648
-
649
- serializers.shared_ptr =
650
- [&](void * arptr, void const * dptr, std::type_info const & baseInfo)
651
- {
652
- Archive & ar = *static_cast<Archive*>(arptr);
653
- writeMetadata(ar);
654
-
655
- auto ptr = PolymorphicCasters::template downcast<T>( dptr, baseInfo );
656
-
657
- #ifdef _MSC_VER
658
- savePolymorphicSharedPtr( ar, ptr, ::cereal::traits::has_shared_from_this<T>::type() ); // MSVC doesn't like typename here
659
- #else // not _MSC_VER
660
- savePolymorphicSharedPtr( ar, ptr, typename ::cereal::traits::has_shared_from_this<T>::type() );
661
- #endif // _MSC_VER
662
- };
663
-
664
- serializers.unique_ptr =
665
- [&](void * arptr, void const * dptr, std::type_info const & baseInfo)
666
- {
667
- Archive & ar = *static_cast<Archive*>(arptr);
668
- writeMetadata(ar);
669
-
670
- std::unique_ptr<T const, EmptyDeleter<T const>> const ptr( PolymorphicCasters::template downcast<T>( dptr, baseInfo ) );
671
-
672
- ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
673
- };
674
-
675
- map.insert( { std::move(key), std::move(serializers) } );
676
- }
677
- };
678
-
679
- //! Used to help out argument dependent lookup for finding potential overloads
680
- //! of instantiate_polymorphic_binding
681
- struct adl_tag {};
682
-
683
- //! Tag for init_binding, bind_to_archives and instantiate_polymorphic_binding. Due to the use of anonymous
684
- //! namespace it becomes a different type in each translation unit.
685
- namespace { struct polymorphic_binding_tag {}; }
686
-
687
- //! Causes the static object bindings between an archive type and a serializable type T
688
- template <class Archive, class T>
689
- struct create_bindings
690
- {
691
- static const InputBindingCreator<Archive, T> &
692
- load(std::true_type)
693
- {
694
- return cereal::detail::StaticObject<InputBindingCreator<Archive, T>>::getInstance();
695
- }
696
-
697
- static const OutputBindingCreator<Archive, T> &
698
- save(std::true_type)
699
- {
700
- return cereal::detail::StaticObject<OutputBindingCreator<Archive, T>>::getInstance();
701
- }
702
-
703
- inline static void load(std::false_type) {}
704
- inline static void save(std::false_type) {}
705
- };
706
-
707
- //! When specialized, causes the compiler to instantiate its parameter
708
- template <void(*)()>
709
- struct instantiate_function {};
710
-
711
- /*! This struct is used as the return type of instantiate_polymorphic_binding
712
- for specific Archive types. When the compiler looks for overloads of
713
- instantiate_polymorphic_binding, it will be forced to instantiate this
714
- struct during overload resolution, even though it will not be part of a valid
715
- overload */
716
- template <class Archive, class T>
717
- struct polymorphic_serialization_support
718
- {
719
- #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
720
- //! Creates the appropriate bindings depending on whether the archive supports
721
- //! saving or loading
722
- virtual CEREAL_DLL_EXPORT void instantiate() CEREAL_USED;
723
- #else // NOT _MSC_VER
724
- //! Creates the appropriate bindings depending on whether the archive supports
725
- //! saving or loading
726
- static CEREAL_DLL_EXPORT void instantiate() CEREAL_USED;
727
- //! This typedef causes the compiler to instantiate this static function
728
- typedef instantiate_function<instantiate> unused;
729
- #endif // _MSC_VER
730
- };
731
-
732
- // instantiate implementation
733
- template <class Archive, class T>
734
- CEREAL_DLL_EXPORT void polymorphic_serialization_support<Archive,T>::instantiate()
735
- {
736
- create_bindings<Archive,T>::save( std::integral_constant<bool,
737
- std::is_base_of<detail::OutputArchiveBase, Archive>::value &&
738
- traits::is_output_serializable<T, Archive>::value>{} );
739
-
740
- create_bindings<Archive,T>::load( std::integral_constant<bool,
741
- std::is_base_of<detail::InputArchiveBase, Archive>::value &&
742
- traits::is_input_serializable<T, Archive>::value>{} );
743
- }
744
-
745
- //! Begins the binding process of a type to all registered archives
746
- /*! Archives need to be registered prior to this struct being instantiated via
747
- the CEREAL_REGISTER_ARCHIVE macro. Overload resolution will then force
748
- several static objects to be made that allow us to bind together all
749
- registered archive types with the parameter type T. */
750
- template <class T, class Tag = polymorphic_binding_tag>
751
- struct bind_to_archives
752
- {
753
- //! Binding for non abstract types
754
- void bind(std::false_type) const
755
- {
756
- instantiate_polymorphic_binding(static_cast<T*>(nullptr), 0, Tag{}, adl_tag{});
757
- }
758
-
759
- //! Binding for abstract types
760
- void bind(std::true_type) const
761
- { }
762
-
763
- //! Binds the type T to all registered archives
764
- /*! If T is abstract, we will not serialize it and thus
765
- do not need to make a binding */
766
- bind_to_archives const & bind() const
767
- {
768
- static_assert( std::is_polymorphic<T>::value,
769
- "Attempting to register non polymorphic type" );
770
- bind( std::is_abstract<T>() );
771
- return *this;
772
- }
773
- };
774
-
775
- //! Used to hide the static object used to bind T to registered archives
776
- template <class T, class Tag = polymorphic_binding_tag>
777
- struct init_binding;
778
-
779
- //! Base case overload for instantiation
780
- /*! This will end up always being the best overload due to the second
781
- parameter always being passed as an int. All other overloads will
782
- accept pointers to archive types and have lower precedence than int.
783
-
784
- Since the compiler needs to check all possible overloads, the
785
- other overloads created via CEREAL_REGISTER_ARCHIVE, which will have
786
- lower precedence due to requring a conversion from int to (Archive*),
787
- will cause their return types to be instantiated through the static object
788
- mechanisms even though they are never called.
789
-
790
- See the documentation for the other functions to try and understand this */
791
- template <class T, typename BindingTag>
792
- void instantiate_polymorphic_binding( T*, int, BindingTag, adl_tag ) {}
793
- } // namespace detail
794
- } // namespace cereal
795
-
796
- #endif // CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_