usearch 1.1.1 → 1.2.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 (70) hide show
  1. package/.github/workflows/prerelease.yml +3 -3
  2. package/.github/workflows/release.yml +3 -3
  3. package/.github/workflows/update_version.sh +1 -1
  4. package/.gitmodules +1 -4
  5. package/Cargo.toml +1 -1
  6. package/Package.swift +2 -1
  7. package/README.md +86 -42
  8. package/binding.gyp +16 -12
  9. package/build.gradle +1 -1
  10. package/build.rs +0 -1
  11. package/c/CMakeLists.txt +11 -7
  12. package/c/lib.cpp +36 -24
  13. package/c/usearch.h +42 -12
  14. package/cluster.ipynb +167 -0
  15. package/conanfile.py +1 -1
  16. package/cpp/CMakeLists.txt +8 -3
  17. package/cpp/bench.cpp +2 -2
  18. package/cpp/test.cpp +42 -25
  19. package/docs/benchmarks.md +8 -0
  20. package/docs/compilation.md +7 -7
  21. package/docs/conf.py +27 -24
  22. package/docs/javascript/reference.rst +3 -0
  23. package/golang/README.md +31 -7
  24. package/golang/lib.go +1 -1
  25. package/include/usearch/index.hpp +348 -69
  26. package/include/usearch/index_dense.hpp +587 -179
  27. package/include/usearch/index_plugins.hpp +194 -16
  28. package/java/cloud/unum/usearch/Index.java +13 -0
  29. package/java/cloud/unum/usearch/cloud_unum_usearch_Index.cpp +40 -9
  30. package/java/cloud/unum/usearch/cloud_unum_usearch_Index.h +16 -0
  31. package/javascript/docs.js +111 -0
  32. package/javascript/lib.cpp +29 -9
  33. package/javascript/usearch.d.ts +9 -1
  34. package/objc/USearchObjective.mm +11 -11
  35. package/package.json +2 -2
  36. package/pyproject.toml +1 -1
  37. package/python/lib.cpp +488 -158
  38. package/python/scripts/index_faiss.py +3 -3
  39. package/python/scripts/join.py +6 -6
  40. package/python/scripts/test_index.py +219 -0
  41. package/python/scripts/test_sparse.py +21 -21
  42. package/python/scripts/test_tooling.py +111 -0
  43. package/python/usearch/eval.py +9 -5
  44. package/python/usearch/index.py +491 -216
  45. package/rust/lib.cpp +6 -24
  46. package/rust/lib.hpp +1 -3
  47. package/rust/lib.rs +89 -0
  48. package/setup.py +5 -6
  49. package/wasm/CMakeLists.txt +0 -1
  50. package/wasmer.toml +1 -1
  51. package/python/scripts/test.py +0 -364
  52. package/robin-map/.codecov.yml +0 -5
  53. package/robin-map/.github/workflows/ci.yml +0 -136
  54. package/robin-map/CMakeLists.txt +0 -86
  55. package/robin-map/LICENSE +0 -21
  56. package/robin-map/README.md +0 -483
  57. package/robin-map/cmake/tsl-robin-mapConfig.cmake.in +0 -9
  58. package/robin-map/doxygen.conf +0 -2483
  59. package/robin-map/include/tsl/robin_growth_policy.h +0 -406
  60. package/robin-map/include/tsl/robin_hash.h +0 -1639
  61. package/robin-map/include/tsl/robin_map.h +0 -807
  62. package/robin-map/include/tsl/robin_set.h +0 -660
  63. package/robin-map/tests/CMakeLists.txt +0 -26
  64. package/robin-map/tests/custom_allocator_tests.cpp +0 -138
  65. package/robin-map/tests/main.cpp +0 -26
  66. package/robin-map/tests/policy_tests.cpp +0 -97
  67. package/robin-map/tests/robin_map_tests.cpp +0 -1451
  68. package/robin-map/tests/robin_set_tests.cpp +0 -164
  69. package/robin-map/tests/utils.h +0 -443
  70. package/robin-map/tsl-robin-map.natvis +0 -78
@@ -1,1451 +0,0 @@
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
- #include <tsl/robin_map.h>
25
-
26
- #include <boost/mpl/list.hpp>
27
- #include <boost/test/unit_test.hpp>
28
- #include <cstddef>
29
- #include <cstdint>
30
- #include <functional>
31
- #include <iterator>
32
- #include <memory>
33
- #include <stdexcept>
34
- #include <string>
35
- #include <tuple>
36
- #include <type_traits>
37
- #include <utility>
38
- #include <vector>
39
-
40
- #include "utils.h"
41
-
42
- BOOST_AUTO_TEST_SUITE(test_robin_map)
43
-
44
- using test_types = boost::mpl::list<
45
- tsl::robin_map<std::int64_t, std::int64_t>,
46
- tsl::robin_map<std::string, std::string>,
47
- // Test with hash having a lot of collisions
48
- tsl::robin_map<std::int64_t, std::int64_t, mod_hash<9>>,
49
- tsl::robin_map<std::string, std::string, mod_hash<9>>,
50
- tsl::robin_map<move_only_test, move_only_test, mod_hash<9>>,
51
- tsl::robin_map<copy_only_test, copy_only_test, mod_hash<9>>,
52
- tsl::robin_map<self_reference_member_test, self_reference_member_test,
53
- mod_hash<9>>,
54
-
55
- // other GrowthPolicy
56
- tsl::robin_map<move_only_test, move_only_test, mod_hash<9>,
57
- std::equal_to<move_only_test>,
58
- std::allocator<std::pair<move_only_test, move_only_test>>,
59
- true, tsl::rh::power_of_two_growth_policy<4>>,
60
- tsl::robin_pg_map<move_only_test, move_only_test, mod_hash<9>>,
61
- tsl::robin_map<move_only_test, move_only_test, mod_hash<9>,
62
- std::equal_to<move_only_test>,
63
- std::allocator<std::pair<move_only_test, move_only_test>>,
64
- false, tsl::rh::mod_growth_policy<>>,
65
-
66
- tsl::robin_map<copy_only_test, copy_only_test, mod_hash<9>,
67
- std::equal_to<copy_only_test>,
68
- std::allocator<std::pair<copy_only_test, copy_only_test>>,
69
- false, tsl::rh::power_of_two_growth_policy<4>>,
70
- tsl::robin_pg_map<copy_only_test, copy_only_test, mod_hash<9>>,
71
- tsl::robin_map<copy_only_test, copy_only_test, mod_hash<9>,
72
- std::equal_to<copy_only_test>,
73
- std::allocator<std::pair<copy_only_test, copy_only_test>>,
74
- true, tsl::rh::mod_growth_policy<>>>;
75
-
76
- /**
77
- * insert
78
- */
79
- BOOST_AUTO_TEST_CASE_TEMPLATE(test_insert, HMap, test_types) {
80
- // insert x values, insert them again, check values
81
- using key_t = typename HMap::key_type;
82
- using value_t = typename HMap::mapped_type;
83
-
84
- const std::size_t nb_values = 1000;
85
- HMap map(0);
86
- BOOST_CHECK_EQUAL(map.bucket_count(), 0);
87
-
88
- typename HMap::iterator it;
89
- bool inserted;
90
-
91
- for (std::size_t i = 0; i < nb_values; i++) {
92
- std::tie(it, inserted) =
93
- map.insert({utils::get_key<key_t>(i), utils::get_value<value_t>(i)});
94
-
95
- BOOST_CHECK_EQUAL(it->first, utils::get_key<key_t>(i));
96
- BOOST_CHECK_EQUAL(it->second, utils::get_value<value_t>(i));
97
- BOOST_CHECK(inserted);
98
- }
99
- BOOST_CHECK_EQUAL(map.size(), nb_values);
100
-
101
- for (std::size_t i = 0; i < nb_values; i++) {
102
- std::tie(it, inserted) = map.insert(
103
- {utils::get_key<key_t>(i), utils::get_value<value_t>(i + 1)});
104
-
105
- BOOST_CHECK_EQUAL(it->first, utils::get_key<key_t>(i));
106
- BOOST_CHECK_EQUAL(it->second, utils::get_value<value_t>(i));
107
- BOOST_CHECK(!inserted);
108
- }
109
-
110
- for (std::size_t i = 0; i < nb_values; i++) {
111
- it = map.find(utils::get_key<key_t>(i));
112
-
113
- BOOST_CHECK_EQUAL(it->first, utils::get_key<key_t>(i));
114
- BOOST_CHECK_EQUAL(it->second, utils::get_value<value_t>(i));
115
- }
116
- }
117
-
118
- BOOST_AUTO_TEST_CASE(test_range_insert) {
119
- // create a vector<std::pair> of values to insert, insert part of them in the
120
- // map, check values
121
- const int nb_values = 1000;
122
- std::vector<std::pair<int, int>> values_to_insert(nb_values);
123
- for (int i = 0; i < nb_values; i++) {
124
- values_to_insert[i] = std::make_pair(i, i + 1);
125
- }
126
-
127
- tsl::robin_map<int, int> map = {{-1, 1}, {-2, 2}};
128
- map.insert(std::next(values_to_insert.begin(), 10),
129
- values_to_insert.end() - 5);
130
-
131
- BOOST_CHECK_EQUAL(map.size(), 987);
132
-
133
- BOOST_CHECK_EQUAL(map.at(-1), 1);
134
- BOOST_CHECK_EQUAL(map.at(-2), 2);
135
-
136
- for (int i = 10; i < nb_values - 5; i++) {
137
- BOOST_CHECK_EQUAL(map.at(i), i + 1);
138
- }
139
- }
140
-
141
- BOOST_AUTO_TEST_CASE(test_rehash_0) {
142
- tsl::robin_map<int, int, std::hash<int>, std::equal_to<int>,
143
- std::allocator<std::pair<int, int>>, true>
144
- map;
145
- map.rehash(0);
146
- }
147
-
148
- BOOST_AUTO_TEST_CASE(test_insert_with_hint) {
149
- tsl::robin_map<int, int> map{{1, 0}, {2, 1}, {3, 2}};
150
-
151
- // Wrong hint
152
- BOOST_CHECK(map.insert(map.find(2), std::make_pair(3, 4)) == map.find(3));
153
-
154
- // Good hint
155
- BOOST_CHECK(map.insert(map.find(2), std::make_pair(2, 4)) == map.find(2));
156
-
157
- // end() hint
158
- BOOST_CHECK(map.insert(map.find(10), std::make_pair(2, 4)) == map.find(2));
159
-
160
- BOOST_CHECK_EQUAL(map.size(), 3);
161
-
162
- // end() hint, new value
163
- BOOST_CHECK_EQUAL(map.insert(map.find(10), std::make_pair(4, 3))->first, 4);
164
-
165
- // Wrong hint, new value
166
- BOOST_CHECK_EQUAL(map.insert(map.find(2), std::make_pair(5, 4))->first, 5);
167
-
168
- BOOST_CHECK_EQUAL(map.size(), 5);
169
- }
170
-
171
- /**
172
- * emplace_hint
173
- */
174
- BOOST_AUTO_TEST_CASE(test_emplace_hint) {
175
- tsl::robin_map<int, int> map{{1, 0}, {2, 1}, {3, 2}};
176
-
177
- // Wrong hint
178
- BOOST_CHECK(map.emplace_hint(map.find(2), std::piecewise_construct,
179
- std::forward_as_tuple(3),
180
- std::forward_as_tuple(4)) == map.find(3));
181
-
182
- // Good hint
183
- BOOST_CHECK(map.emplace_hint(map.find(2), std::piecewise_construct,
184
- std::forward_as_tuple(2),
185
- std::forward_as_tuple(4)) == map.find(2));
186
-
187
- // end() hint
188
- BOOST_CHECK(map.emplace_hint(map.find(10), std::piecewise_construct,
189
- std::forward_as_tuple(2),
190
- std::forward_as_tuple(4)) == map.find(2));
191
-
192
- BOOST_CHECK_EQUAL(map.size(), 3);
193
-
194
- // end() hint, new value
195
- BOOST_CHECK_EQUAL(
196
- map.emplace_hint(map.find(10), std::piecewise_construct,
197
- std::forward_as_tuple(4), std::forward_as_tuple(3))
198
- ->first,
199
- 4);
200
-
201
- // Wrong hint, new value
202
- BOOST_CHECK_EQUAL(
203
- map.emplace_hint(map.find(2), std::piecewise_construct,
204
- std::forward_as_tuple(5), std::forward_as_tuple(4))
205
- ->first,
206
- 5);
207
-
208
- BOOST_CHECK_EQUAL(map.size(), 5);
209
- }
210
-
211
- /**
212
- * emplace
213
- */
214
- BOOST_AUTO_TEST_CASE(test_emplace) {
215
- tsl::robin_map<std::int64_t, move_only_test> map;
216
- tsl::robin_map<std::int64_t, move_only_test>::iterator it;
217
- bool inserted;
218
-
219
- std::tie(it, inserted) =
220
- map.emplace(std::piecewise_construct, std::forward_as_tuple(10),
221
- std::forward_as_tuple(1));
222
- BOOST_CHECK_EQUAL(it->first, 10);
223
- BOOST_CHECK_EQUAL(it->second, move_only_test(1));
224
- BOOST_CHECK(inserted);
225
-
226
- std::tie(it, inserted) =
227
- map.emplace(std::piecewise_construct, std::forward_as_tuple(10),
228
- std::forward_as_tuple(3));
229
- BOOST_CHECK_EQUAL(it->first, 10);
230
- BOOST_CHECK_EQUAL(it->second, move_only_test(1));
231
- BOOST_CHECK(!inserted);
232
- }
233
-
234
- /**
235
- * try_emplace
236
- */
237
- BOOST_AUTO_TEST_CASE(test_try_emplace) {
238
- tsl::robin_map<std::int64_t, move_only_test> map;
239
- tsl::robin_map<std::int64_t, move_only_test>::iterator it;
240
- bool inserted;
241
-
242
- std::tie(it, inserted) = map.try_emplace(10, 1);
243
- BOOST_CHECK_EQUAL(it->first, 10);
244
- BOOST_CHECK_EQUAL(it->second, move_only_test(1));
245
- BOOST_CHECK(inserted);
246
-
247
- std::tie(it, inserted) = map.try_emplace(10, 3);
248
- BOOST_CHECK_EQUAL(it->first, 10);
249
- BOOST_CHECK_EQUAL(it->second, move_only_test(1));
250
- BOOST_CHECK(!inserted);
251
- }
252
-
253
- BOOST_AUTO_TEST_CASE(test_try_emplace_2) {
254
- // Insert x values with try_emplace, insert them again, check with find.
255
- tsl::robin_map<std::string, move_only_test> map;
256
- tsl::robin_map<std::string, move_only_test>::iterator it;
257
- bool inserted;
258
-
259
- const std::size_t nb_values = 1000;
260
- for (std::size_t i = 0; i < nb_values; i++) {
261
- std::tie(it, inserted) = map.try_emplace(utils::get_key<std::string>(i), i);
262
-
263
- BOOST_CHECK_EQUAL(it->first, utils::get_key<std::string>(i));
264
- BOOST_CHECK_EQUAL(it->second, move_only_test(i));
265
- BOOST_CHECK(inserted);
266
- }
267
- BOOST_CHECK_EQUAL(map.size(), nb_values);
268
-
269
- for (std::size_t i = 0; i < nb_values; i++) {
270
- std::tie(it, inserted) =
271
- map.try_emplace(utils::get_key<std::string>(i), i + 1);
272
-
273
- BOOST_CHECK_EQUAL(it->first, utils::get_key<std::string>(i));
274
- BOOST_CHECK_EQUAL(it->second, move_only_test(i));
275
- BOOST_CHECK(!inserted);
276
- }
277
-
278
- for (std::size_t i = 0; i < nb_values; i++) {
279
- it = map.find(utils::get_key<std::string>(i));
280
-
281
- BOOST_CHECK_EQUAL(it->first, utils::get_key<std::string>(i));
282
- BOOST_CHECK_EQUAL(it->second, move_only_test(i));
283
- }
284
- }
285
-
286
- BOOST_AUTO_TEST_CASE(test_try_emplace_hint) {
287
- tsl::robin_map<std::int64_t, move_only_test> map(0);
288
-
289
- // end() hint, new value
290
- auto it = map.try_emplace(map.find(10), 10, 1);
291
- BOOST_CHECK_EQUAL(it->first, 10);
292
- BOOST_CHECK_EQUAL(it->second, move_only_test(1));
293
-
294
- // Good hint
295
- it = map.try_emplace(map.find(10), 10, 3);
296
- BOOST_CHECK_EQUAL(it->first, 10);
297
- BOOST_CHECK_EQUAL(it->second, move_only_test(1));
298
-
299
- // Wrong hint, new value
300
- it = map.try_emplace(map.find(10), 1, 3);
301
- BOOST_CHECK_EQUAL(it->first, 1);
302
- BOOST_CHECK_EQUAL(it->second, move_only_test(3));
303
- }
304
-
305
- /**
306
- * insert_or_assign
307
- */
308
- BOOST_AUTO_TEST_CASE(test_insert_or_assign) {
309
- tsl::robin_map<std::int64_t, move_only_test> map;
310
- tsl::robin_map<std::int64_t, move_only_test>::iterator it;
311
- bool inserted;
312
-
313
- std::tie(it, inserted) = map.insert_or_assign(10, move_only_test(1));
314
- BOOST_CHECK_EQUAL(it->first, 10);
315
- BOOST_CHECK_EQUAL(it->second, move_only_test(1));
316
- BOOST_CHECK(inserted);
317
-
318
- std::tie(it, inserted) = map.insert_or_assign(10, move_only_test(3));
319
- BOOST_CHECK_EQUAL(it->first, 10);
320
- BOOST_CHECK_EQUAL(it->second, move_only_test(3));
321
- BOOST_CHECK(!inserted);
322
- }
323
-
324
- BOOST_AUTO_TEST_CASE(test_insert_or_assign_hint) {
325
- tsl::robin_map<std::int64_t, move_only_test> map(0);
326
-
327
- // end() hint, new value
328
- auto it = map.insert_or_assign(map.find(10), 10, move_only_test(1));
329
- BOOST_CHECK_EQUAL(it->first, 10);
330
- BOOST_CHECK_EQUAL(it->second, move_only_test(1));
331
-
332
- // Good hint
333
- it = map.insert_or_assign(map.find(10), 10, move_only_test(3));
334
- BOOST_CHECK_EQUAL(it->first, 10);
335
- BOOST_CHECK_EQUAL(it->second, move_only_test(3));
336
-
337
- // Bad hint, new value
338
- it = map.insert_or_assign(map.find(10), 1, move_only_test(3));
339
- BOOST_CHECK_EQUAL(it->first, 1);
340
- BOOST_CHECK_EQUAL(it->second, move_only_test(3));
341
- }
342
-
343
- /**
344
- * erase
345
- */
346
- BOOST_AUTO_TEST_CASE(test_range_erase_all) {
347
- // insert x values, delete all with iterators
348
- using HMap = tsl::robin_map<std::string, std::int64_t>;
349
-
350
- const std::size_t nb_values = 1000;
351
- HMap map = utils::get_filled_hash_map<HMap>(nb_values);
352
-
353
- auto it = map.erase(map.begin(), map.end());
354
- BOOST_CHECK(it == map.end());
355
- BOOST_CHECK(map.empty());
356
- }
357
-
358
- BOOST_AUTO_TEST_CASE(test_range_erase) {
359
- // insert x values, delete all with iterators except 10 first and 780 last
360
- // values
361
- using HMap = tsl::robin_map<std::string, std::int64_t>;
362
-
363
- const std::size_t nb_values = 1000;
364
- HMap map = utils::get_filled_hash_map<HMap>(nb_values);
365
-
366
- auto it_first = std::next(map.begin(), 10);
367
- auto it_last = std::next(map.begin(), 220);
368
-
369
- auto it = map.erase(it_first, it_last);
370
- BOOST_CHECK_EQUAL(std::distance(it, map.end()), 780);
371
- BOOST_CHECK_EQUAL(map.size(), 790);
372
- BOOST_CHECK_EQUAL(std::distance(map.begin(), map.end()), 790);
373
-
374
- for (auto& val : map) {
375
- BOOST_CHECK_EQUAL(map.count(val.first), 1);
376
- }
377
- }
378
-
379
- BOOST_AUTO_TEST_CASE_TEMPLATE(test_erase_loop, HMap, test_types) {
380
- // insert x values, delete all one by one with iterator
381
- std::size_t nb_values = 1000;
382
-
383
- HMap map = utils::get_filled_hash_map<HMap>(nb_values);
384
- HMap map2 = utils::get_filled_hash_map<HMap>(nb_values);
385
-
386
- auto it = map.begin();
387
- // Use second map to check for key after delete as we may not copy the key
388
- // with move-only types.
389
- auto it2 = map2.begin();
390
- while (it != map.end()) {
391
- it = map.erase(it);
392
- --nb_values;
393
-
394
- BOOST_CHECK_EQUAL(map.count(it2->first), 0);
395
- BOOST_CHECK_EQUAL(map.size(), nb_values);
396
- ++it2;
397
- }
398
-
399
- BOOST_CHECK(map.empty());
400
- }
401
-
402
- BOOST_AUTO_TEST_CASE_TEMPLATE(test_erase_loop_range, HMap, test_types) {
403
- // insert x values, delete all five by five with iterators
404
- const std::size_t hop = 5;
405
- std::size_t nb_values = 1000;
406
-
407
- BOOST_REQUIRE_EQUAL(nb_values % hop, 0);
408
-
409
- HMap map = utils::get_filled_hash_map<HMap>(nb_values);
410
-
411
- auto it = map.begin();
412
- while (it != map.end()) {
413
- it = map.erase(it, std::next(it, hop));
414
- nb_values -= hop;
415
-
416
- BOOST_CHECK_EQUAL(map.size(), nb_values);
417
- }
418
-
419
- BOOST_CHECK(map.empty());
420
- }
421
-
422
- BOOST_AUTO_TEST_CASE_TEMPLATE(test_insert_erase_insert, HMap, test_types) {
423
- // insert x/2 values, delete x/4 values, insert x/2 values, find each value
424
- using key_t = typename HMap::key_type;
425
- using value_t = typename HMap::mapped_type;
426
-
427
- const std::size_t nb_values = 2000;
428
- HMap map(10);
429
- typename HMap::iterator it;
430
- bool inserted;
431
-
432
- // Insert nb_values/2
433
- for (std::size_t i = 0; i < nb_values / 2; i++) {
434
- std::tie(it, inserted) =
435
- map.insert({utils::get_key<key_t>(i), utils::get_value<value_t>(i)});
436
-
437
- BOOST_CHECK_EQUAL(it->first, utils::get_key<key_t>(i));
438
- BOOST_CHECK_EQUAL(it->second, utils::get_value<value_t>(i));
439
- BOOST_CHECK(inserted);
440
- }
441
- BOOST_CHECK_EQUAL(map.size(), nb_values / 2);
442
-
443
- // Delete nb_values/4
444
- for (std::size_t i = 0; i < nb_values / 2; i++) {
445
- if (i % 2 == 0) {
446
- BOOST_CHECK_EQUAL(map.erase(utils::get_key<key_t>(i)), 1);
447
- }
448
- }
449
- BOOST_CHECK_EQUAL(map.size(), nb_values / 4);
450
-
451
- // Insert nb_values/2
452
- for (std::size_t i = nb_values / 2; i < nb_values; i++) {
453
- std::tie(it, inserted) =
454
- map.insert({utils::get_key<key_t>(i), utils::get_value<value_t>(i)});
455
-
456
- BOOST_CHECK_EQUAL(it->first, utils::get_key<key_t>(i));
457
- BOOST_CHECK_EQUAL(it->second, utils::get_value<value_t>(i));
458
- BOOST_CHECK(inserted);
459
- }
460
- BOOST_CHECK_EQUAL(map.size(), nb_values - nb_values / 4);
461
-
462
- // Find
463
- for (std::size_t i = 0; i < nb_values; i++) {
464
- if (i % 2 == 0 && i < nb_values / 2) {
465
- it = map.find(utils::get_key<key_t>(i));
466
-
467
- BOOST_CHECK(it == map.end());
468
- } else {
469
- it = map.find(utils::get_key<key_t>(i));
470
-
471
- BOOST_REQUIRE(it != map.end());
472
- BOOST_CHECK_EQUAL(it->first, utils::get_key<key_t>(i));
473
- BOOST_CHECK_EQUAL(it->second, utils::get_value<value_t>(i));
474
- }
475
- }
476
- }
477
-
478
- BOOST_AUTO_TEST_CASE(test_range_erase_same_iterators) {
479
- // insert x values, test erase with same iterator as each parameter, check if
480
- // returned mutable iterator is valid.
481
- const std::size_t nb_values = 100;
482
- auto map =
483
- utils::get_filled_hash_map<tsl::robin_map<std::int64_t, std::int64_t>>(
484
- nb_values);
485
-
486
- tsl::robin_map<std::int64_t, std::int64_t>::const_iterator it_const =
487
- map.cbegin();
488
- std::advance(it_const, 10);
489
-
490
- tsl::robin_map<std::int64_t, std::int64_t>::iterator it_mutable =
491
- map.erase(it_const, it_const);
492
- BOOST_CHECK(it_const == it_mutable);
493
- BOOST_CHECK(map.mutable_iterator(it_const) == it_mutable);
494
- BOOST_CHECK_EQUAL(map.size(), 100);
495
-
496
- it_mutable.value() = -100;
497
- BOOST_CHECK_EQUAL(it_const.value(), -100);
498
- }
499
-
500
- /**
501
- * max_load_factor
502
- */
503
- BOOST_AUTO_TEST_CASE(test_max_load_factor_extreme_factors) {
504
- tsl::robin_map<std::int64_t, std::int64_t> map;
505
-
506
- map.max_load_factor(0.0f);
507
- BOOST_CHECK_GT(map.max_load_factor(), 0.0f);
508
-
509
- map.max_load_factor(10.0f);
510
- BOOST_CHECK_LT(map.max_load_factor(), 1.0f);
511
- }
512
-
513
- /**
514
- * min_load_factor
515
- */
516
- BOOST_AUTO_TEST_CASE(test_min_load_factor_extreme_factors) {
517
- tsl::robin_map<std::int64_t, std::int64_t> map;
518
-
519
- BOOST_CHECK_EQUAL(map.min_load_factor(), 0.0f);
520
- BOOST_CHECK_LT(map.min_load_factor(), map.max_load_factor());
521
-
522
- map.min_load_factor(-10.0f);
523
- BOOST_CHECK_EQUAL(map.min_load_factor(), 0.0f);
524
-
525
- map.min_load_factor(0.9f);
526
- map.max_load_factor(0.1f);
527
-
528
- // max_load_factor should always be > min_load_factor.
529
- // Factors should have been clamped.
530
- BOOST_CHECK_LT(map.min_load_factor(), map.max_load_factor());
531
- }
532
-
533
- BOOST_AUTO_TEST_CASE(test_min_load_factor) {
534
- // set min_load_factor to 0.15 and max_load_factor to 0.5.
535
- // rehash to 100 buckets, insert 50 elements, erase until load_factor() <
536
- // min_load_factor(), insert an element, check if map has shrinked.
537
- const std::size_t nb_values = 50;
538
- tsl::robin_map<std::int64_t, std::int64_t> map;
539
-
540
- map.min_load_factor(0.15f);
541
- BOOST_CHECK_EQUAL(map.min_load_factor(), 0.15f);
542
-
543
- map.max_load_factor(0.5f);
544
- BOOST_CHECK_EQUAL(map.max_load_factor(), 0.5f);
545
-
546
- map.rehash(nb_values * 2);
547
- for (std::size_t i = 0; i < nb_values; i++) {
548
- map.insert(
549
- {utils::get_key<std::int64_t>(i), utils::get_value<std::int64_t>(i)});
550
- }
551
- BOOST_CHECK_GT(map.load_factor(), map.min_load_factor());
552
-
553
- while (map.load_factor() >= map.min_load_factor()) {
554
- map.erase(map.begin());
555
- }
556
-
557
- // Shrink is done on insert.
558
- map.insert({utils::get_key<std::int64_t>(map.bucket_count()),
559
- utils::get_value<std::int64_t>(map.bucket_count())});
560
- BOOST_CHECK_GT(map.load_factor(), map.min_load_factor());
561
- }
562
-
563
- BOOST_AUTO_TEST_CASE(test_min_load_factor_range_erase) {
564
- // set min_load_factor to 0.15 and max_load_factor to 0.5.
565
- // rehash to 100 buckets, insert 50 elements, erase 40 with range erase,
566
- // insert an element, check if map has shrinked.
567
- const std::size_t nb_values = 50;
568
- const std::size_t nb_values_erase = 40;
569
- tsl::robin_map<std::int64_t, std::int64_t> map;
570
-
571
- map.min_load_factor(0.15f);
572
- BOOST_CHECK_EQUAL(map.min_load_factor(), 0.15f);
573
-
574
- map.max_load_factor(0.5f);
575
- BOOST_CHECK_EQUAL(map.max_load_factor(), 0.5f);
576
-
577
- map.rehash(nb_values * 2);
578
- for (std::size_t i = 0; i < nb_values; i++) {
579
- map.insert(
580
- {utils::get_key<std::int64_t>(i), utils::get_value<std::int64_t>(i)});
581
- }
582
- BOOST_CHECK_GT(map.load_factor(), map.min_load_factor());
583
-
584
- map.erase(std::next(map.begin(), nb_values - nb_values_erase), map.end());
585
-
586
- // Shrink is done on insert.
587
- map.insert({utils::get_key<std::int64_t>(map.bucket_count()),
588
- utils::get_value<std::int64_t>(map.bucket_count())});
589
- BOOST_CHECK_GT(map.load_factor(), map.min_load_factor());
590
- BOOST_CHECK_LT(map.bucket_count(), nb_values * 2);
591
- }
592
-
593
- /**
594
- * rehash
595
- */
596
- BOOST_AUTO_TEST_CASE(test_rehash_empty) {
597
- // test rehash(0), test find/erase/insert on map.
598
- const std::size_t nb_values = 100;
599
- auto map =
600
- utils::get_filled_hash_map<tsl::robin_map<std::int64_t, std::int64_t>>(
601
- nb_values);
602
-
603
- const std::size_t bucket_count = map.bucket_count();
604
- BOOST_CHECK(bucket_count >= nb_values);
605
-
606
- map.clear();
607
- BOOST_CHECK_EQUAL(map.bucket_count(), bucket_count);
608
- BOOST_CHECK(map.empty());
609
-
610
- map.rehash(0);
611
- BOOST_CHECK_EQUAL(map.bucket_count(), 0);
612
- BOOST_CHECK(map.empty());
613
-
614
- BOOST_CHECK(map.find(1) == map.end());
615
- BOOST_CHECK_EQUAL(map.erase(1), 0);
616
- BOOST_CHECK(map.insert({1, 10}).second);
617
- BOOST_CHECK_EQUAL(map.at(1), 10);
618
- }
619
-
620
- /**
621
- * operator== and operator!=
622
- */
623
- BOOST_AUTO_TEST_CASE(test_compare) {
624
- const tsl::robin_map<std::string, std::int64_t> map1 = {
625
- {"a", 1}, {"e", 5}, {"d", 4}, {"c", 3}, {"b", 2}};
626
- const tsl::robin_map<std::string, std::int64_t> map1_copy = {
627
- {"e", 5}, {"c", 3}, {"b", 2}, {"a", 1}, {"d", 4}};
628
- const tsl::robin_map<std::string, std::int64_t> map2 = {
629
- {"e", 5}, {"c", 3}, {"b", 2}, {"a", 1}, {"d", 4}, {"f", 6}};
630
- const tsl::robin_map<std::string, std::int64_t> map3 = {
631
- {"e", 5}, {"c", 3}, {"b", 2}, {"a", 1}};
632
- const tsl::robin_map<std::string, std::int64_t> map4 = {
633
- {"a", 1}, {"e", 5}, {"d", 4}, {"c", 3}, {"b", 26}};
634
- const tsl::robin_map<std::string, std::int64_t> map5 = {
635
- {"a", 1}, {"e", 5}, {"d", 4}, {"c", 3}, {"z", 2}};
636
-
637
- BOOST_CHECK(map1 == map1_copy);
638
- BOOST_CHECK(map1_copy == map1);
639
-
640
- BOOST_CHECK(map1 != map2);
641
- BOOST_CHECK(map2 != map1);
642
-
643
- BOOST_CHECK(map1 != map3);
644
- BOOST_CHECK(map3 != map1);
645
-
646
- BOOST_CHECK(map1 != map4);
647
- BOOST_CHECK(map4 != map1);
648
-
649
- BOOST_CHECK(map1 != map5);
650
- BOOST_CHECK(map5 != map1);
651
-
652
- BOOST_CHECK(map2 != map3);
653
- BOOST_CHECK(map3 != map2);
654
-
655
- BOOST_CHECK(map2 != map4);
656
- BOOST_CHECK(map4 != map2);
657
-
658
- BOOST_CHECK(map2 != map5);
659
- BOOST_CHECK(map5 != map2);
660
-
661
- BOOST_CHECK(map3 != map4);
662
- BOOST_CHECK(map4 != map3);
663
-
664
- BOOST_CHECK(map3 != map5);
665
- BOOST_CHECK(map5 != map3);
666
-
667
- BOOST_CHECK(map4 != map5);
668
- BOOST_CHECK(map5 != map4);
669
- }
670
-
671
- /**
672
- * clear
673
- */
674
- BOOST_AUTO_TEST_CASE(test_clear) {
675
- // insert x values, clear map, test insert
676
- using HMap = tsl::robin_map<std::int64_t, std::int64_t>;
677
-
678
- const std::size_t nb_values = 1000;
679
- auto map = utils::get_filled_hash_map<HMap>(nb_values);
680
-
681
- map.clear();
682
- BOOST_CHECK_EQUAL(map.size(), 0);
683
- BOOST_CHECK_EQUAL(std::distance(map.begin(), map.end()), 0);
684
-
685
- map.insert({5, -5});
686
- map.insert({{1, -1}, {2, -1}, {4, -4}, {3, -3}});
687
-
688
- BOOST_CHECK(map == (HMap({{5, -5}, {1, -1}, {2, -1}, {4, -4}, {3, -3}})));
689
- }
690
-
691
- BOOST_AUTO_TEST_CASE(test_clear_with_min_load_factor) {
692
- // insert x values, clear map, test insert
693
- using HMap = tsl::robin_map<std::int64_t, std::int64_t>;
694
-
695
- const std::size_t nb_values = 1000;
696
- auto map = utils::get_filled_hash_map<HMap>(nb_values);
697
- map.min_load_factor(0.1f);
698
-
699
- map.clear();
700
- BOOST_CHECK_EQUAL(map.bucket_count(), 0);
701
- BOOST_CHECK_EQUAL(map.size(), 0);
702
- BOOST_CHECK_EQUAL(std::distance(map.begin(), map.end()), 0);
703
-
704
- map.insert({5, -5});
705
- map.insert({{1, -1}, {2, -1}, {4, -4}, {3, -3}});
706
-
707
- BOOST_CHECK(map == (HMap({{5, -5}, {1, -1}, {2, -1}, {4, -4}, {3, -3}})));
708
- }
709
-
710
- /**
711
- * iterator.value()
712
- */
713
- BOOST_AUTO_TEST_CASE(test_modify_value_through_iterator) {
714
- // insert x values, modify value of even keys with iterators, check values
715
- const std::size_t nb_values = 100;
716
- auto map =
717
- utils::get_filled_hash_map<tsl::robin_map<std::int64_t, std::int64_t>>(
718
- nb_values);
719
-
720
- for (auto it = map.begin(); it != map.end(); it++) {
721
- if (it.key() % 2 == 0) {
722
- it.value() = -1;
723
- }
724
- }
725
-
726
- for (auto& val : map) {
727
- if (val.first % 2 == 0) {
728
- BOOST_CHECK_EQUAL(val.second, -1);
729
- } else {
730
- BOOST_CHECK_NE(val.second, -1);
731
- }
732
- }
733
- }
734
-
735
- BOOST_AUTO_TEST_CASE(test_modify_value_through_iterator_with_const_qualifier) {
736
- tsl::robin_map<int, int> map = {{0, 1}};
737
- const auto it = map.begin();
738
-
739
- BOOST_CHECK_EQUAL(it->second, 1);
740
- it.value() += 10;
741
- BOOST_CHECK_EQUAL(it->second, 11);
742
- }
743
-
744
- /**
745
- * constructor
746
- */
747
-
748
- BOOST_AUTO_TEST_CASE(test_extreme_bucket_count_value_construction) {
749
- // std::bad_alloc or std::length_error will be thrown depending on the
750
- // platform overcommit
751
- TSL_RH_CHECK_THROW_EITHER(
752
- (tsl::robin_map<int, int, std::hash<int>, std::equal_to<int>,
753
- std::allocator<std::pair<int, int>>, false,
754
- tsl::rh::power_of_two_growth_policy<2>>(
755
- std::numeric_limits<std::size_t>::max())),
756
- std::bad_alloc, std::length_error);
757
-
758
- TSL_RH_CHECK_THROW_EITHER(
759
- (tsl::robin_map<int, int, std::hash<int>, std::equal_to<int>,
760
- std::allocator<std::pair<int, int>>, false,
761
- tsl::rh::power_of_two_growth_policy<2>>(
762
- std::numeric_limits<std::size_t>::max() / 2 + 1)),
763
- std::bad_alloc, std::length_error);
764
-
765
- TSL_RH_CHECK_THROW_EITHER(
766
- (tsl::robin_map<int, int, std::hash<int>, std::equal_to<int>,
767
- std::allocator<std::pair<int, int>>, false,
768
- tsl::rh::prime_growth_policy>(
769
- std::numeric_limits<std::size_t>::max())),
770
- std::bad_alloc, std::length_error);
771
-
772
- TSL_RH_CHECK_THROW_EITHER(
773
- (tsl::robin_map<int, int, std::hash<int>, std::equal_to<int>,
774
- std::allocator<std::pair<int, int>>, false,
775
- tsl::rh::prime_growth_policy>(
776
- std::numeric_limits<std::size_t>::max() / 2)),
777
- std::bad_alloc, std::length_error);
778
-
779
- TSL_RH_CHECK_THROW_EITHER(
780
- (tsl::robin_map<int, int, std::hash<int>, std::equal_to<int>,
781
- std::allocator<std::pair<int, int>>, false,
782
- tsl::rh::mod_growth_policy<>>(
783
- std::numeric_limits<std::size_t>::max())),
784
- std::bad_alloc, std::length_error);
785
- }
786
-
787
- BOOST_AUTO_TEST_CASE(test_range_construct) {
788
- tsl::robin_map<int, int> map = {{2, 1}, {1, 0}, {3, 2}};
789
-
790
- tsl::robin_map<int, int> map2(map.begin(), map.end());
791
- tsl::robin_map<int, int> map3(map.cbegin(), map.cend());
792
- }
793
-
794
- /**
795
- * operator=(std::initializer_list)
796
- */
797
- BOOST_AUTO_TEST_CASE(test_assign_operator) {
798
- tsl::robin_map<std::int64_t, std::int64_t> map = {{0, 10}, {-2, 20}};
799
- BOOST_CHECK_EQUAL(map.size(), 2);
800
-
801
- map = {{1, 3}, {2, 4}};
802
- BOOST_CHECK_EQUAL(map.size(), 2);
803
- BOOST_CHECK_EQUAL(map.at(1), 3);
804
- BOOST_CHECK_EQUAL(map.at(2), 4);
805
- BOOST_CHECK(map.find(0) == map.end());
806
-
807
- map = {};
808
- BOOST_CHECK(map.empty());
809
- }
810
-
811
- /**
812
- * move/copy constructor/operator
813
- */
814
- BOOST_AUTO_TEST_CASE(test_move_constructor) {
815
- // insert x values in map, move map into map_move with move constructor, check
816
- // map and map_move, insert additional values in map_move, check map_move
817
- using HMap = tsl::robin_map<std::string, move_only_test>;
818
-
819
- const std::size_t nb_values = 100;
820
- HMap map = utils::get_filled_hash_map<HMap>(nb_values);
821
- HMap map_move(std::move(map));
822
-
823
- BOOST_CHECK(map_move == utils::get_filled_hash_map<HMap>(nb_values));
824
- BOOST_CHECK(map == (HMap()));
825
-
826
- for (std::size_t i = nb_values; i < nb_values * 2; i++) {
827
- map_move.insert(
828
- {utils::get_key<std::string>(i), utils::get_value<move_only_test>(i)});
829
- }
830
-
831
- BOOST_CHECK_EQUAL(map_move.size(), nb_values * 2);
832
- BOOST_CHECK(map_move == utils::get_filled_hash_map<HMap>(nb_values * 2));
833
- }
834
-
835
- BOOST_AUTO_TEST_CASE(test_move_constructor_empty) {
836
- tsl::robin_map<std::string, move_only_test> map(0);
837
- tsl::robin_map<std::string, move_only_test> map_move(std::move(map));
838
-
839
- BOOST_CHECK(map.empty());
840
- BOOST_CHECK(map_move.empty());
841
-
842
- BOOST_CHECK(map.find("") == map.end());
843
- BOOST_CHECK(map_move.find("") == map_move.end());
844
- }
845
-
846
- BOOST_AUTO_TEST_CASE(test_move_operator) {
847
- // insert x values in map, move map into map_move with move operator, check
848
- // map and map_move, insert additional values in map_move, check map_move
849
- using HMap = tsl::robin_map<std::string, move_only_test>;
850
-
851
- const std::size_t nb_values = 100;
852
- HMap map = utils::get_filled_hash_map<HMap>(nb_values);
853
- HMap map_move = utils::get_filled_hash_map<HMap>(1);
854
- map_move = std::move(map);
855
-
856
- BOOST_CHECK(map_move == utils::get_filled_hash_map<HMap>(nb_values));
857
- BOOST_CHECK(map == (HMap()));
858
-
859
- for (std::size_t i = nb_values; i < nb_values * 2; i++) {
860
- map_move.insert(
861
- {utils::get_key<std::string>(i), utils::get_value<move_only_test>(i)});
862
- }
863
-
864
- BOOST_CHECK_EQUAL(map_move.size(), nb_values * 2);
865
- BOOST_CHECK(map_move == utils::get_filled_hash_map<HMap>(nb_values * 2));
866
- }
867
-
868
- BOOST_AUTO_TEST_CASE(test_move_operator_empty) {
869
- tsl::robin_map<std::string, move_only_test> map(0);
870
- tsl::robin_map<std::string, move_only_test> map_move;
871
- map_move = (std::move(map));
872
-
873
- BOOST_CHECK(map.empty());
874
- BOOST_CHECK(map_move.empty());
875
-
876
- BOOST_CHECK(map.find("") == map.end());
877
- BOOST_CHECK(map_move.find("") == map_move.end());
878
- }
879
-
880
- BOOST_AUTO_TEST_CASE(test_reassign_moved_object_move_constructor) {
881
- using HMap = tsl::robin_map<std::string, std::string>;
882
-
883
- HMap map = {{"Key1", "Value1"}, {"Key2", "Value2"}, {"Key3", "Value3"}};
884
- HMap map_move(std::move(map));
885
-
886
- BOOST_CHECK_EQUAL(map_move.size(), 3);
887
- BOOST_CHECK_EQUAL(map.size(), 0);
888
-
889
- map = {{"Key4", "Value4"}, {"Key5", "Value5"}};
890
- BOOST_CHECK(map == (HMap({{"Key4", "Value4"}, {"Key5", "Value5"}})));
891
- }
892
-
893
- BOOST_AUTO_TEST_CASE(test_reassign_moved_object_move_operator) {
894
- using HMap = tsl::robin_map<std::string, std::string>;
895
-
896
- HMap map = {{"Key1", "Value1"}, {"Key2", "Value2"}, {"Key3", "Value3"}};
897
- HMap map_move = std::move(map);
898
-
899
- BOOST_CHECK_EQUAL(map_move.size(), 3);
900
- BOOST_CHECK_EQUAL(map.size(), 0);
901
-
902
- map = {{"Key4", "Value4"}, {"Key5", "Value5"}};
903
- BOOST_CHECK(map == (HMap({{"Key4", "Value4"}, {"Key5", "Value5"}})));
904
- }
905
-
906
- BOOST_AUTO_TEST_CASE(test_use_after_move_constructor) {
907
- using HMap = tsl::robin_map<std::string, move_only_test>;
908
-
909
- const std::size_t nb_values = 100;
910
- HMap map = utils::get_filled_hash_map<HMap>(nb_values);
911
- HMap map_move(std::move(map));
912
-
913
- BOOST_CHECK(map == (HMap()));
914
- BOOST_CHECK_EQUAL(map.size(), 0);
915
- BOOST_CHECK_EQUAL(map.bucket_count(), 0);
916
- BOOST_CHECK_EQUAL(map.erase("a"), 0);
917
- BOOST_CHECK(map.find("a") == map.end());
918
-
919
- for (std::size_t i = 0; i < nb_values; i++) {
920
- map.insert(
921
- {utils::get_key<std::string>(i), utils::get_value<move_only_test>(i)});
922
- }
923
-
924
- BOOST_CHECK_EQUAL(map.size(), nb_values);
925
- BOOST_CHECK(map == map_move);
926
- }
927
-
928
- BOOST_AUTO_TEST_CASE(test_use_after_move_operator) {
929
- using HMap = tsl::robin_map<std::string, move_only_test>;
930
-
931
- const std::size_t nb_values = 100;
932
- HMap map = utils::get_filled_hash_map<HMap>(nb_values);
933
- HMap map_move(0);
934
- map_move = std::move(map);
935
-
936
- BOOST_CHECK(map == (HMap()));
937
- BOOST_CHECK_EQUAL(map.size(), 0);
938
- BOOST_CHECK_EQUAL(map.bucket_count(), 0);
939
- BOOST_CHECK_EQUAL(map.erase("a"), 0);
940
- BOOST_CHECK(map.find("a") == map.end());
941
-
942
- for (std::size_t i = 0; i < nb_values; i++) {
943
- map.insert(
944
- {utils::get_key<std::string>(i), utils::get_value<move_only_test>(i)});
945
- }
946
-
947
- BOOST_CHECK_EQUAL(map.size(), nb_values);
948
- BOOST_CHECK(map == map_move);
949
- }
950
-
951
- BOOST_AUTO_TEST_CASE(test_copy_constructor_and_operator) {
952
- using HMap = tsl::robin_map<std::string, std::string, mod_hash<9>>;
953
-
954
- const std::size_t nb_values = 100;
955
- HMap map = utils::get_filled_hash_map<HMap>(nb_values);
956
-
957
- HMap map_copy = map;
958
- HMap map_copy2(map);
959
- HMap map_copy3 = utils::get_filled_hash_map<HMap>(1);
960
- map_copy3 = map;
961
-
962
- BOOST_CHECK(map == map_copy);
963
- map.clear();
964
-
965
- BOOST_CHECK(map_copy == map_copy2);
966
- BOOST_CHECK(map_copy == map_copy3);
967
- }
968
-
969
- BOOST_AUTO_TEST_CASE(test_copy_constructor_empty) {
970
- tsl::robin_map<std::string, int> map(0);
971
- tsl::robin_map<std::string, int> map_copy(map);
972
-
973
- BOOST_CHECK(map.empty());
974
- BOOST_CHECK(map_copy.empty());
975
-
976
- BOOST_CHECK(map.find("") == map.end());
977
- BOOST_CHECK(map_copy.find("") == map_copy.end());
978
- }
979
-
980
- BOOST_AUTO_TEST_CASE(test_copy_operator_empty) {
981
- tsl::robin_map<std::string, int> map(0);
982
- tsl::robin_map<std::string, int> map_copy(16);
983
- map_copy = map;
984
-
985
- BOOST_CHECK(map.empty());
986
- BOOST_CHECK(map_copy.empty());
987
-
988
- BOOST_CHECK(map.find("") == map.end());
989
- BOOST_CHECK(map_copy.find("") == map_copy.end());
990
- }
991
-
992
- /**
993
- * at
994
- */
995
- BOOST_AUTO_TEST_CASE(test_at) {
996
- // insert x values, use at for known and unknown values.
997
- const tsl::robin_map<std::int64_t, std::int64_t> map = {{0, 10}, {-2, 20}};
998
-
999
- BOOST_CHECK_EQUAL(map.at(0), 10);
1000
- BOOST_CHECK_EQUAL(map.at(-2), 20);
1001
- TSL_RH_CHECK_THROW(map.at(1), std::out_of_range);
1002
- }
1003
-
1004
- /**
1005
- * contains
1006
- */
1007
- BOOST_AUTO_TEST_CASE(test_contains) {
1008
- tsl::robin_map<std::int64_t, std::int64_t> map = {{0, 10}, {-2, 20}};
1009
-
1010
- BOOST_CHECK(map.contains(0));
1011
- BOOST_CHECK(map.contains(-2));
1012
- BOOST_CHECK(!map.contains(-3));
1013
- }
1014
-
1015
- /**
1016
- * equal_range
1017
- */
1018
- BOOST_AUTO_TEST_CASE(test_equal_range) {
1019
- const tsl::robin_map<std::int64_t, std::int64_t> map = {{0, 10}, {-2, 20}};
1020
-
1021
- auto it_pair = map.equal_range(0);
1022
- BOOST_REQUIRE_EQUAL(std::distance(it_pair.first, it_pair.second), 1);
1023
- BOOST_CHECK_EQUAL(it_pair.first->second, 10);
1024
-
1025
- it_pair = map.equal_range(1);
1026
- BOOST_CHECK(it_pair.first == it_pair.second);
1027
- BOOST_CHECK(it_pair.first == map.end());
1028
- }
1029
-
1030
- /**
1031
- * operator[]
1032
- */
1033
- BOOST_AUTO_TEST_CASE(test_access_operator) {
1034
- // insert x values, use at for known and unknown values.
1035
- tsl::robin_map<std::int64_t, std::int64_t> map = {{0, 10}, {-2, 20}};
1036
-
1037
- BOOST_CHECK_EQUAL(map[0], 10);
1038
- BOOST_CHECK_EQUAL(map[-2], 20);
1039
- BOOST_CHECK_EQUAL(map[2], std::int64_t());
1040
-
1041
- BOOST_CHECK_EQUAL(map.size(), 3);
1042
- }
1043
-
1044
- /**
1045
- * swap
1046
- */
1047
- BOOST_AUTO_TEST_CASE(test_swap) {
1048
- tsl::robin_map<std::int64_t, std::int64_t> map = {{1, 10}, {8, 80}, {3, 30}};
1049
- tsl::robin_map<std::int64_t, std::int64_t> map2 = {{4, 40}, {5, 50}};
1050
-
1051
- using std::swap;
1052
- swap(map, map2);
1053
-
1054
- BOOST_CHECK(map ==
1055
- (tsl::robin_map<std::int64_t, std::int64_t>{{4, 40}, {5, 50}}));
1056
- BOOST_CHECK(map2 == (tsl::robin_map<std::int64_t, std::int64_t>{
1057
- {1, 10}, {8, 80}, {3, 30}}));
1058
-
1059
- map.insert({6, 60});
1060
- map2.insert({4, 40});
1061
-
1062
- BOOST_CHECK(map == (tsl::robin_map<std::int64_t, std::int64_t>{
1063
- {4, 40}, {5, 50}, {6, 60}}));
1064
- BOOST_CHECK(map2 == (tsl::robin_map<std::int64_t, std::int64_t>{
1065
- {1, 10}, {8, 80}, {3, 30}, {4, 40}}));
1066
- }
1067
-
1068
- BOOST_AUTO_TEST_CASE(test_swap_empty) {
1069
- tsl::robin_map<std::int64_t, std::int64_t> map = {{1, 10}, {8, 80}, {3, 30}};
1070
- tsl::robin_map<std::int64_t, std::int64_t> map2;
1071
-
1072
- using std::swap;
1073
- swap(map, map2);
1074
-
1075
- BOOST_CHECK(map == (tsl::robin_map<std::int64_t, std::int64_t>{}));
1076
- BOOST_CHECK(map2 == (tsl::robin_map<std::int64_t, std::int64_t>{
1077
- {1, 10}, {8, 80}, {3, 30}}));
1078
-
1079
- map.insert({6, 60});
1080
- map2.insert({4, 40});
1081
-
1082
- BOOST_CHECK(map == (tsl::robin_map<std::int64_t, std::int64_t>{{6, 60}}));
1083
- BOOST_CHECK(map2 == (tsl::robin_map<std::int64_t, std::int64_t>{
1084
- {1, 10}, {8, 80}, {3, 30}, {4, 40}}));
1085
- }
1086
-
1087
- /**
1088
- * serialize and deserialize
1089
- */
1090
- BOOST_AUTO_TEST_CASE(test_serialize_desearialize_empty) {
1091
- // serialize empty map; deserialize in new map; check equal.
1092
- // for deserialization, test it with and without hash compatibility.
1093
- const tsl::robin_map<std::string, move_only_test> empty_map(0);
1094
-
1095
- serializer serial;
1096
- empty_map.serialize(serial);
1097
-
1098
- deserializer dserial(serial.str());
1099
- auto empty_map_deserialized = decltype(empty_map)::deserialize(dserial, true);
1100
- BOOST_CHECK(empty_map_deserialized == empty_map);
1101
-
1102
- deserializer dserial2(serial.str());
1103
- empty_map_deserialized = decltype(empty_map)::deserialize(dserial2, false);
1104
- BOOST_CHECK(empty_map_deserialized == empty_map);
1105
- }
1106
-
1107
- BOOST_AUTO_TEST_CASE(test_serialize_desearialize) {
1108
- // insert x values; delete some values; serialize map; deserialize in new map;
1109
- // check equal. for deserialization, test it with and without hash
1110
- // compatibility.
1111
- const std::size_t nb_values = 1000;
1112
-
1113
- tsl::robin_map<std::int32_t, move_only_test> map;
1114
- for (std::size_t i = 0; i < nb_values + 40; i++) {
1115
- map.insert(
1116
- {utils::get_key<std::int32_t>(i), utils::get_value<move_only_test>(i)});
1117
- }
1118
-
1119
- for (std::size_t i = nb_values; i < nb_values + 40; i++) {
1120
- map.erase(utils::get_key<std::int32_t>(i));
1121
- }
1122
- BOOST_CHECK_EQUAL(map.size(), nb_values);
1123
-
1124
- serializer serial;
1125
- map.serialize(serial);
1126
-
1127
- deserializer dserial(serial.str());
1128
- auto map_deserialized = decltype(map)::deserialize(dserial, true);
1129
- BOOST_CHECK(map == map_deserialized);
1130
-
1131
- deserializer dserial2(serial.str());
1132
- map_deserialized = decltype(map)::deserialize(dserial2, false);
1133
- BOOST_CHECK(map_deserialized == map);
1134
-
1135
- // Deserializing a map with StoreHash=true from a map serialized with
1136
- // StoreHash=false with hash_compatible=true should throw an exception.
1137
- deserializer dserial3(serial.str());
1138
- TSL_RH_CHECK_THROW(
1139
- (tsl::robin_map<std::int32_t, move_only_test, std::hash<std::int32_t>,
1140
- std::equal_to<std::int32_t>,
1141
- std::allocator<std::pair<std::int32_t, move_only_test>>,
1142
- true>::deserialize(dserial3, true)),
1143
- std::runtime_error);
1144
- }
1145
-
1146
- BOOST_AUTO_TEST_CASE(test_serialize_desearialize_with_store_hash) {
1147
- // insert x values; delete some values; serialize map; deserialize in new map;
1148
- // check equal. for deserialization, test it with and without hash
1149
- // compatibility.
1150
- const std::size_t nb_values = 1000;
1151
-
1152
- tsl::robin_map<std::int32_t, move_only_test, std::hash<std::int32_t>,
1153
- std::equal_to<std::int32_t>,
1154
- std::allocator<std::pair<std::int32_t, move_only_test>>, true>
1155
- map;
1156
- for (std::size_t i = 0; i < nb_values + 40; i++) {
1157
- map.insert(
1158
- {utils::get_key<std::int32_t>(i), utils::get_value<move_only_test>(i)});
1159
- }
1160
-
1161
- for (std::size_t i = nb_values; i < nb_values + 40; i++) {
1162
- map.erase(utils::get_key<std::int32_t>(i));
1163
- }
1164
- BOOST_CHECK_EQUAL(map.size(), nb_values);
1165
-
1166
- serializer serial;
1167
- map.serialize(serial);
1168
-
1169
- deserializer dserial(serial.str());
1170
- auto map_deserialized = decltype(map)::deserialize(dserial, true);
1171
- BOOST_CHECK(map == map_deserialized);
1172
-
1173
- deserializer dserial2(serial.str());
1174
- map_deserialized = decltype(map)::deserialize(dserial2, false);
1175
- BOOST_CHECK(map_deserialized == map);
1176
-
1177
- // Deserializing a map with StoreHash=false from a map serialized with
1178
- // StoreHash=true with hash_compatible=true should throw an exception.
1179
- deserializer dserial3(serial.str());
1180
- TSL_RH_CHECK_THROW((tsl::robin_map<std::int32_t, move_only_test>::deserialize(
1181
- dserial3, true)),
1182
- std::runtime_error);
1183
- }
1184
-
1185
- BOOST_AUTO_TEST_CASE(test_serialize_desearialize_with_different_hash) {
1186
- // insert x values; serialize map; deserialize in new map which has a
1187
- // different hash; check equal
1188
- struct hash_str_diff {
1189
- std::size_t operator()(const std::string& str) const {
1190
- return std::hash<std::string>()(str) + 123;
1191
- }
1192
- };
1193
-
1194
- const std::size_t nb_values = 1000;
1195
-
1196
- tsl::robin_map<std::string, move_only_test> map;
1197
- for (std::size_t i = 0; i < nb_values; i++) {
1198
- map.insert(
1199
- {utils::get_key<std::string>(i), utils::get_value<move_only_test>(i)});
1200
- }
1201
- BOOST_CHECK_EQUAL(map.size(), nb_values);
1202
-
1203
- serializer serial;
1204
- map.serialize(serial);
1205
-
1206
- deserializer dserial(serial.str());
1207
- auto map_deserialized =
1208
- tsl::robin_map<std::string, move_only_test, hash_str_diff>::deserialize(
1209
- dserial, false);
1210
-
1211
- BOOST_CHECK_EQUAL(map_deserialized.size(), map.size());
1212
- for (const auto& val : map) {
1213
- BOOST_CHECK(map_deserialized.find(val.first) != map_deserialized.end());
1214
- }
1215
- }
1216
-
1217
- /**
1218
- * KeyEqual
1219
- */
1220
- BOOST_AUTO_TEST_CASE(test_key_equal) {
1221
- // Use a KeyEqual and Hash where any odd unsigned number 'x' is equal to
1222
- // 'x-1'. Make sure that KeyEqual is called (and not ==).
1223
- struct hash {
1224
- std::size_t operator()(std::uint64_t v) const {
1225
- if (v % 2u == 1u) {
1226
- return std::hash<std::uint64_t>()(v - 1);
1227
- } else {
1228
- return std::hash<std::uint64_t>()(v);
1229
- }
1230
- }
1231
- };
1232
-
1233
- struct key_equal {
1234
- bool operator()(std::uint64_t lhs, std::uint64_t rhs) const {
1235
- if (lhs % 2u == 1u) {
1236
- lhs--;
1237
- }
1238
-
1239
- if (rhs % 2u == 1u) {
1240
- rhs--;
1241
- }
1242
-
1243
- return lhs == rhs;
1244
- }
1245
- };
1246
-
1247
- tsl::robin_map<std::uint64_t, std::uint64_t, hash, key_equal> map;
1248
- BOOST_CHECK(map.insert({2, 10}).second);
1249
- BOOST_CHECK_EQUAL(map.at(2), 10);
1250
- BOOST_CHECK_EQUAL(map.at(3), 10);
1251
- BOOST_CHECK(!map.insert({3, 10}).second);
1252
-
1253
- BOOST_CHECK_EQUAL(map.size(), 1);
1254
- }
1255
-
1256
- /**
1257
- * other
1258
- */
1259
- BOOST_AUTO_TEST_CASE(test_heterogeneous_lookups) {
1260
- struct hash_ptr {
1261
- std::size_t operator()(const std::unique_ptr<int>& p) const {
1262
- return std::hash<std::uintptr_t>()(
1263
- reinterpret_cast<std::uintptr_t>(p.get()));
1264
- }
1265
-
1266
- std::size_t operator()(std::uintptr_t p) const {
1267
- return std::hash<std::uintptr_t>()(p);
1268
- }
1269
-
1270
- std::size_t operator()(const int* const& p) const {
1271
- return std::hash<std::uintptr_t>()(reinterpret_cast<std::uintptr_t>(p));
1272
- }
1273
- };
1274
-
1275
- struct equal_to_ptr {
1276
- using is_transparent = std::true_type;
1277
-
1278
- bool operator()(const std::unique_ptr<int>& p1,
1279
- const std::unique_ptr<int>& p2) const {
1280
- return p1 == p2;
1281
- }
1282
-
1283
- bool operator()(const std::unique_ptr<int>& p1, std::uintptr_t p2) const {
1284
- return reinterpret_cast<std::uintptr_t>(p1.get()) == p2;
1285
- }
1286
-
1287
- bool operator()(std::uintptr_t p1, const std::unique_ptr<int>& p2) const {
1288
- return p1 == reinterpret_cast<std::uintptr_t>(p2.get());
1289
- }
1290
-
1291
- bool operator()(const std::unique_ptr<int>& p1,
1292
- const int* const& p2) const {
1293
- return p1.get() == p2;
1294
- }
1295
-
1296
- bool operator()(const int* const& p1,
1297
- const std::unique_ptr<int>& p2) const {
1298
- return p1 == p2.get();
1299
- }
1300
- };
1301
-
1302
- std::unique_ptr<int> ptr1(new int(1));
1303
- std::unique_ptr<int> ptr2(new int(2));
1304
- std::unique_ptr<int> ptr3(new int(3));
1305
- int other = -1;
1306
-
1307
- const std::uintptr_t addr1 = reinterpret_cast<std::uintptr_t>(ptr1.get());
1308
- const int* const addr2 = ptr2.get();
1309
- const int* const addr_unknown = &other;
1310
-
1311
- tsl::robin_map<std::unique_ptr<int>, int, hash_ptr, equal_to_ptr> map;
1312
- map.insert({std::move(ptr1), 4});
1313
- map.insert({std::move(ptr2), 5});
1314
- map.insert({std::move(ptr3), 6});
1315
-
1316
- BOOST_CHECK_EQUAL(map.size(), 3);
1317
-
1318
- BOOST_CHECK_EQUAL(map.at(addr1), 4);
1319
- BOOST_CHECK_EQUAL(map.at(addr2), 5);
1320
- TSL_RH_CHECK_THROW(map.at(addr_unknown), std::out_of_range);
1321
-
1322
- BOOST_REQUIRE(map.find(addr1) != map.end());
1323
- BOOST_CHECK_EQUAL(*map.find(addr1)->first, 1);
1324
-
1325
- BOOST_REQUIRE(map.find(addr2) != map.end());
1326
- BOOST_CHECK_EQUAL(*map.find(addr2)->first, 2);
1327
-
1328
- BOOST_CHECK(map.find(addr_unknown) == map.end());
1329
-
1330
- BOOST_CHECK_EQUAL(map.count(addr1), 1);
1331
- BOOST_CHECK_EQUAL(map.count(addr2), 1);
1332
- BOOST_CHECK_EQUAL(map.count(addr_unknown), 0);
1333
-
1334
- BOOST_CHECK_EQUAL(map.erase(addr1), 1);
1335
- BOOST_CHECK_EQUAL(map.erase(addr2), 1);
1336
- BOOST_CHECK_EQUAL(map.erase(addr_unknown), 0);
1337
-
1338
- BOOST_CHECK_EQUAL(map.size(), 1);
1339
- }
1340
-
1341
- /**
1342
- * Various operations on empty map
1343
- */
1344
- BOOST_AUTO_TEST_CASE(test_empty_map) {
1345
- tsl::robin_map<std::string, int> map(0);
1346
-
1347
- BOOST_CHECK_EQUAL(map.bucket_count(), 0);
1348
- BOOST_CHECK_EQUAL(map.size(), 0);
1349
- BOOST_CHECK_EQUAL(map.load_factor(), 0);
1350
- BOOST_CHECK(map.empty());
1351
-
1352
- BOOST_CHECK(map.begin() == map.end());
1353
- BOOST_CHECK(map.begin() == map.cend());
1354
- BOOST_CHECK(map.cbegin() == map.cend());
1355
-
1356
- BOOST_CHECK(map.find("") == map.end());
1357
- BOOST_CHECK(map.find("test") == map.end());
1358
-
1359
- BOOST_CHECK_EQUAL(map.count(""), 0);
1360
- BOOST_CHECK_EQUAL(map.count("test"), 0);
1361
-
1362
- BOOST_CHECK(!map.contains(""));
1363
- BOOST_CHECK(!map.contains("test"));
1364
-
1365
- TSL_RH_CHECK_THROW(map.at(""), std::out_of_range);
1366
- TSL_RH_CHECK_THROW(map.at("test"), std::out_of_range);
1367
-
1368
- auto range = map.equal_range("test");
1369
- BOOST_CHECK(range.first == range.second);
1370
-
1371
- BOOST_CHECK_EQUAL(map.erase("test"), 0);
1372
- BOOST_CHECK(map.erase(map.begin(), map.end()) == map.end());
1373
-
1374
- BOOST_CHECK_EQUAL(map["new value"], int{});
1375
- }
1376
-
1377
- /**
1378
- * Test precalculated hash
1379
- */
1380
- BOOST_AUTO_TEST_CASE(test_precalculated_hash) {
1381
- tsl::robin_map<int, int, identity_hash<int>> map = {
1382
- {1, -1}, {2, -2}, {3, -3}, {4, -4}, {5, -5}, {6, -6}};
1383
- const tsl::robin_map<int, int, identity_hash<int>> map_const = map;
1384
-
1385
- /**
1386
- * find
1387
- */
1388
- BOOST_REQUIRE(map.find(3, map.hash_function()(3)) != map.end());
1389
- BOOST_CHECK_EQUAL(map.find(3, map.hash_function()(3))->second, -3);
1390
-
1391
- BOOST_REQUIRE(map_const.find(3, map_const.hash_function()(3)) !=
1392
- map_const.end());
1393
- BOOST_CHECK_EQUAL(map_const.find(3, map_const.hash_function()(3))->second,
1394
- -3);
1395
-
1396
- BOOST_REQUIRE_NE(map.hash_function()(2), map.hash_function()(3));
1397
- BOOST_CHECK(map.find(3, map.hash_function()(2)) == map.end());
1398
-
1399
- /**
1400
- * at
1401
- */
1402
- BOOST_CHECK_EQUAL(map.at(3, map.hash_function()(3)), -3);
1403
- BOOST_CHECK_EQUAL(map_const.at(3, map_const.hash_function()(3)), -3);
1404
-
1405
- BOOST_REQUIRE_NE(map.hash_function()(2), map.hash_function()(3));
1406
- TSL_RH_CHECK_THROW(map.at(3, map.hash_function()(2)), std::out_of_range);
1407
-
1408
- /**
1409
- * contains
1410
- */
1411
- BOOST_CHECK(map.contains(3, map.hash_function()(3)));
1412
- BOOST_CHECK(map_const.contains(3, map_const.hash_function()(3)));
1413
-
1414
- BOOST_REQUIRE_NE(map.hash_function()(2), map.hash_function()(3));
1415
- BOOST_CHECK(!map.contains(3, map.hash_function()(2)));
1416
-
1417
- /**
1418
- * count
1419
- */
1420
- BOOST_CHECK_EQUAL(map.count(3, map.hash_function()(3)), 1);
1421
- BOOST_CHECK_EQUAL(map_const.count(3, map_const.hash_function()(3)), 1);
1422
-
1423
- BOOST_REQUIRE_NE(map.hash_function()(2), map.hash_function()(3));
1424
- BOOST_CHECK_EQUAL(map.count(3, map.hash_function()(2)), 0);
1425
-
1426
- /**
1427
- * equal_range
1428
- */
1429
- auto it_range = map.equal_range(3, map.hash_function()(3));
1430
- BOOST_REQUIRE_EQUAL(std::distance(it_range.first, it_range.second), 1);
1431
- BOOST_CHECK_EQUAL(it_range.first->second, -3);
1432
-
1433
- auto it_range_const = map_const.equal_range(3, map_const.hash_function()(3));
1434
- BOOST_REQUIRE_EQUAL(
1435
- std::distance(it_range_const.first, it_range_const.second), 1);
1436
- BOOST_CHECK_EQUAL(it_range_const.first->second, -3);
1437
-
1438
- it_range = map.equal_range(3, map.hash_function()(2));
1439
- BOOST_REQUIRE_NE(map.hash_function()(2), map.hash_function()(3));
1440
- BOOST_CHECK_EQUAL(std::distance(it_range.first, it_range.second), 0);
1441
-
1442
- /**
1443
- * erase
1444
- */
1445
- BOOST_CHECK_EQUAL(map.erase(3, map.hash_function()(3)), 1);
1446
-
1447
- BOOST_REQUIRE_NE(map.hash_function()(2), map.hash_function()(4));
1448
- BOOST_CHECK_EQUAL(map.erase(4, map.hash_function()(2)), 0);
1449
- }
1450
-
1451
- BOOST_AUTO_TEST_SUITE_END()