splay v1/p1; every search via locate()
This commit is contained in:
parent
65f4bf6bf4
commit
37321594e3
2 changed files with 874 additions and 854 deletions
|
@ -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);
|
||||||
|
|
267
include/sl.h
267
include/sl.h
|
@ -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); \
|
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/** \
|
/** \
|
||||||
|
|
Loading…
Reference in a new issue