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);
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
348 void clear() noexcept { empty(); }
349
351 [[nodiscard]] size_t size() const noexcept { return num_nodes; }
352
354 [[nodiscard]] bool is_empty() const noexcept { return num_nodes == 0; }
355
357 Compare & get_compare() noexcept { return cmp; }
358
360 const Compare & get_compare() const noexcept { return cmp; }
361
370 Key * insert(const Key & key)
371 {
372 Node * update[maxLevel];
373 Node * x = header;
374
375 // Find position
376 for (int i = current_level - 1; i >= 0; --i)
377 {
378 while (x->forward[i] != nullptr and cmp(x->forward[i]->key, key))
379 x = x->forward[i];
380 update[i] = x;
381 }
382
383 x = x->forward[0];
384
385 // Key already exists?
386 if (x != nullptr and keys_equal(x->key, key))
387 return nullptr;
388
389 int lvl = random_level();
390
391 if (lvl > current_level)
392 {
393 for (int i = current_level; i < lvl; ++i)
394 update[i] = header;
396 }
397
398 Node * new_node = new Node(key, lvl);
399
400 for (int i = 0; i < lvl; ++i)
401 {
402 new_node->forward[i] = update[i]->forward[i];
403 update[i]->forward[i] = new_node;
404 }
405
406 ++num_nodes;
407 return &new_node->key;
408 }
409
416 Key * insert(Key && key)
417 {
418 Node * update[maxLevel];
419 Node * x = header;
420
421 for (int i = current_level - 1; i >= 0; --i)
422 {
423 while (x->forward[i] != nullptr and cmp(x->forward[i]->key, key))
424 x = x->forward[i];
425 update[i] = x;
426 }
427
428 x = x->forward[0];
429
430 if (x != nullptr and keys_equal(x->key, key))
431 return nullptr;
432
433 int lvl = random_level();
434
435 if (lvl > current_level)
436 {
437 for (int i = current_level; i < lvl; ++i)
438 update[i] = header;
440 }
441
442 Node * new_node = new Node(std::move(key), lvl);
443
444 for (int i = 0; i < lvl; ++i)
445 {
446 new_node->forward[i] = update[i]->forward[i];
447 update[i]->forward[i] = new_node;
448 }
449
450 ++num_nodes;
451 return &new_node->key;
452 }
453
461 Key & insert_unique(const Key & key)
462 {
463 Key * ptr = insert(key);
464 ah_domain_error_if(ptr == nullptr)
465 << "DynSkipList::insert_unique: key already exists";
466 return *ptr;
467 }
468
470 Key & append(const Key & key)
471 {
472 Key * ptr = insert(key);
473 if (ptr == nullptr)
474 return *search(key); // Return existing if duplicate
475 return *ptr;
476 }
477
478 Key & append(Key && key)
479 {
480 Key * ptr = insert(std::move(key));
481 if (ptr == nullptr)
482 {
483 // Key was moved but duplicate, need to search again
484 // This is a limitation - we've moved the key
485 ah_domain_error_if(true) << "append: duplicate key after move";
486 }
487 return *ptr;
488 }
489
495 Key * search_or_insert(const Key & key)
496 {
497 Key * existing = search(key);
498 if (existing != nullptr)
499 return existing;
500 return insert(key);
501 }
502
508 [[nodiscard]] Key * search(const Key & key) const noexcept
509 {
510 Node * x = header;
511
512 for (int i = current_level - 1; i >= 0; --i)
513 while (x->forward[i] != nullptr and cmp(x->forward[i]->key, key))
514 x = x->forward[i];
515
516 x = x->forward[0];
517
518 if (x != nullptr and keys_equal(x->key, key))
519 return const_cast<Key*>(&x->key);
520
521 return nullptr;
522 }
523
525 [[nodiscard]] bool has(const Key & key) const noexcept
526 {
527 return search(key) != nullptr;
528 }
529
536 [[nodiscard]] bool contains(const Key & key) const noexcept { return has(key); }
537
539 [[nodiscard]] bool exist(const Key & key) const noexcept { return has(key); }
540
547 [[nodiscard]] Key & find(const Key & key)
548 {
549 Key * ptr = search(key);
550 ah_domain_error_if(ptr == nullptr)
551 << "DynSkipList::find: key not found";
552 return *ptr;
553 }
554
556 [[nodiscard]] const Key & find(const Key & key) const
557 {
558 Key * ptr = search(key);
559 ah_domain_error_if(ptr == nullptr)
560 << "DynSkipList::find: key not found";
561 return *ptr;
562 }
563
569 size_t remove(const Key & key)
570 {
571 Node * update[maxLevel];
572 Node * x = header;
573
574 for (int i = current_level - 1; i >= 0; --i)
575 {
576 while (x->forward[i] != nullptr and cmp(x->forward[i]->key, key))
577 x = x->forward[i];
578 update[i] = x;
579 }
580
581 x = x->forward[0];
582
583 if (x == nullptr or not keys_equal(x->key, key))
584 return 0;
585
586 for (int i = 0; i < current_level; ++i)
587 {
588 if (update[i]->forward[i] != x)
589 break;
590 update[i]->forward[i] = x->forward[i];
591 }
592
593 delete x;
594
595 while (current_level > 1 and header->forward[current_level - 1] == nullptr)
597
598 --num_nodes;
599 return 1;
600 }
601
608 Key del(const Key & key)
609 {
610 Node * update[maxLevel];
611 Node * x = header;
612
613 for (int i = current_level - 1; i >= 0; --i)
614 {
615 while (x->forward[i] != nullptr and cmp(x->forward[i]->key, key))
616 x = x->forward[i];
617 update[i] = x;
618 }
619
620 x = x->forward[0];
621
622 ah_domain_error_if(x == nullptr or not keys_equal(x->key, key))
623 << "DynSkipList::del: key not found";
624
625 Key ret_val = std::move(x->key);
626
627 for (int i = 0; i < current_level; ++i)
628 {
629 if (update[i]->forward[i] != x)
630 break;
631 update[i]->forward[i] = x->forward[i];
632 }
633
634 delete x;
635
636 while (current_level > 1 and header->forward[current_level - 1] == nullptr)
638
639 --num_nodes;
640 return ret_val;
641 }
642
644 [[nodiscard]] const Key & min() const
645 {
646 ah_domain_error_if(is_empty()) << "DynSkipList::min: set is empty";
647 return header->forward[0]->key;
648 }
649
651 [[nodiscard]] const Key & get_first() const { return min(); }
652
654 [[nodiscard]] const Key & max() const
655 {
656 ah_domain_error_if(is_empty()) << "DynSkipList::max: set is empty";
657
658 Node * x = header->forward[0];
659 while (x->forward[0] != nullptr)
660 x = x->forward[0];
661 return x->key;
662 }
663
665 [[nodiscard]] const Key & get_last() const { return max(); }
666
667 // =========================================================================
668 // Set operations
669 // =========================================================================
670
677 {
678 DynSkipList result(*this);
679 for (auto it = other.begin(); it.has_curr(); it.next())
680 result.insert(it.get_curr());
681 return result;
682 }
683
690 {
691 DynSkipList result;
692 for (auto it = begin(); it.has_curr(); it.next())
693 if (other.has(it.get_curr()))
694 result.insert(it.get_curr());
695 return result;
696 }
697
704 {
705 DynSkipList result;
706 for (auto it = begin(); it.has_curr(); it.next())
707 if (not other.has(it.get_curr()))
708 result.insert(it.get_curr());
709 return result;
710 }
711
712 // =========================================================================
713 // Iterator
714 // =========================================================================
715
721 {
722 const DynSkipList * list_ptr = nullptr;
723 Node * curr = nullptr;
724
725 public:
727
729
731 : list_ptr(&list), curr(list.header->forward[0])
732 {}
733
734 [[nodiscard]] bool has_curr() const noexcept { return curr != nullptr; }
735
737 {
738 return curr != nullptr and curr->forward[0] == nullptr;
739 }
740
741 [[nodiscard]] const Key & get_curr() const
742 {
743 ah_overflow_error_if(curr == nullptr) << "DynSkipList::Iterator overflow";
744 return curr->key;
745 }
746
748 {
749 return curr->key;
750 }
751
752 Key & get_curr()
753 {
754 ah_overflow_error_if(curr == nullptr) << "DynSkipList::Iterator overflow";
755 return curr->key;
756 }
757
758 [[nodiscard]] const Key & get_key() const { return get_curr(); }
759
760 void next()
761 {
762 ah_overflow_error_if(curr == nullptr) << "DynSkipList::Iterator::next overflow";
763 next_ne();
764 }
765
767 {
768 if (curr != nullptr)
769 curr = curr->forward[0];
770 }
771
773 {
774 if (list_ptr != nullptr)
776 }
777
779
780 Iterator & operator=(const Iterator &) noexcept = default;
781
782 [[nodiscard]] bool operator==(const Iterator & it) const noexcept
783 {
784 return curr == it.curr;
785 }
786
787 [[nodiscard]] bool operator!=(const Iterator & it) const noexcept
788 {
789 return curr != it.curr;
790 }
791
793 {
794 next_ne();
795 return *this;
796 }
797
798 Iterator operator++(int) noexcept
799 {
800 Iterator ret = *this;
801 next_ne();
802 return ret;
803 }
804
805 [[nodiscard]] const Key & operator*() const { return get_curr(); }
806 [[nodiscard]] const Key * operator->() const { return &get_curr(); }
807 };
808
811
814
815 // =========================================================================
816 // Functional operations
817 // =========================================================================
818
819 template <class Operation>
820 bool traverse(Operation & op) const
821 {
822 for (auto it = begin(); it.has_curr(); it.next())
823 if (not op(it.get_curr()))
824 return false;
825 return true;
826 }
827
828 template <class Operation>
829 bool traverse(Operation && op = Operation()) const
830 {
831 return traverse<Operation>(op);
832 }
833
834 template <class Operation>
835 void for_each(Operation & op) const
836 {
837 for (auto it = begin(); it.has_curr(); it.next())
838 op(it.get_curr());
839 }
840
841 template <class Operation>
842 void for_each(Operation && op = Operation()) const
843 {
845 }
846
847 template <class Pred>
848 bool all(Pred & pred) const
849 {
850 for (auto it = begin(); it.has_curr(); it.next())
851 if (not pred(it.get_curr()))
852 return false;
853 return true;
854 }
855
856 template <class Pred>
857 bool all(Pred && pred = Pred()) const
858 {
859 return all<Pred>(pred);
860 }
861
862 template <class Pred>
863 bool exists(Pred & pred) const
864 {
865 for (auto it = begin(); it.has_curr(); it.next())
866 if (pred(it.get_curr()))
867 return true;
868 return false;
869 }
870
871 template <class Pred>
872 bool exists(Pred && pred = Pred()) const
873 {
874 return exists<Pred>(pred);
875 }
876
877 template <class Pred>
878 bool none(Pred & pred) const
879 {
880 return not exists(pred);
881 }
882
883 template <class Pred>
884 bool none(Pred && pred = Pred()) const
885 {
886 return none<Pred>(pred);
887 }
888
889 template <typename T>
890 T foldl(const T & init, std::function<T(const T &, const Key &)> 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 T acc = init;
902 for (auto it = begin(); it.has_curr(); it.next())
903 acc = op(acc, it.get_curr());
904 return acc;
905 }
906
907 template <typename T, class Operation>
908 T foldl(const T & init, Operation && op) const
909 {
910 return foldl<T, Operation>(init, op);
911 }
912};
913
914} // end namespace Aleph
915
916# 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
Empties the container.
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
Checks if a key exists in the set.
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:642
Common sequential searching methods on containers.
Definition ah-dry.H:196
Mixin that adds STL begin()/end() and cbegin()/cend() to Aleph containers.
Freq_Node * pred
Predecessor node in level-order traversal.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
void next()
Advance all underlying iterators (bounds-checked).
Definition ah-zip.H:171
static std::atomic< bool > init
Definition hash-fct.C:53
STL namespace.
Internal node structure.
Node(const Key &k, int lvl)
Generic list of items stored in a container.
Definition ah-dry.H:1714
Generic traversal of the container through its iterator.
Definition ah-dry.H:67
Special constructors common to Aleph-w ( ) containers.
Definition ah-dry.H:586
ValueArg< size_t > seed
Definition testHash.C:48
static int * k