From d304eaf407523282128d14a8bb8f400c9f3981af Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Tue, 19 Mar 2024 13:22:55 -0400 Subject: [PATCH] impl gte/lte for find and get --- examples/slm.c | 4 +- include/sl.h | 169 +++++++++++++++++++++++++++++++++++-------------- 2 files changed, 125 insertions(+), 48 deletions(-) diff --git a/examples/slm.c b/examples/slm.c index 6ead2b7..5234394 100644 --- a/examples/slm.c +++ b/examples/slm.c @@ -40,8 +40,8 @@ SKIPLIST_DECL( * do that you'll have to supply some blocks of code used to * extract data from within your nodes. */ -SKIPLIST_GETTER( - slex, api_, get, int, int, { query.key = key; }, { return node->value; }) +SKIPLIST_GETTERS( + slex, api_, int, int, { query.key = key; }, { return node->value; }) /* * Now we need a way to compare the nodes you defined above. diff --git a/include/sl.h b/include/sl.h index bd47f5b..0ad91ac 100644 --- a/include/sl.h +++ b/include/sl.h @@ -238,7 +238,10 @@ return slist->slh_tail->field.sle_prev; \ } \ \ - /* -- skip_locate_ */ \ + /* -- skip_locate_ \ + * Locates a node that matches another node returning the path to that \ + * node and the match in path[0]. \ + */ \ decl##_node_t **prefix##skip_locate_##decl(decl##_t *slist, \ decl##_node_t *n) \ { \ @@ -246,7 +249,7 @@ decl##_node_t **path; \ decl##_node_t *elm = slist->slh_head; \ \ - if (n == NULL) \ + if (!slist || !n) \ return NULL; \ \ i = slist->max + 1; \ @@ -336,6 +339,88 @@ } \ */ \ \ + /* -- skip_find_ \ + * Find a node that matches another node. This differs from the locate() \ + * API in that it does not return the path to the node, only the match. \ + * This avoids an alloc/free for the path. \ + */ \ + decl##_node_t *prefix##skip_find_##decl(decl##_t *slist, decl##_node_t *n) \ + { \ + unsigned int i; \ + decl##_node_t *elm = slist->slh_head; \ + \ + if (!slist || !n) \ + return NULL; \ + \ + i = slist->max + 1; \ + i = slist->level; \ + \ + 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; \ + } \ + return NULL; \ + } \ + \ + /* -- skip_find_gte \ + * Return the matching node or the next greater node after that. \ + */ \ + decl##_node_t *prefix##skip_find_gte_##decl(decl##_t *slist, \ + decl##_node_t *n) \ + { \ + unsigned int i; \ + decl##_node_t *elm = slist->slh_head; \ + \ + if (!slist || !n) \ + return NULL; \ + \ + i = slist->max + 1; \ + i = slist->level; \ + \ + 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]; \ + return elm; \ + } \ + \ + /* -- skip_find_lte \ + * Return the matching node or the last one before it. \ + */ \ + decl##_node_t *prefix##skip_find_lte_##decl(decl##_t *slist, \ + decl##_node_t *n) \ + { \ + unsigned int i; \ + decl##_node_t *elm = slist->slh_head; \ + \ + if (!slist || !n) \ + return NULL; \ + \ + i = slist->max + 1; \ + i = slist->level; \ + \ + 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--); \ + if (__skip_key_compare_##decl(slist, elm->field.sle_next[0], n, \ + slist->aux) == 0) { \ + return elm->field.sle_next[0]; \ + } \ + return elm; \ + } \ + \ /* -- skip_update_ \ * Locates a node in the list that equals the `new` node and then \ * uses the `update_node_blk` to update the contents. \ @@ -344,15 +429,13 @@ */ \ int prefix##skip_update_##decl(decl##_t *slist, decl##_node_t *new) \ { \ - decl##_node_t **path, *node; \ + decl##_node_t *node; \ \ if (!slist || !new) \ return -1; \ \ - path = prefix##skip_locate_##decl(slist, new); \ - if (ARRAY_SIZE(path) > 0) { \ - node = path[0]; \ - ARRAY_FREE(path); \ + node = prefix##skip_find_##decl(slist, new); \ + if (node) { \ update_node_blk; \ return 0; \ } \ @@ -397,32 +480,6 @@ return 0; \ } \ \ - /* -- skip_find_ */ \ - decl##_node_t *prefix##skip_find_##decl(decl##_t *slist, decl##_node_t *n) \ - { \ - ((void)slist); /* TODO */ \ - ((void)n); \ - return 0; \ - } \ - \ - /* -- skip_find_gte */ \ - decl##_node_t *prefix##skip_find_gte_##decl(decl##_t *slist, \ - decl##_node_t *n) \ - { \ - ((void)slist); /* TODO */ \ - ((void)n); \ - return 0; \ - } \ - \ - /* -- skip_find_lte */ \ - decl##_node_t *prefix##skip_find_lte_##decl(decl##_t *slist, \ - decl##_node_t *n) \ - { \ - ((void)slist); /* TODO */ \ - ((void)n); \ - return 0; \ - } \ - \ /* -- skip_next_node_ */ \ decl##_node_t *prefix##skip_next_node_##decl(decl##_t *slist, \ decl##_node_t *n) \ @@ -474,19 +531,39 @@ return 0; \ } -#define SKIPLIST_GETTER(decl, prefix, name, ktype, vtype, qblk, rblk) \ - vtype prefix##skip_##name##_##decl(decl##_t *slist, ktype key) \ - { \ - decl##_node_t **path, *node, query; \ - \ - qblk; \ - path = prefix##skip_locate_##decl(slist, &query); \ - if (ARRAY_SIZE(path) > 0) { \ - node = path[0]; \ - ARRAY_FREE(path); \ - rblk; \ - } \ - return (vtype)0; \ +#define SKIPLIST_GETTERS(decl, prefix, ktype, vtype, qblk, rblk) \ + vtype prefix##skip_get_##decl(decl##_t *slist, ktype key) \ + { \ + decl##_node_t *node, query; \ + \ + qblk; \ + node = prefix##skip_find_##decl(slist, &query); \ + if (node) { \ + rblk; \ + } \ + return (vtype)0; \ + } \ + vtype prefix##skip_gte_##decl(decl##_t *slist, ktype key) \ + { \ + decl##_node_t *node, query; \ + \ + qblk; \ + node = prefix##skip_find_gte_##decl(slist, &query); \ + if (node != slist->slh_tail) { \ + rblk; \ + } \ + return (vtype)0; \ + } \ + vtype prefix##skip_lte_##decl(decl##_t *slist, ktype key) \ + { \ + decl##_node_t *node, query; \ + \ + qblk; \ + node = prefix##skip_find_lte_##decl(slist, &query); \ + if (node != slist->slh_head) { \ + rblk; \ + } \ + return (vtype)0; \ } #define SKIPLIST_DECL_DOT(decl, prefix, field) \