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
@@ -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