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
@@ -0,0 +1,406 @@
1
+ /**
2
+ * MIT License
3
+ *
4
+ * Copyright (c) 2017 Thibaut Goetghebuer-Planchon <tessil@gmx.com>
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in
14
+ * all copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+ #ifndef TSL_ROBIN_GROWTH_POLICY_H
25
+ #define TSL_ROBIN_GROWTH_POLICY_H
26
+
27
+ #include <algorithm>
28
+ #include <array>
29
+ #include <climits>
30
+ #include <cmath>
31
+ #include <cstddef>
32
+ #include <cstdint>
33
+ #include <iterator>
34
+ #include <limits>
35
+ #include <ratio>
36
+ #include <stdexcept>
37
+
38
+ #ifdef TSL_DEBUG
39
+ #define tsl_rh_assert(expr) assert(expr)
40
+ #else
41
+ #define tsl_rh_assert(expr) (static_cast<void>(0))
42
+ #endif
43
+
44
+ /**
45
+ * If exceptions are enabled, throw the exception passed in parameter, otherwise
46
+ * call std::terminate.
47
+ */
48
+ #if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || \
49
+ (defined(_MSC_VER) && defined(_CPPUNWIND))) && \
50
+ !defined(TSL_NO_EXCEPTIONS)
51
+ #define TSL_RH_THROW_OR_TERMINATE(ex, msg) throw ex(msg)
52
+ #else
53
+ #define TSL_RH_NO_EXCEPTIONS
54
+ #ifdef TSL_DEBUG
55
+ #include <iostream>
56
+ #define TSL_RH_THROW_OR_TERMINATE(ex, msg) \
57
+ do { \
58
+ std::cerr << msg << std::endl; \
59
+ std::terminate(); \
60
+ } while (0)
61
+ #else
62
+ #define TSL_RH_THROW_OR_TERMINATE(ex, msg) std::terminate()
63
+ #endif
64
+ #endif
65
+
66
+ #if defined(__GNUC__) || defined(__clang__)
67
+ #define TSL_RH_LIKELY(exp) (__builtin_expect(!!(exp), true))
68
+ #else
69
+ #define TSL_RH_LIKELY(exp) (exp)
70
+ #endif
71
+
72
+ #define TSL_RH_UNUSED(x) static_cast<void>(x)
73
+
74
+ namespace tsl {
75
+ namespace rh {
76
+
77
+ /**
78
+ * Grow the hash table by a factor of GrowthFactor keeping the bucket count to a
79
+ * power of two. It allows the table to use a mask operation instead of a modulo
80
+ * operation to map a hash to a bucket.
81
+ *
82
+ * GrowthFactor must be a power of two >= 2.
83
+ */
84
+ template <std::size_t GrowthFactor>
85
+ class power_of_two_growth_policy {
86
+ public:
87
+ /**
88
+ * Called on the hash table creation and on rehash. The number of buckets for
89
+ * the table is passed in parameter. This number is a minimum, the policy may
90
+ * update this value with a higher value if needed (but not lower).
91
+ *
92
+ * If 0 is given, min_bucket_count_in_out must still be 0 after the policy
93
+ * creation and bucket_for_hash must always return 0 in this case.
94
+ */
95
+ explicit power_of_two_growth_policy(std::size_t& min_bucket_count_in_out) {
96
+ if (min_bucket_count_in_out > max_bucket_count()) {
97
+ TSL_RH_THROW_OR_TERMINATE(std::length_error,
98
+ "The hash table exceeds its maximum size.");
99
+ }
100
+
101
+ if (min_bucket_count_in_out > 0) {
102
+ min_bucket_count_in_out =
103
+ round_up_to_power_of_two(min_bucket_count_in_out);
104
+ m_mask = min_bucket_count_in_out - 1;
105
+ } else {
106
+ m_mask = 0;
107
+ }
108
+ }
109
+
110
+ /**
111
+ * Return the bucket [0, bucket_count()) to which the hash belongs.
112
+ * If bucket_count() is 0, it must always return 0.
113
+ */
114
+ std::size_t bucket_for_hash(std::size_t hash) const noexcept {
115
+ return hash & m_mask;
116
+ }
117
+
118
+ /**
119
+ * Return the number of buckets that should be used on next growth.
120
+ */
121
+ std::size_t next_bucket_count() const {
122
+ if ((m_mask + 1) > max_bucket_count() / GrowthFactor) {
123
+ TSL_RH_THROW_OR_TERMINATE(std::length_error,
124
+ "The hash table exceeds its maximum size.");
125
+ }
126
+
127
+ return (m_mask + 1) * GrowthFactor;
128
+ }
129
+
130
+ /**
131
+ * Return the maximum number of buckets supported by the policy.
132
+ */
133
+ std::size_t max_bucket_count() const {
134
+ // Largest power of two.
135
+ return (std::numeric_limits<std::size_t>::max() / 2) + 1;
136
+ }
137
+
138
+ /**
139
+ * Reset the growth policy as if it was created with a bucket count of 0.
140
+ * After a clear, the policy must always return 0 when bucket_for_hash is
141
+ * called.
142
+ */
143
+ void clear() noexcept { m_mask = 0; }
144
+
145
+ private:
146
+ static std::size_t round_up_to_power_of_two(std::size_t value) {
147
+ if (is_power_of_two(value)) {
148
+ return value;
149
+ }
150
+
151
+ if (value == 0) {
152
+ return 1;
153
+ }
154
+
155
+ --value;
156
+ for (std::size_t i = 1; i < sizeof(std::size_t) * CHAR_BIT; i *= 2) {
157
+ value |= value >> i;
158
+ }
159
+
160
+ return value + 1;
161
+ }
162
+
163
+ static constexpr bool is_power_of_two(std::size_t value) {
164
+ return value != 0 && (value & (value - 1)) == 0;
165
+ }
166
+
167
+ protected:
168
+ static_assert(is_power_of_two(GrowthFactor) && GrowthFactor >= 2,
169
+ "GrowthFactor must be a power of two >= 2.");
170
+
171
+ std::size_t m_mask;
172
+ };
173
+
174
+ /**
175
+ * Grow the hash table by GrowthFactor::num / GrowthFactor::den and use a modulo
176
+ * to map a hash to a bucket. Slower but it can be useful if you want a slower
177
+ * growth.
178
+ */
179
+ template <class GrowthFactor = std::ratio<3, 2>>
180
+ class mod_growth_policy {
181
+ public:
182
+ explicit mod_growth_policy(std::size_t& min_bucket_count_in_out) {
183
+ if (min_bucket_count_in_out > max_bucket_count()) {
184
+ TSL_RH_THROW_OR_TERMINATE(std::length_error,
185
+ "The hash table exceeds its maximum size.");
186
+ }
187
+
188
+ if (min_bucket_count_in_out > 0) {
189
+ m_mod = min_bucket_count_in_out;
190
+ } else {
191
+ m_mod = 1;
192
+ }
193
+ }
194
+
195
+ std::size_t bucket_for_hash(std::size_t hash) const noexcept {
196
+ return hash % m_mod;
197
+ }
198
+
199
+ std::size_t next_bucket_count() const {
200
+ if (m_mod == max_bucket_count()) {
201
+ TSL_RH_THROW_OR_TERMINATE(std::length_error,
202
+ "The hash table exceeds its maximum size.");
203
+ }
204
+
205
+ const double next_bucket_count =
206
+ std::ceil(double(m_mod) * REHASH_SIZE_MULTIPLICATION_FACTOR);
207
+ if (!std::isnormal(next_bucket_count)) {
208
+ TSL_RH_THROW_OR_TERMINATE(std::length_error,
209
+ "The hash table exceeds its maximum size.");
210
+ }
211
+
212
+ if (next_bucket_count > double(max_bucket_count())) {
213
+ return max_bucket_count();
214
+ } else {
215
+ return std::size_t(next_bucket_count);
216
+ }
217
+ }
218
+
219
+ std::size_t max_bucket_count() const { return MAX_BUCKET_COUNT; }
220
+
221
+ void clear() noexcept { m_mod = 1; }
222
+
223
+ private:
224
+ static constexpr double REHASH_SIZE_MULTIPLICATION_FACTOR =
225
+ 1.0 * GrowthFactor::num / GrowthFactor::den;
226
+ static const std::size_t MAX_BUCKET_COUNT =
227
+ std::size_t(double(std::numeric_limits<std::size_t>::max() /
228
+ REHASH_SIZE_MULTIPLICATION_FACTOR));
229
+
230
+ static_assert(REHASH_SIZE_MULTIPLICATION_FACTOR >= 1.1,
231
+ "Growth factor should be >= 1.1.");
232
+
233
+ std::size_t m_mod;
234
+ };
235
+
236
+ namespace detail {
237
+
238
+ #if SIZE_MAX >= ULLONG_MAX
239
+ #define TSL_RH_NB_PRIMES 51
240
+ #elif SIZE_MAX >= ULONG_MAX
241
+ #define TSL_RH_NB_PRIMES 40
242
+ #else
243
+ #define TSL_RH_NB_PRIMES 23
244
+ #endif
245
+
246
+ static constexpr const std::array<std::size_t, TSL_RH_NB_PRIMES> PRIMES = {{
247
+ 1u,
248
+ 5u,
249
+ 17u,
250
+ 29u,
251
+ 37u,
252
+ 53u,
253
+ 67u,
254
+ 79u,
255
+ 97u,
256
+ 131u,
257
+ 193u,
258
+ 257u,
259
+ 389u,
260
+ 521u,
261
+ 769u,
262
+ 1031u,
263
+ 1543u,
264
+ 2053u,
265
+ 3079u,
266
+ 6151u,
267
+ 12289u,
268
+ 24593u,
269
+ 49157u,
270
+ #if SIZE_MAX >= ULONG_MAX
271
+ 98317ul,
272
+ 196613ul,
273
+ 393241ul,
274
+ 786433ul,
275
+ 1572869ul,
276
+ 3145739ul,
277
+ 6291469ul,
278
+ 12582917ul,
279
+ 25165843ul,
280
+ 50331653ul,
281
+ 100663319ul,
282
+ 201326611ul,
283
+ 402653189ul,
284
+ 805306457ul,
285
+ 1610612741ul,
286
+ 3221225473ul,
287
+ 4294967291ul,
288
+ #endif
289
+ #if SIZE_MAX >= ULLONG_MAX
290
+ 6442450939ull,
291
+ 12884901893ull,
292
+ 25769803751ull,
293
+ 51539607551ull,
294
+ 103079215111ull,
295
+ 206158430209ull,
296
+ 412316860441ull,
297
+ 824633720831ull,
298
+ 1649267441651ull,
299
+ 3298534883309ull,
300
+ 6597069766657ull,
301
+ #endif
302
+ }};
303
+
304
+ template <unsigned int IPrime>
305
+ static constexpr std::size_t mod(std::size_t hash) {
306
+ return hash % PRIMES[IPrime];
307
+ }
308
+
309
+ // MOD_PRIME[iprime](hash) returns hash % PRIMES[iprime]. This table allows for
310
+ // faster modulo as the compiler can optimize the modulo code better with a
311
+ // constant known at the compilation.
312
+ static constexpr const std::array<std::size_t (*)(std::size_t),
313
+ TSL_RH_NB_PRIMES>
314
+ MOD_PRIME = {{
315
+ &mod<0>, &mod<1>, &mod<2>, &mod<3>, &mod<4>, &mod<5>,
316
+ &mod<6>, &mod<7>, &mod<8>, &mod<9>, &mod<10>, &mod<11>,
317
+ &mod<12>, &mod<13>, &mod<14>, &mod<15>, &mod<16>, &mod<17>,
318
+ &mod<18>, &mod<19>, &mod<20>, &mod<21>, &mod<22>,
319
+ #if SIZE_MAX >= ULONG_MAX
320
+ &mod<23>, &mod<24>, &mod<25>, &mod<26>, &mod<27>, &mod<28>,
321
+ &mod<29>, &mod<30>, &mod<31>, &mod<32>, &mod<33>, &mod<34>,
322
+ &mod<35>, &mod<36>, &mod<37>, &mod<38>, &mod<39>,
323
+ #endif
324
+ #if SIZE_MAX >= ULLONG_MAX
325
+ &mod<40>, &mod<41>, &mod<42>, &mod<43>, &mod<44>, &mod<45>,
326
+ &mod<46>, &mod<47>, &mod<48>, &mod<49>, &mod<50>,
327
+ #endif
328
+ }};
329
+
330
+ } // namespace detail
331
+
332
+ /**
333
+ * Grow the hash table by using prime numbers as bucket count. Slower than
334
+ * tsl::rh::power_of_two_growth_policy in general but will probably distribute
335
+ * the values around better in the buckets with a poor hash function.
336
+ *
337
+ * To allow the compiler to optimize the modulo operation, a lookup table is
338
+ * used with constant primes numbers.
339
+ *
340
+ * With a switch the code would look like:
341
+ * \code
342
+ * switch(iprime) { // iprime is the current prime of the hash table
343
+ * case 0: hash % 5ul;
344
+ * break;
345
+ * case 1: hash % 17ul;
346
+ * break;
347
+ * case 2: hash % 29ul;
348
+ * break;
349
+ * ...
350
+ * }
351
+ * \endcode
352
+ *
353
+ * Due to the constant variable in the modulo the compiler is able to optimize
354
+ * the operation by a series of multiplications, substractions and shifts.
355
+ *
356
+ * The 'hash % 5' could become something like 'hash - (hash * 0xCCCCCCCD) >> 34)
357
+ * * 5' in a 64 bits environment.
358
+ */
359
+ class prime_growth_policy {
360
+ public:
361
+ explicit prime_growth_policy(std::size_t& min_bucket_count_in_out) {
362
+ auto it_prime = std::lower_bound(
363
+ detail::PRIMES.begin(), detail::PRIMES.end(), min_bucket_count_in_out);
364
+ if (it_prime == detail::PRIMES.end()) {
365
+ TSL_RH_THROW_OR_TERMINATE(std::length_error,
366
+ "The hash table exceeds its maximum size.");
367
+ }
368
+
369
+ m_iprime = static_cast<unsigned int>(
370
+ std::distance(detail::PRIMES.begin(), it_prime));
371
+ if (min_bucket_count_in_out > 0) {
372
+ min_bucket_count_in_out = *it_prime;
373
+ } else {
374
+ min_bucket_count_in_out = 0;
375
+ }
376
+ }
377
+
378
+ std::size_t bucket_for_hash(std::size_t hash) const noexcept {
379
+ return detail::MOD_PRIME[m_iprime](hash);
380
+ }
381
+
382
+ std::size_t next_bucket_count() const {
383
+ if (m_iprime + 1 >= detail::PRIMES.size()) {
384
+ TSL_RH_THROW_OR_TERMINATE(std::length_error,
385
+ "The hash table exceeds its maximum size.");
386
+ }
387
+
388
+ return detail::PRIMES[m_iprime + 1];
389
+ }
390
+
391
+ std::size_t max_bucket_count() const { return detail::PRIMES.back(); }
392
+
393
+ void clear() noexcept { m_iprime = 0; }
394
+
395
+ private:
396
+ unsigned int m_iprime;
397
+
398
+ static_assert(std::numeric_limits<decltype(m_iprime)>::max() >=
399
+ detail::PRIMES.size(),
400
+ "The type of m_iprime is not big enough.");
401
+ };
402
+
403
+ } // namespace rh
404
+ } // namespace tsl
405
+
406
+ #endif