Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
skiplist_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 <gsl/gsl_rng.h>
40#include <climits>
41#include <vector>
42#include <algorithm>
43#include <string>
44#include <tpl_skipList.H>
45
46using namespace Aleph;
47
48// Specialize computeMaxKey for int
49template<>
51{
52 return INT_MAX;
53}
54
55// Specialize computeMaxKey for std::string keys
56template<>
58{
59 return std::string(256, '\xFF'); // Max string
60}
61
62namespace {
63
64// Fixed seed for reproducible tests
65constexpr unsigned long TEST_SEED = 42;
66
67// Helper to allocate a SkipList node with proper size
68template <class Key, class Type>
69typename SkipList<Key, Type>::Node* allocate_node(const Key& key, const Type& data, int level)
70{
71 // Node uses flexible array member, need extra space for forward pointers
72 size_t size = sizeof(typename SkipList<Key, Type>::Node) +
73 sizeof(typename SkipList<Key, Type>::Node*) * level;
74 void* mem = ::operator new(size);
75 return new (mem) typename SkipList<Key, Type>::Node(key, data, level);
76}
77
78template <class Key, class Type>
80{
81 if (node)
82 {
83 node->~Node();
84 ::operator delete(node);
85 }
86}
87
88// Test fixture
89class SkipListTest : public ::testing::Test
90{
91protected:
92 using SL = SkipList<int, int>;
93
94 SL* skiplist = nullptr;
95 std::vector<SL::Node*> allocated_nodes;
96
97 void SetUp() override
98 {
99 skiplist = new SL(TEST_SEED, 0.5);
100 }
101
102 void TearDown() override
103 {
104 // Clean up all allocated nodes
105 for (auto* node : allocated_nodes)
106 deallocate_node<int, int>(node);
107 allocated_nodes.clear();
108
109 delete skiplist;
110 }
111
112 SL::Node* create_node(int key, int data = 0)
113 {
114 int level = skiplist->generateRandomLevel();
115 auto* node = allocate_node<int, int>(key, data, level);
116 allocated_nodes.push_back(node);
117 return node;
118 }
119
120 SL::Node* create_node_with_level(int key, int data, int level)
121 {
122 auto* node = allocate_node<int, int>(key, data, level);
123 allocated_nodes.push_back(node);
124 return node;
125 }
126};
127
128// ============================================================================
129// Construction Tests
130// ============================================================================
131
132TEST_F(SkipListTest, ConstructorDefault)
133{
134 EXPECT_TRUE(skiplist->checkSkipList());
135}
136
138{
140 EXPECT_TRUE(sl.checkSkipList());
141}
142
144{
145 SkipList<int, int> sl; // Uses time-based seed
147}
148
149TEST_F(SkipListTest, SetSeed)
150{
151 skiplist->set_seed(123);
152 int level1 = skiplist->generateRandomLevel();
153 skiplist->set_seed(123);
154 int level2 = skiplist->generateRandomLevel();
155 EXPECT_EQ(level1, level2); // Same seed should give same result
156}
157
158TEST_F(SkipListTest, GslRngObject)
159{
160 gsl_rng* rng = skiplist->gsl_rng_object();
161 EXPECT_NE(rng, nullptr);
162}
163
164// ============================================================================
165// Insert Tests
166// ============================================================================
167
168TEST_F(SkipListTest, InsertSingleElement)
169{
170 auto* node = create_node(42, 100);
171 skiplist->insert(node);
172
173 EXPECT_TRUE(skiplist->checkSkipList());
174 EXPECT_EQ(skiplist->get_first(), node);
175}
176
178{
179 for (int i = 1; i <= 10; ++i)
180 {
181 auto* node = create_node(i, i * 10);
182 skiplist->insert(node);
183 }
184
185 EXPECT_TRUE(skiplist->checkSkipList());
186
187 // Verify first element
188 auto* first = skiplist->get_first();
189 ASSERT_NE(first, nullptr);
190 EXPECT_EQ(first->get_key(), 1);
191}
192
194{
195 for (int i = 10; i >= 1; --i)
196 {
197 auto* node = create_node(i, i * 10);
198 skiplist->insert(node);
199 }
200
201 EXPECT_TRUE(skiplist->checkSkipList());
202
203 // Verify first element is smallest
204 auto* first = skiplist->get_first();
205 ASSERT_NE(first, nullptr);
206 EXPECT_EQ(first->get_key(), 1);
207}
208
210{
211 std::vector<int> keys = {5, 2, 8, 1, 9, 3, 7, 4, 6, 10};
212
213 for (int key : keys)
214 {
215 auto* node = create_node(key, key * 10);
216 skiplist->insert(node);
217 }
218
219 EXPECT_TRUE(skiplist->checkSkipList());
220
221 // Verify order by traversing
222 auto* current = skiplist->get_first();
223 int expected = 1;
224 while (current != nullptr && current->get_key() < INT_MAX)
225 {
226 EXPECT_EQ(current->get_key(), expected);
227 ++expected;
228 current = current->get_next();
229 }
230 EXPECT_EQ(expected, 11); // Should have seen 1-10
231}
232
233// ============================================================================
234// Search Tests
235// ============================================================================
236
237TEST_F(SkipListTest, SearchEmptyList)
238{
239 auto* result = skiplist->search(42);
240 EXPECT_EQ(result, nullptr);
241}
242
243TEST_F(SkipListTest, SearchExistingElement)
244{
245 auto* node = create_node(42, 100);
246 skiplist->insert(node);
247
248 auto* found = skiplist->search(42);
249 ASSERT_NE(found, nullptr);
250 EXPECT_EQ(found->get_key(), 42);
251 EXPECT_EQ(found->get_data(), 100);
252}
253
254TEST_F(SkipListTest, SearchNonExistingElement)
255{
256 auto* node = create_node(42, 100);
257 skiplist->insert(node);
258
259 EXPECT_EQ(skiplist->search(41), nullptr);
260 EXPECT_EQ(skiplist->search(43), nullptr);
261 EXPECT_EQ(skiplist->search(0), nullptr);
262 EXPECT_EQ(skiplist->search(100), nullptr);
263}
264
265TEST_F(SkipListTest, SearchMultipleElements)
266{
267 for (int i = 1; i <= 100; ++i)
268 {
269 auto* node = create_node(i * 2, i * 100); // Even keys only
270 skiplist->insert(node);
271 }
272
273 // Search for existing elements
274 for (int i = 1; i <= 100; ++i)
275 {
276 auto* found = skiplist->search(i * 2);
277 ASSERT_NE(found, nullptr) << "Key " << i * 2 << " not found";
278 EXPECT_EQ(found->get_key(), i * 2);
279 EXPECT_EQ(found->get_data(), i * 100);
280 }
281
282 // Search for non-existing elements (odd numbers)
283 for (int i = 1; i <= 100; ++i)
284 {
285 auto* found = skiplist->search(i * 2 - 1);
286 EXPECT_EQ(found, nullptr) << "Key " << i * 2 - 1 << " should not exist";
287 }
288}
289
290// ============================================================================
291// Remove Tests
292// ============================================================================
293
294TEST_F(SkipListTest, RemoveFromEmptyList)
295{
296 auto* result = skiplist->remove(42);
297 EXPECT_EQ(result, nullptr);
298}
299
300TEST_F(SkipListTest, RemoveSingleElement)
301{
302 auto* node = create_node(42, 100);
303 skiplist->insert(node);
304
305 auto* removed = skiplist->remove(42);
306 ASSERT_NE(removed, nullptr);
307 EXPECT_EQ(removed->get_key(), 42);
308 EXPECT_TRUE(skiplist->checkSkipList());
309
310 // Should not find it anymore
311 EXPECT_EQ(skiplist->search(42), nullptr);
312}
313
314TEST_F(SkipListTest, RemoveNonExistingElement)
315{
316 auto* node = create_node(42, 100);
317 skiplist->insert(node);
318
319 EXPECT_EQ(skiplist->remove(41), nullptr);
320 EXPECT_EQ(skiplist->remove(43), nullptr);
321
322 // Original should still exist
323 EXPECT_NE(skiplist->search(42), nullptr);
324}
325
326TEST_F(SkipListTest, RemoveFirstElement)
327{
328 for (int i = 1; i <= 5; ++i)
329 {
330 auto* node = create_node(i, i * 10);
331 skiplist->insert(node);
332 }
333
334 auto* removed = skiplist->remove(1);
335 ASSERT_NE(removed, nullptr);
336 EXPECT_EQ(removed->get_key(), 1);
337 EXPECT_TRUE(skiplist->checkSkipList());
338
339 // New first should be 2
340 auto* first = skiplist->get_first();
341 ASSERT_NE(first, nullptr);
342 EXPECT_EQ(first->get_key(), 2);
343}
344
345TEST_F(SkipListTest, RemoveLastElement)
346{
347 for (int i = 1; i <= 5; ++i)
348 {
349 auto* node = create_node(i, i * 10);
350 skiplist->insert(node);
351 }
352
353 auto* removed = skiplist->remove(5);
354 ASSERT_NE(removed, nullptr);
355 EXPECT_EQ(removed->get_key(), 5);
356 EXPECT_TRUE(skiplist->checkSkipList());
357
358 // 5 should not be found
359 EXPECT_EQ(skiplist->search(5), nullptr);
360}
361
362TEST_F(SkipListTest, RemoveMiddleElement)
363{
364 for (int i = 1; i <= 5; ++i)
365 {
366 auto* node = create_node(i, i * 10);
367 skiplist->insert(node);
368 }
369
370 auto* removed = skiplist->remove(3);
371 ASSERT_NE(removed, nullptr);
372 EXPECT_EQ(removed->get_key(), 3);
373 EXPECT_TRUE(skiplist->checkSkipList());
374
375 // 3 should not be found, but 2 and 4 should
376 EXPECT_EQ(skiplist->search(3), nullptr);
377 EXPECT_NE(skiplist->search(2), nullptr);
378 EXPECT_NE(skiplist->search(4), nullptr);
379}
380
381TEST_F(SkipListTest, RemoveAllElements)
382{
383 for (int i = 1; i <= 10; ++i)
384 {
385 auto* node = create_node(i, i * 10);
386 skiplist->insert(node);
387 }
388
389 // Remove in random order
390 std::vector<int> order = {5, 1, 9, 3, 7, 2, 8, 4, 6, 10};
391 for (int key : order)
392 {
393 auto* removed = skiplist->remove(key);
394 ASSERT_NE(removed, nullptr) << "Failed to remove key " << key;
395 EXPECT_TRUE(skiplist->checkSkipList());
396 }
397}
398
399// ============================================================================
400// Level Generation Tests
401// ============================================================================
402
404{
405 constexpr int max_level = 32; // Same as SL::maxLevel
406 for (int i = 0; i < 1000; ++i)
407 {
408 int level = skiplist->generateRandomLevel();
409 EXPECT_GE(level, 1);
411 }
412}
413
415{
416 // With p=0.5, about 50% should be level 1, 25% level 2, etc.
417 constexpr int max_level = 32; // Same as SL::maxLevel
418 std::vector<int> counts(max_level + 1, 0);
419 const int trials = 10000;
420
421 for (int i = 0; i < trials; ++i)
422 {
423 int level = skiplist->generateRandomLevel();
424 counts[level]++;
425 }
426
427 // Level 1 should be most common (roughly 50%)
428 EXPECT_GT(counts[1], trials * 0.4); // At least 40%
429 EXPECT_LT(counts[1], trials * 0.6); // At most 60%
430
431 // Level 2 should be about half of level 1
432 double ratio = static_cast<double>(counts[2]) / counts[1];
433 EXPECT_GT(ratio, 0.35);
434 EXPECT_LT(ratio, 0.65);
435}
436
437// ============================================================================
438// Node Tests
439// ============================================================================
440
441TEST_F(SkipListTest, NodeGettersSetters)
442{
443 auto* node = create_node_with_level(42, 100, 5);
444
445 EXPECT_EQ(node->get_key(), 42);
446 EXPECT_EQ(node->get_data(), 100);
447 EXPECT_EQ(node->getLevel(), 5);
448
449 // Modify data
450 node->get_data() = 200;
451 EXPECT_EQ(node->get_data(), 200);
452}
453
454// ============================================================================
455// Integration Tests
456// ============================================================================
457
458TEST_F(SkipListTest, InterleavedInsertRemove)
459{
460 // Insert some elements
461 for (int i = 1; i <= 5; ++i)
462 {
463 auto* node = create_node(i, i);
464 skiplist->insert(node);
465 }
466
467 // Remove even, insert more
468 (void)skiplist->remove(2);
469 (void)skiplist->remove(4);
470
471 auto* node6 = create_node(6, 6);
472 auto* node7 = create_node(7, 7);
473 skiplist->insert(node6);
474 skiplist->insert(node7);
475
476 EXPECT_TRUE(skiplist->checkSkipList());
477
478 // Check expected state
479 EXPECT_NE(skiplist->search(1), nullptr);
480 EXPECT_EQ(skiplist->search(2), nullptr);
481 EXPECT_NE(skiplist->search(3), nullptr);
482 EXPECT_EQ(skiplist->search(4), nullptr);
483 EXPECT_NE(skiplist->search(5), nullptr);
484 EXPECT_NE(skiplist->search(6), nullptr);
485 EXPECT_NE(skiplist->search(7), nullptr);
486}
487
488TEST_F(SkipListTest, LargeScale)
489{
490 const int N = 1000;
491
492 // Insert N elements
493 for (int i = 0; i < N; ++i)
494 {
495 auto* node = create_node(i, i * 10);
496 skiplist->insert(node);
497 }
498
499 EXPECT_TRUE(skiplist->checkSkipList());
500
501 // Search all
502 for (int i = 0; i < N; ++i)
503 {
504 auto* found = skiplist->search(i);
505 ASSERT_NE(found, nullptr) << "Key " << i << " not found";
506 }
507
508 // Remove half (even numbers)
509 for (int i = 0; i < N; i += 2)
510 {
511 auto* removed = skiplist->remove(i);
512 ASSERT_NE(removed, nullptr) << "Failed to remove key " << i;
513 }
514
515 EXPECT_TRUE(skiplist->checkSkipList());
516
517 // Verify remaining
518 for (int i = 0; i < N; ++i)
519 {
520 auto* found = skiplist->search(i);
521 if (i % 2 == 0)
522 EXPECT_EQ(found, nullptr) << "Key " << i << " should have been removed";
523 else
524 EXPECT_NE(found, nullptr) << "Key " << i << " should still exist";
525 }
526}
527
528// ============================================================================
529// String Key Tests
530// ============================================================================
531
532class SkipListStringTest : public ::testing::Test
533{
534protected:
536
537 SL* skiplist = nullptr;
538 std::vector<SL::Node*> allocated_nodes;
539
540 void SetUp() override
541 {
542 skiplist = new SL(TEST_SEED, 0.5);
543 }
544
545 void TearDown() override
546 {
547 for (auto* node : allocated_nodes)
548 deallocate_node<std::string, int>(node);
549 allocated_nodes.clear();
550 delete skiplist;
551 }
552
553 SL::Node* create_node(const std::string& key, int data = 0)
554 {
555 int level = skiplist->generateRandomLevel();
556 auto* node = allocate_node<std::string, int>(key, data, level);
557 allocated_nodes.push_back(node);
558 return node;
559 }
560};
561
562TEST_F(SkipListStringTest, StringKeys)
563{
564 auto* node1 = create_node("apple", 1);
565 auto* node2 = create_node("banana", 2);
566 auto* node3 = create_node("cherry", 3);
567
568 skiplist->insert(node2);
569 skiplist->insert(node1);
570 skiplist->insert(node3);
571
572 EXPECT_TRUE(skiplist->checkSkipList());
573
574 // Should be in alphabetical order
575 auto* first = skiplist->get_first();
576 ASSERT_NE(first, nullptr);
577 EXPECT_EQ(first->get_key(), "apple");
578
579 // Search
580 auto* found = skiplist->search("banana");
581 ASSERT_NE(found, nullptr);
582 EXPECT_EQ(found->get_data(), 2);
583
584 EXPECT_EQ(skiplist->search("date"), nullptr);
585}
586
587// ============================================================================
588// Iterator Tests
589// ============================================================================
590
591TEST_F(SkipListTest, IteratorEmpty)
592{
593 SL::Iterator it(*skiplist);
594 EXPECT_FALSE(it.has_curr());
595 EXPECT_EQ(it.get_curr_ne(), nullptr);
596}
597
598TEST_F(SkipListTest, IteratorSingleElement)
599{
600 auto* node = create_node(42, 100);
601 skiplist->insert(node);
602
603 SL::Iterator it(*skiplist);
604 ASSERT_TRUE(it.has_curr());
605 EXPECT_EQ(it.get_curr(), node);
606 EXPECT_EQ(it.get_key(), 42);
607 EXPECT_EQ(it.get_data(), 100);
608 EXPECT_TRUE(it.is_last());
609
610 it.next();
611 EXPECT_FALSE(it.has_curr());
612}
613
614TEST_F(SkipListTest, IteratorMultipleElements)
615{
616 for (int i = 1; i <= 5; ++i)
617 {
618 auto* node = create_node(i, i * 10);
619 skiplist->insert(node);
620 }
621
622 // Count elements via iterator
623 int count = 0;
624 int expected_key = 1;
625 for (SL::Iterator it(*skiplist); it.has_curr(); it.next())
626 {
627 EXPECT_EQ(it.get_key(), expected_key);
628 EXPECT_EQ(it.get_data(), expected_key * 10);
629 ++expected_key;
630 ++count;
631 }
632 EXPECT_EQ(count, 5);
633}
634
635TEST_F(SkipListTest, IteratorRangeBasedFor)
636{
637 for (int i = 1; i <= 5; ++i)
638 {
639 auto* node = create_node(i, i * 10);
640 skiplist->insert(node);
641 }
642
643 // Use range-based for with begin()/end()
644 int count = 0;
645 int expected_key = 1;
646 for (auto it = skiplist->begin(); it != skiplist->end(); ++it)
647 {
648 EXPECT_EQ((*it)->get_key(), expected_key);
649 ++expected_key;
650 ++count;
651 }
652 EXPECT_EQ(count, 5);
653}
654
655TEST_F(SkipListTest, IteratorReset)
656{
657 for (int i = 1; i <= 3; ++i)
658 {
659 auto* node = create_node(i, i);
660 skiplist->insert(node);
661 }
662
663 SL::Iterator it(*skiplist);
664 EXPECT_EQ(it.get_key(), 1);
665
666 it.next();
667 EXPECT_EQ(it.get_key(), 2);
668
669 it.reset();
670 EXPECT_EQ(it.get_key(), 1);
671}
672
673TEST_F(SkipListTest, IteratorCopy)
674{
675 for (int i = 1; i <= 3; ++i)
676 {
677 auto* node = create_node(i, i);
678 skiplist->insert(node);
679 }
680
681 SL::Iterator it1(*skiplist);
682 it1.next(); // Now on key 2
683
684 SL::Iterator it2 = it1; // Copy
685 EXPECT_EQ(it2.get_key(), 2);
686
687 it1.next(); // it1 on key 3
688 EXPECT_EQ(it1.get_key(), 3);
689 EXPECT_EQ(it2.get_key(), 2); // it2 unchanged
690}
691
692TEST_F(SkipListTest, IteratorEquality)
693{
694 auto* node = create_node(42, 100);
695 skiplist->insert(node);
696
697 SL::Iterator it1(*skiplist);
698 SL::Iterator it2(*skiplist);
699
700 EXPECT_TRUE(it1 == it2);
701 EXPECT_FALSE(it1 != it2);
702
703 it1.next();
704 EXPECT_FALSE(it1 == it2);
705 EXPECT_TRUE(it1 != it2);
706}
707
708TEST_F(SkipListTest, IteratorOperators)
709{
710 for (int i = 1; i <= 3; ++i)
711 {
712 auto* node = create_node(i, i);
713 skiplist->insert(node);
714 }
715
716 SL::Iterator it(*skiplist);
717
718 // Pre-increment
719 EXPECT_EQ(it.get_key(), 1);
720 ++it;
721 EXPECT_EQ(it.get_key(), 2);
722
723 // Post-increment
724 SL::Iterator it2 = it++;
725 EXPECT_EQ(it2.get_key(), 2); // Old value
726 EXPECT_EQ(it.get_key(), 3); // New value
727}
728
729TEST_F(SkipListTest, IteratorThrowsOnOverflow)
730{
731 SL::Iterator it(*skiplist); // Empty list
732
733 EXPECT_THROW(it.get_curr(), std::overflow_error);
734 EXPECT_THROW(it.next(), std::overflow_error);
735
736 // No throw versions should not throw
737 EXPECT_NO_THROW(it.get_curr_ne());
738 EXPECT_NO_THROW(it.next_ne());
739}
740
741TEST_F(SkipListTest, IteratorLargeScale)
742{
743 const int N = 500;
744 for (int i = 0; i < N; ++i)
745 {
746 auto* node = create_node(i, i);
747 skiplist->insert(node);
748 }
749
750 int count = 0;
751 int expected = 0;
752 for (SL::Iterator it(*skiplist); it.has_curr(); it.next())
753 {
754 EXPECT_EQ(it.get_key(), expected);
755 ++expected;
756 ++count;
757 }
758 EXPECT_EQ(count, N);
759}
760
761} // anonymous namespace
762
763int main(int argc, char** argv)
764{
765 ::testing::InitGoogleTest(&argc, argv);
766 return RUN_ALL_TESTS();
767}
TEST_F(StaticArenaFixture, simple_fail)
Definition ah-arena.cc:59
int main()
T remove()
Remove the first item of the list.
Definition htlist.H:1611
const Key & get_key() const noexcept
int getLevel() const noexcept
const Type & get_data() const noexcept
Skip List - a probabilistic ordered data structure.
bool checkSkipList() const noexcept
Verify skip list invariants (for debugging).
static mt19937 rng
#define N
Definition fib.C:294
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
size_t size(Node *root) noexcept
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
STL namespace.
EepicNode * allocate_node(const string &str)
Definition ntreepic.C:550
Skip list: probabilistic sorted linked structure.