splay v1/p1; every search via locate()

This commit is contained in:
Gregory Burd 2024-03-31 16:37:14 -04:00
parent 65f4bf6bf4
commit 37321594e3
2 changed files with 874 additions and 854 deletions

View file

@ -68,16 +68,11 @@ SKIPLIST_DECL(
}, },
/* free entry: node */ /* free entry: node */
{ free(node->value); }, { free(node->value); },
/* update entry: rc, src, dest */ /* update entry: rc, node, value */
{ {
char *new = calloc(strlen(node->value) + 1, sizeof(char)); if (node->value)
if (new == NULL) {
rc = ENOMEM;
} else {
strncpy(new, node->value, strlen(node->value));
free(node->value); free(node->value);
node->value = new; node->value = (char*)value;
}
}, },
/* archive an entry: rc, src, dest */ /* archive an entry: rc, src, dest */
{ {
@ -178,6 +173,7 @@ SKIPLIST_DECL_DOT(sample, api_, entries)
void void
sprintf_sample_node(sample_node_t *node, char *buf) sprintf_sample_node(sample_node_t *node, char *buf)
{ {
// sprintf(buf, "h:%lu <<>> %d:%s", node->entries.sle_hits, node->key, node->value);
sprintf(buf, "%d:%s", node->key, node->value); sprintf(buf, "%d:%s", node->key, node->value);
} }
@ -298,8 +294,8 @@ main()
shuffle(array, asz); shuffle(array, asz);
for (i = 0; i < asz; i++) { for (i = 0; i < asz; i++) {
numeral = int_to_roman_numeral(array[i]); numeral = to_lower(int_to_roman_numeral(array[i]));
rc = api_skip_put_sample(list, array[i], to_lower(numeral)); rc = api_skip_put_sample(list, array[i], numeral);
CHECK; CHECK;
#ifdef SNAPSHOTS #ifdef SNAPSHOTS
if (i > TEST_ARRAY_SIZE + 1) { if (i > TEST_ARRAY_SIZE + 1) {
@ -314,7 +310,10 @@ main()
#endif #endif
char *v = api_skip_get_sample(list, array[i]); char *v = api_skip_get_sample(list, array[i]);
CHECK; CHECK;
api_skip_set_sample(list, array[i], to_upper(v)); char *upper_numeral = calloc(1, strlen(v) + 1);
strncpy(upper_numeral, v, strlen(v));
to_upper(upper_numeral);
api_skip_set_sample(list, array[i], upper_numeral);
CHECK; CHECK;
} }
numeral = int_to_roman_numeral(-1); numeral = int_to_roman_numeral(-1);
@ -358,7 +357,7 @@ main()
#ifdef SNAPSHOTS #ifdef SNAPSHOTS
//api_skip_restore_snapshot_sample(list, snap_ids[snap_i - 1]); //api_skip_restore_snapshot_sample(list, snap_ids[snap_i - 1]);
api_skip_release_snapshots_sample(list); //api_skip_release_snapshots_sample(list);
#endif #endif
assert(strcmp(api_skip_pos_sample(list, SKIP_GTE, -(TEST_ARRAY_SIZE)-1)->value, int_to_roman_numeral(-(TEST_ARRAY_SIZE))) == 0); assert(strcmp(api_skip_pos_sample(list, SKIP_GTE, -(TEST_ARRAY_SIZE)-1)->value, int_to_roman_numeral(-(TEST_ARRAY_SIZE))) == 0);

View file

@ -200,6 +200,7 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
struct decl##_node *sle_prev, **sle_next; \ struct decl##_node *sle_prev, **sle_next; \
size_t sle_height; \ size_t sle_height; \
size_t sle_era; \ size_t sle_era; \
size_t sle_hits; \
} }
#define SKIPLIST_FOREACH_H2T(decl, prefix, list, elm, iter) \ #define SKIPLIST_FOREACH_H2T(decl, prefix, list, elm, iter) \
@ -235,9 +236,12 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
/* Skiplist structure and type */ \ /* Skiplist structure and type */ \
typedef struct decl { \ typedef struct decl { \
size_t slh_length, slh_height, slh_max_height; \ size_t slh_length, slh_height, slh_max_height; \
void *slh_aux; \
decl##_node_t *slh_head; \
decl##_node_t *slh_tail; \
struct { \ struct { \
void (*free_entry)(decl##_node_t *); \ void (*free_entry)(decl##_node_t *); \
int (*update_entry)(decl##_node_t *); \ 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)(struct decl *, decl##_node_t *, decl##_node_t *, void *); \
@ -249,9 +253,9 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
size_t (*snapshot_incr_era)(struct decl *); \ size_t (*snapshot_incr_era)(struct decl *); \
void (*snapshot_record_era)(struct decl *, decl##_node_t *); \ void (*snapshot_record_era)(struct decl *, decl##_node_t *); \
} slh_fns; \ } slh_fns; \
void *slh_aux; \ struct { \
decl##_node_t *slh_head; \ size_t threshold; \
decl##_node_t *slh_tail; \ } slh_splay; \
struct { \ struct { \
size_t era; \ size_t era; \
decl##_node_t *pres; \ decl##_node_t *pres; \
@ -283,7 +287,7 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
* \ * \
* Wraps the `update_entry_blk` code into `slh_fns.update_entry`. \ * Wraps the `update_entry_blk` code into `slh_fns.update_entry`. \
*/ \ */ \
static int __skip_update_entry_fn_##decl(decl##_node_t *node) \ static int __skip_update_entry_fn_##decl(decl##_node_t *node, void *value) \
{ \ { \
int rc = 0; \ int rc = 0; \
update_entry_blk; \ update_entry_blk; \
@ -575,6 +579,18 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
return nodes; \ return nodes; \
} \ } \
\ \
/** \
* -- __skip_rebalance_ TODO \
* \
*/ \
static void __skip_rebalance_##decl(decl##_t *slist, size_t len, decl##_node_t **path, size_t par_sum) \
{ \
((void)slist); \
((void)len); \
((void)path); \
((void)par_sum); \
} \
\
/** \ /** \
* -- __skip_locate_ \ * -- __skip_locate_ \
* \ * \
@ -586,7 +602,7 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
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, decl##_node_t **path) \
{ \ { \
unsigned int i; \ unsigned int i; \
size_t len = 0; \ size_t par_sum = 0, len = 0; \
decl##_node_t *elm = slist->slh_head; \ decl##_node_t *elm = slist->slh_head; \
\ \
if (slist == NULL || n == NULL) \ if (slist == NULL || n == NULL) \
@ -598,11 +614,14 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
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] = elm; \
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] = elm; \
path[0]->field.sle_hits++; \
__skip_rebalance_##decl(slist, len, path, par_sum); \
} \ } \
return len; \ return len; \
} \ } \
@ -616,10 +635,10 @@ 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]; \
int rc = 0; \ int rc = 0; \
static decl##_node_t apath[SKIPLIST_MAX_HEIGHT + 1]; \
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 = (decl##_node_t **)&apath; \ decl##_node_t *node, **path = apath; \
\ \
if (slist == NULL || new == NULL) \ if (slist == NULL || new == NULL) \
return ENOENT; \ return ENOENT; \
@ -725,29 +744,33 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
* \ * \
* Find a node that matches the node `n`. This differs from the locate() \ * Find a node that matches the node `n`. This differs from the locate() \
* API in that it does not return the path to the node, only the match. \ * API in that it does not return the path to the node, only the match. \
* \
* NOTE: This differs from _locate() in that it avoids an alloc/free \
* for the path when SKIPLIST_MAX_HEIGHT == 1. \
*/ \ */ \
decl##_node_t *prefix##skip_position_eq_##decl(decl##_t *slist, decl##_node_t *n) \ decl##_node_t *prefix##skip_position_eq_##decl(decl##_t *slist, decl##_node_t *query) \
{ \ { \
unsigned int i; \ static decl##_node_t *apath[SKIPLIST_MAX_HEIGHT + 1]; \
decl##_node_t *elm = slist->slh_head; \ size_t len = 0; \
decl##_node_t *rc = NULL, *node, **path = apath; \
\ \
if (slist == NULL || n == NULL) \ /* Allocate a buffer, or use a static one. */ \
return NULL; \ if (SKIPLIST_MAX_HEIGHT == 1) { \
\ path = malloc(sizeof(decl##_node_t *) * slist->slh_max_height + 1); \
i = slist->slh_head->field.sle_height; \ if (path == NULL) \
\ goto done; \
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) \
elm = elm->field.sle_next[i]; \
} while (i--); \
elm = elm->field.sle_next[0]; \
if (__skip_compare_nodes_##decl(slist, elm, n, slist->slh_aux) == 0) { \
return elm; \
} \ } \
return NULL; \ memset(path, 0, sizeof(decl##_node_t *) * slist->slh_max_height + 1); \
\
/* Find a `path` to `new` in the list and a match (`path[0]`) if it exists. */ \
len = __skip_locate_##decl(slist, query, path); \
if (len == 0) \
goto done; \
node = path[0]; \
if (node != NULL) \
rc = node; \
done:; \
if (SKIPLIST_MAX_HEIGHT == 1) \
free(path); \
\
return rc; \
} \ } \
\ \
/** \ /** \
@ -756,30 +779,34 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
* Position and return a cursor at the first node that is equal to \ * Position and return a cursor at the first node that is equal to \
* or greater than the provided node `n`, otherwise if the largest \ * or greater than the provided node `n`, otherwise if the largest \
* key is less than the key in `n` return NULL. \ * key is less than the key in `n` return NULL. \
* \
* NOTE: This differs from _locate() in that it avoids an alloc/free \
* for the path when SKIPLIST_MAX_HEIGHT == 1. \
*/ \ */ \
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]; \
int cmp; \ int cmp; \
unsigned int i; \ decl##_node_t *node, **path = apath; \
decl##_node_t *elm = slist->slh_head; \
\ \
if (slist == NULL || query == NULL) \ /* Allocate a buffer, or use a static one. */ \
return NULL; \ if (SKIPLIST_MAX_HEIGHT == 1) { \
\ path = malloc(sizeof(decl##_node_t *) * slist->slh_max_height + 1); \
i = slist->slh_head->field.sle_height; \ if (path == NULL) \
goto done; \
} \
memset(path, 0, sizeof(decl##_node_t *) * slist->slh_max_height + 1); \
\ \
/* Find a `path` to `new` in the list and a match (`path[0]`) if it exists. */ \
__skip_locate_##decl(slist, query, path); \
node = path[1]; \
do { \ do { \
while (elm != slist->slh_tail && elm->field.sle_next[i] && __skip_compare_nodes_##decl(slist, elm->field.sle_next[i], query, slist->slh_aux) < 0) \ node = node->field.sle_next[0]; \
elm = elm->field.sle_next[i]; \ cmp = __skip_compare_nodes_##decl(slist, node, query, slist->slh_aux); \
} while (i--); \
do { \
elm = elm->field.sle_next[0]; \
cmp = __skip_compare_nodes_##decl(slist, elm, query, slist->slh_aux); \
} while (cmp < 0); \ } while (cmp < 0); \
return elm; \ \
done:; \
if (SKIPLIST_MAX_HEIGHT == 1) \
free(path); \
\
return node; \
} \ } \
\ \
/** \ /** \
@ -788,30 +815,36 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
* Position and return a cursor at the first node that is greater than \ * Position and return a cursor at the first node that is greater than \
* the provided node `n`. If the largestkey is less than the key in `n` \ * the provided node `n`. If the largestkey is less than the key in `n` \
* return NULL. \ * return NULL. \
* \
* NOTE: This differs from _locate() in that it avoids an alloc/free \
* for the path when SKIPLIST_MAX_HEIGHT == 1. \
*/ \ */ \
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]; \
int cmp; \ int cmp; \
unsigned int i; \ decl##_node_t *node, **path = apath; \
decl##_node_t *elm = slist->slh_head; \
\ \
if (slist == NULL || query == NULL) \ /* Allocate a buffer, or use a static one. */ \
return NULL; \ if (SKIPLIST_MAX_HEIGHT == 1) { \
\ path = malloc(sizeof(decl##_node_t *) * slist->slh_max_height + 1); \
i = slist->slh_head->field.sle_height; \ if (path == NULL) \
goto done; \
} \
memset(path, 0, sizeof(decl##_node_t *) * slist->slh_max_height + 1); \
\ \
/* Find a `path` to `new` in the list and a match (`path[0]`) if it exists. */ \
__skip_locate_##decl(slist, query, path); \
node = path[1]; \
if (node == slist->slh_tail) \
goto done; \
do { \ do { \
while (elm != slist->slh_tail && elm->field.sle_next[i] && __skip_compare_nodes_##decl(slist, elm->field.sle_next[i], query, slist->slh_aux) < 0) \ node = node->field.sle_next[0]; \
elm = elm->field.sle_next[i]; \ cmp = __skip_compare_nodes_##decl(slist, node, query, slist->slh_aux); \
} while (i--); \ } while (cmp <= 0 && node != slist->slh_tail); \
do { \ \
elm = elm->field.sle_next[0]; \ done:; \
cmp = __skip_compare_nodes_##decl(slist, elm, query, slist->slh_aux); \ if (SKIPLIST_MAX_HEIGHT == 1) \
} while (cmp <= 0); \ free(path); \
return elm; \ \
return node; \
} \ } \
\ \
/** \ /** \
@ -820,35 +853,32 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
* Position and return a cursor at the last node that is less than \ * Position and return a cursor at the last node that is less than \
* or equal to node `n`. \ * or equal to node `n`. \
* Return NULL if nothing is less than or equal. \ * Return NULL if nothing is less than or equal. \
* \
* NOTE: This differs from _locate() in that it avoids an alloc/free \
* for the path when SKIPLIST_MAX_HEIGHT == 1. \
*/ \ */ \
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) \
{ \ { \
int cmp; \ static decl##_node_t *apath[SKIPLIST_MAX_HEIGHT + 1]; \
unsigned int i; \ decl##_node_t *node, **path = apath; \
decl##_node_t *elm = slist->slh_head; \
\ \
if (slist == NULL || query == NULL) \ /* Allocate a buffer, or use a static one. */ \
return NULL; \ if (SKIPLIST_MAX_HEIGHT == 1) { \
\ path = malloc(sizeof(decl##_node_t *) * slist->slh_max_height + 1); \
i = slist->slh_head->field.sle_height; \ if (path == NULL) \
\ goto done; \
do { \
while (elm != slist->slh_tail && elm->field.sle_next[i] && __skip_compare_nodes_##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_compare_nodes_##decl(slist, elm, query, slist->slh_aux) == 0) { \
return elm; \
} else { \
do { \
elm = elm->field.sle_prev; \
cmp = __skip_compare_nodes_##decl(slist, elm, query, slist->slh_aux); \
} while (cmp >= 0); \
} \ } \
return elm; \ memset(path, 0, sizeof(decl##_node_t *) * slist->slh_max_height + 1); \
\
/* Find a `path` to `new` in the list and a match (`path[0]`) if it exists. */ \
__skip_locate_##decl(slist, query, path); \
node = path[0]; \
if (node) \
goto done; \
node = path[1]; \
\
done:; \
if (SKIPLIST_MAX_HEIGHT == 1) \
free(path); \
\
return node; \
} \ } \
\ \
/** \ /** \
@ -856,40 +886,35 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
* \ * \
* Position and return a cursor at the last node that is less than \ * Position and return a cursor at the last node that is less than \
* to the node `n`. Return NULL if nothing is less than or equal. \ * to the node `n`. Return NULL if nothing is less than or equal. \
* \
* NOTE: This differs from _locate() in that it avoids an alloc/free \
* for the path when SKIPLIST_MAX_HEIGHT == 1. \
*/ \ */ \
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) \
{ \ { \
int cmp; \ static decl##_node_t *apath[SKIPLIST_MAX_HEIGHT + 1]; \
unsigned int i; \ decl##_node_t *node, **path = apath; \
decl##_node_t *elm = slist->slh_head; \
\ \
if (slist == NULL || query == NULL) \ /* Allocate a buffer, or use a static one. */ \
return NULL; \ if (SKIPLIST_MAX_HEIGHT == 1) { \
path = malloc(sizeof(decl##_node_t *) * slist->slh_max_height + 1); \
if (path == NULL) \
goto done; \
} \
memset(path, 0, sizeof(decl##_node_t *) * slist->slh_max_height + 1); \
\ \
i = slist->slh_head->field.sle_height; \ /* Find a `path` to `new` in the list and a match (`path[0]`) if it exists. */ \
__skip_locate_##decl(slist, query, path); \
node = path[1]; \
\ \
do { \ done:; \
while (elm != slist->slh_tail && elm->field.sle_next[i] && __skip_compare_nodes_##decl(slist, elm->field.sle_next[i], query, slist->slh_aux) < 0) \ if (SKIPLIST_MAX_HEIGHT == 1) \
elm = elm->field.sle_next[i]; \ free(path); \
} while (i--); \ \
elm = elm->field.sle_next[0]; \ return node; \
do { \
elm = elm->field.sle_prev; \
cmp = __skip_compare_nodes_##decl(slist, elm, query, slist->slh_aux); \
} while (cmp >= 0); \
return elm; \
} \ } \
\ \
/** \ /** \
* -- skip_position_ \ * -- skip_position_ \
* \ * \
* Position a cursor relative to `n`. \ * Position a cursor relative to `n`. \
* \
* NOTE: This differs from _locate() in that it avoids an alloc/free \
* for the path when SKIPLIST_MAX_HEIGHT == 1. \
*/ \ */ \
decl##_node_t *prefix##skip_position_##decl(decl##_t *slist, skip_pos_##decl_t op, decl##_node_t *query) \ decl##_node_t *prefix##skip_position_##decl(decl##_t *slist, skip_pos_##decl_t op, decl##_node_t *query) \
{ \ { \
@ -925,11 +950,11 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
* WARNING: Do not update the portion of the node used for ordering \ * WARNING: Do not update the portion of the node used for ordering \
* (e.g. `key`) unless you really know what you're doing. \ * (e.g. `key`) unless you really know what you're doing. \
*/ \ */ \
int prefix##skip_update_##decl(decl##_t *slist, decl##_node_t *dest) \ int prefix##skip_update_##decl(decl##_t *slist, decl##_node_t *query, void *value) \
{ \ { \
static decl##_node_t apath[SKIPLIST_MAX_HEIGHT + 1]; \ static decl##_node_t *apath[SKIPLIST_MAX_HEIGHT + 1]; \
int rc = 0, np; \ int rc = 0, np; \
decl##_node_t *src, **path = (decl##_node_t **)&apath; \ decl##_node_t *node, **path = apath; \
\ \
if (slist == NULL) \ if (slist == NULL) \
return -1; \ return -1; \
@ -942,31 +967,29 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
} \ } \
memset(path, 0, sizeof(decl##_node_t *) * slist->slh_max_height + 1); \ memset(path, 0, sizeof(decl##_node_t *) * slist->slh_max_height + 1); \
\ \
__skip_locate_##decl(slist, dest, path); \ __skip_locate_##decl(slist, query, path); \
src = path[0]; \ node = path[0]; \
\ \
if (SKIPLIST_MAX_HEIGHT == 1) \ if (SKIPLIST_MAX_HEIGHT == 1) \
free(path); \ free(path); \
\ \
if (src == NULL) \ if (node == NULL) \
return -1; \ return -1; \
\ \
/* 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 \
moment. */ \ moment. */ \
if (slist->slh_fns.preserve_node) { \ if (slist->slh_fns.preserve_node) { \
np = slist->slh_fns.preserve_node(slist, src, NULL); \ np = slist->slh_fns.preserve_node(slist, node, NULL); \
if (np > 0) \ if (np > 0) \
return np; \ return np; \
if (slist->slh_fns.snapshot_incr_era) \
slist->slh_fns.snapshot_incr_era(slist); \
} \ } \
\ \
slist->slh_fns.update_entry(src); \ slist->slh_fns.update_entry(node, value); \
\ \
/* Record the era for this node to enable snapshots. */ \ /* Record the era for this node to enable snapshots. */ \
if (slist->slh_fns.snapshot_record_era) \ if (slist->slh_fns.snapshot_record_era) \
slist->slh_fns.snapshot_record_era(slist, src); \ slist->slh_fns.snapshot_record_era(slist, node); \
\ \
return rc; \ return rc; \
} \ } \
@ -978,10 +1001,10 @@ 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 decl##_node_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 = (decl##_node_t **)&apath; \ decl##_node_t *node, **path = apath; \
\ \
if (slist == NULL || query == NULL) \ if (slist == NULL || query == NULL) \
return -1; \ return -1; \
@ -1007,8 +1030,6 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
np = slist->slh_fns.preserve_node(slist, node, NULL); \ np = slist->slh_fns.preserve_node(slist, node, NULL); \
if (np > 0) \ if (np > 0) \
return np; \ return np; \
if (slist->slh_fns.snapshot_incr_era) \
slist->slh_fns.snapshot_incr_era(slist); \
} \ } \
/* We found it, set the next->prev to the node->prev keeping in mind \ /* We found it, set the next->prev to the node->prev keeping in mind \
that the next node might be the tail). */ \ that the next node might be the tail). */ \
@ -1192,6 +1213,7 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
if (slist == NULL) \ if (slist == NULL) \
return 0; \ return 0; \
slist->slh_snap.era = slist->slh_fns.snapshot_current_era(slist); \ slist->slh_snap.era = slist->slh_fns.snapshot_current_era(slist); \
slist->slh_fns.snapshot_incr_era(slist); \
return slist->slh_snap.era; \ return slist->slh_snap.era; \
} \ } \
\ \
@ -1796,8 +1818,7 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
{ \ { \
decl##_node_t node; \ decl##_node_t node; \
node.key = key; \ node.key = key; \
node.value = value; \ return prefix##skip_update_##decl(slist, &node, (void *)value); \
return prefix##skip_update_##decl(slist, &node); \
} \ } \
\ \
/** \ /** \