Coverage Report

Created: 2025-08-03 06:36

/src/frr/lib/skiplist.c
Line
Count
Source (jump to first uncovered line)
1
// SPDX-License-Identifier: LicenseRef-Skiplist-BSD-0-Clause
2
/*
3
 * Copyright 1990 William Pugh
4
 *
5
 * Permission to include in quagga provide on March 31, 2016
6
 */
7
8
/*
9
 * Skip List implementation based on code from William Pugh.
10
 * ftp://ftp.cs.umd.edu/pub/skipLists/
11
 *
12
 * Skip Lists are a probabilistic alternative to balanced trees, as
13
 * described in the June 1990 issue of CACM and were invented by
14
 * William Pugh in 1987.
15
 *
16
 * This file contains source code to implement a dictionary using
17
 * skip lists and a test driver to test the routines.
18
 *
19
 * A couple of comments about this implementation:
20
 *   The routine randomLevel has been hard-coded to generate random
21
 *   levels using p=0.25. It can be easily changed.
22
 *
23
 *   The insertion routine has been implemented so as to use the
24
 *   dirty hack described in the CACM paper: if a random level is
25
 *   generated that is more than the current maximum level, the
26
 *   current maximum level plus one is used instead.
27
 *
28
 *   Levels start at zero and go up to MaxLevel (which is equal to
29
 *  (MaxNumberOfLevels-1).
30
 *
31
 * The run-time flag SKIPLIST_FLAG_ALLOW_DUPLICATES determines whether or
32
 * not duplicates are allowed for a given list. If set, duplicates are
33
 * allowed and act in a FIFO manner. If not set, an insertion of a value
34
 * already in the list updates the previously existing binding.
35
 *
36
 * BitsInRandom is defined to be the number of bits returned by a call to
37
 * random(). For most all machines with 32-bit integers, this is 31 bits
38
 * as currently set.
39
 */
40
41
42
#include <zebra.h>
43
44
#include "memory.h"
45
#include "log.h"
46
#include "vty.h"
47
#include "skiplist.h"
48
#include "lib_errors.h"
49
#include "network.h"
50
51
DEFINE_MTYPE_STATIC(LIB, SKIP_LIST, "Skip List");
52
DEFINE_MTYPE_STATIC(LIB, SKIP_LIST_NODE, "Skip Node");
53
DEFINE_MTYPE_STATIC(LIB, SKIP_LIST_STATS, "Skiplist Counters");
54
55
0
#define BitsInRandom 31
56
57
0
#define MaxNumberOfLevels 16
58
0
#define MaxLevel (MaxNumberOfLevels-1)
59
#define newNodeOfLevel(l)                                                      \
60
0
  XCALLOC(MTYPE_SKIP_LIST_NODE,                                          \
61
0
    sizeof(struct skiplistnode)                                    \
62
0
      + (l) * sizeof(struct skiplistnode *))
63
64
/* XXX must match type of (struct skiplist).level_stats */
65
#define newStatsOfLevel(l)                                                     \
66
0
  XCALLOC(MTYPE_SKIP_LIST_STATS, ((l) + 1) * sizeof(int))
67
68
static int randomsLeft;
69
static int randomBits;
70
71
#ifdef SKIPLIST_DEBUG
72
#define CHECKLAST(sl)                                                          \
73
  do {                                                                   \
74
    if ((sl)->header->forward[0] && !(sl)->last)                   \
75
      assert(0);                                             \
76
    if (!(sl)->header->forward[0] && (sl)->last)                   \
77
      assert(0);                                             \
78
  } while (0)
79
#else
80
#define CHECKLAST(sl)
81
#endif
82
83
84
static int randomLevel(void)
85
0
{
86
0
  register int level = 0;
87
0
  register int b;
88
89
0
  do {
90
0
    if (randomsLeft <= 0) {
91
0
      randomBits = frr_weak_random();
92
0
      randomsLeft = BitsInRandom / 2;
93
0
    }
94
0
    b = randomBits & 3;
95
0
    randomBits >>= 2;
96
0
    --randomsLeft;
97
98
0
    if (!b) {
99
0
      level++;
100
0
      if (level >= MaxLevel)
101
0
        return MaxLevel;
102
0
    }
103
0
  } while (!b);
104
105
0
  return level;
106
0
}
107
108
static int default_cmp(const void *key1, const void *key2)
109
0
{
110
0
  if (key1 < key2)
111
0
    return -1;
112
0
  if (key1 > key2)
113
0
    return 1;
114
0
  return 0;
115
0
}
116
117
unsigned int skiplist_count(struct skiplist *l)
118
0
{
119
0
  return l->count;
120
0
}
121
122
struct skiplist *skiplist_new(int flags,
123
            int (*cmp)(const void *key1, const void *key2),
124
            void (*del)(void *val))
125
0
{
126
0
  struct skiplist *new;
127
128
0
  new = XCALLOC(MTYPE_SKIP_LIST, sizeof(struct skiplist));
129
0
  assert(new);
130
131
0
  new->level = 0;
132
0
  new->count = 0;
133
0
  new->header = newNodeOfLevel(MaxNumberOfLevels);
134
0
  new->level_stats = newStatsOfLevel(MaxNumberOfLevels);
135
136
0
  new->flags = flags;
137
0
  if (cmp)
138
0
    new->cmp = cmp;
139
0
  else
140
0
    new->cmp = default_cmp;
141
142
0
  if (del)
143
0
    new->del = del;
144
145
0
  return new;
146
0
}
147
148
void skiplist_free(struct skiplist *l)
149
0
{
150
0
  register struct skiplistnode *p, *q;
151
152
0
  p = l->header;
153
154
0
  do {
155
0
    q = p->forward[0];
156
0
    if (l->del && p != l->header)
157
0
      (*l->del)(p->value);
158
0
    XFREE(MTYPE_SKIP_LIST_NODE, p);
159
0
    p = q;
160
0
  } while (p);
161
162
0
  XFREE(MTYPE_SKIP_LIST_STATS, l->level_stats);
163
0
  XFREE(MTYPE_SKIP_LIST, l);
164
0
}
165
166
167
int skiplist_insert(register struct skiplist *l, register void *key,
168
        register void *value)
169
0
{
170
0
  register int k;
171
0
  struct skiplistnode *update[MaxNumberOfLevels];
172
0
  register struct skiplistnode *p, *q;
173
174
0
  CHECKLAST(l);
175
176
#ifdef SKIPLIST_DEBUG
177
  /* DEBUG */
178
  if (!key) {
179
    flog_err(EC_LIB_DEVELOPMENT, "%s: key is 0, value is %p",
180
       __func__, value);
181
  }
182
#endif
183
184
0
  p = l->header;
185
0
  k = l->level;
186
0
  do {
187
0
    while (q = p->forward[k], q && (*l->cmp)(q->key, key) < 0)
188
0
      p = q;
189
0
    update[k] = p;
190
0
  } while (--k >= 0);
191
192
0
  if (!(l->flags & SKIPLIST_FLAG_ALLOW_DUPLICATES) && q
193
0
      && ((*l->cmp)(q->key, key) == 0)) {
194
195
0
    return -1;
196
0
  }
197
198
0
  k = randomLevel();
199
0
  assert(k >= 0);
200
0
  if (k > l->level) {
201
0
    k = ++l->level;
202
0
    update[k] = l->header;
203
0
  }
204
205
0
  q = newNodeOfLevel(k);
206
0
  q->key = key;
207
0
  q->value = value;
208
0
#ifdef SKIPLIST_0TIMER_DEBUG
209
0
  q->flags = SKIPLIST_NODE_FLAG_INSERTED; /* debug */
210
0
#endif
211
212
0
  ++(l->level_stats[k]);
213
#ifdef SKIPLIST_DEBUG
214
  zlog_debug("%s: incremented level_stats @%p:%d, now %d", __func__, l, k,
215
       l->level_stats[k]);
216
#endif
217
218
0
  do {
219
0
    p = update[k];
220
0
    q->forward[k] = p->forward[k];
221
0
    p->forward[k] = q;
222
0
  } while (--k >= 0);
223
224
  /*
225
   * If this is the last item in the list, update the "last" pointer
226
   */
227
0
  if (!q->forward[0]) {
228
0
    l->last = q;
229
0
  }
230
231
0
  ++(l->count);
232
233
0
  CHECKLAST(l);
234
235
0
  return 0;
236
0
}
237
238
int skiplist_delete(register struct skiplist *l, register void *key,
239
        register void *value) /* used only if duplicates allowed */
240
0
{
241
0
  register int k, m;
242
0
  struct skiplistnode *update[MaxNumberOfLevels];
243
0
  register struct skiplistnode *p, *q;
244
245
0
  CHECKLAST(l);
246
247
  /* to make debugging easier */
248
0
  for (k = 0; k < MaxNumberOfLevels; ++k)
249
0
    update[k] = NULL;
250
251
0
  p = l->header;
252
0
  k = m = l->level;
253
0
  do {
254
0
    while (q = p->forward[k], q && (*l->cmp)(q->key, key) < 0)
255
0
      p = q;
256
0
    update[k] = p;
257
0
  } while (--k >= 0);
258
259
0
  if (l->flags & SKIPLIST_FLAG_ALLOW_DUPLICATES) {
260
0
    while (q && ((*l->cmp)(q->key, key) == 0)
261
0
           && (q->value != value)) {
262
0
      int i;
263
0
      for (i = 0; i <= l->level; ++i) {
264
0
        if (update[i]->forward[i] == q)
265
0
          update[i] = q;
266
0
      }
267
0
      q = q->forward[0];
268
0
    }
269
0
  }
270
271
0
  if (q && (*l->cmp)(q->key, key) == 0) {
272
0
    if (!(l->flags & SKIPLIST_FLAG_ALLOW_DUPLICATES)
273
0
        || (q->value == value)) {
274
275
/*
276
 * found node to delete
277
 */
278
0
#ifdef SKIPLIST_0TIMER_DEBUG
279
0
      q->flags &= ~SKIPLIST_NODE_FLAG_INSERTED;
280
0
#endif
281
      /*
282
       * If we are deleting the last element of the list,
283
       * update the list's "last" pointer.
284
       */
285
0
      if (l->last == q) {
286
0
        if (update[0] == l->header)
287
0
          l->last = NULL;
288
0
        else
289
0
          l->last = update[0];
290
0
      }
291
292
0
      for (k = 0; k <= m && (p = update[k])->forward[k] == q;
293
0
           k++) {
294
0
        p->forward[k] = q->forward[k];
295
0
      }
296
0
      --(l->level_stats[k - 1]);
297
#ifdef SKIPLIST_DEBUG
298
      zlog_debug("%s: decremented level_stats @%p:%d, now %d",
299
           __func__, l, k - 1, l->level_stats[k - 1]);
300
#endif
301
0
      if (l->del)
302
0
        (*l->del)(q->value);
303
0
      XFREE(MTYPE_SKIP_LIST_NODE, q);
304
0
      while (l->header->forward[m] == NULL && m > 0)
305
0
        m--;
306
0
      l->level = m;
307
0
      CHECKLAST(l);
308
0
      --(l->count);
309
0
      return 0;
310
0
    }
311
0
  }
312
313
0
  CHECKLAST(l);
314
0
  return -1;
315
0
}
316
317
/*
318
 * Obtain first value matching "key". Unless SKIPLIST_FLAG_ALLOW_DUPLICATES
319
 * is set, this will also be the only value matching "key".
320
 *
321
 * Also set a cursor for use with skiplist_next_value.
322
 */
323
int skiplist_first_value(register struct skiplist *l, /* in */
324
       register const void *key,    /* in */
325
       void **valuePointer,       /* out */
326
       void **cursor)         /* out */
327
0
{
328
0
  register int k;
329
0
  register struct skiplistnode *p, *q;
330
331
0
  p = l->header;
332
0
  k = l->level;
333
334
0
  do {
335
0
    while (q = p->forward[k], q && (*l->cmp)(q->key, key) < 0)
336
0
      p = q;
337
338
0
  } while (--k >= 0);
339
340
0
  if (!q || (*l->cmp)(q->key, key))
341
0
    return -1;
342
343
0
  if (valuePointer)
344
0
    *valuePointer = q->value;
345
346
0
  if (cursor)
347
0
    *cursor = q;
348
349
0
  return 0;
350
0
}
351
352
int skiplist_search(register struct skiplist *l, register void *key,
353
        void **valuePointer)
354
0
{
355
0
  return skiplist_first_value(l, key, valuePointer, NULL);
356
0
}
357
358
359
/*
360
 * Caller supplies key and value of an existing item in the list.
361
 * Function returns the value of the next list item that has the
362
 * same key (useful when SKIPLIST_FLAG_ALLOW_DUPLICATES is set).
363
 *
364
 * Returns 0 on success. If the caller-supplied key and value
365
 * do not correspond to a list element, or if they specify the
366
 * last element with the given key, -1 is returned.
367
 */
368
int skiplist_next_value(register struct skiplist *l, /* in */
369
      register const void *key,   /* in */
370
      void **valuePointer,   /* in/out */
371
      void **cursor)         /* in/out */
372
0
{
373
0
  register int k;
374
0
  register struct skiplistnode *p, *q;
375
376
0
  CHECKLAST(l);
377
378
0
  if (!(l->flags & SKIPLIST_FLAG_ALLOW_DUPLICATES)) {
379
0
    return -1;
380
0
  }
381
382
0
  if (!cursor || !*cursor) {
383
0
    p = l->header;
384
0
    k = l->level;
385
386
    /*
387
     * Find matching key
388
     */
389
0
    do {
390
0
      while (q = p->forward[k],
391
0
             q && (*l->cmp)(q->key, key) < 0)
392
0
        p = q;
393
0
    } while (--k >= 0);
394
395
    /*
396
     * Find matching value
397
     */
398
0
    while (q && ((*l->cmp)(q->key, key) == 0)
399
0
           && (q->value != *valuePointer)) {
400
0
      q = q->forward[0];
401
0
    }
402
403
0
    if (!q || ((*l->cmp)(q->key, key) != 0)
404
0
        || (q->value != *valuePointer)) {
405
      /*
406
       * No matching value
407
       */
408
0
      CHECKLAST(l);
409
0
      return -1;
410
0
    }
411
0
  } else {
412
0
    q = (struct skiplistnode *)*cursor;
413
0
  }
414
415
  /*
416
   * Advance cursor
417
   */
418
0
  q = q->forward[0];
419
420
  /*
421
   * If we reached end-of-list or if the key is no longer the same,
422
   * then return error
423
   */
424
0
  if (!q || ((*l->cmp)(q->key, key) != 0))
425
0
    return -1;
426
427
0
  *valuePointer = q->value;
428
0
  if (cursor)
429
0
    *cursor = q;
430
0
  CHECKLAST(l);
431
0
  return 0;
432
0
}
433
434
int skiplist_first(register struct skiplist *l, void **keyPointer,
435
       void **valuePointer)
436
0
{
437
0
  register struct skiplistnode *p;
438
439
0
  CHECKLAST(l);
440
0
  p = l->header->forward[0];
441
0
  if (!p)
442
0
    return -1;
443
444
0
  if (keyPointer)
445
0
    *keyPointer = p->key;
446
447
0
  if (valuePointer)
448
0
    *valuePointer = p->value;
449
450
0
  CHECKLAST(l);
451
452
0
  return 0;
453
0
}
454
455
int skiplist_last(register struct skiplist *l, void **keyPointer,
456
      void **valuePointer)
457
0
{
458
0
  CHECKLAST(l);
459
0
  if (l->last) {
460
0
    if (keyPointer)
461
0
      *keyPointer = l->last->key;
462
0
    if (valuePointer)
463
0
      *valuePointer = l->last->value;
464
0
    return 0;
465
0
  }
466
0
  return -1;
467
0
}
468
469
/*
470
 * true = empty
471
 */
472
int skiplist_empty(register struct skiplist *l)
473
0
{
474
0
  CHECKLAST(l);
475
0
  if (l->last)
476
0
    return 0;
477
0
  return 1;
478
0
}
479
480
/*
481
 * Use this to walk the list. Caller sets *cursor to NULL to obtain
482
 * first element. Return value of 0 indicates valid cursor/element
483
 * returned, otherwise NULL cursor arg or EOL.
484
 */
485
int skiplist_next(register struct skiplist *l, /* in */
486
      void **keyPointer,     /* out */
487
      void **valuePointer,   /* out */
488
      void **cursor)         /* in/out */
489
0
{
490
0
  struct skiplistnode *p;
491
492
0
  if (!cursor)
493
0
    return -1;
494
495
0
  CHECKLAST(l);
496
497
0
  if (!*cursor) {
498
0
    p = l->header->forward[0];
499
0
  } else {
500
0
    p = *cursor;
501
0
    p = p->forward[0];
502
0
  }
503
0
  *cursor = p;
504
505
0
  if (!p)
506
0
    return -1;
507
508
0
  if (keyPointer)
509
0
    *keyPointer = p->key;
510
511
0
  if (valuePointer)
512
0
    *valuePointer = p->value;
513
514
0
  CHECKLAST(l);
515
516
0
  return 0;
517
0
}
518
519
int skiplist_delete_first(register struct skiplist *l)
520
0
{
521
0
  register int k;
522
0
  register struct skiplistnode *p, *q;
523
0
  int nodelevel = 0;
524
525
0
  CHECKLAST(l);
526
527
0
  p = l->header;
528
0
  q = l->header->forward[0];
529
530
0
  if (!q)
531
0
    return -1;
532
533
0
  for (k = l->level; k >= 0; --k) {
534
0
    if (p->forward[k] == q) {
535
0
      p->forward[k] = q->forward[k];
536
0
      if ((k == l->level) && (p->forward[k] == NULL)
537
0
          && (l->level > 0))
538
0
        --(l->level);
539
0
      if (!nodelevel)
540
0
        nodelevel = k;
541
0
    }
542
0
  }
543
544
0
#ifdef SKIPLIST_0TIMER_DEBUG
545
0
  q->flags &= ~SKIPLIST_NODE_FLAG_INSERTED;
546
0
#endif
547
  /*
548
   * If we are deleting the last element of the list,
549
   * update the list's "last" pointer.
550
   */
551
0
  if (l->last == q) {
552
0
    l->last = NULL;
553
0
  }
554
555
0
  --(l->level_stats[nodelevel]);
556
#ifdef SKIPLIST_DEBUG
557
  zlog_debug("%s: decremented level_stats @%p:%d, now %d", __func__, l,
558
       nodelevel, l->level_stats[nodelevel]);
559
#endif
560
561
0
  if (l->del)
562
0
    (*l->del)(q->value);
563
564
0
  XFREE(MTYPE_SKIP_LIST_NODE, q);
565
566
0
  CHECKLAST(l);
567
568
0
  --(l->count);
569
570
0
  return 0;
571
0
}
572
573
void skiplist_debug(struct vty *vty, struct skiplist *l)
574
0
{
575
0
  int i;
576
577
0
  if (!l)
578
0
    return;
579
580
0
  vty_out(vty, "Skiplist %p has max level %d\n", l, l->level);
581
0
  for (i = l->level; i >= 0; --i)
582
0
    vty_out(vty, "  @%d: %d\n", i, l->level_stats[i]);
583
0
}
584
585
static void *scramble(int i)
586
0
{
587
0
  uintptr_t result;
588
589
0
  result = (unsigned)(i & 0xff) << 24;
590
0
  result |= (unsigned)i >> 8;
591
592
0
  return (void *)result;
593
0
}
594
595
0
#define sampleSize 65536
596
void skiplist_test(struct vty *vty)
597
0
{
598
0
  struct skiplist *l;
599
0
  register int i, k;
600
0
  void *keys[sampleSize];
601
0
  void *v = NULL;
602
603
0
  zlog_debug("%s: entry", __func__);
604
605
0
  l = skiplist_new(SKIPLIST_FLAG_ALLOW_DUPLICATES, NULL, NULL);
606
607
0
  zlog_debug("%s: skiplist_new returned %p", __func__, l);
608
609
0
  for (i = 0; i < 4; i++) {
610
611
0
    for (k = 0; k < sampleSize; k++) {
612
0
      if (!(k % 1000)) {
613
0
        zlog_debug("%s: (%d:%d)", __func__, i, k);
614
0
      }
615
      // keys[k] = (void *)random();
616
0
      keys[k] = scramble(k);
617
0
      if (skiplist_insert(l, keys[k], keys[k]))
618
0
        zlog_debug("error in insert #%d,#%d", i, k);
619
0
    }
620
621
0
    zlog_debug("%s: inserts done", __func__);
622
623
0
    for (k = 0; k < sampleSize; k++) {
624
625
0
      if (!(k % 1000))
626
0
        zlog_debug("[%d:%d]", i, k);
627
0
      if (skiplist_search(l, keys[k], &v))
628
0
        zlog_debug("error in search #%d,#%d", i, k);
629
630
0
      if (v != keys[k])
631
0
        zlog_debug("search returned wrong value");
632
0
    }
633
634
635
0
    for (k = 0; k < sampleSize; k++) {
636
637
0
      if (!(k % 1000))
638
0
        zlog_debug("<%d:%d>", i, k);
639
0
      if (skiplist_delete(l, keys[k], keys[k]))
640
0
        zlog_debug("error in delete");
641
0
      keys[k] = scramble(k ^ 0xf0f0f0f0);
642
0
      if (skiplist_insert(l, keys[k], keys[k]))
643
0
        zlog_debug("error in insert #%d,#%d", i, k);
644
0
    }
645
646
0
    for (k = 0; k < sampleSize; k++) {
647
648
0
      if (!(k % 1000))
649
0
        zlog_debug("{%d:%d}", i, k);
650
0
      if (skiplist_delete_first(l))
651
0
        zlog_debug("error in delete_first");
652
0
    }
653
0
  }
654
655
0
  skiplist_free(l);
656
0
}