libdict 1.0.7
Data Structure C Library
Loading...
Searching...
No Matches
skiplist.c
Go to the documentation of this file.
1/*
2 * libdict -- skiplist implementation.
3 *
4 * Copyright (c) 2001-2014, Farooq Mela
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/*
29 * cf. [Pugh 1990], [Sedgewick 1998]
30 */
31
32#include "skiplist.h"
33
34#include <string.h> /* For memset() */
35#include "dict_private.h"
36
37typedef struct skip_node skip_node;
38
39struct skip_node {
40 void* key;
41 void* datum;
43 unsigned link_count;
45};
46
47/* A node can be given at most max_link - 1 links, so max_link must be at
48 * least 2 for the list to be able to link anything at all. */
49#define MIN_LINK 2
50#define MAX_LINK 32
51
59
64
65/* Vtable thunks. The vtable slot types take void*, and calling a function
66 * through a function-pointer type that is not compatible with the function's
67 * own type is undefined behaviour (C11 6.5.2.2p9), so each slot below gets a
68 * thunk with the exact slot signature instead of a cast. A cast would also
69 * hide a genuine signature mismatch. */
70static dict_itor* vt_skiplist_dict_itor_new(void* obj) { return skiplist_dict_itor_new(obj); }
71static size_t vt_skiplist_free(void* obj, dict_delete_func delete_func) { return skiplist_free(obj, delete_func); }
72static dict_insert_result vt_skiplist_insert(void* obj, void* key) { return skiplist_insert(obj, key); }
73static void** vt_skiplist_search(void* obj, const void* key) { return skiplist_search(obj, key); }
74static void** vt_skiplist_search_le(void* obj, const void* key) { return skiplist_search_le(obj, key); }
75static void** vt_skiplist_search_lt(void* obj, const void* key) { return skiplist_search_lt(obj, key); }
76static void** vt_skiplist_search_ge(void* obj, const void* key) { return skiplist_search_ge(obj, key); }
77static void** vt_skiplist_search_gt(void* obj, const void* key) { return skiplist_search_gt(obj, key); }
78static dict_remove_result vt_skiplist_remove(void* obj, const void* key) { return skiplist_remove(obj, key); }
79static size_t vt_skiplist_clear(void* obj, dict_delete_func delete_func) { return skiplist_clear(obj, delete_func); }
80static size_t vt_skiplist_traverse(void* obj, dict_visit_func visit, void* user_data) { return skiplist_traverse(obj, visit, user_data); }
81static size_t vt_skiplist_count(const void* obj) { return skiplist_count(obj); }
82static bool vt_skiplist_verify(const void* obj) { return skiplist_verify(obj); }
83static void vt_skiplist_itor_free(void* itor) { skiplist_itor_free(itor); }
84static bool vt_skiplist_itor_valid(const void* itor) { return skiplist_itor_valid(itor); }
85static void vt_skiplist_itor_invalidate(void* itor) { skiplist_itor_invalidate(itor); }
86static bool vt_skiplist_itor_next(void* itor) { return skiplist_itor_next(itor); }
87static bool vt_skiplist_itor_prev(void* itor) { return skiplist_itor_prev(itor); }
88static bool vt_skiplist_itor_nextn(void* itor, size_t count) { return skiplist_itor_nextn(itor, count); }
89static bool vt_skiplist_itor_prevn(void* itor, size_t count) { return skiplist_itor_prevn(itor, count); }
90static bool vt_skiplist_itor_first(void* itor) { return skiplist_itor_first(itor); }
91static bool vt_skiplist_itor_last(void* itor) { return skiplist_itor_last(itor); }
92static void* vt_skiplist_itor_key(void* itor) { return dict_unconst(skiplist_itor_key(itor)); }
93static void** vt_skiplist_itor_datum(void* itor) { return skiplist_itor_datum(itor); }
94static bool vt_skiplist_itor_search(void* itor, const void* key) { return skiplist_itor_search(itor, key); }
95static bool vt_skiplist_itor_search_le(void* itor, const void* key) { return skiplist_itor_search_le(itor, key); }
96static bool vt_skiplist_itor_search_lt(void* itor, const void* key) { return skiplist_itor_search_lt(itor, key); }
97static bool vt_skiplist_itor_search_ge(void* itor, const void* key) { return skiplist_itor_search_ge(itor, key); }
98static bool vt_skiplist_itor_search_gt(void* itor, const void* key) { return skiplist_itor_search_gt(itor, key); }
99static bool vt_skiplist_itor_remove(void* itor) { return skiplist_itor_remove(itor); }
100static int vt_skiplist_itor_compare(void* itor1, void* itor2) { return skiplist_itor_compare(itor1, itor2); }
101
102static const dict_vtable skiplist_vtable = {
103 true,
104 vt_skiplist_dict_itor_new,
105 vt_skiplist_free,
106 vt_skiplist_insert,
107 vt_skiplist_search,
108 vt_skiplist_search_le,
109 vt_skiplist_search_lt,
110 vt_skiplist_search_ge,
111 vt_skiplist_search_gt,
112 vt_skiplist_remove,
113 vt_skiplist_clear,
114 vt_skiplist_traverse,
115 NULL,
116 vt_skiplist_count,
117 vt_skiplist_verify,
118};
119
120static const itor_vtable skiplist_itor_vtable = {
121 vt_skiplist_itor_free,
122 vt_skiplist_itor_valid,
123 vt_skiplist_itor_invalidate,
124 vt_skiplist_itor_next,
125 vt_skiplist_itor_prev,
126 vt_skiplist_itor_nextn,
127 vt_skiplist_itor_prevn,
128 vt_skiplist_itor_first,
129 vt_skiplist_itor_last,
130 vt_skiplist_itor_key,
131 vt_skiplist_itor_datum,
132 vt_skiplist_itor_search,
133 vt_skiplist_itor_search_le,
134 vt_skiplist_itor_search_lt,
135 vt_skiplist_itor_search_ge,
136 vt_skiplist_itor_search_gt,
137 vt_skiplist_itor_remove,
138 vt_skiplist_itor_compare,
139};
140
141static inline skip_node* node_new(void* key, unsigned link_count);
142static inline void node_insert(skiplist* list, skip_node* x, skip_node** update);
143static inline skip_node* node_search(skiplist* list, const void* key);
144static inline skip_node* node_search_le(skiplist* list, const void* key);
145static inline skip_node* node_search_lt(skiplist* list, const void* key);
146static inline skip_node* node_search_ge(skiplist* list, const void* key);
147static inline skip_node* node_search_gt(skiplist* list, const void* key);
148static inline unsigned rand_link_count(skiplist* list);
149
151skiplist_new(dict_compare_func cmp_func, unsigned max_link)
152{
153 ASSERT(cmp_func != NULL);
154
155 /* Clamp both ends, as the upper bound always was. rand_link_count() gives
156 * at most max_link - 1 links, so a max_link below MIN_LINK would yield
157 * zero-link nodes that node_insert() never links into the list, losing
158 * every element and leaking it. */
159 if (max_link < MIN_LINK)
160 max_link = MIN_LINK;
161 else if (max_link > MAX_LINK)
162 max_link = MAX_LINK;
163
164 skiplist* list = MALLOC(sizeof(*list));
165 if (list) {
166 if (!(list->head = node_new(NULL, max_link))) {
167 FREE(list);
168 return NULL;
169 }
170
171 list->max_link = max_link;
172 list->top_link = 0;
173 list->cmp_func = cmp_func;
174 list->count = 0;
175 }
176 return list;
177}
178
179dict*
180skiplist_dict_new(dict_compare_func cmp_func, unsigned max_link)
181{
182 dict* dct = MALLOC(sizeof(*dct));
183 if (dct) {
184 if (!(dct->_object = skiplist_new(cmp_func, max_link))) {
185 FREE(dct);
186 return NULL;
187 }
188 dct->_vtable = &skiplist_vtable;
189 }
190 return dct;
191}
192
193size_t
195{
196 size_t count = skiplist_clear(list, delete_func);
197 FREE(list->head);
198 FREE(list);
199 return count;
200}
201
202static inline void
203node_insert(skiplist* list, skip_node* x, skip_node** update)
204{
205 const unsigned nlinks = x->link_count;
206 ASSERT(nlinks < list->max_link);
207
208 if (list->top_link < nlinks) {
209 for (unsigned k = list->top_link+1; k <= nlinks; k++) {
210 ASSERT(!update[k]);
211 update[k] = list->head;
212 }
213 list->top_link = nlinks;
214 }
215
216 x->prev = (update[0] == list->head) ? NULL : update[0];
217 if (update[0]->link[0])
218 update[0]->link[0]->prev = x;
219 for (unsigned k = 0; k < nlinks; k++) {
220 ASSERT(update[k]->link_count > k);
221 x->link[k] = update[k]->link[k];
222 update[k]->link[k] = x;
223 }
224 ++list->count;
225}
226
228skiplist_insert(skiplist* list, void* key)
229{
230 skip_node* x = list->head;
231 skip_node* update[MAX_LINK] = { 0 };
232 for (unsigned k = list->top_link+1; k-->0; ) {
233 ASSERT(x->link_count > k);
234 for (;;) {
235 skip_node* const y = x->link[k];
236 if (!y)
237 break;
238 const int cmp = list->cmp_func(key, y->key);
239 if (cmp < 0) {
240 while (k > 0 && x->link[k - 1] == y)
241 update[k--] = x;
242 break;
243 } else if (cmp == 0)
244 return (dict_insert_result) { &y->datum, false };
245 x = y;
246 }
247 update[k] = x;
248 }
249
250 x = node_new(key, rand_link_count(list));
251 if (!x)
252 return (dict_insert_result) { NULL, false };
253 node_insert(list, x, update);
254 return (dict_insert_result) { &x->datum, true };
255}
256
257static inline skip_node*
258node_search(skiplist* list, const void* key)
259{
260 skip_node* x = list->head;
261 for (unsigned k = list->top_link+1; k-->0;) {
262 for (;;) {
263 skip_node* const y = x->link[k];
264 if (!y)
265 break;
266 const int cmp = list->cmp_func(key, y->key);
267 if (cmp < 0) {
268 while (k > 0 && x->link[k - 1] == y)
269 k--;
270 break;
271 } else if (cmp == 0)
272 return y;
273 x = y;
274 }
275 }
276 return NULL;
277}
278
279static inline skip_node*
280node_search_le(skiplist* list, const void* key)
281{
282 skip_node* x = list->head;
283 for (unsigned k = list->top_link+1; k-->0;) {
284 for (;;) {
285 skip_node* const y = x->link[k];
286 if (!y)
287 break;
288 const int cmp = list->cmp_func(key, y->key);
289 if (cmp < 0) {
290 while (k > 0 && x->link[k - 1] == y)
291 k--;
292 break;
293 } else if (cmp == 0)
294 return y;
295 x = y;
296 }
297 }
298 return x == list->head ? NULL : x;
299}
300
301static inline skip_node*
302node_search_lt(skiplist* list, const void* key)
303{
304 skip_node* x = list->head;
305 for (unsigned k = list->top_link+1; k-->0;) {
306 for (;;) {
307 skip_node* const y = x->link[k];
308 if (!y)
309 break;
310 const int cmp = list->cmp_func(key, y->key);
311 if (cmp < 0) {
312 while (k > 0 && x->link[k - 1] == y)
313 k--;
314 break;
315 } else if (cmp == 0)
316 return y->prev;
317 x = y;
318 }
319 }
320 return x == list->head ? NULL : x;
321}
322
323static inline skip_node*
324node_search_ge(skiplist* list, const void* key)
325{
326 skip_node* x = list->head;
327 skip_node* ret = NULL;
328 for (unsigned k = list->top_link+1; k-->0;) {
329 for (;;) {
330 skip_node* const y = x->link[k];
331 if (!y)
332 break;
333 const int cmp = list->cmp_func(key, y->key);
334 if (cmp < 0) {
335 ret = y;
336 while (k > 0 && x->link[k - 1] == y)
337 k--;
338 break;
339 } else if (cmp == 0)
340 return y;
341 x = y;
342 }
343 }
344 return ret;
345}
346
347static inline skip_node*
348node_search_gt(skiplist* list, const void* key)
349{
350 skip_node* x = list->head;
351 skip_node* ret = NULL;
352 for (unsigned k = list->top_link+1; k-->0;) {
353 for (;;) {
354 skip_node* const y = x->link[k];
355 if (!y)
356 break;
357 const int cmp = list->cmp_func(key, y->key);
358 if (cmp < 0) {
359 ret = y;
360 while (k > 0 && x->link[k - 1] == y)
361 k--;
362 break;
363 } else if (cmp == 0)
364 return y->link[0];
365 x = y;
366 }
367 }
368 return ret;
369}
370
371void**
372skiplist_search(skiplist* list, const void* key)
373{
374 skip_node* x = node_search(list, key);
375 return x ? &x->datum : NULL;
376}
377
378void**
379skiplist_search_le(skiplist* list, const void* key)
380{
381 skip_node* x = node_search_le(list, key);
382 return x ? &x->datum : NULL;
383}
384
385void**
386skiplist_search_lt(skiplist* list, const void* key)
387{
388 skip_node* x = node_search_lt(list, key);
389 return x ? &x->datum : NULL;
390}
391
392void**
393skiplist_search_ge(skiplist* list, const void* key)
394{
395 skip_node* x = node_search_ge(list, key);
396 return x ? &x->datum : NULL;
397}
398
399void**
400skiplist_search_gt(skiplist* list, const void* key)
401{
402 skip_node* x = node_search_gt(list, key);
403 return x ? &x->datum : NULL;
404}
405
407skiplist_remove(skiplist* list, const void* key)
408{
409 skip_node* x = list->head;
410 skip_node* update[MAX_LINK] = { 0 };
411 bool found = false;
412 for (unsigned k = list->top_link+1; k-->0;) {
413 ASSERT(x->link_count > k);
414 for (;;) {
415 skip_node* const y = x->link[k];
416 if (!y)
417 break;
418 const int cmp = list->cmp_func(key, y->key);
419 if (cmp > 0)
420 x = y;
421 else {
422 while (k > 0 && x->link[k - 1] == y)
423 update[k--] = x;
424 if (cmp == 0)
425 found = true;
426 break;
427 }
428 }
429 update[k] = x;
430 }
431 if (!found)
432 return (dict_remove_result) { NULL, NULL, false };
433 x = x->link[0];
434 for (unsigned k = 0; k <= list->top_link; k++) {
435 ASSERT(update[k] != NULL);
436 ASSERT(update[k]->link_count > k);
437 if (update[k]->link[k] != x) break;
438 update[k]->link[k] = x->link[k];
439 }
440 if (x->prev)
441 x->prev->link[0] = x->link[0];
442 if (x->link[0])
443 x->link[0]->prev = x->prev;
444 dict_remove_result result = { x->key, x->datum, true };
445 FREE(x);
446 while (list->top_link > 0 && !list->head->link[list->top_link-1])
447 list->top_link--;
448 list->count--;
449 return result;
450}
451
452size_t
454{
455 skip_node* node = list->head->link[0];
456 while (node) {
457 skip_node* next = node->link[0];
458 if (delete_func) delete_func(node->key, node->datum);
459 FREE(node);
460 node = next;
461 }
462
463 const size_t count = list->count;
464 list->count = 0;
465 list->head->link[list->top_link] = NULL;
466 while (list->top_link)
467 list->head->link[--list->top_link] = NULL;
468
469 return count;
470}
471
472size_t
473skiplist_traverse(skiplist* list, dict_visit_func visit, void* user_data)
474{
475 size_t count = 0;
476 for (skip_node* node = list->head->link[0]; node; node = node->link[0]) {
477 ++count;
478 if (!visit(node->key, node->datum, user_data)) break;
479 }
480 return count;
481}
482
483size_t
485{
486 return list->count;
487}
488
489bool
491{
492 if (list->count == 0) {
493 VERIFY(list->top_link == 0);
494 } else {
495 VERIFY(list->top_link > 0);
496 }
497 VERIFY(list->top_link < list->max_link);
498 for (unsigned i = 0; i < list->top_link; ++i) {
499 VERIFY(list->head->link[i] != NULL);
500 }
501 for (unsigned i = list->top_link; i < list->max_link; ++i) {
502 VERIFY(list->head->link[i] == NULL);
503 }
504 unsigned observed_top_link = 0;
505 size_t observed_count = 0;
506
507 skip_node* prev = NULL;
508 skip_node* node = list->head->link[0];
509 while (node) {
510 if (observed_top_link < node->link_count)
511 observed_top_link = node->link_count;
512
513 VERIFY(node->prev == prev);
514 VERIFY(node->link_count >= 1);
515 VERIFY(node->link_count <= list->top_link);
516 for (unsigned k = 0; k < node->link_count; k++) {
517 if (node->link[k]) {
518 /* To occupy level k a node needs links 0..k, i.e. more than k
519 * of them. */
520 VERIFY(node->link[k]->link_count > k);
521 /* Links must run strictly forward in key order. */
522 VERIFY(list->cmp_func(node->key, node->link[k]->key) < 0);
523 }
524 }
525
526 ++observed_count;
527 prev = node;
528 node = node->link[0];
529 }
530 VERIFY(list->top_link == observed_top_link);
531 VERIFY(list->count == observed_count);
532 return true;
533}
534
535size_t
536skiplist_link_count_histogram(const skiplist* list, size_t counts[], size_t ncounts)
537{
538 for (size_t i = 0; i < ncounts; ++i)
539 counts[i] = 0;
540
541 size_t max_num_links = 0;
542 for (const skip_node* node = list->head->link[0]; node; node = node->link[0]) {
543 if (max_num_links < node->link_count)
544 max_num_links = node->link_count;
545 if (ncounts > node->link_count)
546 counts[node->link_count]++;
547 }
548 return max_num_links;
549}
550
553{
554 skiplist_itor* itor = MALLOC(sizeof(*itor));
555 if (itor) {
556 itor->list = list;
557 itor->node = NULL;
558 }
559 return itor;
560}
561
564{
565 dict_itor* itor = MALLOC(sizeof(*itor));
566 if (itor) {
567 if (!(itor->_itor = skiplist_itor_new(list))) {
568 FREE(itor);
569 return NULL;
570 }
571 itor->_vtable = &skiplist_itor_vtable;
572 }
573 return itor;
574}
575
576void
578{
579 FREE(itor);
580}
581
582bool
584{
585 return itor->node != NULL;
586}
587
588void
590{
591 itor->node = NULL;
592}
593
594bool
596{
597 if (itor->node)
598 itor->node = itor->node->link[0];
599 return itor->node != NULL;
600}
601
602bool
604{
605 if (itor->node)
606 itor->node = itor->node->prev;
607 return itor->node != NULL;
608}
609
610bool
612{
613 while (count--)
614 if (!skiplist_itor_next(itor))
615 return false;
616 return itor->node != NULL;
617}
618
619bool
621{
622 while (count--)
623 if (!skiplist_itor_prev(itor))
624 return false;
625 return itor->node != NULL;
626}
627
628bool
630{
631 return (itor->node = itor->list->head->link[0]) != NULL;
632}
633
634bool
636{
637 skip_node* x = itor->list->head;
638 for (unsigned k = itor->list->top_link; k-->0;) {
639 while (x->link[k])
640 x = x->link[k];
641 }
642 if (x == itor->list->head) {
643 itor->node = NULL;
644 return false;
645 } else {
646 itor->node = x;
647 return true;
648 }
649}
650
651bool
652skiplist_itor_search(skiplist_itor* itor, const void* key)
653{
654 return (itor->node = node_search(itor->list, key)) != NULL;
655}
656
657bool
659{
660 return (itor->node = node_search_le(itor->list, key)) != NULL;
661}
662
663bool
665{
666 return (itor->node = node_search_lt(itor->list, key)) != NULL;
667}
668
669bool
671{
672 return (itor->node = node_search_ge(itor->list, key)) != NULL;
673}
674
675bool
677{
678 return (itor->node = node_search_gt(itor->list, key)) != NULL;
679}
680
681const void*
683{
684 return itor->node ? itor->node->key : NULL;
685}
686
687void**
689{
690 return itor->node ? &itor->node->datum : NULL;
691}
692
693int
695{
696 ASSERT(itor1->list == itor2->list);
697 if (!itor1->node)
698 return !itor2->node ? 0 : -1;
699 if (!itor2->node)
700 return 1;
701 return itor1->list->cmp_func(itor1->node->key, itor2->node->key);
702}
703
704bool
706{
707 if (!itor->node)
708 return false;
709 /* XXX make this smarter */
710 dict_remove_result result = skiplist_remove(itor->list, itor->node->key);
711 ASSERT(result.removed);
712 itor->node = NULL;
713 return result.removed;
714}
715
716static inline skip_node*
717node_new(void* key, unsigned link_count)
718{
719 ASSERT(link_count >= 1);
720
721 skip_node* node = MALLOC(sizeof(*node) +
722 sizeof(node->link[0]) * link_count);
723 if (node) {
724 node->key = key;
725 node->datum = NULL;
726 node->prev = NULL;
727 node->link_count = link_count;
728 memset(node->link, 0, sizeof(node->link[0]) * link_count);
729 }
730 return node;
731}
732
733/* Returns a link count in [1, max_link - 1], geometrically distributed with
734 * ratio 1/4 (two coin flips per level). */
735static inline unsigned
736rand_link_count(skiplist* list)
737{
738 /* dict_ctz() requires a nonzero argument and random() does return 0, so
739 * fold zero onto the largest trailing-zero count it could represent. */
740 const unsigned r = dict_rand();
741 const unsigned tz = r ? dict_ctz(r) : DICT_RAND_BITS;
742 const unsigned count = tz / 2 + 1;
743 ASSERT(list->max_link >= MIN_LINK);
744 return MIN(count, list->max_link - 1);
745}
int(* dict_compare_func)(const void *, const void *)
A pointer to a function that compares two keys.
Definition dict.h:59
void(* dict_delete_func)(void *, void *)
A pointer to a function that is called when a key-value pair gets removed from a dictionary.
Definition dict.h:62
bool(* dict_visit_func)(const void *, void *, void *)
A pointer to a function used for iterating over dictionary contents.
Definition dict.h:64
#define FREE(p)
#define ASSERT(expr)
#define VERIFY(expr)
#define MIN(a, b)
#define DICT_RAND_BITS
#define MALLOC(n)
bool skiplist_itor_search_le(skiplist_itor *itor, const void *key)
Position |itor| on the greatest key less than or equal to |key| and return true, or unposition it and...
Definition skiplist.c:658
size_t skiplist_traverse(skiplist *list, dict_visit_func visit, void *user_data)
Call |visit|(key, datum, |user_data|) for each element in key order, stopping early if |visit| return...
Definition skiplist.c:473
skiplist * skiplist_new(dict_compare_func cmp_func, unsigned max_link)
Create an empty skip list that orders keys with |cmp_func| (must not be NULL).
Definition skiplist.c:151
bool skiplist_itor_search_gt(skiplist_itor *itor, const void *key)
Position |itor| on the least key greater than |key| and return true, or unposition it and return fals...
Definition skiplist.c:676
bool skiplist_itor_remove(skiplist_itor *itor)
Remove the element |itor| is positioned on and unposition |itor|; return false if it was not position...
Definition skiplist.c:705
void ** skiplist_search_le(skiplist *list, const void *key)
Return the address of the datum of the greatest key less than or equal to |key|, or NULL if there is ...
Definition skiplist.c:379
void ** skiplist_search(skiplist *list, const void *key)
Return the address of the datum stored for |key|, or NULL if |key| is not present.
Definition skiplist.c:372
bool skiplist_itor_search(skiplist_itor *itor, const void *key)
Position |itor| on |key| and return true, or unposition it and return false if |key| is not present.
Definition skiplist.c:652
bool skiplist_verify(const skiplist *list)
Check the internal invariants of the list and return true if they hold, or print the first failed che...
Definition skiplist.c:490
bool skiplist_itor_first(skiplist_itor *itor)
Position |itor| on the first element in key order and return true, or unposition it and return false ...
Definition skiplist.c:629
bool skiplist_itor_next(skiplist_itor *itor)
Move |itor| to the next element in key order and return true, or unposition it and return false if th...
Definition skiplist.c:595
bool skiplist_itor_prevn(skiplist_itor *itor, size_t count)
Move |itor| |count| elements back and return whether it is still positioned.
Definition skiplist.c:620
size_t skiplist_free(skiplist *list, dict_delete_func delete_func)
Remove every element, calling |delete_func|(key, datum) for each unless |delete_func| is NULL,...
Definition skiplist.c:194
void skiplist_itor_invalidate(skiplist_itor *itor)
Unposition |itor|, so that it is not positioned on any element.
Definition skiplist.c:589
const void * skiplist_itor_key(const skiplist_itor *itor)
Return the key |itor| is positioned on, or NULL if it is not positioned.
Definition skiplist.c:682
void ** skiplist_search_gt(skiplist *list, const void *key)
Return the address of the datum of the least key greater than |key|, or NULL if there is none.
Definition skiplist.c:400
bool skiplist_itor_search_lt(skiplist_itor *itor, const void *key)
Position |itor| on the greatest key less than |key| and return true, or unposition it and return fals...
Definition skiplist.c:664
bool skiplist_itor_valid(const skiplist_itor *itor)
Return whether |itor| is positioned on an element.
Definition skiplist.c:583
dict * skiplist_dict_new(dict_compare_func cmp_func, unsigned max_link)
Like skiplist_new(), but wrapped in a generic dict for use with the dict_* macros.
Definition skiplist.c:180
void ** skiplist_search_ge(skiplist *list, const void *key)
Return the address of the datum of the least key greater than or equal to |key|, or NULL if there is ...
Definition skiplist.c:393
#define MIN_LINK
Definition skiplist.c:49
bool skiplist_itor_search_ge(skiplist_itor *itor, const void *key)
Position |itor| on the least key greater than or equal to |key| and return true, or unposition it and...
Definition skiplist.c:670
int skiplist_itor_compare(const skiplist_itor *itor1, const skiplist_itor *itor2)
Compare the positions of two iterators over the same list: return a negative value,...
Definition skiplist.c:694
void ** skiplist_itor_datum(skiplist_itor *itor)
Return the address of the datum |itor| is positioned on, through which it can be read or replaced,...
Definition skiplist.c:688
dict_itor * skiplist_dict_itor_new(skiplist *list)
Like skiplist_itor_new(), but wrapped in a generic dict_itor for use with the dict_itor_* macros.
Definition skiplist.c:563
void ** skiplist_search_lt(skiplist *list, const void *key)
Return the address of the datum of the greatest key less than |key|, or NULL if there is none.
Definition skiplist.c:386
#define MAX_LINK
Definition skiplist.c:50
void skiplist_itor_free(skiplist_itor *itor)
Free an iterator.
Definition skiplist.c:577
dict_insert_result skiplist_insert(skiplist *list, void *key)
Insert |key| unless an equal key is present.
Definition skiplist.c:228
bool skiplist_itor_nextn(skiplist_itor *itor, size_t count)
Move |itor| |count| elements forward and return whether it is still positioned.
Definition skiplist.c:611
skiplist_itor * skiplist_itor_new(skiplist *list)
Create an iterator over |list| that is not positioned on any element yet.
Definition skiplist.c:552
size_t skiplist_clear(skiplist *list, dict_delete_func delete_func)
Remove every element, calling |delete_func|(key, datum) for each unless |delete_func| is NULL.
Definition skiplist.c:453
size_t skiplist_count(const skiplist *list)
Return the number of elements.
Definition skiplist.c:484
dict_remove_result skiplist_remove(skiplist *list, const void *key)
Remove the element with key |key|.
Definition skiplist.c:407
bool skiplist_itor_last(skiplist_itor *itor)
Position |itor| on the last element in key order and return true, or unposition it and return false i...
Definition skiplist.c:635
size_t skiplist_link_count_histogram(const skiplist *list, size_t counts[], size_t ncounts)
Compute the histogram of link counts of the skiplist.
Definition skiplist.c:536
bool skiplist_itor_prev(skiplist_itor *itor)
Move |itor| to the previous element in key order and return true, or unposition it and return false i...
Definition skiplist.c:603
Skip list [Pugh 1990].
void * _itor
Definition dict.h:235
const itor_vtable * _vtable
Definition dict.h:236
The operations of one container type.
Definition dict.h:110
Definition dict.h:164
void * _object
Definition dict.h:165
const dict_vtable * _vtable
Definition dict.h:166
skip_node * prev
Definition skiplist.c:42
void * datum
Definition skiplist.c:41
void * key
Definition skiplist.c:40
unsigned link_count
Definition skiplist.c:43
skip_node * link[]
Definition skiplist.c:44
skiplist * list
Definition skiplist.c:61
skip_node * node
Definition skiplist.c:62
skip_node * head
Definition skiplist.c:53
unsigned max_link
Definition skiplist.c:54
dict_compare_func cmp_func
Definition skiplist.c:56
size_t count
Definition skiplist.c:57
unsigned top_link
Definition skiplist.c:55