Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_dynSkipList.H
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
67# ifndef TPL_DYNSKIPLIST_H
68# define TPL_DYNSKIPLIST_H
69
70# include <climits>
71# include <ctime>
72# include <utility>
73# include <initializer_list>
74# include <gsl/gsl_rng.h>
75# include <ah-errors.H>
76# include <ah-args-ctor.H>
77# include <ahDry.H>
78# include <ahFunctional.H>
79# include <ahIterator.H>
80# include <ah-iterator.H>
81# include <ah-dry.H>
82
83namespace Aleph {
84
110template <typename Key, class Compare = std::less<Key>>
112 : public GenericTraverse<DynSkipList<Key, Compare>>,
113 public SpecialCtors<DynSkipList<Key, Compare>, Key>,
114 public LocateFunctions<DynSkipList<Key, Compare>, Key>,
115 public FunctionalMethods<DynSkipList<Key, Compare>, Key>,
116 public GenericItems<DynSkipList<Key, Compare>, Key>,
117 public StlAlephIterator<DynSkipList<Key, Compare>>
118{
119public:
120
123
125 using Item_Type = Key;
126
128 using Key_Type = Key;
129
131 static constexpr int maxLevel = 32;
132
134 static constexpr double defaultProbability = 0.5;
135
136private:
137
139 struct Node
140 {
141 Key key;
142 int level;
144
145 Node(const Key & k, int lvl) : key(k), level(lvl)
146 {
147 forward = new Node*[lvl];
148 for (int i = 0; i < lvl; ++i)
149 forward[i] = nullptr;
150 }
151
152 Node(Key && k, int lvl) : key(std::move(k)), level(lvl)
153 {
154 forward = new Node*[lvl];
155 for (int i = 0; i < lvl; ++i)
156 forward[i] = nullptr;
157 }
158
159 // Dummy header node constructor
160 explicit Node(int lvl) : level(lvl)
161 {
162 forward = new Node*[lvl];
163 for (int i = 0; i < lvl; ++i)
164 forward[i] = nullptr;
165 }
166
168 {
169 delete[] forward;
170 }
171 };
172
174 gsl_rng * r; // GSL random number generator
175 size_t num_nodes = 0;
178 Compare cmp;
179
180 void init(unsigned long seed)
181 {
183 ah_bad_alloc_if(r == nullptr);
184 gsl_rng_set(r, seed % gsl_rng_max(r));
185 }
186
188 {
189 int lvl = 1;
191 ++lvl;
192 return lvl;
193 }
194
195 // Check if two keys are equal using the comparator
196 bool keys_equal(const Key & k1, const Key & k2) const noexcept
197 {
198 return not cmp(k1, k2) and not cmp(k2, k1);
199 }
200
201public:
202
204 void set_seed(unsigned long seed) noexcept { gsl_rng_set(r, seed); }
205
208
213 DynSkipList(unsigned long seed, double p = defaultProbability)
214 : r(nullptr), probability(p)
215 {
216 header = new Node(maxLevel);
217 init(seed);
218 }
219
223 explicit DynSkipList(double p = defaultProbability)
225 {
226 // Empty
227 }
228
230
233 : GenericTraverse<DynSkipList<Key, Compare>>(),
234 SpecialCtors<DynSkipList<Key, Compare>, Key>(),
235 LocateFunctions<DynSkipList<Key, Compare>, Key>(),
236 FunctionalMethods<DynSkipList<Key, Compare>, Key>(),
237 GenericItems<DynSkipList<Key, Compare>, Key>(),
238 StlAlephIterator<DynSkipList<Key, Compare>>(),
240 {
241 header = new Node(maxLevel);
242 init(time(nullptr)); // New GSL RNG for the copy
243 for (auto it = other.begin(); it.has_curr(); it.next())
244 insert(it.get_curr());
245 }
246
249 : header(other.header),
250 r(other.r),
251 num_nodes(other.num_nodes),
252 current_level(other.current_level),
253 probability(other.probability),
254 cmp(std::move(other.cmp))
255 {
256 other.header = new Node(maxLevel);
257 other.r = nullptr;
258 other.num_nodes = 0;
259 other.current_level = 1;
260 }
261
264 {
265 empty();
266 delete header;
267 if (r != nullptr)
269 }
270
273 {
274 if (this == &other)
275 return *this;
276
277 empty();
278 probability = other.probability;
279 cmp = other.cmp;
280 // Keep our own GSL RNG
281
282 for (auto it = other.begin(); it.has_curr(); it.next())
283 insert(it.get_curr());
284
285 return *this;
286 }
287
290 {
291 if (this == &other)
292 return *this;
293
294 empty();
295 delete header;
296 if (r != nullptr)
298
299 header = other.header;
300 r = other.r;
301 num_nodes = other.num_nodes;
302 current_level = other.current_level;
303 probability = other.probability;
304 cmp = std::move(other.cmp);
305
306 other.header = new Node(maxLevel);
307 other.r = nullptr;
308 other.num_nodes = 0;
309 other.current_level = 1;
310
311 return *this;
312 }
313
315 void swap(DynSkipList & other) noexcept
316 {
317 std::swap(header, other.header);
318 std::swap(r, other.r);
319 std::swap(num_nodes, other.num_nodes);
320 std::swap(current_level, other.current_level);
321 std::swap(probability, other.probability);
322 std::swap(cmp, other.cmp);
323 }
324
329 {
330 Node * curr = header->forward[0];
331 while (curr != nullptr)
332 {
333 Node * next = curr->forward[0];
334 delete curr;
335 curr = next;
336 }
337 for (int i = 0; i < maxLevel; ++i)
338 header->forward[i] = nullptr;
339 num_nodes = 0;
340 current_level = 1;
341 }
342
344 void clear() noexcept { empty(); }
345
347 [[nodiscard]] size_t size() const noexcept { return num_nodes; }
348
350 [[nodiscard]] bool is_empty() const noexcept { return num_nodes == 0; }
351
353 Compare & get_compare() noexcept { return cmp; }
354
356 const Compare & get_compare() const noexcept { return cmp; }
357
366 Key * insert(const Key & key)
367 {
368 Node * update[maxLevel];
369 Node * x = header;
370
371 // Find position
372 for (int i = current_level - 1; i >= 0; --i)
373 {
374 while (x->forward[i] != nullptr and cmp(x->forward[i]->key, key))
375 x = x->forward[i];
376 update[i] = x;
377 }
378
379 x = x->forward[0];
380
381 // Key already exists?
382 if (x != nullptr and keys_equal(x->key, key))
383 return nullptr;
384
385 int lvl = random_level();
386
387 if (lvl > current_level)
388 {
389 for (int i = current_level; i < lvl; ++i)
390 update[i] = header;
392 }
393
394 Node * new_node = new Node(key, lvl);
395
396 for (int i = 0; i < lvl; ++i)
397 {
398 new_node->forward[i] = update[i]->forward[i];
399 update[i]->forward[i] = new_node;
400 }
401
402 ++num_nodes;
403 return &new_node->key;
404 }
405
412 Key * insert(Key && key)
413 {
414 Node * update[maxLevel];
415 Node * x = header;
416
417 for (int i = current_level - 1; i >= 0; --i)
418 {
419 while (x->forward[i] != nullptr and cmp(x->forward[i]->key, key))
420 x = x->forward[i];
421 update[i] = x;
422 }
423
424 x = x->forward[0];
425
426 if (x != nullptr and keys_equal(x->key, key))
427 return nullptr;
428
429 int lvl = random_level();
430
431 if (lvl > current_level)
432 {
433 for (int i = current_level; i < lvl; ++i)
434 update[i] = header;
436 }
437
438 Node * new_node = new Node(std::move(key), lvl);
439
440 for (int i = 0; i < lvl; ++i)
441 {
442 new_node->forward[i] = update[i]->forward[i];
443 update[i]->forward[i] = new_node;
444 }
445
446 ++num_nodes;
447 return &new_node->key;
448 }
449
457 Key & insert_unique(const Key & key)
458 {
459 Key * ptr = insert(key);
460 ah_domain_error_if(ptr == nullptr)
461 << "DynSkipList::insert_unique: key already exists";
462 return *ptr;
463 }
464
466 Key & append(const Key & key)
467 {
468 Key * ptr = insert(key);
469 if (ptr == nullptr)
470 return *search(key); // Return existing if duplicate
471 return *ptr;
472 }
473
474 Key & append(Key && key)
475 {
476 Key * ptr = insert(std::move(key));
477 if (ptr == nullptr)
478 {
479 // Key was moved but duplicate, need to search again
480 // This is a limitation - we've moved the key
481 ah_domain_error_if(true) << "append: duplicate key after move";
482 }
483 return *ptr;
484 }
485
491 Key * search_or_insert(const Key & key)
492 {
493 Key * existing = search(key);
494 if (existing != nullptr)
495 return existing;
496 return insert(key);
497 }
498
504 [[nodiscard]] Key * search(const Key & key) const noexcept
505 {
506 Node * x = header;
507
508 for (int i = current_level - 1; i >= 0; --i)
509 while (x->forward[i] != nullptr and cmp(x->forward[i]->key, key))
510 x = x->forward[i];
511
512 x = x->forward[0];
513
514 if (x != nullptr and keys_equal(x->key, key))
515 return const_cast<Key*>(&x->key);
516
517 return nullptr;
518 }
519
521 [[nodiscard]] bool has(const Key & key) const noexcept
522 {
523 return search(key) != nullptr;
524 }
525
527 [[nodiscard]] bool contains(const Key & key) const noexcept { return has(key); }
528
530 [[nodiscard]] bool exist(const Key & key) const noexcept { return has(key); }
531
538 [[nodiscard]] Key & find(const Key & key)
539 {
540 Key * ptr = search(key);
541 ah_domain_error_if(ptr == nullptr)
542 << "DynSkipList::find: key not found";
543 return *ptr;
544 }
545
547 [[nodiscard]] const Key & find(const Key & key) const
548 {
549 Key * ptr = search(key);
550 ah_domain_error_if(ptr == nullptr)
551 << "DynSkipList::find: key not found";
552 return *ptr;
553 }
554
560 size_t remove(const Key & key)
561 {
562 Node * update[maxLevel];
563 Node * x = header;
564
565 for (int i = current_level - 1; i >= 0; --i)
566 {
567 while (x->forward[i] != nullptr and cmp(x->forward[i]->key, key))
568 x = x->forward[i];
569 update[i] = x;
570 }
571
572 x = x->forward[0];
573
574 if (x == nullptr or not keys_equal(x->key, key))
575 return 0;
576
577 for (int i = 0; i < current_level; ++i)
578 {
579 if (update[i]->forward[i] != x)
580 break;
581 update[i]->forward[i] = x->forward[i];
582 }
583
584 delete x;
585
586 while (current_level > 1 and header->forward[current_level - 1] == nullptr)
588
589 --num_nodes;
590 return 1;
591 }
592
599 Key del(const Key & key)
600 {
601 Node * update[maxLevel];
602 Node * x = header;
603
604 for (int i = current_level - 1; i >= 0; --i)
605 {
606 while (x->forward[i] != nullptr and cmp(x->forward[i]->key, key))
607 x = x->forward[i];
608 update[i] = x;
609 }
610
611 x = x->forward[0];
612
613 ah_domain_error_if(x == nullptr or not keys_equal(x->key, key))
614 << "DynSkipList::del: key not found";
615
616 Key ret_val = std::move(x->key);
617
618 for (int i = 0; i < current_level; ++i)
619 {
620 if (update[i]->forward[i] != x)
621 break;
622 update[i]->forward[i] = x->forward[i];
623 }
624
625 delete x;
626
627 while (current_level > 1 and header->forward[current_level - 1] == nullptr)
629
630 --num_nodes;
631 return ret_val;
632 }
633
635 [[nodiscard]] const Key & min() const
636 {
637 ah_domain_error_if(is_empty()) << "DynSkipList::min: set is empty";
638 return header->forward[0]->key;
639 }
640
642 [[nodiscard]] const Key & get_first() const { return min(); }
643
645 [[nodiscard]] const Key & max() const
646 {
647 ah_domain_error_if(is_empty()) << "DynSkipList::max: set is empty";
648
649 Node * x = header->forward[0];
650 while (x->forward[0] != nullptr)
651 x = x->forward[0];
652 return x->key;
653 }
654
656 [[nodiscard]] const Key & get_last() const { return max(); }
657
658 // =========================================================================
659 // Set operations
660 // =========================================================================
661
668 {
669 DynSkipList result(*this);
670 for (auto it = other.begin(); it.has_curr(); it.next())
671 result.insert(it.get_curr());
672 return result;
673 }
674
681 {
682 DynSkipList result;
683 for (auto it = begin(); it.has_curr(); it.next())
684 if (other.has(it.get_curr()))
685 result.insert(it.get_curr());
686 return result;
687 }
688
695 {
696 DynSkipList result;
697 for (auto it = begin(); it.has_curr(); it.next())
698 if (not other.has(it.get_curr()))
699 result.insert(it.get_curr());
700 return result;
701 }
702
703 // =========================================================================
704 // Iterator
705 // =========================================================================
706
712 {
713 const DynSkipList * list_ptr = nullptr;
714 Node * curr = nullptr;
715
716 public:
718
720
722 : list_ptr(&list), curr(list.header->forward[0])
723 {}
724
725 [[nodiscard]] bool has_curr() const noexcept { return curr != nullptr; }
726
728 {
729 return curr != nullptr and curr->forward[0] == nullptr;
730 }
731
732 [[nodiscard]] const Key & get_curr() const
733 {
734 ah_overflow_error_if(curr == nullptr) << "DynSkipList::Iterator overflow";
735 return curr->key;
736 }
737
739 {
740 return curr->key;
741 }
742
743 Key & get_curr()
744 {
745 ah_overflow_error_if(curr == nullptr) << "DynSkipList::Iterator overflow";
746 return curr->key;
747 }
748
749 [[nodiscard]] const Key & get_key() const { return get_curr(); }
750
751 void next()
752 {
753 ah_overflow_error_if(curr == nullptr) << "DynSkipList::Iterator::next overflow";
754 next_ne();
755 }
756
758 {
759 if (curr != nullptr)
760 curr = curr->forward[0];
761 }
762
764 {
765 if (list_ptr != nullptr)
767 }
768
770
771 Iterator & operator=(const Iterator &) noexcept = default;
772
773 [[nodiscard]] bool operator==(const Iterator & it) const noexcept
774 {
775 return curr == it.curr;
776 }
777
778 [[nodiscard]] bool operator!=(const Iterator & it) const noexcept
779 {
780 return curr != it.curr;
781 }
782
784 {
785 next_ne();
786 return *this;
787 }
788
789 Iterator operator++(int) noexcept
790 {
791 Iterator ret = *this;
792 next_ne();
793 return ret;
794 }
795
796 [[nodiscard]] const Key & operator*() const { return get_curr(); }
797 [[nodiscard]] const Key * operator->() const { return &get_curr(); }
798 };
799
802
805
806 // =========================================================================
807 // Functional operations
808 // =========================================================================
809
810 template <class Operation>
811 bool traverse(Operation & op) const
812 {
813 for (auto it = begin(); it.has_curr(); it.next())
814 if (not op(it.get_curr()))
815 return false;
816 return true;
817 }
818
819 template <class Operation>
820 bool traverse(Operation && op = Operation()) const
821 {
822 return traverse<Operation>(op);
823 }
824
825 template <class Operation>
826 void for_each(Operation & op) const
827 {
828 for (auto it = begin(); it.has_curr(); it.next())
829 op(it.get_curr());
830 }
831
832 template <class Operation>
833 void for_each(Operation && op = Operation()) const
834 {
836 }
837
838 template <class Pred>
839 bool all(Pred & pred) const
840 {
841 for (auto it = begin(); it.has_curr(); it.next())
842 if (not pred(it.get_curr()))
843 return false;
844 return true;
845 }
846
847 template <class Pred>
848 bool all(Pred && pred = Pred()) const
849 {
850 return all<Pred>(pred);
851 }
852
853 template <class Pred>
854 bool exists(Pred & pred) const
855 {
856 for (auto it = begin(); it.has_curr(); it.next())
857 if (pred(it.get_curr()))
858 return true;
859 return false;
860 }
861
862 template <class Pred>
863 bool exists(Pred && pred = Pred()) const
864 {
865 return exists<Pred>(pred);
866 }
867
868 template <class Pred>
869 bool none(Pred & pred) const
870 {
871 return not exists(pred);
872 }
873
874 template <class Pred>
875 bool none(Pred && pred = Pred()) const
876 {
877 return none<Pred>(pred);
878 }
879
880 template <typename T>
881 T foldl(const T & init, std::function<T(const T &, const Key &)> op) const
882 {
883 T acc = init;
884 for (auto it = begin(); it.has_curr(); it.next())
885 acc = op(acc, it.get_curr());
886 return acc;
887 }
888
889 template <typename T, class Operation>
890 T foldl(const T & init, Operation & op) const
891 {
892 T acc = init;
893 for (auto it = begin(); it.has_curr(); it.next())
894 acc = op(acc, it.get_curr());
895 return acc;
896 }
897
898 template <typename T, class Operation>
899 T foldl(const T & init, Operation && op) const
900 {
901 return foldl<T, Operation>(init, op);
902 }
903};
904
905} // end namespace Aleph
906
907# endif // TPL_DYNSKIPLIST_H
Variadic constructor macros for containers.
Container traversal and functional operation mixins.
Exception handling system with formatted messages for Aleph-w.
#define ah_overflow_error_if(C)
Throws std::overflow_error if condition holds.
Definition ah-errors.H:463
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:522
#define ah_bad_alloc_if(C)
Throws std::bad_alloc if condition holds.
Definition ah-errors.H:429
STL-compatible iterator adapters for Aleph containers.
DRY (Don't Repeat Yourself) utilities and macros.
#define Special_Ctors(Set_Type, Type)
Generates special constructors for containers.
Definition ahDry.H:113
Functional programming utilities for Aleph-w containers.
Iterator traits and STL-compatible iterator wrappers.
Forward iterator for DynSkipList.
Iterator & operator=(const Iterator &) noexcept=default
bool operator!=(const Iterator &it) const noexcept
bool is_last() const noexcept
const Key * operator->() const
const Key & get_curr_ne() const noexcept
Iterator operator++(int) noexcept
Iterator() noexcept=default
bool operator==(const Iterator &it) const noexcept
const Key & operator*() const
bool has_curr() const noexcept
Iterator & operator++() noexcept
Dynamic ordered set implemented with a Skip List.
Key & append(const Key &key)
Append method for Special_Ctors compatibility (aliases to insert)
bool none(Pred &&pred=Pred()) const
Key * search_or_insert(const Key &key)
Search and insert if not found.
void set_seed(unsigned long seed) noexcept
Set the random number generator seed.
size_t remove(const Key &key)
Remove a key from the set.
void empty() noexcept
Remove all elements from the set.
void swap(DynSkipList &other) noexcept
Swap contents with another DynSkipList.
static constexpr int maxLevel
Maximum number of levels (supports up to 2^32 elements efficiently)
DynSkipList(const DynSkipList &other)
Copy constructor.
bool traverse(Operation &&op=Operation()) const
Iterator begin() const noexcept
DynSkipList(DynSkipList &&other) noexcept
Move constructor.
static constexpr double defaultProbability
Default probability for level generation (0.5 = geometric distribution)
bool exists(Pred &&pred=Pred()) const
bool exist(const Key &key) const noexcept
Alias for has()
void clear() noexcept
Alias for empty() for STL compatibility.
T foldl(const T &init, std::function< T(const T &, const Key &)> op) const
Key * insert(Key &&key)
Insert an element into the set (move version).
Key del(const Key &key)
Remove and return a key.
bool exists(Pred &pred) const
Key Item_Type
The type of element that stores the container.
Iterator get_it() const noexcept
Alias for begin() - for generic programming.
Key & append(Key &&key)
Compare & get_compare() noexcept
Get the comparison functor.
bool traverse(Operation &op) const
bool contains(const Key &key) const noexcept
Alias for has() for STL-like interface.
T foldl(const T &init, Operation &&op) const
DynSkipList(double p=defaultProbability)
Construct a DynSkipList with time-based seed.
DynSkipList & operator=(const DynSkipList &other)
Copy assignment operator.
DynSkipList & operator=(DynSkipList &&other) noexcept
Move assignment operator.
~DynSkipList()
Destructor - frees all nodes and GSL random number generator.
Key & find(const Key &key)
Find a key, throwing if not found.
void for_each(Operation &&op=Operation()) const
DynSkipList intersect(const DynSkipList &other) const
Compute the intersection of two sets.
bool all(Pred &&pred=Pred()) const
DynSkipList diff(const DynSkipList &other) const
Compute the difference of two sets.
gsl_rng * gsl_rng_object() noexcept
Get a pointer to the GSL random number generator.
const Key & min() const
Return the minimum element (first in sorted order)
const Compare & get_compare() const noexcept
Get the comparison functor (const version)
Key * insert(const Key &key)
Insert an element into the set.
Key & insert_unique(const Key &key)
Insert an element, throwing if it already exists.
DynSkipList join(const DynSkipList &other) const
Compute the union of two sets.
Iterator end() const noexcept
bool is_empty() const noexcept
Return true if the set is empty.
const Key & find(const Key &key) const
Const version of find()
size_t size() const noexcept
Return the number of elements in the set.
bool keys_equal(const Key &k1, const Key &k2) const noexcept
DynSkipList(unsigned long seed, double p=defaultProbability)
Construct a DynSkipList with given seed and probability.
bool all(Pred &pred) const
bool has(const Key &key) const noexcept
Return true if the key exists in the set.
const Key & get_first() const
Alias for min()
const Key & max() const
Return the maximum element (last in sorted order)
void for_each(Operation &op) const
Key * search(const Key &key) const noexcept
Search for a key in the set.
void init(unsigned long seed)
const Key & get_last() const
Alias for max()
int random_level() const noexcept
bool none(Pred &pred) const
T foldl(const T &init, Operation &op) const
Key Key_Type
The type of element that stores the container.
Common methods to the Aleph-w ( ) containers.
Definition ah-dry.H:548
Aleph::DynList< __T > maps(Operation &op) const
Map the elements of the container.
Definition ah-dry.H:904
Common sequential searching methods on containers.
Definition ah-dry.H:164
Mixin that adds STL begin()/end() and cbegin()/cend() to Aleph containers.
iterator begin() noexcept
Return an STL-compatible iterator to the first element.
Freq_Node * pred
Predecessor node in level-order traversal.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:107
static bool init
Definition hash-fct.C:47
void next()
Advance all underlying iterators (bounds-checked).
Definition ah-zip.H:175
STL namespace.
Internal node structure.
Node(const Key &k, int lvl)
Generic list of items stored in a container.
Definition ah-dry.H:1501
Generic traversal of the container through its iterator.
Definition ah-dry.H:65
Special constructors common to Aleph-w ( ) containers.
Definition ah-dry.H:492