move prev into sle; use sizeof, not offset, add revs to entry

This commit is contained in:
Gregory Burd 2024-03-20 15:23:27 -04:00
parent d3d491f1c7
commit 48a09e0c4d
2 changed files with 92 additions and 90 deletions

View file

@ -30,18 +30,18 @@
* another, logic you'll provide in SKIP_DECL as a block below. * another, logic you'll provide in SKIP_DECL as a block below.
*/ */
struct slex_node { struct slex_node {
int key; int key;
int value; int value;
SKIP_ENTRY(slex_node) entries; SKIP_ENTRY(slex_node) entries;
}; };
/* /*
* Generate all the access functions for our type of Skiplist. * Generate all the access functions for our type of Skiplist.
*/ */
SKIPLIST_DECL( SKIPLIST_DECL(
slex, api_, entries, slex, api_, entries,
/* free node */ { (void)node; }, /* free node */ { (void)node; },
/* update node */ { node->value = new->value; }) /* update node */ { node->value = new->value; })
/* /*
* Getter * Getter
@ -50,7 +50,7 @@ SKIPLIST_DECL(
* extract data from within your nodes. * extract data from within your nodes.
*/ */
SKIPLIST_GETTERS( SKIPLIST_GETTERS(
slex, api_, int, int, { query.key = key; }, { return node->value; }) slex, api_, int, int, { query.key = key; }, { return node->value; })
/* /*
* Now we need a way to compare the nodes you defined above. * Now we need a way to compare the nodes you defined above.
@ -76,13 +76,13 @@ SKIPLIST_GETTERS(
int int
__slm_key_compare(slex_t *list, slex_node_t *a, slex_node_t *b, void *aux) __slm_key_compare(slex_t *list, slex_node_t *a, slex_node_t *b, void *aux)
{ {
(void)list; (void)list;
(void)aux; (void)aux;
if (a->key < b->key) if (a->key < b->key)
return -1; return -1;
if (a->key > b->key) if (a->key > b->key)
return 1; return 1;
return 0; return 0;
} }
#define DOT #define DOT
@ -93,71 +93,71 @@ SKIPLIST_DECL_DOT(slex, api_, entries)
void void
sprintf_slex_node(slex_node_t *node, char *buf) sprintf_slex_node(slex_node_t *node, char *buf)
{ {
sprintf(buf, "%d:%d", node->key, node->value); sprintf(buf, "%d:%d", node->key, node->value);
} }
#endif #endif
int int
main() main()
{ {
int rc = 0; int rc = 0;
/* Allocate and initialize a Skiplist. */ /* Allocate and initialize a Skiplist. */
slex_t *list = (slex_t *)malloc(sizeof(slex_t)); slex_t *list = (slex_t *)malloc(sizeof(slex_t));
if (list == NULL) { if (list == NULL) {
rc = ENOMEM; rc = ENOMEM;
goto fail; goto fail;
} }
rc = api_skip_init_slex(list, 12, __slm_key_compare); rc = api_skip_init_slex(list, 12, __slm_key_compare);
if (rc)
return rc;
struct slex_node *n;
/* Insert 7 key/value pairs into the list. */
for (int i = -200; i <= 200; i++) {
int v;
slex_node_t new;
rc = api_skip_alloc_node_slex(list, &n);
if (rc) if (rc)
return rc; return rc;
n->key = i;
n->value = i;
api_skip_insert_slex(list, n);
v = api_skip_get_slex(list, i);
((void)v);
new.key = n->key;
new.value = n->value * 10;
api_skip_update_slex(list, &new);
}
slex_node_t q; struct slex_node *n;
q.key = 0;
api_skip_remove_slex(list, &q);
// assert(api_skip_gte_slex(list, -3000000) == -20); /* Insert 7 key/value pairs into the list. */
assert(api_skip_gte_slex(list, -2) == -20); for (int i = -50; i <= 50; i++) {
assert(api_skip_gte_slex(list, 0) == 10); int v;
// assert(api_skip_gte_slex(list, 0) == 0); slex_node_t new;
assert(api_skip_gte_slex(list, 2) == 20); rc = api_skip_alloc_node_slex(list, &n);
assert(api_skip_gte_slex(list, 30000000) == 0); if (rc)
return rc;
n->key = i;
n->value = i;
api_skip_insert_slex(list, n);
v = api_skip_get_slex(list, i);
((void)v);
new.key = n->key;
new.value = n->value * 10;
api_skip_update_slex(list, &new);
}
assert(api_skip_lte_slex(list, -3000000) == 0); slex_node_t q;
assert(api_skip_lte_slex(list, -2) == -20); q.key = 0;
assert(api_skip_lte_slex(list, 0) == -10); api_skip_remove_slex(list, &q);
// assert(api_skip_lte_slex(list, 0) == 0);
assert(api_skip_lte_slex(list, 2) == 20);
// assert(api_skip_lte_slex(list, 30000000) == 20);
FILE *of = fopen("/tmp/slm.dot", "w"); // assert(api_skip_gte_slex(list, -3000000) == -20);
if (!of) { assert(api_skip_gte_slex(list, -2) == -20);
perror("Failed to open file /tmp/slm.dot"); assert(api_skip_gte_slex(list, 0) == 10);
return EXIT_FAILURE; // assert(api_skip_gte_slex(list, 0) == 0);
} assert(api_skip_gte_slex(list, 2) == 20);
api_skip_dot_slex(of, list, 0, sprintf_slex_node); assert(api_skip_gte_slex(list, 30000000) == 0);
fclose(of);
api_skip_destroy_slex(list); 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, 30000000) == 20);
FILE *of = fopen("/tmp/slm.dot", "w");
if (!of) {
perror("Failed to open file /tmp/slm.dot");
return EXIT_FAILURE;
}
api_skip_dot_slex(of, list, 0, sprintf_slex_node);
fclose(of);
api_skip_destroy_slex(list);
fail:; fail:;
return rc; return rc;
} }

View file

@ -104,14 +104,16 @@
struct type *slh_tail; \ struct type *slh_tail; \
} }
#define SKIP_ENTRY(type) \ #define SKIP_ENTRY(type) \
struct { \ struct __skiplist_entry { \
struct __sle { \ struct __skiplist_idx { \
struct type **next; \ struct type *prev, **next; \
size_t cap; \ size_t cap, len; \
size_t len; \ } sle; \
} sle; \ struct __skiplist_revs { \
struct type *sle_prev; \ struct __skiplist_idx **rev; \
size_t ref; \
} **slr; \
} }
/* /*
@ -120,7 +122,7 @@
#define SKIP_FIRST(head) ((head)->slh_head) #define SKIP_FIRST(head) ((head)->slh_head)
#define SKIP_LAST(head) ((head)->slh_tail) #define SKIP_LAST(head) ((head)->slh_tail)
#define SKIP_NEXT(elm, field) ((elm)->field.sle.next[0]) #define SKIP_NEXT(elm, field) ((elm)->field.sle.next[0])
#define SKIP_PREV(elm, field) ((elm)->field.sle_prev) #define SKIP_PREV(elm, field) ((elm)->field.sle.prev)
#define SKIP_EMPTY(head) ((head)->length == 0) #define SKIP_EMPTY(head) ((head)->length == 0)
/* /*
@ -204,8 +206,8 @@
{ \ { \
decl##_node_t *n; \ decl##_node_t *n; \
/* Calculate the size of the struct sle within decl##_node_t, multiply \ /* Calculate the size of the struct sle within decl##_node_t, multiply \
by array size. */ \ by array size. (16/24 bytes on 32/64 bit systems) */ \
size_t sle_arr_sz = (sizeof(size_t) + offsetof(struct __sle, len)) * slist->max; \ size_t sle_arr_sz = sizeof(struct __skiplist_idx) * slist->max; \
n = (decl##_node_t *)calloc(1, sizeof(decl##_node_t) + sle_arr_sz); \ n = (decl##_node_t *)calloc(1, sizeof(decl##_node_t) + sle_arr_sz); \
if (n == NULL) \ if (n == NULL) \
return ENOMEM; \ return ENOMEM; \
@ -239,11 +241,11 @@
slist->slh_head->field.sle.len = slist->max; \ slist->slh_head->field.sle.len = slist->max; \
for (i = 0; i < slist->max; i++) \ for (i = 0; i < slist->max; i++) \
slist->slh_head->field.sle.next[i] = slist->slh_tail; \ slist->slh_head->field.sle.next[i] = slist->slh_tail; \
slist->slh_head->field.sle_prev = NULL; \ slist->slh_head->field.sle.prev = NULL; \
slist->slh_tail->field.sle.len = slist->max; \ slist->slh_tail->field.sle.len = slist->max; \
for (i = 0; i < slist->max; i++) \ for (i = 0; i < slist->max; i++) \
slist->slh_tail->field.sle.next[i] = NULL; \ slist->slh_tail->field.sle.next[i] = NULL; \
slist->slh_head->field.sle_prev = slist->slh_tail; \ slist->slh_head->field.sle.prev = slist->slh_tail; \
/* NOTE: Here's a testing aid, simply set `max` to a negative number to \ /* 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. \ * seed the PRNG in a predictable way and have reproducible random numbers. \
*/ \ */ \
@ -283,7 +285,7 @@
/* -- skip_tail_ */ \ /* -- skip_tail_ */ \
decl##_node_t *prefix##skip_tail_##decl(decl##_t *slist) \ decl##_node_t *prefix##skip_tail_##decl(decl##_t *slist) \
{ \ { \
return slist->slh_tail->field.sle_prev; \ return slist->slh_tail->field.sle.prev; \
} \ } \
\ \
/* -- __skip_locate_ \ /* -- __skip_locate_ \
@ -350,9 +352,9 @@
n->field.sle.next[i] = slist->slh_tail; \ n->field.sle.next[i] = slist->slh_tail; \
} \ } \
} \ } \
n->field.sle_prev = path[1]; \ n->field.sle.prev = path[1]; \
if (n->field.sle.next[0] == slist->slh_tail) { \ if (n->field.sle.next[0] == slist->slh_tail) { \
slist->slh_tail->field.sle_prev = n; \ slist->slh_tail->field.sle.prev = n; \
} \ } \
if (level > slist->level) { \ if (level > slist->level) { \
slist->level = level; \ slist->level = level; \
@ -453,7 +455,7 @@
return elm; \ return elm; \
} else { \ } else { \
do { \ do { \
elm = elm->field.sle_prev; \ elm = elm->field.sle.prev; \
cmp = __skip_key_compare_##decl(slist, elm, n, slist->aux); \ cmp = __skip_key_compare_##decl(slist, elm, n, slist->aux); \
} while (cmp > 0); \ } while (cmp > 0); \
} \ } \
@ -503,7 +505,7 @@
len = __skip_locate_##decl(slist, n, path); \ len = __skip_locate_##decl(slist, n, path); \
node = path[0]; \ node = path[0]; \
if (node) { \ if (node) { \
node->field.sle.next[0]->field.sle_prev = node->field.sle_prev; \ node->field.sle.next[0]->field.sle.prev = node->field.sle.prev; \
for (i = 1; i <= len; i++) { \ for (i = 1; i <= len; i++) { \
if (path[i]->field.sle.next[i - 1] != node) \ if (path[i]->field.sle.next[i - 1] != node) \
break; \ break; \
@ -546,9 +548,9 @@
{ \ { \
if (slist == NULL || n == NULL) \ if (slist == NULL || n == NULL) \
return NULL; \ return NULL; \
if (n->field.sle_prev == slist->slh_head) \ if (n->field.sle.prev == slist->slh_head) \
return NULL; \ return NULL; \
return n->field.sle_prev; \ return n->field.sle.prev; \
} \ } \
\ \
/* -- skip_destroy_ */ \ /* -- skip_destroy_ */ \
@ -769,10 +771,10 @@
fprintf(os, "\"node%zu %p\" [label = \"", nsg, (void *)slist->slh_tail); \ fprintf(os, "\"node%zu %p\" [label = \"", nsg, (void *)slist->slh_tail); \
level = tail->field.sle.len - 1; \ level = tail->field.sle.len - 1; \
do { \ do { \
fprintf(os, "<w%zu> %p", level, (void *)node->field.sle_prev); \ fprintf(os, "<w%zu> %p", level, (void *)node->field.sle.prev); \
if (level && node->field.sle_prev != slist->slh_head) \ if (level && node->field.sle.prev != slist->slh_head) \
fprintf(os, " | "); \ fprintf(os, " | "); \
} while (level-- && node->field.sle_prev != slist->slh_head); \ } while (level-- && node->field.sle.prev != slist->slh_head); \
fprintf(os, "\" shape = \"record\"];\n"); \ fprintf(os, "\" shape = \"record\"];\n"); \
} \ } \
\ \