Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
dynmapohash_test.cc
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
33
38#include <gtest/gtest.h>
39#include <string>
40#include <vector>
41#include <tpl_dynMapOhash.H>
42
43using namespace Aleph;
44
45// =============================================================================
46// Test Fixtures
47// =============================================================================
48
49class MapODhashTest : public ::testing::Test
50{
51protected:
54
55 void SetUp() override
56 {
57 // Start with empty maps
58 }
59
61 {
62 map.insert("one", 1);
63 map.insert("two", 2);
64 map.insert("three", 3);
65 map.insert("four", 4);
66 map.insert("five", 5);
67 }
68
70 {
71 int_map.insert(1, "one");
72 int_map.insert(2, "two");
73 int_map.insert(3, "three");
74 }
75};
76
77class MapOLhashTest : public ::testing::Test
78{
79protected:
81
83 {
84 map.insert("alpha", 1);
85 map.insert("beta", 2);
86 map.insert("gamma", 3);
87 }
88};
89
90// =============================================================================
91// Construction Tests
92// =============================================================================
93
95{
96 EXPECT_EQ(map.size(), 0u);
97 EXPECT_TRUE(map.is_empty());
98}
99
101{
102 EXPECT_EQ(map.size(), 0u);
103 EXPECT_TRUE(map.is_empty());
104}
105
107{
108 MapODhash<int, int> map(101);
109 EXPECT_EQ(map.size(), 0u);
110}
111
125
138
139// =============================================================================
140// Insert Tests
141// =============================================================================
142
144{
145 std::string key = "test";
146 int value = 42;
147
148 auto * pair = map.insert(key, value);
149 ASSERT_NE(pair, nullptr);
150 EXPECT_EQ(pair->first, "test");
151 EXPECT_EQ(pair->second, 42);
152 EXPECT_EQ(map.size(), 1u);
153}
154
156{
157 std::string key = "moved";
158 std::string value = "hello_world";
159
160 auto * pair = int_map.insert(100, std::move(value));
161 ASSERT_NE(pair, nullptr);
162 EXPECT_EQ(pair->first, 100);
163 EXPECT_EQ(pair->second, "hello_world");
164}
165
167{
168 std::string key = "key";
169 int value = 99;
170
171 auto * pair = map.insert(std::move(key), std::move(value));
172 ASSERT_NE(pair, nullptr);
173 EXPECT_EQ(pair->first, "key");
174 EXPECT_EQ(pair->second, 99);
175}
176
178{
179 std::string key = "movekey";
180 int value = 77;
181
182 auto * pair = map.insert(std::move(key), value);
183 ASSERT_NE(pair, nullptr);
184 EXPECT_EQ(pair->first, "movekey");
185 EXPECT_EQ(pair->second, 77);
186}
187
189{
190 map.insert("dup", 1);
191 auto * pair = map.insert("dup", 2);
192 EXPECT_EQ(pair, nullptr);
193 EXPECT_EQ(map["dup"], 1); // Original value preserved
194}
195
197{
198 populate_map();
199 EXPECT_EQ(map.size(), 5u);
200 EXPECT_TRUE(map.has("one"));
201 EXPECT_TRUE(map.has("five"));
202}
203
204// =============================================================================
205// Search Tests
206// =============================================================================
207
209{
210 populate_map();
211
212 auto * pair = map.search("three");
213 ASSERT_NE(pair, nullptr);
214 EXPECT_EQ(pair->first, "three");
215 EXPECT_EQ(pair->second, 3);
216}
217
219{
220 populate_map();
221
222 auto * pair = map.search("nonexistent");
223 EXPECT_EQ(pair, nullptr);
224}
225
227{
228 populate_map();
229
230 std::string key = "two";
231 auto * pair = map.search(std::move(key));
232 ASSERT_NE(pair, nullptr);
233 EXPECT_EQ(pair->second, 2);
234}
235
237{
238 auto * pair = map.search("anything");
239 EXPECT_EQ(pair, nullptr);
240}
241
242// =============================================================================
243// Has/Contains Tests
244// =============================================================================
245
247{
248 populate_map();
249 EXPECT_TRUE(map.has("one"));
250 EXPECT_TRUE(map.has("five"));
251}
252
254{
255 populate_map();
256 EXPECT_FALSE(map.has("nonexistent"));
257 EXPECT_FALSE(map.has(""));
258}
259
261{
262 populate_map();
263 std::string key = "three";
264 EXPECT_TRUE(map.has(std::move(key)));
265}
266
268{
269 populate_map();
270 EXPECT_EQ(map.contains("one"), map.has("one"));
271 EXPECT_EQ(map.contains("nonexistent"), map.has("nonexistent"));
272}
273
275{
276 populate_map();
277 std::string key = "two";
278 EXPECT_TRUE(map.contains(std::move(key)));
279}
280
281// =============================================================================
282// Find Tests
283// =============================================================================
284
286{
287 populate_map();
288
289 int & value = map.find("three");
290 EXPECT_EQ(value, 3);
291}
292
294{
295 populate_map();
296
297 map.find("two") = 22;
298 EXPECT_EQ(map.find("two"), 22);
299}
300
302{
303 populate_map();
304 EXPECT_THROW((void)map.find("nonexistent"), std::domain_error);
305}
306
308{
309 populate_map();
310 std::string key = "four";
311 EXPECT_EQ(map.find(std::move(key)), 4);
312}
313
315{
316 populate_map();
317 const auto & const_map = map;
318
319 const int & value = const_map.find("one");
320 EXPECT_EQ(value, 1);
321}
322
324{
325 populate_map();
326 const auto & const_map = map;
327
328 EXPECT_THROW((void)const_map.find("missing"), std::domain_error);
329}
330
331// =============================================================================
332// Operator[] Tests
333// =============================================================================
334
336{
337 populate_map();
338 EXPECT_EQ(map["one"], 1);
339 EXPECT_EQ(map["five"], 5);
340}
341
343{
344 map["new_key"] = 100;
345 EXPECT_TRUE(map.has("new_key"));
346 EXPECT_EQ(map["new_key"], 100);
347}
348
350{
351 int & value = map["defaulted"];
352 EXPECT_EQ(value, 0); // Default-initialized int
353 value = 42;
354 EXPECT_EQ(map["defaulted"], 42);
355}
356
358{
359 std::string key = "moved_key";
360 map[std::move(key)] = 55;
361 EXPECT_EQ(map["moved_key"], 55);
362}
363
365{
366 populate_map();
367 const auto & const_map = map;
368
369 EXPECT_EQ(const_map["two"], 2);
370}
371
373{
374 populate_map();
375 const auto & const_map = map;
376
377 EXPECT_THROW((void)const_map["missing"], std::domain_error);
378}
379
380// =============================================================================
381// Remove Tests
382// =============================================================================
383
385{
386 populate_map();
387 size_t original_size = map.size();
388
389 map.remove("three");
390
391 EXPECT_EQ(map.size(), original_size - 1);
392 EXPECT_FALSE(map.has("three"));
393}
394
396{
397 populate_map();
398 EXPECT_THROW(map.remove("nonexistent"), std::domain_error);
399}
400
402{
403 populate_map();
404 std::string key = "two";
405
406 map.remove(std::move(key));
407 EXPECT_FALSE(map.has("two"));
408}
409
411{
412 populate_map();
413
414 map.remove("one");
415 map.remove("two");
416 map.remove("three");
417 map.remove("four");
418 map.remove("five");
419
420 EXPECT_EQ(map.size(), 0u);
421 EXPECT_TRUE(map.is_empty());
422}
423
425{
426 populate_map();
427 auto * pair = map.search("three");
428 ASSERT_NE(pair, nullptr);
429
430 map.remove_by_data(pair->second);
431 EXPECT_FALSE(map.has("three"));
432}
433
434// =============================================================================
435// Keys and Values Tests
436// =============================================================================
437
439{
440 populate_map();
441
442 auto key_list = map.keys();
443 EXPECT_EQ(key_list.size(), 5u);
444
445 // Check all expected keys are present
446 bool has_one = false, has_two = false, has_three = false;
447 bool has_four = false, has_five = false;
448
449 key_list.traverse([&](const std::string & k) {
450 if (k == "one") has_one = true;
451 else if (k == "two") has_two = true;
452 else if (k == "three") has_three = true;
453 else if (k == "four") has_four = true;
454 else if (k == "five") has_five = true;
455 return true;
456 });
457
463}
464
466{
467 populate_map();
468
469 auto value_list = map.values();
471
472 // Sum should be 1+2+3+4+5 = 15
473 int sum = 0;
474 value_list.traverse([&sum](int v) {
475 sum += v;
476 return true;
477 });
478 EXPECT_EQ(sum, 15);
479}
480
482{
483 populate_map();
484
485 auto ptr_list = map.values_ptr();
486 EXPECT_EQ(ptr_list.size(), 5u);
487
488 // Modify through pointers
489 ptr_list.traverse([](int * p) {
490 *p *= 10;
491 return true;
492 });
493
494 // Verify modifications
495 EXPECT_EQ(map["one"], 10);
496 EXPECT_EQ(map["two"], 20);
497}
498
500{
501 populate_map();
502
503 auto ptr_list = map.items_ptr();
504 EXPECT_EQ(ptr_list.size(), 5u);
505
506 // Verify we can access both key and value
507 ptr_list.traverse([](auto * pair) {
508 EXPECT_FALSE(pair->first.empty());
509 return true;
510 });
511}
512
514{
515 auto key_list = map.keys();
516 EXPECT_EQ(key_list.size(), 0u);
517}
518
520{
521 auto value_list = map.values();
523}
524
525// =============================================================================
526// Static Helper Function Tests
527// =============================================================================
528
530{
531 populate_map();
532 auto * pair = map.search("one");
533 ASSERT_NE(pair, nullptr);
534
537}
538
540{
541 populate_map();
542 auto * pair = map.search("two");
543 ASSERT_NE(pair, nullptr);
544
547 EXPECT_EQ(recovered_pair->first, "two");
548}
549
551{
552 populate_map();
553 auto * pair = map.search("three");
554 ASSERT_NE(pair, nullptr);
555
556 int & data = MapODhash<std::string, int>::get_data(pair->first);
557 EXPECT_EQ(data, 3);
558
559 // Modify through this reference
560 data = 333;
561 EXPECT_EQ(map["three"], 333);
562}
563
565{
566 populate_map();
567 auto * pair = map.search("four");
568 ASSERT_NE(pair, nullptr);
569
570 const std::string & key = MapODhash<std::string, int>::get_key(&pair->second);
571 EXPECT_EQ(key, "four");
572}
573
575{
576 populate_map();
577 const auto & const_map = map;
578 const auto * pair = const_map.search("one");
579 ASSERT_NE(pair, nullptr);
580
583}
584
586{
587 populate_map();
588 const auto & const_map = map;
589 const auto * pair = const_map.search("two");
590 ASSERT_NE(pair, nullptr);
591
594}
595
597{
598 populate_map();
599 const auto & const_map = map;
600 const auto * pair = const_map.search("three");
601 ASSERT_NE(pair, nullptr);
602
603 const int & data = MapODhash<std::string, int>::get_data(pair->first);
604 EXPECT_EQ(data, 3);
605}
606
608{
609 populate_map();
610 const auto & const_map = map;
611 const auto * pair = const_map.search("four");
612 ASSERT_NE(pair, nullptr);
613
614 const std::string & key = MapODhash<std::string, int>::get_key(&pair->second);
615 EXPECT_EQ(key, "four");
616}
617
618// =============================================================================
619// Iterator Tests
620// =============================================================================
621
623{
624 populate_map();
625
626 size_t count = 0;
627 for (MapODhash<std::string, int>::Iterator it(map); it.has_curr(); it.next_ne())
628 {
629 auto & pair = it.get_curr();
630 EXPECT_FALSE(pair.first.empty());
631 ++count;
632 }
633
634 EXPECT_EQ(count, 5u);
635}
636
642
644{
645 populate_map();
646
647 int sum = 0;
648 map.traverse([&sum](const auto & pair) {
649 sum += pair.second;
650 return true;
651 });
652
653 EXPECT_EQ(sum, 15);
654}
655
657{
658 populate_map();
659
660 int count = 0;
661 bool result = map.traverse([&count](const auto &) {
662 ++count;
663 return count < 3; // Stop after 3 elements
664 });
665
666 EXPECT_FALSE(result); // Stopped early
667 EXPECT_EQ(count, 3);
668}
669
670// =============================================================================
671// MapOLhash Specific Tests
672// =============================================================================
673
675{
676 populate_map();
677
678 EXPECT_TRUE(map.has("alpha"));
679 EXPECT_TRUE(map.has("beta"));
680 EXPECT_TRUE(map.has("gamma"));
681 EXPECT_EQ(map.size(), 3u);
682}
683
685{
686 map.insert("test", 42);
687 auto * pair = map.search("test");
688 ASSERT_NE(pair, nullptr);
689 EXPECT_EQ(pair->second, 42);
690}
691
693{
694 populate_map();
695 map.remove("beta");
696
697 EXPECT_FALSE(map.has("beta"));
698 EXPECT_TRUE(map.has("alpha"));
699 EXPECT_TRUE(map.has("gamma"));
700}
701
702// =============================================================================
703// Large Scale Tests
704// =============================================================================
705
707{
709
710 constexpr int N = 10000;
711 for (int i = 0; i < N; ++i)
712 map.insert(i, i * 2);
713
714 EXPECT_EQ(map.size(), static_cast<size_t>(N));
715
716 // Verify all elements
717 for (int i = 0; i < N; ++i)
718 {
719 ASSERT_TRUE(map.has(i)) << "Missing key: " << i;
720 EXPECT_EQ(map[i], i * 2);
721 }
722}
723
725{
727
728 constexpr int N = 1000;
729 for (int i = 0; i < N; ++i)
730 map.insert(i, i);
731
732 // Remove even numbers
733 for (int i = 0; i < N; i += 2)
734 map.remove(i);
735
736 EXPECT_EQ(map.size(), static_cast<size_t>(N / 2));
737
738 // Verify only odd numbers remain
739 for (int i = 0; i < N; ++i)
740 {
741 if (i % 2 == 0)
742 EXPECT_FALSE(map.has(i));
743 else
744 EXPECT_TRUE(map.has(i));
745 }
746}
747
749{
751
752 for (int i = 0; i < 500; ++i)
753 {
754 map.insert(i, i);
755 if (i > 100)
756 map.remove(i - 100);
757 }
758
759 // Remaining keys are 0 plus the last 100 inserted keys (400-499).
760 EXPECT_EQ(map.size(), 101u);
761 EXPECT_TRUE(map.has(0));
762 for (int i = 400; i < 500; ++i)
763 EXPECT_TRUE(map.has(i));
764}
765
766// =============================================================================
767// Edge Cases
768// =============================================================================
769
771{
772 map.insert("", 0);
773 EXPECT_TRUE(map.has(""));
774 EXPECT_EQ(map[""], 0);
775}
776
778{
779 map.insert("neg", -100);
780 EXPECT_EQ(map["neg"], -100);
781}
782
784{
786 map.insert(0, "zero");
787 EXPECT_TRUE(map.has(0));
788 EXPECT_EQ(map[0], "zero");
789}
790
792{
794 map.insert(-5, 50);
795 map.insert(-100, 1000);
796
797 EXPECT_TRUE(map.has(-5));
798 EXPECT_TRUE(map.has(-100));
799 EXPECT_EQ(map[-5], 50);
800 EXPECT_EQ(map[-100], 1000);
801}
802
803// =============================================================================
804// Assignment Operators
805// =============================================================================
806
808{
810 original.insert("a", 1);
811 original.insert("b", 2);
812
814 copy.insert("x", 100); // Some existing content
815
816 copy = original;
817
818 EXPECT_EQ(copy.size(), 2u);
819 EXPECT_TRUE(copy.has("a"));
820 EXPECT_TRUE(copy.has("b"));
821 EXPECT_FALSE(copy.has("x")); // Old content gone
822}
823
825{
827 original.insert("m", 10);
828 original.insert("n", 20);
829
831 target = std::move(original);
832
833 EXPECT_EQ(target.size(), 2u);
834 EXPECT_TRUE(target.has("m"));
835 EXPECT_TRUE(target.has("n"));
836}
837
839{
841 map.insert("self", 42);
842
843 map = map; // Self-assignment
844
845 EXPECT_EQ(map.size(), 1u);
846 EXPECT_EQ(map["self"], 42);
847}
848
849// =============================================================================
850// Type Alias Tests
851// =============================================================================
852
854{
855 // Verify type aliases exist and are correct
856 static_assert(std::is_same_v<MapODhash<std::string, int>::Key_Type, std::string>);
857 static_assert(std::is_same_v<MapODhash<std::string, int>::Data_Type, int>);
858 static_assert(std::is_same_v<MapODhash<std::string, int>::Value_Type, int>);
859 static_assert(std::is_same_v<MapODhash<std::string, int>::Item_Type,
860 std::pair<std::string, int>>);
861}
862
863// =============================================================================
864// Comparison with Linear Probing
865// =============================================================================
866
868{
871
872 // Insert same data
873 for (int i = 0; i < 100; ++i)
874 {
875 std::string val = std::to_string(i * 10);
876 od_map.insert(i, val);
877 ol_map.insert(i, val);
878 }
879
881
882 // Verify same content
883 for (int i = 0; i < 100; ++i)
884 {
885 EXPECT_TRUE(od_map.has(i));
886 EXPECT_TRUE(ol_map.has(i));
887 EXPECT_EQ(od_map[i], ol_map[i]);
888 }
889}
890
891// =============================================================================
892// Functional Methods (inherited)
893// =============================================================================
894
896{
897 populate_map();
898
899 auto filtered = map.filter([](const auto & pair) {
900 return pair.second > 2;
901 });
902
903 EXPECT_EQ(filtered.size(), 3u); // three, four, five
904}
905
907{
908 populate_map();
909
910 auto doubled = map.template maps<int>([](const auto & pair) {
911 return pair.second * 2;
912 });
913
914 int sum = 0;
915 doubled.traverse([&sum](int v) {
916 sum += v;
917 return true;
918 });
919
920 EXPECT_EQ(sum, 30); // (1+2+3+4+5) * 2 = 30
921}
922
924{
925 populate_map();
926
927 int sum = map.template foldl<int>(0, [](int acc, const auto & pair) {
928 return acc + pair.second;
929 });
930
931 EXPECT_EQ(sum, 15);
932}
933
935{
936 populate_map();
937
938 bool all_positive = map.all([](const auto & pair) {
939 return pair.second > 0;
940 });
941
943
944 map["zero"] = 0;
945
946 all_positive = map.all([](const auto & pair) {
947 return pair.second > 0;
948 });
949
951}
952
954{
955 populate_map();
956
957 bool has_three = map.exists([](const auto & pair) {
958 return pair.second == 3;
959 });
960
962
963 bool has_ten = map.exists([](const auto & pair) {
964 return pair.second == 10;
965 });
966
968}
969
970// =============================================================================
971// Main
972// =============================================================================
973
974int main(int argc, char ** argv)
975{
976 ::testing::InitGoogleTest(&argc, argv);
977 return RUN_ALL_TESTS();
978}
int main()
T & insert(const T &item)
Insert a new item by copy.
Definition htlist.H:1502
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1319
Aleph::DynList< T > filter(Operation &operation) const
Filter the elements of a container according to a matching criteria.
Definition ah-dry.H:1135
bool exists(Operation &op) const
Test for existence in the container of an element satisfying a criteria.
Definition ah-dry.H:846
bool all(Operation &operation) const
Check if all the elements of container satisfy a condition.
Definition ah-dry.H:816
void SetUp() override
MapODhash< std::string, int > map
MapODhash< int, std::string > int_map
MapOLhash< std::string, int > map
#define TEST(name)
TEST_F(MapODhashTest, DefaultConstruction)
#define N
Definition fib.C:294
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
Itor2 copy(Itor1 sourceBeg, const Itor1 &sourceEnd, Itor2 destBeg)
Copy elements from one range to another.
Definition ahAlgo.H:584
std::pair< First, Second > pair
Alias to std::pair kept for backwards compatibility.
Definition ahPair.H:89
DynList< T > maps(const C &c, Op op)
Classic map operation.
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Definition ahAlgo.H:127
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
Open addressing hash map using double hashing.
Open addressing hash map using linear probing.
void remove(const Key &key)
Remove an entry by key.
bool has(const Key &key) const noexcept
Check if a key exists in the map.
Pair * insert(const Key &key, const Data &data)
Insert a key-value pair (copy semantics).
Aleph::DynList< T > keys() const
Definition ah-dry.H:1516
bool traverse(Operation &operation) noexcept(traverse_is_noexcept< Operation >())
Traverse the container via its iterator and performs a conditioned operation on each item.
Definition ah-dry.H:95
Dynamic map with open hashing.