remove cruft, api TODOs
This commit is contained in:
parent
e8d3645ed4
commit
81d2f817f2
|
@ -28,9 +28,21 @@ struct slex_node {
|
|||
|
||||
/*
|
||||
* Generate all the access functions for our type of Skiplist.
|
||||
* The last argument to this macro is a block of code used to
|
||||
* compare the nodes you defined above.
|
||||
* This block can expect four arguments:
|
||||
*/
|
||||
SKIPLIST_DECL(slex, api_, entries, { (void)node; })
|
||||
|
||||
/*
|
||||
* Getter
|
||||
* 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
|
||||
* extract data from within your nodes.
|
||||
*/
|
||||
SKIPLIST_GETTER(
|
||||
slex, api_, get, int, int, { query.key = key; }, { return node->value; })
|
||||
|
||||
/*
|
||||
* Now we need a way to compare the nodes you defined above.
|
||||
* Let's create a function with four arguments:
|
||||
* - a reference to the Skiplist, `slist`
|
||||
* - the two nodes to compare, `a` and `b`
|
||||
* - and `aux`, which you can use to pass into this function
|
||||
|
@ -38,18 +50,17 @@ struct slex_node {
|
|||
* `aux` is passed from the value in the Skiplist, you can
|
||||
* modify that value at any time to suit your needs.
|
||||
*
|
||||
* Your block should result in a return statement:
|
||||
* Your function should result in a return statement:
|
||||
* a < b : return -1
|
||||
* a == b : return 0
|
||||
* a > b : return 1
|
||||
*
|
||||
* This result provides the ordering within the Skiplist. Sometimes
|
||||
* your block of code will not be used when comparing nodes. This
|
||||
* happens when `a` or `b` are references to the head or tail of the
|
||||
* your function will not be used when comparing nodes. This will
|
||||
* happen when `a` or `b` are references to the head or tail of the
|
||||
* list or when `a == b`. In those cases the comparison function
|
||||
* returns before using the code in your block, don't panic. :)
|
||||
*/
|
||||
SKIPLIST_DECL(slex, api_, entries)
|
||||
int
|
||||
__slm_key_compare(slex_t *list, slex_node_t *a, slex_node_t *b, void *aux)
|
||||
{
|
||||
|
@ -85,12 +96,16 @@ main()
|
|||
goto fail;
|
||||
}
|
||||
rc = api_skip_init_slex(list, 12, 4, __slm_key_compare);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
struct slex_node *n;
|
||||
|
||||
/* Insert 7 key/value pairs into the list. */
|
||||
for (int i = -2; i <= 2; i++) {
|
||||
SKIP_ALLOC_NODE(list, n, slex_node, entries);
|
||||
rc = api_skip_alloc_node_slex(list, &n);
|
||||
if (rc)
|
||||
return rc;
|
||||
n->key = i;
|
||||
n->value = i;
|
||||
api_skip_insert_slex(list, n);
|
||||
|
|
307
include/sl.h
307
include/sl.h
|
@ -25,88 +25,23 @@
|
|||
* - https://github.com/paulross/skiplist
|
||||
* Copyright (c) 2017-2023 Paul Ross
|
||||
* - gist skiplist.c
|
||||
* - queue.h
|
||||
* - khash.h
|
||||
* - async_nif.h
|
||||
*/
|
||||
|
||||
#ifndef _SYS_SKIPLIST_H_
|
||||
#define _SYS_SKIPLIST_H_
|
||||
#ifndef _SKIPLIST_H_
|
||||
#define _SKIPLIST_H_
|
||||
|
||||
/*
|
||||
* This file defines a skiplist data structure with a similar API to those
|
||||
* datastructures defined in FreeBSD's <sys/queue.h> header.
|
||||
* This file defines a skiplist data structure.
|
||||
*
|
||||
* In 1990 William Pugh published:
|
||||
* - Skiplists: a probabilistic alternative to balanced trees.
|
||||
* https://www.cl.cam.ac.uk/teaching/2005/Algorithms/skiplists.pdf
|
||||
* A Skiplist is an ordered data structure providing expected O(Log(n)) lookup,
|
||||
* insertion, and deletion complexity.
|
||||
*
|
||||
*
|
||||
* For details on the use of these macros, see the queue(3) manual page.
|
||||
*
|
||||
*
|
||||
* SKIP SPLAYED_SKIP
|
||||
* _HEAD + +
|
||||
* _HEAD_INITIALIZER + +
|
||||
* _ENTRY + +
|
||||
* _INIT + +
|
||||
* _DISPOSE + +
|
||||
* _EMPTY + +
|
||||
* _FIRST + +
|
||||
* _NEXT + +
|
||||
* _PREV + +
|
||||
* _LAST - +
|
||||
* _FOREACH + +
|
||||
* _FOREACH_REVERSE + +
|
||||
* _INSERT + +
|
||||
* _UPDATE + +
|
||||
* _BULK_INSERT + +
|
||||
* _REMOVE + +
|
||||
* _LOCATE + +
|
||||
*
|
||||
*/
|
||||
|
||||
#define SKIPLIST_MACRO_DEBUG 0
|
||||
#if SKIPLIST_MACRO_DEBUG
|
||||
/* Store the last 2 places the element or head was altered */
|
||||
struct sl_trace {
|
||||
char *lastfile;
|
||||
int lastline;
|
||||
char *prevfile;
|
||||
int prevline;
|
||||
};
|
||||
|
||||
#define TRACEBUF struct sl_trace trace;
|
||||
#define TRASHIT(x) \
|
||||
do { \
|
||||
(x) = (void *)-1; \
|
||||
} while (0)
|
||||
|
||||
#define SLD_TRACE_HEAD(head) \
|
||||
do { \
|
||||
(head)->trace.prevline = (head)->trace.lastline; \
|
||||
(head)->trace.prevfile = (head)->trace.lastfile; \
|
||||
(head)->trace.lastline = __LINE__; \
|
||||
(head)->trace.lastfile = __FILE__; \
|
||||
} while (0)
|
||||
|
||||
#define SLD_TRACE_ELEM(elem) \
|
||||
do { \
|
||||
(elem)->trace.prevline = (elem)->trace.lastline; \
|
||||
(elem)->trace.prevfile = (elem)->trace.lastfile; \
|
||||
(elem)->trace.lastline = __LINE__; \
|
||||
(elem)->trace.lastfile = __FILE__; \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
#define SLD_TRACE_ELEM(elem)
|
||||
#define SLD_TRACE_HEAD(head)
|
||||
#define TRACEBUF
|
||||
#define TRASHIT(x)
|
||||
#endif /* QUEUE_MACRO_DEBUG */
|
||||
|
||||
/*
|
||||
* Private, internal API.
|
||||
*/
|
||||
|
@ -142,24 +77,12 @@ struct sl_trace {
|
|||
void *aux; \
|
||||
struct type *slh_head; \
|
||||
struct type *slh_tail; \
|
||||
TRACEBUF \
|
||||
}
|
||||
|
||||
#define SKIP_HEAD_DEFAULT_INITIALIZER(cmp) \
|
||||
{ \
|
||||
0, 0, 12, 4, cmp, NULL, NULL, NULL \
|
||||
}
|
||||
|
||||
#define SKIP_HEAD_INITIALIZER(cmp, max, fanout) \
|
||||
{ \
|
||||
0, 0, max, fanout, cmp, NULL, NULL, NULL \
|
||||
}
|
||||
|
||||
#define SKIP_ENTRY(type) \
|
||||
struct { \
|
||||
struct type **sle_next; \
|
||||
struct type *sle_prev; \
|
||||
TRACEBUF \
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -171,25 +94,6 @@ struct sl_trace {
|
|||
#define SKIP_PREV(elm, field) ((elm)->field.sle_prev)
|
||||
#define SKIP_EMPTY(head) ((head)->length == 0)
|
||||
|
||||
#if 0
|
||||
#define SKIP_FOREACH(var, head, field) \
|
||||
for ((var) = SKIP_FIRST(head); (var) != SKIP_END(head); \
|
||||
(var) = SKIP_NEXT(var, field))
|
||||
|
||||
#define SKIP_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = SKIP_FIRST(head); (var) && ((tvar) = SKIP_NEXT(var, field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
|
||||
for ((var) = TAILQ_LAST(head, headname); (var) != TAILQ_END(head); \
|
||||
(var) = TAILQ_PREV(var, headname, field))
|
||||
|
||||
#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
|
||||
for ((var) = TAILQ_LAST(head, headname); (var) != TAILQ_END(head) && \
|
||||
((tvar) = TAILQ_PREV(var, headname, field), 1); \
|
||||
(var) = (tvar))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Skip List functions.
|
||||
*/
|
||||
|
@ -207,65 +111,7 @@ struct sl_trace {
|
|||
fn \
|
||||
}
|
||||
|
||||
#define SKIP_INIT(head, max, fanout, type, field, fn) \
|
||||
do { \
|
||||
(head)->level = 0; \
|
||||
(head)->length = 0; \
|
||||
(head)->max = max; \
|
||||
(head)->fanout = fanout; \
|
||||
(head)->cmp = fn; \
|
||||
SKIP_ALLOC_NODE(head, (head)->slh_head, type, field); \
|
||||
SKIP_ALLOC_NODE(head, (head)->slh_tail, type, field); \
|
||||
ARRAY_SET_LENGTH((head)->slh_head->field.sle_next, max); \
|
||||
for (size_t __i = 0; __i < ARRAY_SIZE((head)->slh_head->field.sle_next); \
|
||||
__i++) { \
|
||||
(head)->slh_head->field.sle_next[__i] = (head)->slh_tail; \
|
||||
} \
|
||||
(head)->slh_head->field.sle_prev = NULL; \
|
||||
ARRAY_SET_LENGTH((head)->slh_tail->field.sle_next, max); \
|
||||
for (size_t __i = 0; __i < ARRAY_SIZE((head)->slh_tail->field.sle_next); \
|
||||
__i++) { \
|
||||
(head)->slh_tail->field.sle_next[__i] = NULL; \
|
||||
} \
|
||||
(head)->slh_head->field.sle_prev = (head)->slh_tail; \
|
||||
SLD_TRACE_HEAD(head); \
|
||||
} while (0)
|
||||
|
||||
#define SKIP_DEFAULT_INIT(head, fn, type, field) \
|
||||
do { \
|
||||
(head)->level = 0; \
|
||||
(head)->length = 0; \
|
||||
(head)->max = 12; \
|
||||
(head)->fanout = 4; \
|
||||
(head)->cmp = fn; \
|
||||
SKIP_ALLOC_NODE(head, (head)->slh_head, type, field); \
|
||||
SKIP_ALLOC_NODE(head, (head)->slh_tail, type, field); \
|
||||
ARRAY_SET_LENGTH((head)->slh_head->field.sle_next, (head)->max); \
|
||||
for (size_t __i = 0; __i < ARRAY_SIZE((head)->slh_head->field.sle_next); \
|
||||
__i++) { \
|
||||
(head)->slh_head->field.sle_next[__i] = (head)->slh_tail; \
|
||||
} \
|
||||
(head)->slh_head->field.sle_prev = NULL; \
|
||||
ARRAY_SET_LENGTH((head)->slh_tail->field.sle_next, (head)->max); \
|
||||
for (size_t __i = 0; __i < ARRAY_SIZE((head)->slh_tail->field.sle_next); \
|
||||
__i++) { \
|
||||
(head)->slh_tail->field.sle_next[__i] = NULL; \
|
||||
} \
|
||||
(head)->slh_head->field.sle_prev = (head)->slh_tail; \
|
||||
SLD_TRACE_HEAD(head); \
|
||||
} while (0)
|
||||
|
||||
#define SKIP_ALLOC_NODE(head, var, type, field) \
|
||||
do { \
|
||||
(var) = (struct type *)calloc(1, sizeof(struct type)); \
|
||||
ARRAY_ALLOC((var)->field.sle_next, struct type, (head)->max); \
|
||||
if ((var) && (var)->field.sle_next) { \
|
||||
ARRAY_SET_SIZE((var)->field.sle_next, (head)->max); \
|
||||
ARRAY_SET_LENGTH((var)->field.sle_next, 0); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SKIPLIST_DECL(decl, prefix, field) \
|
||||
#define SKIPLIST_DECL(decl, prefix, field, free_node_blk) \
|
||||
\
|
||||
/* Skiplist node type */ \
|
||||
typedef struct decl##_node decl##_node_t; \
|
||||
|
@ -277,7 +123,6 @@ struct sl_trace {
|
|||
void *aux; \
|
||||
decl##_node_t *slh_head; \
|
||||
decl##_node_t *slh_tail; \
|
||||
TRACEBUF \
|
||||
} decl##_t; \
|
||||
\
|
||||
/* -- __skip_key_compare_ \
|
||||
|
@ -364,10 +209,58 @@ struct sl_trace {
|
|||
/* -- skip_free_node_ */ \
|
||||
void prefix##skip_free_node_##decl(decl##_node_t *node) \
|
||||
{ \
|
||||
free_node_blk; \
|
||||
free(node->field.sle_next); \
|
||||
free(node); \
|
||||
} \
|
||||
\
|
||||
/* -- skip_destroy_ */ \
|
||||
int prefix##skip_destroy_##decl(decl##_t *slist, decl##_node_t *n) \
|
||||
{ \
|
||||
((void)slist); /* TODO */ \
|
||||
((void)n); \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
/* -- skip_size_ */ \
|
||||
int prefix##skip_size_##decl(decl##_t *slist, decl##_node_t *n) \
|
||||
{ \
|
||||
((void)slist); /* TODO */ \
|
||||
((void)n); \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
/* -- skip_empty_ */ \
|
||||
int prefix##skip_empty_##decl(decl##_t *slist) \
|
||||
{ \
|
||||
((void)slist); /* TODO */ \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
/* -- skip_head_ */ \
|
||||
int prefix##skip_head_##decl(decl##_t *slist, decl##_node_t *n) \
|
||||
{ \
|
||||
((void)slist); /* TODO */ \
|
||||
((void)n); \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
/* -- skip_tail_ */ \
|
||||
int prefix##skip_tail_##decl(decl##_t *slist, decl##_node_t *n) \
|
||||
{ \
|
||||
((void)slist); /* TODO */ \
|
||||
((void)n); \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
/* -- skip_locate_ */ \
|
||||
decl##_node_t *prefix##skip_locate_##decl(decl##_t *slist, decl##_node_t *n) \
|
||||
{ \
|
||||
((void)slist); /* TODO */ \
|
||||
((void)n); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
/* -- skip_insert_ */ \
|
||||
int prefix##skip_insert_##decl(decl##_t *slist, decl##_node_t *n) \
|
||||
{ \
|
||||
|
@ -418,6 +311,70 @@ struct sl_trace {
|
|||
return 0; \
|
||||
} \
|
||||
\
|
||||
/* -- skip_insert_dup_ */ \
|
||||
int prefix##skip_insert_dup_##decl(decl##_t *slist, decl##_node_t *n) \
|
||||
{ \
|
||||
((void)slist); /* TODO */ \
|
||||
((void)n); \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
/* -- skip_update_ */ \
|
||||
int prefix##skip_update_##decl(decl##_t *slist, decl##_node_t *n) \
|
||||
{ \
|
||||
((void)slist); /* TODO */ \
|
||||
((void)n); \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
/* -- skip_delete_ */ \
|
||||
int prefix##skip_delete_##decl(decl##_t *slist, decl##_node_t *n) \
|
||||
{ \
|
||||
((void)slist); /* TODO */ \
|
||||
((void)n); \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
/* -- skip_find_ */ \
|
||||
int prefix##skip_find_##decl(decl##_t *slist, decl##_node_t *n) \
|
||||
{ \
|
||||
((void)slist); /* TODO */ \
|
||||
((void)n); \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
/* -- skip_find_gte */ \
|
||||
int prefix##skip_find_gte_##decl(decl##_t *slist, decl##_node_t *n) \
|
||||
{ \
|
||||
((void)slist); /* TODO */ \
|
||||
((void)n); \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
/* -- skip_find_lte */ \
|
||||
int prefix##skip_find_lte_##decl(decl##_t *slist, decl##_node_t *n) \
|
||||
{ \
|
||||
((void)slist); /* TODO */ \
|
||||
((void)n); \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
/* -- skip_next_node_ */ \
|
||||
int prefix##skip_next_node_##decl(decl##_t *slist, decl##_node_t *n) \
|
||||
{ \
|
||||
((void)slist); /* TODO */ \
|
||||
((void)n); \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
/* -- skip_prev_node_ */ \
|
||||
int prefix##skip_prev_node_##decl(decl##_t *slist, decl##_node_t *n) \
|
||||
{ \
|
||||
((void)slist); /* TODO */ \
|
||||
((void)n); \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
/* -- __skip_integrity_check_ */ \
|
||||
static int __skip_integrity_check_##decl(decl##_t *slist) \
|
||||
{ \
|
||||
|
@ -425,6 +382,15 @@ struct sl_trace {
|
|||
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 *node, query; \
|
||||
qblk; \
|
||||
node = prefix##skip_locate_##decl(slist, &query); \
|
||||
rblk; \
|
||||
}
|
||||
|
||||
#define SKIPLIST_DECL_DOT(decl, prefix, field) \
|
||||
\
|
||||
/* A type for a function that writes into a char[2048] buffer \
|
||||
|
@ -602,25 +568,4 @@ struct sl_trace {
|
|||
return 0; \
|
||||
}
|
||||
|
||||
#if 0
|
||||
#define SKIP_REMOVE(head, elm, field) \
|
||||
do { \
|
||||
if ((elm)->field.le_next != NULL) \
|
||||
(elm)->field.le_next->field.le_prev = (elm)->field.le_prev; \
|
||||
*(elm)->field.le_prev = (elm)->field.le_next; \
|
||||
_Q_INVALIDATE((elm)->field.le_prev); \
|
||||
_Q_INVALIDATE((elm)->field.le_next); \
|
||||
} while (0)
|
||||
|
||||
#define SKIP_REPLACE(elm, elm2, field) \
|
||||
do { \
|
||||
if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
|
||||
(elm2)->field.le_next->field.le_prev = &(elm2)->field.le_next; \
|
||||
(elm2)->field.le_prev = (elm)->field.le_prev; \
|
||||
*(elm2)->field.le_prev = (elm2); \
|
||||
_Q_INVALIDATE((elm)->field.le_prev); \
|
||||
_Q_INVALIDATE((elm)->field.le_next); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_SKIPLIST_H_ */
|
||||
#endif /* _SKIPLIST_H_ */
|
||||
|
|
Loading…
Reference in a new issue