add lt/gt; fixes
This commit is contained in:
parent
efd1933c62
commit
307d817ee0
2 changed files with 202 additions and 83 deletions
|
@ -50,7 +50,7 @@ SKIPLIST_DECL(
|
||||||
new->key = node->key;
|
new->key = node->key;
|
||||||
char *nv = calloc(strlen(node->value) + 1, sizeof(char));
|
char *nv = calloc(strlen(node->value) + 1, sizeof(char));
|
||||||
if (nv == NULL)
|
if (nv == NULL)
|
||||||
return NULL; /* leaks some memory... TODO */
|
return NULL; // leaks some memory... TODO
|
||||||
new->value = strncpy(nv, node->value, strlen(node->value));
|
new->value = strncpy(nv, node->value, strlen(node->value));
|
||||||
},
|
},
|
||||||
/* size in bytes of the content stored in an entry by you */
|
/* size in bytes of the content stored in an entry by you */
|
||||||
|
@ -66,13 +66,15 @@ sprintf_slex_node(slex_node_t *node, char *buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Getter
|
* Getters and Setters
|
||||||
* It can be useful to have simple get/put-style API, but to
|
* It can be useful to have simple get/put-style API, but to
|
||||||
* do that you'll have to supply some blocks of code used to
|
* do that you'll have to supply some blocks of code used to
|
||||||
* extract data from within your nodes.
|
* extract data from within your nodes.
|
||||||
*/
|
*/
|
||||||
SKIPLIST_GETTERS(
|
SKIPLIST_KV_ACCESS(
|
||||||
slex, api_, int, char *, { query.key = key; }, { return node->value; })
|
slex, api_, int, char *,
|
||||||
|
/* query blk */ { query.key = key; },
|
||||||
|
/* return blk */ { return node->value; })
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now we need a way to compare the nodes you defined above.
|
* Now we need a way to compare the nodes you defined above.
|
||||||
|
@ -196,43 +198,32 @@ main()
|
||||||
array[j] = i;
|
array[j] = i;
|
||||||
shuffle(array, asz);
|
shuffle(array, asz);
|
||||||
|
|
||||||
for (int i = 0; i <= asz; i++) {
|
for (int i = 0; i < asz; i++) {
|
||||||
struct slex_node *n;
|
rc = api_skip_put_slex(list, array[i], to_lower(int_to_roman_numeral(array[i])));
|
||||||
char *v;
|
char *v = api_skip_get_slex(list, array[i]);
|
||||||
slex_node_t new;
|
api_skip_set_slex(list, array[i], to_upper(v));
|
||||||
rc = api_skip_alloc_node_slex(list, &n);
|
|
||||||
if (rc)
|
|
||||||
return rc;
|
|
||||||
n->key = array[i];
|
|
||||||
n->value = to_lower(int_to_roman_numeral(array[i]));
|
|
||||||
api_skip_insert_slex(list, n);
|
|
||||||
v = api_skip_get_slex(list, array[i]);
|
|
||||||
((void)v);
|
|
||||||
new.key = n->key;
|
|
||||||
new.value = to_upper(n->value);
|
|
||||||
api_skip_update_slex(list, &new);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
slex_node_t q;
|
api_skip_del_slex(list, 0);
|
||||||
q.key = 0;
|
|
||||||
api_skip_remove_slex(list, &q);
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
snap = api_skip_snapshot_slex(list);
|
snap = api_skip_snapshot_slex(list);
|
||||||
restored = api_skip_restore_snapshot_slex(snap, __skip_key_compare_slex);
|
restored = api_skip_restore_snapshot_slex(snap, __skip_key_compare_slex);
|
||||||
api_skip_dispose_snapshot_slex(snap);
|
api_skip_dispose_snapshot_slex(snap);
|
||||||
api_skip_destroy_slex(restored);
|
api_skip_destroy_slex(restored);
|
||||||
|
#endif
|
||||||
|
|
||||||
assert(api_skip_gte_slex(list, -6) == int_to_roman_numeral(-5));
|
assert(strcmp(api_skip_pos_slex(list, SKIP_GTE, -(TEST_ARRAY_SIZE) -1)->value, int_to_roman_numeral(-(TEST_ARRAY_SIZE))) == 0);
|
||||||
assert(api_skip_gte_slex(list, -2) == int_to_roman_numeral(-2));
|
assert(strcmp(api_skip_pos_slex(list, SKIP_GTE, -2)->value, int_to_roman_numeral(-2)) == 0);
|
||||||
assert(api_skip_gte_slex(list, 0) == int_to_roman_numeral(0));
|
assert(strcmp(api_skip_pos_slex(list, SKIP_GTE, 0)->value, int_to_roman_numeral(1)) == 0);
|
||||||
assert(api_skip_gte_slex(list, 2) == int_to_roman_numeral(2));
|
assert(strcmp(api_skip_pos_slex(list, SKIP_GTE, 2)->value, int_to_roman_numeral(2)) == 0);
|
||||||
assert(api_skip_gte_slex(list, 6) == int_to_roman_numeral(0));
|
assert(api_skip_pos_slex(list, SKIP_GTE, (TEST_ARRAY_SIZE + 1)) == NULL);
|
||||||
|
|
||||||
assert(api_skip_lte_slex(list, -6) == int_to_roman_numeral(0));
|
assert(api_skip_pos_slex(list, SKIP_LTE, -(TEST_ARRAY_SIZE) - 1) == NULL);
|
||||||
assert(api_skip_lte_slex(list, -2) == int_to_roman_numeral(-2));
|
assert(strcmp(api_skip_pos_slex(list, SKIP_LTE, -2)->value, int_to_roman_numeral(-2)) == 0);
|
||||||
assert(api_skip_lte_slex(list, 0) == int_to_roman_numeral(-10));
|
assert(strcmp(api_skip_pos_slex(list, SKIP_LTE, 0)->value, int_to_roman_numeral(-1)) == 0);
|
||||||
assert(api_skip_lte_slex(list, 2) == int_to_roman_numeral(2));
|
assert(strcmp(api_skip_pos_slex(list, SKIP_LTE, 2)->value, int_to_roman_numeral(2)) == 0);
|
||||||
assert(api_skip_lte_slex(list, 6) == int_to_roman_numeral(20));
|
assert(strcmp(api_skip_pos_slex(list, SKIP_LTE, (TEST_ARRAY_SIZE + 1))->value, int_to_roman_numeral(TEST_ARRAY_SIZE)) == 0);
|
||||||
|
|
||||||
FILE *of = fopen("/tmp/slm.dot", "w");
|
FILE *of = fopen("/tmp/slm.dot", "w");
|
||||||
if (!of) {
|
if (!of) {
|
||||||
|
|
196
include/sl.h
196
include/sl.h
|
@ -201,6 +201,8 @@
|
||||||
struct decl##_node **nodes; \
|
struct decl##_node **nodes; \
|
||||||
}; \
|
}; \
|
||||||
\
|
\
|
||||||
|
typedef enum { SKIP_EQ = 0, SKIP_LTE = -1, SKIP_LT = -2, SKIP_GTE = 1, SKIP_GT = 2 } skip_pos_##decl_t; \
|
||||||
|
\
|
||||||
/* -- __skip_key_compare_ \
|
/* -- __skip_key_compare_ \
|
||||||
* \
|
* \
|
||||||
* This function takes four arguments: \
|
* This function takes four arguments: \
|
||||||
|
@ -423,12 +425,14 @@
|
||||||
return __skip_insert_##decl(slist, n, 1); \
|
return __skip_insert_##decl(slist, n, 1); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/* -- skip_find_ \
|
/* -- skip_position_eq_ \
|
||||||
* Find a node that matches another node. 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. \
|
||||||
* This avoids an alloc/free for the path. \
|
* \
|
||||||
|
* 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_find_##decl(decl##_t *slist, decl##_node_t *n) \
|
decl##_node_t *prefix##skip_position_eq_##decl(decl##_t *slist, decl##_node_t *n) \
|
||||||
{ \
|
{ \
|
||||||
unsigned int i; \
|
unsigned int i; \
|
||||||
decl##_node_t *elm = slist->slh_head; \
|
decl##_node_t *elm = slist->slh_head; \
|
||||||
|
@ -449,10 +453,15 @@
|
||||||
return NULL; \
|
return NULL; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/* -- skip_find_gte \
|
/* -- skip_position_gte \
|
||||||
* Return the matching node or the next greater node after that. \
|
* Position and return a cursor at the first node that is equal to \
|
||||||
|
* or greater than the provided node `n`, otherwise if the largest \
|
||||||
|
* 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_find_gte_##decl(decl##_t *slist, decl##_node_t *n) \
|
decl##_node_t *prefix##skip_position_gte_##decl(decl##_t *slist, decl##_node_t *n) \
|
||||||
{ \
|
{ \
|
||||||
int cmp; \
|
int cmp; \
|
||||||
unsigned int i; \
|
unsigned int i; \
|
||||||
|
@ -474,10 +483,45 @@
|
||||||
return elm; \
|
return elm; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/* -- skip_find_lte \
|
/* -- skip_position_gt TODO \
|
||||||
* Return the matching node or the last one before it. \
|
* 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` \
|
||||||
|
* 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_find_lte_##decl(decl##_t *slist, decl##_node_t *n) \
|
decl##_node_t *prefix##skip_position_gt_##decl(decl##_t *slist, decl##_node_t *n) \
|
||||||
|
{ \
|
||||||
|
int cmp; \
|
||||||
|
unsigned int i; \
|
||||||
|
decl##_node_t *elm = slist->slh_head; \
|
||||||
|
\
|
||||||
|
if (slist == NULL || n == NULL) \
|
||||||
|
return NULL; \
|
||||||
|
\
|
||||||
|
i = slist->slh_head->field.sle.len; \
|
||||||
|
\
|
||||||
|
do { \
|
||||||
|
while (elm && __skip_key_compare_##decl(slist, elm->field.sle.next[i], n, slist->aux) < 0) \
|
||||||
|
elm = elm->field.sle.next[i]; \
|
||||||
|
} while (i--); \
|
||||||
|
do { \
|
||||||
|
elm = elm->field.sle.next[0]; \
|
||||||
|
cmp = __skip_key_compare_##decl(slist, elm, n, slist->aux); \
|
||||||
|
} while (cmp < 0); \
|
||||||
|
return elm; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* -- skip_position_lte \
|
||||||
|
* Position and return a cursor at the last node that is less than \
|
||||||
|
* or equal to 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_lte_##decl(decl##_t *slist, decl##_node_t *n) \
|
||||||
{ \
|
{ \
|
||||||
int cmp; \
|
int cmp; \
|
||||||
unsigned int i; \
|
unsigned int i; \
|
||||||
|
@ -504,9 +548,74 @@
|
||||||
return elm; \
|
return elm; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
|
/* -- skip_position_lt TODO \
|
||||||
|
* 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. \
|
||||||
|
* \
|
||||||
|
* 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 *n) \
|
||||||
|
{ \
|
||||||
|
int cmp; \
|
||||||
|
unsigned int i; \
|
||||||
|
decl##_node_t *elm = slist->slh_head; \
|
||||||
|
\
|
||||||
|
if (slist == NULL || n == NULL) \
|
||||||
|
return NULL; \
|
||||||
|
\
|
||||||
|
i = slist->slh_head->field.sle.len; \
|
||||||
|
\
|
||||||
|
do { \
|
||||||
|
while (elm && __skip_key_compare_##decl(slist, elm->field.sle.next[i], n, slist->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) { \
|
||||||
|
return elm; \
|
||||||
|
} else { \
|
||||||
|
do { \
|
||||||
|
elm = elm->field.sle.prev; \
|
||||||
|
cmp = __skip_key_compare_##decl(slist, elm, n, slist->aux); \
|
||||||
|
} while (cmp > 0); \
|
||||||
|
} \
|
||||||
|
return elm; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* -- skip_position_ \
|
||||||
|
* Position a cursor relative to `n`. \
|
||||||
|
* This 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 *n) \
|
||||||
|
{ \
|
||||||
|
decl##_node_t *node; \
|
||||||
|
\
|
||||||
|
switch (op) { \
|
||||||
|
case (SKIP_LT): \
|
||||||
|
node = prefix##skip_position_lt_##decl(slist, n); \
|
||||||
|
break; \
|
||||||
|
case (SKIP_LTE): \
|
||||||
|
node = prefix##skip_position_lte_##decl(slist, n); \
|
||||||
|
break; \
|
||||||
|
case (SKIP_GTE): \
|
||||||
|
node = prefix##skip_position_gte_##decl(slist, n); \
|
||||||
|
break; \
|
||||||
|
case (SKIP_GT): \
|
||||||
|
node = prefix##skip_position_gt_##decl(slist, n); \
|
||||||
|
break; \
|
||||||
|
default: \
|
||||||
|
case (SKIP_EQ): \
|
||||||
|
node = prefix##skip_position_eq_##decl(slist, n); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
return node; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
/* -- skip_update_ \
|
/* -- skip_update_ \
|
||||||
* Locates a node in the list that equals the `new` node and then \
|
* Locates a node in the list that equals the `new` node and then \
|
||||||
* uses the `update_node_blk` to update the contents. \
|
* uses the `update_node_blk` to update the contents. \
|
||||||
|
* \
|
||||||
|
* \
|
||||||
* 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. \
|
||||||
*/ \
|
*/ \
|
||||||
|
@ -517,7 +626,7 @@
|
||||||
if (slist == NULL || new == NULL) \
|
if (slist == NULL || new == NULL) \
|
||||||
return -1; \
|
return -1; \
|
||||||
\
|
\
|
||||||
node = prefix##skip_find_##decl(slist, new); \
|
node = prefix##skip_position_eq_##decl(slist, new); \
|
||||||
if (node) { \
|
if (node) { \
|
||||||
update_node_blk; \
|
update_node_blk; \
|
||||||
return 0; \
|
return 0; \
|
||||||
|
@ -615,7 +724,7 @@
|
||||||
return 0; \
|
return 0; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/* -- skip_snapshot_ \
|
/* -- skip_snapshot_ TODO/WIP \
|
||||||
* A snapshot is a read-only view of a Skiplist at a point in \
|
* A snapshot is a read-only view of a Skiplist at a point in \
|
||||||
* time. Once taken, a snapshot must be restored or disposed. \
|
* time. Once taken, a snapshot must be restored or disposed. \
|
||||||
* Any number of snapshots can be created. \
|
* Any number of snapshots can be created. \
|
||||||
|
@ -653,7 +762,7 @@
|
||||||
return snap; \
|
return snap; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/* -- skip_restore_snapshot_ */ \
|
/* -- skip_restore_snapshot_ TODO/WIP */ \
|
||||||
decl##_t *prefix##skip_restore_snapshot_##decl(decl##_snap_t *snap, int (*cmp)(decl##_t * head, decl##_node_t * a, decl##_node_t * b, void *aux)) \
|
decl##_t *prefix##skip_restore_snapshot_##decl(decl##_snap_t *snap, int (*cmp)(decl##_t * head, decl##_node_t * a, decl##_node_t * b, void *aux)) \
|
||||||
{ \
|
{ \
|
||||||
int rc; \
|
int rc; \
|
||||||
|
@ -705,7 +814,7 @@
|
||||||
return NULL; \
|
return NULL; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/* -- skip_dispose_snapshot_ */ \
|
/* -- skip_dispose_snapshot_ TODO/WIP */ \
|
||||||
void prefix##skip_dispose_snapshot_##decl(decl##_snap_t *snap) \
|
void prefix##skip_dispose_snapshot_##decl(decl##_snap_t *snap) \
|
||||||
{ \
|
{ \
|
||||||
decl##_node_t *node; \
|
decl##_node_t *node; \
|
||||||
|
@ -719,7 +828,7 @@
|
||||||
free(snap); \
|
free(snap); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/* -- skip_serialize_ \
|
/* -- skip_serialize_ TODO/WIP \
|
||||||
* Similar to snapshot, but includes the values and encodes them \
|
* Similar to snapshot, but includes the values and encodes them \
|
||||||
* in a portable manner. \
|
* in a portable manner. \
|
||||||
*/ \
|
*/ \
|
||||||
|
@ -760,7 +869,7 @@
|
||||||
return snap; \
|
return snap; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/* -- skip_deserialize_snapshot_ */ \
|
/* -- skip_deserialize_snapshot_ TODO/WIP */ \
|
||||||
decl##_t *prefix##skip_deserialize_##decl(decl##_snap_t *snap, int (*cmp)(decl##_t * head, decl##_node_t * a, decl##_node_t * b, void *aux)) \
|
decl##_t *prefix##skip_deserialize_##decl(decl##_snap_t *snap, int (*cmp)(decl##_t * head, decl##_node_t * a, decl##_node_t * b, void *aux)) \
|
||||||
{ \
|
{ \
|
||||||
int rc; \
|
int rc; \
|
||||||
|
@ -812,46 +921,65 @@
|
||||||
return NULL; \
|
return NULL; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/* -- __skip_integrity_check_ */ \
|
/* -- __skip_integrity_check_ TODO */ \
|
||||||
static int __skip_integrity_check_##decl(decl##_t *slist) \
|
static int __skip_integrity_check_##decl(decl##_t *slist) \
|
||||||
{ \
|
{ \
|
||||||
((void)slist); /* TODO */ \
|
((void)slist); \
|
||||||
return 0; \
|
return 0; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SKIPLIST_GETTERS(decl, prefix, ktype, vtype, qblk, rblk) \
|
#define SKIPLIST_KV_ACCESS(decl, prefix, ktype, vtype, qblk, rblk) \
|
||||||
vtype prefix##skip_get_##decl(decl##_t *slist, ktype key) \
|
vtype prefix##skip_get_##decl(decl##_t *slist, ktype key) \
|
||||||
{ \
|
{ \
|
||||||
decl##_node_t *node, query; \
|
decl##_node_t *node, query; \
|
||||||
\
|
\
|
||||||
qblk; \
|
qblk; \
|
||||||
node = prefix##skip_find_##decl(slist, &query); \
|
node = prefix##skip_position_eq_##decl(slist, &query); \
|
||||||
if (node) { \
|
if (node) { \
|
||||||
rblk; \
|
rblk; \
|
||||||
} \
|
} \
|
||||||
return (vtype)0; \
|
return (vtype)0; \
|
||||||
} \
|
} \
|
||||||
vtype prefix##skip_gte_##decl(decl##_t *slist, ktype key) \
|
\
|
||||||
|
decl##_node_t *prefix##skip_pos_##decl(decl##_t *slist, skip_pos_##decl_t op, ktype key) \
|
||||||
{ \
|
{ \
|
||||||
decl##_node_t *node, query; \
|
decl##_node_t *node, query; \
|
||||||
\
|
\
|
||||||
qblk; \
|
qblk; \
|
||||||
node = prefix##skip_find_gte_##decl(slist, &query); \
|
node = prefix##skip_position_##decl(slist, op, &query); \
|
||||||
if (node != slist->slh_tail) { \
|
if (node != slist->slh_head && node != slist->slh_tail) \
|
||||||
rblk; \
|
return node; \
|
||||||
|
return NULL; \
|
||||||
} \
|
} \
|
||||||
return (vtype)0; \
|
|
||||||
} \
|
|
||||||
vtype prefix##skip_lte_##decl(decl##_t *slist, ktype key) \
|
|
||||||
{ \
|
|
||||||
decl##_node_t *node, query; \
|
|
||||||
\
|
\
|
||||||
qblk; \
|
int prefix##skip_put_##decl(decl##_t *slist, ktype key, vtype value) \
|
||||||
node = prefix##skip_find_lte_##decl(slist, &query); \
|
{ \
|
||||||
if (node != slist->slh_head) { \
|
int rc; \
|
||||||
rblk; \
|
decl##_node_t *node; \
|
||||||
|
rc = prefix##skip_alloc_node_##decl(slist, &node); \
|
||||||
|
if (rc) \
|
||||||
|
return rc; \
|
||||||
|
node->key = key; \
|
||||||
|
node->value = value; \
|
||||||
|
rc = prefix##skip_insert_##decl(slist, node); \
|
||||||
|
if (rc) \
|
||||||
|
prefix##skip_free_node_##decl(node); \
|
||||||
|
return rc; \
|
||||||
} \
|
} \
|
||||||
return (vtype)0; \
|
\
|
||||||
|
int prefix##skip_set_##decl(decl##_t *slist, ktype key, vtype value) \
|
||||||
|
{ \
|
||||||
|
decl##_node_t node; \
|
||||||
|
node.key = key; \
|
||||||
|
node.value = value; \
|
||||||
|
return prefix##skip_update_##decl(slist, &node); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
int prefix##skip_del_##decl(decl##_t *slist, ktype key) \
|
||||||
|
{ \
|
||||||
|
decl##_node_t node; \
|
||||||
|
node.key = key; \
|
||||||
|
return prefix##skip_remove_##decl(slist, &node); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SKIPLIST_DECL_DOT(decl, prefix, field) \
|
#define SKIPLIST_DECL_DOT(decl, prefix, field) \
|
||||||
|
|
Loading…
Reference in a new issue