This commit is contained in:
Gregory Burd 2024-03-20 14:33:08 -04:00
parent 448aa42e6c
commit d3d491f1c7
2 changed files with 32 additions and 13 deletions

View file

@ -7,6 +7,11 @@
#include <time.h>
#include <unistd.h>
/* Setting this will do two things:
* 1) limit our max height across all instances of this datastructure.
* 2) remove a heap allocation on frequently used paths, insert/remove/etc.
* so, use it when you need it.
*/
#define SKIPLIST_MAX_HEIGHT 12
#include "../include/sl.h"
@ -109,7 +114,7 @@ main()
struct slex_node *n;
/* Insert 7 key/value pairs into the list. */
for (int i = -2; i <= 2; i++) {
for (int i = -200; i <= 200; i++) {
int v;
slex_node_t new;
rc = api_skip_alloc_node_slex(list, &n);
@ -129,17 +134,19 @@ main()
q.key = 0;
api_skip_remove_slex(list, &q);
assert(api_skip_gte_slex(list, -3) == -20);
// assert(api_skip_gte_slex(list, -3000000) == -20);
assert(api_skip_gte_slex(list, -2) == -20);
assert(api_skip_gte_slex(list, 0) == 10);
// assert(api_skip_gte_slex(list, 0) == 0);
assert(api_skip_gte_slex(list, 2) == 20);
assert(api_skip_gte_slex(list, 3) == 0);
assert(api_skip_gte_slex(list, 30000000) == 0);
assert(api_skip_lte_slex(list, -3) == 0);
assert(api_skip_lte_slex(list, -3000000) == 0);
assert(api_skip_lte_slex(list, -2) == -20);
assert(api_skip_lte_slex(list, 0) == -10);
// assert(api_skip_lte_slex(list, 0) == 0);
assert(api_skip_lte_slex(list, 2) == 20);
assert(api_skip_lte_slex(list, 3) == 20);
// assert(api_skip_lte_slex(list, 30000000) == 20);
FILE *of = fopen("/tmp/slm.dot", "w");
if (!of) {

View file

@ -226,6 +226,9 @@
slist->level = 0; \
slist->length = 0; \
slist->max = (size_t)(max < 0 ? -max : max); \
slist->max = SKIPLIST_MAX_HEIGHT == 1 ? slist->max : SKIPLIST_MAX_HEIGHT; \
if (SKIPLIST_MAX_HEIGHT > 1 && slist->max > SKIPLIST_MAX_HEIGHT) \
return -1; \
slist->cmp = cmp; \
rc = prefix##skip_alloc_node_##decl(slist, &slist->slh_head); \
if (rc) \
@ -241,8 +244,9 @@
for (i = 0; i < slist->max; i++) \
slist->slh_tail->field.sle.next[i] = NULL; \
slist->slh_head->field.sle_prev = slist->slh_tail; \
/* Testing aid: set `max` to a negative number to seed the PRNG in a \
predictable way and have reproducible numbers. */ \
/* NOTE: Here's a testing aid, simply set `max` to a negative number to \
* seed the PRNG in a predictable way and have reproducible random numbers. \
*/ \
if (max < 0) \
srand(-max); \
else \
@ -315,7 +319,7 @@
/* -- __skip_insert_ */ \
static int __skip_insert_##decl(decl##_t *slist, decl##_node_t *n, int flags) \
{ \
static decl##_node_t apath[SKIPLIST_MAX_HEIGHT]; \
static decl##_node_t apath[SKIPLIST_MAX_HEIGHT + 1]; \
size_t i, len, level; \
decl##_node_t *node, **path = (decl##_node_t **)&apath; \
\
@ -344,13 +348,17 @@
path[i + 1]->field.sle.next[i] = n; \
} else { \
n->field.sle.next[i] = slist->slh_tail; \
slist->level++; \
} \
} \
n->field.sle_prev = path[1]; \
if (n->field.sle.next[0] == slist->slh_tail) { \
slist->slh_tail->field.sle_prev = n; \
} \
if (level > slist->level) { \
slist->level = level; \
slist->slh_head->entries.sle.len = slist->level; \
slist->slh_tail->entries.sle.len = slist->level; \
} \
slist->length++; \
\
if (SKIPLIST_MAX_HEIGHT == 1) \
@ -476,7 +484,7 @@
/* -- skip_remove_ */ \
int prefix##skip_remove_##decl(decl##_t *slist, decl##_node_t *n) \
{ \
static decl##_node_t apath[SKIPLIST_MAX_HEIGHT]; \
static decl##_node_t apath[SKIPLIST_MAX_HEIGHT + 1]; \
size_t i, len, level; \
decl##_node_t *node, **path = (decl##_node_t **)&apath; \
\
@ -511,9 +519,13 @@
\
/* Find all levels in the first element in the list that point \
at the tail and shrink the level. */ \
while (slist->level > 0 && slist->slh_head->field.sle.next[slist->level] == slist->slh_tail) { \
slist->level--; \
} \
i = 0; \
node = slist->slh_head; \
while (node->field.sle.next[i] != slist->slh_tail && i++ < slist->level) \
; \
slist->level = i; \
slist->slh_head->field.sle.len = i; \
slist->slh_tail->field.sle.len = i; \
slist->length--; \
} \
return 0; \