isotree 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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_