pull up struct, rename

This commit is contained in:
Gregory Burd 2024-03-27 21:37:38 -04:00
parent 0f3b3c4f82
commit a723597bdc
2 changed files with 1105 additions and 1089 deletions

View file

@ -29,7 +29,7 @@
//define SNAPSHOTS
//define DOT
#define TEST_ARRAY_SIZE 2000
#define TEST_ARRAY_SIZE 10
/*
@ -165,7 +165,7 @@ int_to_roman_numeral(int num)
char *sym[] = { "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I" }; // Symbols for key values
// The maximum length of the Roman numeral representation for the maximum signed 64-bit integer would be approximately 19 * 3 = 57 characters, assuming
// every digit is represented by its Roman numeral equivalent up to 3 repetitions. Therefore, 64 should be more than enough.
char *res = (char *)calloc(64, sizeof(char));
char *res = (char *)calloc(4096, sizeof(char));
int i = 0;
if (num < 0) {
res[0] = '-';

View file

@ -164,10 +164,8 @@
*/
#define SKIPLIST_ENTRY(type) \
struct __skiplist_##decl_entry { \
struct __skiplist_##decl_idx { \
struct type *prev, **next; \
size_t height; \
} sle; \
struct type *sle_prev, **sle_next; \
size_t sle_height; \
}
/*
@ -247,13 +245,13 @@
for (iter = prefix##skip_size_##decl(list), (elm) = prefix##skip_tailf_##decl(list); (elm) != NULL; \
iter--, (elm) = prefix##skip_prev_node_##decl(list, elm))
#define __SKIP_ENTRIES_T2B(field, elm) for (size_t lvl = elm->field.sle.height; lvl != (size_t)-1; lvl--)
#define __SKIP_ENTRIES_T2B(field, elm) for (size_t lvl = elm->field.sle_height; lvl != (size_t)-1; lvl--)
#define __SKIP_ENTRIES_T2B_FROM(field, elm, off) for (size_t lvl = off; lvl != (size_t)-1; lvl--)
#define __SKIP_IS_LAST_ENTRY_T2B() if (lvl == 0)
#define __SKIP_ENTRIES_B2T(field, elm) for (size_t lvl = 0; lvl < elm->field.sle.height + 1; lvl++)
#define __SKIP_ENTRIES_B2T_FROM(field, elm, off) for (size_t lvl = off; lvl < elm->field.sle.height + 1; lvl++)
#define __SKIP_IS_LAST_ENTRY_B2T() if (lvl + 1 == elm->field.sle.height)
#define __SKIP_ENTRIES_B2T(field, elm) for (size_t lvl = 0; lvl < elm->field.sle_height + 1; lvl++)
#define __SKIP_ENTRIES_B2T_FROM(field, elm, off) for (size_t lvl = off; lvl < elm->field.sle_height + 1; lvl++)
#define __SKIP_IS_LAST_ENTRY_B2T() if (lvl + 1 == elm->field.sle_height)
/*
* Skip List declarations and access methods.
@ -265,9 +263,9 @@
\
/* Skip List structure and type */ \
typedef struct decl { \
size_t level, length, max; \
int (*cmp)(struct decl *, decl##_node_t *, decl##_node_t *, void *); \
void *aux; \
size_t slh_level, slh_length, slh_max, slh_gen; \
int (*slh_cmp)(struct decl *, decl##_node_t *, decl##_node_t *, void *); \
void *slh_aux; \
decl##_node_t *slh_head; \
decl##_node_t *slh_tail; \
} decl##_t; \
@ -302,7 +300,7 @@
return -1; \
if (a == slist->slh_tail || b == slist->slh_head) \
return 1; \
return slist->cmp(slist, a, b, aux); \
return slist->slh_cmp(slist, a, b, aux); \
} \
\
/** \
@ -335,12 +333,12 @@
decl##_node_t *n; \
/* Calculate the size of the struct sle within decl##_node_t, multiply \
by array size. (16/24 bytes on 32/64 bit systems) */ \
size_t sle_arr_sz = sizeof(struct __skiplist_##decl_idx) * slist->max; \
size_t sle_arr_sz = sizeof(struct __skiplist_##decl_entry) * slist->slh_max; \
n = (decl##_node_t *)calloc(1, sizeof(decl##_node_t) + sle_arr_sz); \
if (n == NULL) \
return ENOMEM; \
n->field.sle.height = 0; \
n->field.sle.next = (decl##_node_t **)((uintptr_t)n + sizeof(decl##_node_t)); \
n->field.sle_height = 0; \
n->field.sle_next = (decl##_node_t **)((uintptr_t)n + sizeof(decl##_node_t)); \
*node = n; \
return 0; \
} \
@ -356,12 +354,12 @@
int rc = 0; \
size_t i; \
\
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) \
slist->slh_length = 0; \
slist->slh_max = (size_t)(max < 0 ? -max : max); \
slist->slh_max = SKIPLIST_MAX_HEIGHT == 1 ? slist->slh_max : SKIPLIST_MAX_HEIGHT; \
if (SKIPLIST_MAX_HEIGHT > 1 && slist->slh_max > SKIPLIST_MAX_HEIGHT) \
return -1; \
slist->cmp = cmp; \
slist->slh_cmp = cmp; \
rc = prefix##skip_alloc_node_##decl(slist, &slist->slh_head); \
if (rc) \
goto fail; \
@ -369,15 +367,15 @@
if (rc) \
goto fail; \
\
slist->slh_head->field.sle.height = 0; \
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_height = 0; \
for (i = 0; i < slist->slh_max; i++) \
slist->slh_head->field.sle_next[i] = slist->slh_tail; \
slist->slh_head->field.sle_prev = NULL; \
\
slist->slh_tail->field.sle.height = slist->max - 1; \
for (i = 0; i < slist->max; i++) \
slist->slh_tail->field.sle.next[i] = NULL; \
slist->slh_tail->field.sle.prev = slist->slh_head; \
slist->slh_tail->field.sle_height = slist->slh_max - 1; \
for (i = 0; i < slist->slh_max; i++) \
slist->slh_tail->field.sle_next[i] = NULL; \
slist->slh_tail->field.sle_prev = slist->slh_head; \
\
/* 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. \
@ -411,7 +409,7 @@
*/ \
int prefix##skip_size_##decl(decl##_t *slist) \
{ \
return slist->length; \
return slist->slh_length; \
} \
\
/** \
@ -421,7 +419,7 @@
*/ \
int prefix##skip_is_empty_##decl(decl##_t *slist) \
{ \
return slist->length == 0; \
return slist->slh_length == 0; \
} \
\
/** \
@ -432,7 +430,7 @@
*/ \
decl##_node_t *prefix##skip_head_##decl(decl##_t *slist) \
{ \
return slist->slh_head->field.sle.next[0] == slist->slh_tail ? NULL : slist->slh_head->field.sle.next[0]; \
return slist->slh_head->field.sle_next[0] == slist->slh_tail ? NULL : slist->slh_head->field.sle_next[0]; \
} \
\
/** \
@ -443,7 +441,7 @@
*/ \
decl##_node_t *prefix##skip_tail_##decl(decl##_t *slist) \
{ \
return slist->slh_tail->field.sle.prev == slist->slh_head->field.sle.next[0] ? NULL : slist->slh_tail->field.sle.prev; \
return slist->slh_tail->field.sle_prev == slist->slh_head->field.sle_next[0] ? NULL : slist->slh_tail->field.sle_prev; \
} \
\
/** \
@ -456,9 +454,9 @@
{ \
if (slist == NULL || n == NULL) \
return NULL; \
if (n->field.sle.next[0] == slist->slh_tail) \
if (n->field.sle_next[0] == slist->slh_tail) \
return NULL; \
return n->field.sle.next[0]; \
return n->field.sle_next[0]; \
} \
\
/** \
@ -472,9 +470,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; \
} \
\
/** \
@ -499,8 +497,8 @@
} while (node != NULL); \
\
while (node) { \
next = node->field.sle.next[0]; \
if (next->field.sle.prev) \
next = node->field.sle_next[0]; \
if (next->field.sle_prev) \
free_node_blk; \
free(node); \
} \
@ -537,7 +535,7 @@
* Locates a node that matches another node updating `path` and then \
* returning the length of that path + 1 to the node and the matching \
* node in path[0], or NULL at path[0] where there wasn't a match. \
* sizeof(path) should be `slist->max + 1` \
* sizeof(path) should be `slist->slh_max + 1` \
*/ \
static size_t __skip_locate_##decl(decl##_t *slist, decl##_node_t *n, decl##_node_t **path) \
{ \
@ -549,15 +547,15 @@
return 0; \
\
/* Find the node that matches `node` or NULL. */ \
i = slist->slh_head->field.sle.height; \
i = slist->slh_head->field.sle_height; \
do { \
while (elm != slist->slh_tail && elm->field.sle.next[i] && __skip_key_compare_##decl(slist, elm->field.sle.next[i], n, slist->aux) < 0) \
elm = elm->field.sle.next[i]; \
while (elm != slist->slh_tail && elm->field.sle_next[i] && __skip_key_compare_##decl(slist, elm->field.sle_next[i], n, slist->slh_aux) < 0) \
elm = elm->field.sle_next[i]; \
path[i + 1] = elm; \
len++; \
} while (i--); \
elm = elm->field.sle.next[0]; \
if (__skip_key_compare_##decl(slist, elm, n, slist->aux) == 0) { \
elm = elm->field.sle_next[0]; \
if (__skip_key_compare_##decl(slist, elm, n, slist->slh_aux) == 0) { \
path[0] = elm; \
} \
return len; \
@ -582,11 +580,11 @@
\
/* Allocate a buffer, or use a static one. */ \
if (SKIPLIST_MAX_HEIGHT == 1) { \
path = malloc(sizeof(decl##_node_t *) * slist->max + 1); \
path = malloc(sizeof(decl##_node_t *) * slist->slh_max + 1); \
if (path == NULL) \
return ENOMEM; \
} \
memset(path, 0, sizeof(sizeof(decl##_node_t *) * slist->max + 1)); \
memset(path, 0, sizeof(sizeof(decl##_node_t *) * slist->slh_max + 1)); \
\
/* Find a `path` to `new` in the list and a match (`path[0]`) if it exists. */ \
len = __skip_locate_##decl(slist, new, path); \
@ -597,9 +595,9 @@
return -1; \
} \
/* Coin toss to determine level of this new node [0, max) */ \
cur_height = slist->slh_head->field.sle.height; \
new_height = __skip_toss_##decl(slist->max); \
new->field.sle.height = new_height; \
cur_height = slist->slh_head->field.sle_height; \
new_height = __skip_toss_##decl(slist->slh_max); \
new->field.sle_height = new_height; \
/* Trim the path to at most the new height for the new node. */ \
if (new_height > cur_height) { \
for (i = cur_height + 1; i <= new_height; i++) { \
@ -609,7 +607,7 @@
/* Ensure all next[] point to tail. */ \
__SKIP_ENTRIES_B2T(field, new) \
{ \
new->field.sle.next[lvl] = slist->slh_tail; \
new->field.sle_next[lvl] = slist->slh_tail; \
} \
/* Adjust all forward pointers for each element in the path. */ \
for (i = 0; i <= new_height; i++) { \
@ -617,34 +615,34 @@
next[i] for our new node. Also, don't set the tail's next[i] \
because it is always NULL. */ \
if (path[i + 1] != slist->slh_tail) { \
new->field.sle.next[i] = path[i + 1]->field.sle.next[i]; \
path[i + 1]->field.sle.next[i] = new; \
new->field.sle_next[i] = path[i + 1]->field.sle_next[i]; \
path[i + 1]->field.sle_next[i] = new; \
loc = path[i + 1] == slist->slh_head ? i : loc; \
} else { \
new->field.sle.next[i] = slist->slh_tail; \
new->field.sle_next[i] = slist->slh_tail; \
} \
} \
/* Ensure all slh_head->next[] above loc point to tail. */ \
if (path[1] == slist->slh_head) { \
__SKIP_ENTRIES_B2T_FROM(field, slist->slh_head, loc + 1) \
{ \
slist->slh_head->field.sle.next[lvl] = slist->slh_tail; \
slist->slh_head->field.sle_next[lvl] = slist->slh_tail; \
} \
} \
/* Adujust the previous pointers in the nodes. */ \
new->field.sle.prev = path[1]; \
new->field.sle.next[0]->field.sle.prev = new; \
new->field.sle_prev = path[1]; \
new->field.sle_next[0]->field.sle_prev = new; \
/* Account for insert at tail. */ \
if (new->field.sle.next[0] == slist->slh_tail) { \
slist->slh_tail->field.sle.prev = new; \
if (new->field.sle_next[0] == slist->slh_tail) { \
slist->slh_tail->field.sle_prev = new; \
} \
/* Adjust the head/tail boundary node heights if necessary. */ \
if (new_height > cur_height) { \
slist->slh_head->field.sle.height = new_height; \
slist->slh_tail->field.sle.height = new_height; \
slist->slh_head->field.sle_height = new_height; \
slist->slh_tail->field.sle_height = new_height; \
} \
/* Increase our list length (aka. size, count, etc.) by one. */ \
slist->length++; \
slist->slh_length++; \
\
if (SKIPLIST_MAX_HEIGHT == 1) \
free(path); \
@ -690,14 +688,14 @@
if (slist == NULL || n == NULL) \
return NULL; \
\
i = slist->slh_head->field.sle.height; \
i = slist->slh_head->field.sle_height; \
\
do { \
while (elm != slist->slh_tail && elm->field.sle.next[i] && __skip_key_compare_##decl(slist, elm->field.sle.next[i], n, slist->aux) < 0) \
elm = elm->field.sle.next[i]; \
while (elm != slist->slh_tail && elm->field.sle_next[i] && __skip_key_compare_##decl(slist, elm->field.sle_next[i], n, slist->slh_aux) < 0) \
elm = elm->field.sle_next[i]; \
} while (i--); \
elm = elm->field.sle.next[0]; \
if (__skip_key_compare_##decl(slist, elm, n, slist->aux) == 0) { \
elm = elm->field.sle_next[0]; \
if (__skip_key_compare_##decl(slist, elm, n, slist->slh_aux) == 0) { \
return elm; \
} \
return NULL; \
@ -722,15 +720,15 @@
if (slist == NULL || query == NULL) \
return NULL; \
\
i = slist->slh_head->field.sle.height; \
i = slist->slh_head->field.sle_height; \
\
do { \
while (elm != slist->slh_tail && elm->field.sle.next[i] && __skip_key_compare_##decl(slist, elm->field.sle.next[i], query, slist->aux) < 0) \
elm = elm->field.sle.next[i]; \
while (elm != slist->slh_tail && elm->field.sle_next[i] && __skip_key_compare_##decl(slist, elm->field.sle_next[i], query, slist->slh_aux) < 0) \
elm = elm->field.sle_next[i]; \
} while (i--); \
do { \
elm = elm->field.sle.next[0]; \
cmp = __skip_key_compare_##decl(slist, elm, query, slist->aux); \
elm = elm->field.sle_next[0]; \
cmp = __skip_key_compare_##decl(slist, elm, query, slist->slh_aux); \
} while (cmp < 0); \
return elm; \
} \
@ -754,15 +752,15 @@
if (slist == NULL || query == NULL) \
return NULL; \
\
i = slist->slh_head->field.sle.height; \
i = slist->slh_head->field.sle_height; \
\
do { \
while (elm != slist->slh_tail && elm->field.sle.next[i] && __skip_key_compare_##decl(slist, elm->field.sle.next[i], query, slist->aux) < 0) \
elm = elm->field.sle.next[i]; \
while (elm != slist->slh_tail && elm->field.sle_next[i] && __skip_key_compare_##decl(slist, elm->field.sle_next[i], query, slist->slh_aux) < 0) \
elm = elm->field.sle_next[i]; \
} while (i--); \
do { \
elm = elm->field.sle.next[0]; \
cmp = __skip_key_compare_##decl(slist, elm, query, slist->aux); \
elm = elm->field.sle_next[0]; \
cmp = __skip_key_compare_##decl(slist, elm, query, slist->slh_aux); \
} while (cmp <= 0); \
return elm; \
} \
@ -786,19 +784,19 @@
if (slist == NULL || query == NULL) \
return NULL; \
\
i = slist->slh_head->field.sle.height; \
i = slist->slh_head->field.sle_height; \
\
do { \
while (elm != slist->slh_tail && elm->field.sle.next[i] && __skip_key_compare_##decl(slist, elm->field.sle.next[i], query, slist->aux) < 0) \
elm = elm->field.sle.next[i]; \
while (elm != slist->slh_tail && elm->field.sle_next[i] && __skip_key_compare_##decl(slist, elm->field.sle_next[i], query, slist->slh_aux) < 0) \
elm = elm->field.sle_next[i]; \
} while (i--); \
elm = elm->field.sle.next[0]; \
if (__skip_key_compare_##decl(slist, elm, query, slist->aux) == 0) { \
elm = elm->field.sle_next[0]; \
if (__skip_key_compare_##decl(slist, elm, query, slist->slh_aux) == 0) { \
return elm; \
} else { \
do { \
elm = elm->field.sle.prev; \
cmp = __skip_key_compare_##decl(slist, elm, query, slist->aux); \
elm = elm->field.sle_prev; \
cmp = __skip_key_compare_##decl(slist, elm, query, slist->slh_aux); \
} while (cmp >= 0); \
} \
return elm; \
@ -822,16 +820,16 @@
if (slist == NULL || query == NULL) \
return NULL; \
\
i = slist->slh_head->field.sle.height; \
i = slist->slh_head->field.sle_height; \
\
do { \
while (elm != slist->slh_tail && elm->field.sle.next[i] && __skip_key_compare_##decl(slist, elm->field.sle.next[i], query, slist->aux) < 0) \
elm = elm->field.sle.next[i]; \
while (elm != slist->slh_tail && elm->field.sle_next[i] && __skip_key_compare_##decl(slist, elm->field.sle_next[i], query, slist->slh_aux) < 0) \
elm = elm->field.sle_next[i]; \
} while (i--); \
elm = elm->field.sle.next[0]; \
elm = elm->field.sle_next[0]; \
do { \
elm = elm->field.sle.prev; \
cmp = __skip_key_compare_##decl(slist, elm, query, slist->aux); \
elm = elm->field.sle_prev; \
cmp = __skip_key_compare_##decl(slist, elm, query, slist->slh_aux); \
} while (cmp >= 0); \
return elm; \
} \
@ -889,11 +887,11 @@
\
/* Allocate a buffer, or use a static one. */ \
if (SKIPLIST_MAX_HEIGHT == 1) { \
path = malloc(sizeof(decl##_node_t *) * slist->max + 1); \
path = malloc(sizeof(decl##_node_t *) * slist->slh_max + 1); \
if (path == NULL) \
return ENOMEM; \
} \
memset(path, 0, sizeof(sizeof(decl##_node_t *) * slist->max + 1)); \
memset(path, 0, sizeof(sizeof(decl##_node_t *) * slist->slh_max + 1)); \
\
__skip_locate_##decl(slist, new, path); \
node = path[0]; \
@ -921,16 +919,16 @@
\
if (slist == NULL || n == NULL) \
return -1; \
if (slist->length == 0) \
if (slist->slh_length == 0) \
return 0; \
\
/* Allocate a buffer */ \
if (SKIPLIST_MAX_HEIGHT == 1) { \
path = malloc(sizeof(decl##_node_t *) * slist->max + 1); \
path = malloc(sizeof(decl##_node_t *) * slist->slh_max + 1); \
if (path == NULL) \
return ENOMEM; \
} \
memset(path, 0, sizeof(sizeof(decl##_node_t *) * slist->max + 1)); \
memset(path, 0, sizeof(sizeof(decl##_node_t *) * slist->slh_max + 1)); \
\
/* Attempt to locate the node in the list. */ \
len = __skip_locate_##decl(slist, n, path); \
@ -938,24 +936,24 @@
if (node) { \
/* We found it, set the next->prev to the node->prev keeping in mind \
that the next node might be the tail). */ \
node->field.sle.next[0]->field.sle.prev = node->field.sle.prev; \
node->field.sle_next[0]->field.sle_prev = node->field.sle_prev; \
/* Walk the path, stop when the next node is not the one we're \
removing. At each step along our walk... */ \
for (i = 0; i < len; i++) { \
if (path[i + 1]->field.sle.next[i] != node) \
if (path[i + 1]->field.sle_next[i] != node) \
break; \
/* ... adjust the next pointer at that level. */ \
path[i + 1]->field.sle.next[i] = node->field.sle.next[i]; \
path[i + 1]->field.sle_next[i] = node->field.sle_next[i]; \
/* Adjust the height so we're only pointing at the tail once at \
the top so we don't waste steps later when searching. */ \
if (path[i + 1]->field.sle.next[i] == slist->slh_tail) { \
height = path[i + 1]->field.sle.height; \
path[i + 1]->field.sle.height = height - 1; \
if (path[i + 1]->field.sle_next[i] == slist->slh_tail) { \
height = path[i + 1]->field.sle_height; \
path[i + 1]->field.sle_height = height - 1; \
} \
} \
/* Account for delete at tail. */ \
if (node->field.sle.next[0] == slist->slh_tail) { \
slist->slh_tail->field.sle.prev = n->field.sle.prev; \
if (node->field.sle_next[0] == slist->slh_tail) { \
slist->slh_tail->field.sle_prev = n->field.sle_prev; \
} \
\
if (SKIPLIST_MAX_HEIGHT == 1) \
@ -965,12 +963,12 @@
\
/* Reduce the height of the header. */ \
i = 0; \
while (slist->slh_head->field.sle.next[i] != slist->slh_tail && i < slist->slh_head->field.sle.height) \
while (slist->slh_head->field.sle_next[i] != slist->slh_tail && i < slist->slh_head->field.sle_height) \
i++; \
slist->slh_head->field.sle.height = i; \
slist->slh_tail->field.sle.height = i; \
slist->slh_head->field.sle_height = i; \
slist->slh_tail->field.sle_height = i; \
\
slist->length--; \
slist->slh_length--; \
} \
return 0; \
} \
@ -993,6 +991,22 @@
return; \
} \
\
/** \
* -- skip_snapshot_ \
* \
* A snapshot is a read-only view of a Skip List at a point in time. Once \
* taken, a snapshot must be restored or disposed. Any number of snapshots \
* can be created. \
*/ \
size_t prefix##skip_snapshot_##decl(decl##_t *slist) \
{ \
if (slist == NULL) \
return 0; \
\
slist->slh_gen++; \
return slist->slh_gen; \
} \
\
/* Archive of a Skip List */ \
typedef struct decl##_archive { \
decl##_t list; \
@ -1016,7 +1030,7 @@
if (slist == NULL) \
return NULL; \
\
bytes = sizeof(decl##_archive_t) + (slist->length * sizeof(decl##_node_t)); \
bytes = sizeof(decl##_archive_t) + (slist->slh_length * sizeof(decl##_node_t)); \
node = prefix##skip_head_##decl(slist); \
while (node) { \
sizeof_entry_blk; \
@ -1029,8 +1043,8 @@
return NULL; \
\
archive->bytes = bytes; \
archive->list.length = slist->length; \
archive->list.max = slist->max; \
archive->list.slh_length = slist->slh_length; \
archive->list.slh_max = slist->slh_max; \
archive->nodes = (decl##_node_t *)(archive + sizeof(decl##_archive_t)); \
\
i = 0; \
@ -1063,8 +1077,8 @@
if (slist == NULL) \
return NULL; \
\
slist->cmp = cmp; \
slist->max = archive->list.max; \
slist->slh_cmp = cmp; \
slist->slh_max = archive->list.slh_max; \
\
rc = prefix##skip_alloc_node_##decl(slist, &slist->slh_head); \
if (rc) \
@ -1073,24 +1087,24 @@
if (rc) \
goto fail; \
\
slist->slh_head->field.sle.height = 0; \
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_height = 0; \
for (i = 0; i < slist->slh_max; i++) \
slist->slh_head->field.sle_next[i] = slist->slh_tail; \
slist->slh_head->field.sle_prev = NULL; \
\
slist->slh_tail->field.sle.height = slist->max; \
for (i = 0; i < slist->max; i++) \
slist->slh_tail->field.sle.next[i] = NULL; \
slist->slh_tail->field.sle.prev = slist->slh_head; \
slist->slh_tail->field.sle_height = slist->slh_max; \
for (i = 0; i < slist->slh_max; i++) \
slist->slh_tail->field.sle_next[i] = NULL; \
slist->slh_tail->field.sle_prev = slist->slh_head; \
\
i = 0; \
while (archive->list.length > 0) { \
while (archive->list.slh_length > 0) { \
decl##_node_t *n = (decl##_node_t *)archive->nodes + (i++ * sizeof(decl##_node_t)); \
node = (decl##_node_t *)&n; \
rc = prefix##skip_alloc_node_##decl(slist, &new); \
archive_node_blk; \
__skip_insert_##decl(slist, new, 1); \
archive->list.length--; \
archive->list.slh_length--; \
} \
return slist; \
fail:; \
@ -1118,7 +1132,7 @@
{ \
unsigned long nth, n_err = 0; \
decl##_node_t *node, *prev, *next; \
struct __skiplist_##decl_idx *this; \
struct __skiplist_##decl_entry *this; \
\
if (slist == NULL) { \
__skip_integrity_failure_##decl("slist was NULL, nothing to check\n"); \
@ -1140,22 +1154,22 @@
return n_err; \
} \
\
if (slist->cmp == NULL) { \
if (slist->slh_cmp == NULL) { \
__skip_integrity_failure_##decl("skiplist comparison function (cmp) is NULL\n"); \
n_err++; \
return n_err; \
} \
\
if (slist->max < 1) { \
if (slist->slh_max < 1) { \
__skip_integrity_failure_##decl("skiplist max level must be 1 at minimum\n"); \
n_err++; \
if (flags) \
return n_err; \
} \
\
if (slist->level >= slist->max) { \
if (slist->slh_level >= slist->slh_max) { \
/* level is 0-based, max of 12 means level cannot be > 11 */ \
__skip_integrity_failure_##decl("skiplist level %lu in header was >= max %lu\n", slist->level, slist->max); \
__skip_integrity_failure_##decl("skiplist level %lu in header was >= max %lu\n", slist->slh_level, slist->slh_max); \
n_err++; \
if (flags) \
return n_err; \
@ -1168,8 +1182,9 @@
return n_err; \
} \
\
if (SKIPLIST_MAX_HEIGHT > 1 && slist->max > SKIPLIST_MAX_HEIGHT) { \
__skip_integrity_failure_##decl("slist->max %lu cannot be greater than SKIPLIST_MAX_HEIGHT %lu\n", slist->max, (size_t)SKIPLIST_MAX_HEIGHT); \
if (SKIPLIST_MAX_HEIGHT > 1 && slist->slh_max > SKIPLIST_MAX_HEIGHT) { \
__skip_integrity_failure_##decl("slist->slh_max %lu cannot be greater than SKIPLIST_MAX_HEIGHT %lu\n", slist->slh_max, \
(size_t)SKIPLIST_MAX_HEIGHT); \
n_err++; \
if (flags) \
return n_err; \
@ -1179,26 +1194,26 @@
node = slist->slh_head; \
__SKIP_ENTRIES_B2T(field, node) \
{ \
if (node->field.sle.next[lvl] == NULL) { \
if (node->field.sle_next[lvl] == NULL) { \
__skip_integrity_failure_##decl("the head's %lu next node should not be NULL\n", lvl); \
n_err++; \
if (flags) \
return n_err; \
} \
n = lvl; \
if (node->field.sle.next[lvl] == slist->slh_tail) \
if (node->field.sle_next[lvl] == slist->slh_tail) \
break; \
} \
n++; \
__SKIP_ENTRIES_B2T_FROM(field, node, n) \
{ \
if (node->field.sle.next[lvl] == NULL) { \
if (node->field.sle_next[lvl] == NULL) { \
__skip_integrity_failure_##decl("the head's %lu next node should not be NULL\n", lvl); \
n_err++; \
if (flags) \
return n_err; \
} \
if (node->field.sle.next[lvl] != slist->slh_tail) { \
if (node->field.sle_next[lvl] != slist->slh_tail) { \
__skip_integrity_failure_##decl("after internal nodes, the head's %lu next node should always be the tail\n", lvl); \
n_err++; \
if (flags) \
@ -1206,8 +1221,8 @@
} \
} \
\
if (slist->length > 0 && slist->slh_tail->field.sle.prev == slist->slh_head) { \
__skip_integrity_failure_##decl("slist->length is 0, but tail->prev == head, not an internal node\n"); \
if (slist->slh_length > 0 && slist->slh_tail->field.sle_prev == slist->slh_head) { \
__skip_integrity_failure_##decl("slist->slh_length is 0, but tail->prev == head, not an internal node\n"); \
n_err++; \
if (flags) \
return n_err; \
@ -1220,23 +1235,23 @@
/* Validate each node */ \
SKIPLIST_FOREACH_H2T(decl, prefix, slist, node, nth) \
{ \
this = &node->field.sle; \
this = &node->field; \
\
if (this->height >= slist->max) { \
__skip_integrity_failure_##decl("the %luth node's [%p] height %lu is >= max %lu\n", nth, (void *)node, this->height, slist->max); \
if (this->sle_height >= slist->slh_max) { \
__skip_integrity_failure_##decl("the %luth node's [%p] height %lu is >= max %lu\n", nth, (void *)node, this->sle_height, slist->slh_max); \
n_err++; \
if (flags) \
return n_err; \
} \
\
if (this->next == NULL) { \
if (this->sle_next == NULL) { \
__skip_integrity_failure_##decl("the %luth node's [%p] next field should never NULL\n", nth, (void *)node); \
n_err++; \
if (flags) \
return n_err; \
} \
\
if (this->prev == NULL) { \
if (this->sle_prev == NULL) { \
__skip_integrity_failure_##decl("the %luth node [%p] prev field should never NULL\n", nth, (void *)node); \
n_err++; \
if (flags) \
@ -1246,25 +1261,25 @@
size_t n = 0; \
__SKIP_ENTRIES_B2T(field, node) \
{ \
if (this->next[lvl] == NULL) { \
if (this->sle_next[lvl] == NULL) { \
__skip_integrity_failure_##decl("the %luth node's next[%lu] should not be NULL\n", nth, lvl); \
n_err++; \
if (flags) \
return n_err; \
} \
n = lvl; \
if (this->next[lvl] == slist->slh_tail) \
if (this->sle_next[lvl] == slist->slh_tail) \
break; \
} \
n++; \
__SKIP_ENTRIES_B2T_FROM(field, node, n) \
{ \
if (this->next[lvl] == NULL) { \
if (this->sle_next[lvl] == NULL) { \
__skip_integrity_failure_##decl("after the %lunth the %luth node's next[%lu] should not be NULL\n", n, nth, lvl); \
n_err++; \
if (flags) \
return n_err; \
} else if (this->next[lvl] != slist->slh_tail) { \
} else if (this->sle_next[lvl] != slist->slh_tail) { \
__skip_integrity_failure_##decl("after the %lunth the %luth node's next[%lu] should point to the tail\n", n, nth, lvl); \
n_err++; \
if (flags) \
@ -1272,7 +1287,7 @@
} \
} \
\
decl##_node_t *a = (decl##_node_t *)(uintptr_t)this->next; \
decl##_node_t *a = (decl##_node_t *)(uintptr_t)this->sle_next; \
decl##_node_t *b = (decl##_node_t *)(intptr_t)((uintptr_t)node + sizeof(decl##_node_t)); \
if (a != b) { \
__skip_integrity_failure_##decl("the %luth node's [%p] next field isn't at the proper offset relative to the node\n", nth, (void *)node); \
@ -1281,37 +1296,37 @@
return n_err; \
} \
\
next = this->next[0]; \
prev = this->prev; \
if (__skip_key_compare_##decl(slist, node, node, slist->aux) != 0) { \
next = this->sle_next[0]; \
prev = this->sle_prev; \
if (__skip_key_compare_##decl(slist, node, node, slist->slh_aux) != 0) { \
__skip_integrity_failure_##decl("the %luth node [%p] is not equal to itself\n", nth, (void *)node); \
n_err++; \
if (flags) \
return n_err; \
} \
\
if (__skip_key_compare_##decl(slist, node, prev, slist->aux) < 0) { \
if (__skip_key_compare_##decl(slist, node, prev, slist->slh_aux) < 0) { \
__skip_integrity_failure_##decl("the %luth node [%p] is not greater than the prev node [%p]\n", nth, (void *)node, (void *)prev); \
n_err++; \
if (flags) \
return n_err; \
} \
\
if (__skip_key_compare_##decl(slist, node, next, slist->aux) > 0) { \
if (__skip_key_compare_##decl(slist, node, next, slist->slh_aux) > 0) { \
__skip_integrity_failure_##decl("the %luth node [%p] is not less than the next node [%p]\n", nth, (void *)node, (void *)next); \
n_err++; \
if (flags) \
return n_err; \
} \
\
if (__skip_key_compare_##decl(slist, prev, node, slist->aux) > 0) { \
if (__skip_key_compare_##decl(slist, prev, node, slist->slh_aux) > 0) { \
__skip_integrity_failure_##decl("the prev node [%p] is not less than the %luth node [%p]\n", (void *)prev, nth, (void *)node); \
n_err++; \
if (flags) \
return n_err; \
} \
\
if (__skip_key_compare_##decl(slist, next, node, slist->aux) < 0) { \
if (__skip_key_compare_##decl(slist, next, node, slist->slh_aux) < 0) { \
__skip_integrity_failure_##decl("the next node [%p] is not greater than the %luth node [%p]\n", (void *)next, nth, (void *)node); \
n_err++; \
if (flags) \
@ -1319,8 +1334,9 @@
} \
} \
\
if (slist->length != nth) { \
__skip_integrity_failure_slex("slist->length (%lu) doesn't match the count (%lu) of nodes between the head and tail\n", slist->length, nth); \
if (slist->slh_length != nth) { \
__skip_integrity_failure_slex("slist->slh_length (%lu) doesn't match the count (%lu) of nodes between the head and tail\n", slist->slh_length, \
nth); \
n_err++; \
if (flags) \
return n_err; \
@ -1474,7 +1490,7 @@
if (from == NULL || to == NULL) \
return 0; \
\
while (n->field.sle.prev != from) { \
while (n->field.sle_prev != from) { \
w++; \
n = prefix##skip_prev_node_##decl(slist, n); \
} \
@ -1504,7 +1520,7 @@
fflush(os); \
__SKIP_ENTRIES_T2B(field, node) \
{ \
next = (node->field.sle.next[lvl] == slist->slh_tail) ? NULL : node->field.sle.next[lvl]; \
next = (node->field.sle_next[lvl] == slist->slh_tail) ? NULL : node->field.sle_next[lvl]; \
width = __skip_dot_width_##decl(slist, node, next ? next : slist->slh_tail); \
fprintf(os, " { <w%lu> %lu | <f%lu> ", lvl, width, lvl); \
if (next) \
@ -1515,9 +1531,9 @@
} \
if (fn) { \
fn(node, buf); \
fprintf(os, " <f0> \u219F %lu \u226B %s \"\n", node->field.sle.height + 1, buf); \
fprintf(os, " <f0> \u219F %lu \u226B %s \"\n", node->field.sle_height + 1, buf); \
} else { \
fprintf(os, " <f0> \u219F %lu \"\n", node->field.sle.height); \
fprintf(os, " <f0> \u219F %lu \"\n", node->field.sle_height); \
} \
fprintf(os, "shape = \"record\"\n"); \
fprintf(os, "];\n"); \
@ -1526,7 +1542,7 @@
/* Now edges */ \
__SKIP_ENTRIES_B2T(field, node) \
{ \
next = (node->field.sle.next[lvl] == slist->slh_tail) ? NULL : node->field.sle.next[lvl]; \
next = (node->field.sle_next[lvl] == slist->slh_tail) ? NULL : node->field.sle_next[lvl]; \
__skip_dot_write_node_##decl(os, nsg, node); \
fprintf(os, ":f%lu -> ", lvl); \
__skip_dot_write_node_##decl(os, nsg, next); \
@ -1605,7 +1621,7 @@
fprintf(os, "\"HeadNode%lu\" [\n", nsg); \
fprintf(os, "label = \""); \
\
if (slist->slh_head->field.sle.height || slist->slh_head->field.sle.next[0] != slist->slh_tail) \
if (slist->slh_head->field.sle_height || slist->slh_head->field.sle_next[0] != slist->slh_tail) \
letitgo = 1; \
\
/* Write out the fields */ \
@ -1613,7 +1629,7 @@
if (letitgo) { \
__SKIP_ENTRIES_T2B(field, node) \
{ \
next = (node->field.sle.next[lvl] == slist->slh_tail) ? NULL : node->field.sle.next[lvl]; \
next = (node->field.sle_next[lvl] == slist->slh_tail) ? NULL : node->field.sle_next[lvl]; \
width = __skip_dot_width_##decl(slist, node, next ? next : slist->slh_tail); \
fprintf(os, "{ %lu | <f%lu> ", width, lvl); \
if (next) \
@ -1637,7 +1653,7 @@
node = slist->slh_head; \
__SKIP_ENTRIES_B2T(field, node) \
{ \
next = (node->field.sle.next[lvl] == slist->slh_tail) ? NULL : node->field.sle.next[lvl]; \
next = (node->field.sle_next[lvl] == slist->slh_tail) ? NULL : node->field.sle_next[lvl]; \
fprintf(os, "\"HeadNode%lu\":f%lu -> ", nsg, lvl); \
__skip_dot_write_node_##decl(os, nsg, next); \
fprintf(os, ":w%lu [];\n", lvl); \
@ -1664,9 +1680,9 @@
__skip_dot_write_node_##decl(os, nsg, NULL); \
fprintf(os, " [label = \""); \
node = slist->slh_tail; \
size_t th = slist->slh_head->field.sle.height; \
size_t th = slist->slh_head->field.sle_height; \
for (size_t lvl = th; lvl != (size_t)-1; lvl--) { \
next = (node->field.sle.next[lvl] == slist->slh_tail) ? NULL : node->field.sle.next[lvl]; \
next = (node->field.sle_next[lvl] == slist->slh_tail) ? NULL : node->field.sle_next[lvl]; \
fprintf(os, "<w%lu> NULL", lvl); \
__SKIP_IS_LAST_ENTRY_T2B() continue; \
fprintf(os, " | "); \