splay v1/p4; __skiplist_path with intersection

This commit is contained in:
Gregory Burd 2024-04-01 10:50:07 -04:00
parent b62fd4bf6a
commit 8703fbb5a9

View file

@ -195,12 +195,12 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
#endif #endif
/* /*
* A Skiplist contains elements, a portion of which is used to manage those * Every Skiplist node has to hvae an additional section of data used to manage
* elements while the rest is defined by the use case for this declaration. The * nodes in the list. The rest of the datastructure is defined by the use case.
* housekeeping portion is the SKIPLIST_ENTRY below. It maintains the array of * This housekeeping portion is the SKIPLIST_ENTRY, see below. It maintains the
* forward pointers to nodes and has a height (a zero-based count of levels, so * array of forward pointers to nodes and has a height, this height is a a
* a height of `0` means one (1) level and a height of `4` means five (5) * zero-based count of levels, so a height of `0` means one (1) level and a
* levels). * height of `4` means five (5) forward pointers (levels) in the node, [0-4).
*/ */
#define SKIPLIST_ENTRY(decl) \ #define SKIPLIST_ENTRY(decl) \
struct __skiplist_##decl##_entry { \ struct __skiplist_##decl##_entry { \
@ -240,8 +240,11 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
/* Skiplist node type */ \ /* Skiplist node type */ \
typedef struct decl##_node decl##_node_t; \ typedef struct decl##_node decl##_node_t; \
\ \
/* Skiplist structure and type */ \ /* Skiplist type. */ \
typedef struct decl { \ typedef struct decl decl##_t; \
\
/* Skiplist structure */ \
struct decl { \
size_t slh_length, slh_height, slh_max_height; \ size_t slh_length, slh_height, slh_max_height; \
void *slh_aux; \ void *slh_aux; \
decl##_node_t *slh_head; \ decl##_node_t *slh_head; \
@ -251,14 +254,14 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
int (*update_entry)(decl##_node_t *, void *); \ int (*update_entry)(decl##_node_t *, void *); \
int (*archive_entry)(decl##_node_t *, const decl##_node_t *); \ int (*archive_entry)(decl##_node_t *, const decl##_node_t *); \
size_t (*sizeof_entry)(decl##_node_t *); \ size_t (*sizeof_entry)(decl##_node_t *); \
int (*compare_entries)(struct decl *, decl##_node_t *, decl##_node_t *, void *); \ int (*compare_entries)(decl##_t *, decl##_node_t *, decl##_node_t *, void *); \
\ \
/* Optional: Snapshots */ \ /* Optional: Snapshots */ \
int (*preserve_node)(struct decl * slist, const decl##_node_t *src, decl##_node_t **preserved); \ int (*preserve_node)(decl##_t * slist, const decl##_node_t *src, decl##_node_t **preserved); \
void (*release_snapshots)(struct decl *); \ void (*release_snapshots)(decl##_t *); \
size_t (*snapshot_current_era)(struct decl *); \ size_t (*snapshot_current_era)(decl##_t *); \
size_t (*snapshot_incr_era)(struct decl *); \ size_t (*snapshot_incr_era)(decl##_t *); \
void (*snapshot_record_era)(struct decl *, decl##_node_t *); \ void (*snapshot_record_era)(decl##_t *, decl##_node_t *); \
} slh_fns; \ } slh_fns; \
struct { \ struct { \
size_t threshold; /* `k`, the floor of log(max height) */ \ size_t threshold; /* `k`, the floor of log(max height) */ \
@ -268,7 +271,12 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
size_t era; \ size_t era; \
decl##_node_t *pres; \ decl##_node_t *pres; \
} slh_snap; \ } slh_snap; \
} decl##_t; \ }; \
\
typedef struct __skiplist_path_##decl { \
decl##_node_t *node; /* node traversed in the act of location */ \
size_t intersection; /* level at which the node was intersected */ \
} __skiplist_path_##decl##_t; \
\ \
/** \ /** \
* -- __skip_compare_entries_fn_ \ * -- __skip_compare_entries_fn_ \
@ -592,29 +600,31 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
* -- __skip_rebalence_ TODO \ * -- __skip_rebalence_ TODO \
* \ * \
*/ \ */ \
static void __skip_rebalence_##decl(decl##_t *slist, size_t len, decl##_node_t **path, size_t par_sum) \ static void __skip_rebalence_##decl(decl##_t *slist, size_t len, __skiplist_path_##decl##_t path[], size_t par_sum) \
{ \ { \
size_t i; \ size_t i; \
double asc_cond, dsc_cond; \ double asc_cond, dsc_cond; \
\ \
return; /* TODO GSB */ \
/* Moving backwards along the path... */ \ /* Moving backwards along the path... */ \
for (i = 1; i < len; i++) { \ for (i = 1; i < len; i++) { \
if (par_sum > 0) { \ if (par_sum > 0) { \
/* check the decent condition: \ /* check the decent condition: \
par_sum <= hits total / (2 ^ (height of head - height of node)) \ * par_sum <= hits total / (2 ^ (height of head - height of node)) \
*/ \ */ \
dsc_cond = pow(2.0, slist->slh_head->field.sle_height - path[i]->field.sle_height); \ dsc_cond = pow(2.0, slist->slh_head->field.sle_height - path[i].node->field.sle_height); \
if (par_sum <= dsc_cond) { \ if (par_sum <= dsc_cond) { \
/* reduce height by one, change forward pointer */ \ /* reduce height by one, change forward pointer */ \
path[i - 1]->field.sle_next[i] = path[i]->field.sle_next[i]; \ path[i - 1].node->field.sle_next[i] = path[i].node->field.sle_next[i]; \
path[i]->field.sle_next[i] = slist->slh_tail; \ path[i].node->field.sle_next[i] = slist->slh_tail; \
path[i]->field.sle_height--; \ path[i].node->field.sle_height--; \
} \ } \
/* check the ascent condition \ /* check the ascent condition: \
par_sum + node_hits > hits total / (2 ^ (height of head - height of node - 1)) \ * par_sum + node_hits > hits total / (2 ^ (height of head - height of node - 1)) \
*/ \ */ \
asc_cond = pow(2.0, slist->slh_head->field.sle_height - path[i]->field.sle_height - 1); \ asc_cond = pow(2.0, slist->slh_head->field.sle_height - path[i].node->field.sle_height - 1); \
if (+path[i]->field.sle_hits > asc_cond) { \ if (path[i].node->field.sle_hits > asc_cond) { \
((void)0); \
} \ } \
} \ } \
} \ } \
@ -628,7 +638,7 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
* node in path[0], or NULL at path[0] where there wasn't a match. \ * node in path[0], or NULL at path[0] where there wasn't a match. \
* sizeof(path) should be `slist->slh_max_height + 1` \ * sizeof(path) should be `slist->slh_max_height + 1` \
*/ \ */ \
static size_t __skip_locate_##decl(decl##_t *slist, decl##_node_t *n, decl##_node_t **path) \ static size_t __skip_locate_##decl(decl##_t *slist, decl##_node_t *n, __skiplist_path_##decl##_t path[]) \
{ \ { \
unsigned int i; \ unsigned int i; \
size_t par_sum = 0, len = 0; \ size_t par_sum = 0, len = 0; \
@ -640,16 +650,18 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
/* Find the node that matches `node` or NULL. */ \ /* Find the node that matches `node` or NULL. */ \
i = slist->slh_head->field.sle_height; \ i = slist->slh_head->field.sle_height; \
do { \ do { \
while (elm != slist->slh_tail && elm->field.sle_next[i] && __skip_compare_nodes_##decl(slist, elm->field.sle_next[i], n, slist->slh_aux) < 0) \ while (elm != slist->slh_tail && elm->field.sle_next[i] && __skip_compare_nodes_##decl(slist, elm->field.sle_next[i], n, slist->slh_aux) < 0) { \
elm = elm->field.sle_next[i]; \ elm = elm->field.sle_next[i]; \
path[i + 1] = elm; \ path[i + 1].intersection = i; \
} \
path[i + 1].node = elm; \
par_sum += elm->field.sle_hits; \ par_sum += elm->field.sle_hits; \
len++; \ len++; \
} while (i--); \ } while (i--); \
elm = elm->field.sle_next[0]; \ elm = elm->field.sle_next[0]; \
if (__skip_compare_nodes_##decl(slist, elm, n, slist->slh_aux) == 0) { \ if (__skip_compare_nodes_##decl(slist, elm, n, slist->slh_aux) == 0) { \
path[0] = elm; \ path[0].node = elm; \
path[0]->field.sle_hits++; \ path[0].node->field.sle_hits++; \
__skip_rebalence_##decl(slist, len, path, par_sum); \ __skip_rebalence_##decl(slist, len, path, par_sum); \
} \ } \
return len; \ return len; \
@ -664,25 +676,26 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
*/ \ */ \
static int __skip_insert_##decl(decl##_t *slist, decl##_node_t *new, int flags) \ static int __skip_insert_##decl(decl##_t *slist, decl##_node_t *new, int flags) \
{ \ { \
static decl##_node_t *apath[SKIPLIST_MAX_HEIGHT + 1]; \ static __skiplist_path_##decl##_t apath[SKIPLIST_MAX_HEIGHT + 1]; \
int rc = 0; \ int rc = 0; \
size_t i, len, loc = 0, cur_height, new_height; \ size_t i, len, loc = 0, cur_height, new_height; \
decl##_node_t *node, **path = apath; \ decl##_node_t *node; \
__skiplist_path_##decl##_t *path = apath; \
\ \
if (slist == NULL || new == NULL) \ if (slist == NULL || new == NULL) \
return ENOENT; \ return ENOENT; \
\ \
/* Allocate a buffer, or use a static one. */ \ /* Allocate a buffer, or use a static one. */ \
if (SKIPLIST_MAX_HEIGHT == 1) { \ if (SKIPLIST_MAX_HEIGHT == 1) { \
path = malloc(sizeof(decl##_node_t *) * slist->slh_max_height + 1); \ path = malloc(sizeof(__skiplist_path_##decl##_t) * slist->slh_max_height + 1); \
if (path == NULL) \ if (path == NULL) \
return ENOMEM; \ return ENOMEM; \
} \ } \
memset(path, 0, sizeof(decl##_node_t *) * slist->slh_max_height + 1); \ memset(path, 0, sizeof(__skiplist_path_##decl##_t) * slist->slh_max_height + 1); \
\ \
/* Find a `path` to `new` in the list and a match (`path[0]`) if it exists. */ \ /* Find a `path` to `new` in the list and a match (`path[0]`) if it exists. */ \
len = __skip_locate_##decl(slist, new, path); \ len = __skip_locate_##decl(slist, new, path); \
node = path[0]; \ node = path[0].node; \
if (len > 0) { \ if (len > 0) { \
if ((node != NULL) && (flags == 0)) { \ if ((node != NULL) && (flags == 0)) { \
/* Don't insert, duplicate if flag not set. */ \ /* Don't insert, duplicate if flag not set. */ \
@ -695,7 +708,7 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
/* Trim the path to at most the new height for the new node. */ \ /* Trim the path to at most the new height for the new node. */ \
if (new_height > cur_height) { \ if (new_height > cur_height) { \
for (i = cur_height + 1; i <= new_height; i++) { \ for (i = cur_height + 1; i <= new_height; i++) { \
path[i + 1] = slist->slh_tail; \ path[i + 1].node = slist->slh_tail; \
} \ } \
} \ } \
/* Ensure all next[] point to tail. */ \ /* Ensure all next[] point to tail. */ \
@ -708,23 +721,23 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
/* The tail's next[i] is always NULL, we don't want that in the \ /* The tail's next[i] is always NULL, we don't want that in the \
next[i] for our new node. Also, don't set the tail's next[i] \ next[i] for our new node. Also, don't set the tail's next[i] \
because it is always NULL. */ \ because it is always NULL. */ \
if (path[i + 1] != slist->slh_tail) { \ if (path[i + 1].node != slist->slh_tail) { \
new->field.sle_next[i] = path[i + 1]->field.sle_next[i]; \ new->field.sle_next[i] = path[i + 1].node->field.sle_next[i]; \
path[i + 1]->field.sle_next[i] = new; \ path[i + 1].node->field.sle_next[i] = new; \
loc = path[i + 1] == slist->slh_head ? i : loc; \ loc = path[i + 1].node == slist->slh_head ? i : loc; \
} else { \ } 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. */ \ /* Ensure all slh_head->next[] above loc point to tail. */ \
if (path[1] == slist->slh_head) { \ if (path[1].node == slist->slh_head) { \
__SKIP_ENTRIES_B2T_FROM(field, slist->slh_head, loc + 1) \ __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. */ \ /* Adujust the previous pointers in the nodes. */ \
new->field.sle_prev = path[1]; \ new->field.sle_prev = path[1].node; \
new->field.sle_next[0]->field.sle_prev = new; \ new->field.sle_next[0]->field.sle_prev = new; \
/* Account for insert at tail. */ \ /* Account for insert at tail. */ \
if (new->field.sle_next[0] == slist->slh_tail) { \ if (new->field.sle_next[0] == slist->slh_tail) { \
@ -778,30 +791,26 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
*/ \ */ \
decl##_node_t *prefix##skip_position_eq_##decl(decl##_t *slist, decl##_node_t *query) \ decl##_node_t *prefix##skip_position_eq_##decl(decl##_t *slist, decl##_node_t *query) \
{ \ { \
static decl##_node_t *apath[SKIPLIST_MAX_HEIGHT + 1]; \ static __skiplist_path_##decl##_t apath[SKIPLIST_MAX_HEIGHT + 1]; \
size_t len = 0; \ decl##_node_t *node = NULL; \
decl##_node_t *rc = NULL, *node, **path = apath; \ __skiplist_path_##decl##_t *path = apath; \
\ \
/* Allocate a buffer, or use a static one. */ \ /* Allocate a buffer, or use a static one. */ \
if (SKIPLIST_MAX_HEIGHT == 1) { \ if (SKIPLIST_MAX_HEIGHT == 1) { \
path = malloc(sizeof(decl##_node_t *) * slist->slh_max_height + 1); \ path = malloc(sizeof(__skiplist_path_##decl##_t) * slist->slh_max_height + 1); \
if (path == NULL) \ if (path == NULL) \
goto done; \ goto done; \
} \ } \
memset(path, 0, sizeof(decl##_node_t *) * slist->slh_max_height + 1); \ memset(path, 0, sizeof(__skiplist_path_##decl##_t) * slist->slh_max_height + 1); \
\ \
/* Find a `path` to `new` in the list and a match (`path[0]`) if it exists. */ \ /* Find a `path` to `new` in the list and a match (`path[0]`) if it exists. */ \
len = __skip_locate_##decl(slist, query, path); \ __skip_locate_##decl(slist, query, path); \
if (len == 0) \ node = path[0].node; \
goto done; \
node = path[0]; \
if (node != NULL) \
rc = node; \
done:; \ done:; \
if (SKIPLIST_MAX_HEIGHT == 1) \ if (SKIPLIST_MAX_HEIGHT == 1) \
free(path); \ free(path); \
\ \
return rc; \ return node; \
} \ } \
\ \
/** \ /** \
@ -813,21 +822,22 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
*/ \ */ \
decl##_node_t *prefix##skip_position_gte_##decl(decl##_t *slist, decl##_node_t *query) \ decl##_node_t *prefix##skip_position_gte_##decl(decl##_t *slist, decl##_node_t *query) \
{ \ { \
static decl##_node_t *apath[SKIPLIST_MAX_HEIGHT + 1]; \ static __skiplist_path_##decl##_t apath[SKIPLIST_MAX_HEIGHT + 1]; \
int cmp; \ int cmp; \
decl##_node_t *node, **path = apath; \ decl##_node_t *node; \
__skiplist_path_##decl##_t *path = apath; \
\ \
/* Allocate a buffer, or use a static one. */ \ /* Allocate a buffer, or use a static one. */ \
if (SKIPLIST_MAX_HEIGHT == 1) { \ if (SKIPLIST_MAX_HEIGHT == 1) { \
path = malloc(sizeof(decl##_node_t *) * slist->slh_max_height + 1); \ path = malloc(sizeof(__skiplist_path_##decl##_t) * slist->slh_max_height + 1); \
if (path == NULL) \ if (path == NULL) \
goto done; \ goto done; \
} \ } \
memset(path, 0, sizeof(decl##_node_t *) * slist->slh_max_height + 1); \ memset(path, 0, sizeof(__skiplist_path_##decl##_t) * slist->slh_max_height + 1); \
\ \
/* Find a `path` to `new` in the list and a match (`path[0]`) if it exists. */ \ /* Find a `path` to `new` in the list and a match (`path[0]`) if it exists. */ \
__skip_locate_##decl(slist, query, path); \ __skip_locate_##decl(slist, query, path); \
node = path[1]; \ node = path[1].node; \
do { \ do { \
node = node->field.sle_next[0]; \ node = node->field.sle_next[0]; \
cmp = __skip_compare_nodes_##decl(slist, node, query, slist->slh_aux); \ cmp = __skip_compare_nodes_##decl(slist, node, query, slist->slh_aux); \
@ -849,21 +859,22 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
*/ \ */ \
decl##_node_t *prefix##skip_position_gt_##decl(decl##_t *slist, decl##_node_t *query) \ decl##_node_t *prefix##skip_position_gt_##decl(decl##_t *slist, decl##_node_t *query) \
{ \ { \
static decl##_node_t *apath[SKIPLIST_MAX_HEIGHT + 1]; \ static __skiplist_path_##decl##_t apath[SKIPLIST_MAX_HEIGHT + 1]; \
int cmp; \ int cmp; \
decl##_node_t *node, **path = apath; \ decl##_node_t *node; \
__skiplist_path_##decl##_t *path = apath; \
\ \
/* Allocate a buffer, or use a static one. */ \ /* Allocate a buffer, or use a static one. */ \
if (SKIPLIST_MAX_HEIGHT == 1) { \ if (SKIPLIST_MAX_HEIGHT == 1) { \
path = malloc(sizeof(decl##_node_t *) * slist->slh_max_height + 1); \ path = malloc(sizeof(__skiplist_path_##decl##_t) * slist->slh_max_height + 1); \
if (path == NULL) \ if (path == NULL) \
goto done; \ goto done; \
} \ } \
memset(path, 0, sizeof(decl##_node_t *) * slist->slh_max_height + 1); \ memset(path, 0, sizeof(__skiplist_path_##decl##_t) * slist->slh_max_height + 1); \
\ \
/* Find a `path` to `new` in the list and a match (`path[0]`) if it exists. */ \ /* Find a `path` to `new` in the list and a match (`path[0]`) if it exists. */ \
__skip_locate_##decl(slist, query, path); \ __skip_locate_##decl(slist, query, path); \
node = path[1]; \ node = path[1].node; \
if (node == slist->slh_tail) \ if (node == slist->slh_tail) \
goto done; \ goto done; \
do { \ do { \
@ -887,23 +898,24 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
*/ \ */ \
decl##_node_t *prefix##skip_position_lte_##decl(decl##_t *slist, decl##_node_t *query) \ decl##_node_t *prefix##skip_position_lte_##decl(decl##_t *slist, decl##_node_t *query) \
{ \ { \
static decl##_node_t *apath[SKIPLIST_MAX_HEIGHT + 1]; \ static __skiplist_path_##decl##_t apath[SKIPLIST_MAX_HEIGHT + 1]; \
decl##_node_t *node, **path = apath; \ decl##_node_t *node; \
__skiplist_path_##decl##_t *path = apath; \
\ \
/* Allocate a buffer, or use a static one. */ \ /* Allocate a buffer, or use a static one. */ \
if (SKIPLIST_MAX_HEIGHT == 1) { \ if (SKIPLIST_MAX_HEIGHT == 1) { \
path = malloc(sizeof(decl##_node_t *) * slist->slh_max_height + 1); \ path = malloc(sizeof(__skiplist_path_##decl##_t) * slist->slh_max_height + 1); \
if (path == NULL) \ if (path == NULL) \
goto done; \ goto done; \
} \ } \
memset(path, 0, sizeof(decl##_node_t *) * slist->slh_max_height + 1); \ memset(path, 0, sizeof(__skiplist_path_##decl##_t) * slist->slh_max_height + 1); \
\ \
/* Find a `path` to `new` in the list and a match (`path[0]`) if it exists. */ \ /* Find a `path` to `new` in the list and a match (`path[0]`) if it exists. */ \
__skip_locate_##decl(slist, query, path); \ __skip_locate_##decl(slist, query, path); \
node = path[0]; \ node = path[0].node; \
if (node) \ if (node) \
goto done; \ goto done; \
node = path[1]; \ node = path[1].node; \
\ \
done:; \ done:; \
if (SKIPLIST_MAX_HEIGHT == 1) \ if (SKIPLIST_MAX_HEIGHT == 1) \
@ -920,20 +932,21 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
*/ \ */ \
decl##_node_t *prefix##skip_position_lt_##decl(decl##_t *slist, decl##_node_t *query) \ decl##_node_t *prefix##skip_position_lt_##decl(decl##_t *slist, decl##_node_t *query) \
{ \ { \
static decl##_node_t *apath[SKIPLIST_MAX_HEIGHT + 1]; \ static __skiplist_path_##decl##_t apath[SKIPLIST_MAX_HEIGHT + 1]; \
decl##_node_t *node, **path = apath; \ decl##_node_t *node; \
__skiplist_path_##decl##_t *path = apath; \
\ \
/* Allocate a buffer, or use a static one. */ \ /* Allocate a buffer, or use a static one. */ \
if (SKIPLIST_MAX_HEIGHT == 1) { \ if (SKIPLIST_MAX_HEIGHT == 1) { \
path = malloc(sizeof(decl##_node_t *) * slist->slh_max_height + 1); \ path = malloc(sizeof(__skiplist_path_##decl##_t) * slist->slh_max_height + 1); \
if (path == NULL) \ if (path == NULL) \
goto done; \ goto done; \
} \ } \
memset(path, 0, sizeof(decl##_node_t *) * slist->slh_max_height + 1); \ memset(path, 0, sizeof(__skiplist_path_##decl##_t) * slist->slh_max_height + 1); \
\ \
/* Find a `path` to `new` in the list and a match (`path[0]`) if it exists. */ \ /* Find a `path` to `new` in the list and a match (`path[0]`) if it exists. */ \
__skip_locate_##decl(slist, query, path); \ __skip_locate_##decl(slist, query, path); \
node = path[1]; \ node = path[1].node; \
\ \
done:; \ done:; \
if (SKIPLIST_MAX_HEIGHT == 1) \ if (SKIPLIST_MAX_HEIGHT == 1) \
@ -983,23 +996,24 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
*/ \ */ \
int prefix##skip_update_##decl(decl##_t *slist, decl##_node_t *query, void *value) \ int prefix##skip_update_##decl(decl##_t *slist, decl##_node_t *query, void *value) \
{ \ { \
static decl##_node_t *apath[SKIPLIST_MAX_HEIGHT + 1]; \ static __skiplist_path_##decl##_t apath[SKIPLIST_MAX_HEIGHT + 1]; \
int rc = 0, np; \ int rc = 0, np; \
decl##_node_t *node, **path = apath; \ decl##_node_t *node; \
__skiplist_path_##decl##_t *path = apath; \
\ \
if (slist == NULL) \ if (slist == NULL) \
return -1; \ return -1; \
\ \
/* Allocate a buffer, or use a static one. */ \ /* Allocate a buffer, or use a static one. */ \
if (SKIPLIST_MAX_HEIGHT == 1) { \ if (SKIPLIST_MAX_HEIGHT == 1) { \
path = malloc(sizeof(decl##_node_t *) * slist->slh_max_height + 1); \ path = malloc(sizeof(__skiplist_path_##decl##_t) * slist->slh_max_height + 1); \
if (path == NULL) \ if (path == NULL) \
return ENOMEM; \ return ENOMEM; \
} \ } \
memset(path, 0, sizeof(decl##_node_t *) * slist->slh_max_height + 1); \ memset(path, 0, sizeof(__skiplist_path_##decl##_t) * slist->slh_max_height + 1); \
\ \
__skip_locate_##decl(slist, query, path); \ __skip_locate_##decl(slist, query, path); \
node = path[0]; \ node = path[0].node; \
\ \
if (SKIPLIST_MAX_HEIGHT == 1) \ if (SKIPLIST_MAX_HEIGHT == 1) \
free(path); \ free(path); \
@ -1032,10 +1046,11 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
*/ \ */ \
int prefix##skip_remove_node_##decl(decl##_t *slist, decl##_node_t *query) \ int prefix##skip_remove_node_##decl(decl##_t *slist, decl##_node_t *query) \
{ \ { \
static decl##_node_t *apath[SKIPLIST_MAX_HEIGHT + 1]; \ static __skiplist_path_##decl##_t apath[SKIPLIST_MAX_HEIGHT + 1]; \
int np = 0; \ int np = 0; \
size_t i, len, height; \ size_t i, len, height; \
decl##_node_t *node, **path = apath; \ decl##_node_t *node; \
__skiplist_path_##decl##_t *path = apath; \
\ \
if (slist == NULL || query == NULL) \ if (slist == NULL || query == NULL) \
return -1; \ return -1; \
@ -1044,15 +1059,15 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
\ \
/* Allocate a buffer */ \ /* Allocate a buffer */ \
if (SKIPLIST_MAX_HEIGHT == 1) { \ if (SKIPLIST_MAX_HEIGHT == 1) { \
path = malloc(sizeof(decl##_node_t *) * slist->slh_max_height + 1); \ path = malloc(sizeof(__skiplist_path_##decl##_t) * slist->slh_max_height + 1); \
if (path == NULL) \ if (path == NULL) \
return ENOMEM; \ return ENOMEM; \
} \ } \
memset(path, 0, sizeof(decl##_node_t *) * slist->slh_max_height + 1); \ memset(path, 0, sizeof(__skiplist_path_##decl##_t) * slist->slh_max_height + 1); \
\ \
/* Attempt to locate the node in the list. */ \ /* Attempt to locate the node in the list. */ \
len = __skip_locate_##decl(slist, query, path); \ len = __skip_locate_##decl(slist, query, path); \
node = path[0]; \ node = path[0].node; \
if (node) { \ if (node) { \
/* If the optional snapshots feature is configured, use it now. \ /* If the optional snapshots feature is configured, use it now. \
Snapshots preserve the node if it is younger than our snapshot \ Snapshots preserve the node if it is younger than our snapshot \
@ -1068,15 +1083,15 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
/* Walk the path, stop when the next node is not the one we're \ /* Walk the path, stop when the next node is not the one we're \
removing. At each step along our walk... */ \ removing. At each step along our walk... */ \
for (i = 0; i < len; i++) { \ for (i = 0; i < len; i++) { \
if (path[i + 1]->field.sle_next[i] != node) \ if (path[i + 1].node->field.sle_next[i] != node) \
break; \ break; \
/* ... adjust the next pointer at that level. */ \ /* ... adjust the next pointer at that level. */ \
path[i + 1]->field.sle_next[i] = node->field.sle_next[i]; \ path[i + 1].node->field.sle_next[i] = node->field.sle_next[i]; \
/* Adjust the height so we're only pointing at the tail once at \ /* Adjust the height so we're only pointing at the tail once at \
the top so we don't waste steps later when searching. */ \ the top so we don't waste steps later when searching. */ \
if (path[i + 1]->field.sle_next[i] == slist->slh_tail) { \ if (path[i + 1].node->field.sle_next[i] == slist->slh_tail) { \
height = path[i + 1]->field.sle_height; \ height = path[i + 1].node->field.sle_height; \
path[i + 1]->field.sle_height = height - 1; \ path[i + 1].node->field.sle_height = height - 1; \
} \ } \
} \ } \
/* Account for delete at tail. */ \ /* Account for delete at tail. */ \