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.
*/
struct slex_node {
int key;
int value;
SKIP_ENTRY(slex_node) entries;
int key;
int value;
SKIP_ENTRY(slex_node) entries;
};
/*
* Generate all the access functions for our type of Skiplist.
*/
SKIPLIST_DECL(
slex, api_, entries,
/* free node */ { (void)node; },
/* update node */ { node->value = new->value; })
slex, api_, entries,
/* free node */ { (void)node; },
/* update node */ { node->value = new->value; })
/*
* Getter
@ -50,7 +50,7 @@ SKIPLIST_DECL(
* extract data from within your nodes.
*/
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.
@ -76,13 +76,13 @@ SKIPLIST_GETTERS(
int
__slm_key_compare(slex_t *list, slex_node_t *a, slex_node_t *b, void *aux)
{
(void)list;
(void)aux;
if (a->key < b->key)
return -1;
if (a->key > b->key)
return 1;
return 0;
(void)list;
(void)aux;
if (a->key < b->key)
return -1;
if (a->key > b->key)
return 1;
return 0;
}
#define DOT
@ -93,71 +93,71 @@ SKIPLIST_DECL_DOT(slex, api_, entries)
void
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
int
main()
{
int rc = 0;
/* Allocate and initialize a Skiplist. */
slex_t *list = (slex_t *)malloc(sizeof(slex_t));
if (list == NULL) {
rc = ENOMEM;
goto fail;
}
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);
int rc = 0;
/* Allocate and initialize a Skiplist. */
slex_t *list = (slex_t *)malloc(sizeof(slex_t));
if (list == NULL) {
rc = ENOMEM;
goto fail;
}
rc = api_skip_init_slex(list, 12, __slm_key_compare);
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);
}
return rc;
slex_node_t q;
q.key = 0;
api_skip_remove_slex(list, &q);
struct slex_node *n;
// 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, 30000000) == 0);
/* Insert 7 key/value pairs into the list. */
for (int i = -50; i <= 50; i++) {
int v;
slex_node_t new;
rc = api_skip_alloc_node_slex(list, &n);
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);
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);
slex_node_t q;
q.key = 0;
api_skip_remove_slex(list, &q);
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);
// 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, 30000000) == 0);
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:;
return rc;
return rc;
}

View file

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