move prev into sle; use sizeof, not offset, add revs to entry
This commit is contained in:
parent
d3d491f1c7
commit
48a09e0c4d
134
examples/slm.c
134
examples/slm.c
|
@ -30,18 +30,18 @@
|
|||
* another, logic you'll provide in SKIP_DECL as a block below.
|
||||
*/
|
||||
struct slex_node {
|
||||
int key;
|
||||
int value;
|
||||
SKIP_ENTRY(slex_node) entries;
|
||||
int key;
|
||||
int value;
|
||||
SKIP_ENTRY(slex_node) entries;
|
||||
};
|
||||
|
||||
/*
|
||||
* Generate all the access functions for our type of Skiplist.
|
||||
*/
|
||||
SKIPLIST_DECL(
|
||||
slex, api_, entries,
|
||||
/* free node */ { (void)node; },
|
||||
/* update node */ { node->value = new->value; })
|
||||
slex, api_, entries,
|
||||
/* free node */ { (void)node; },
|
||||
/* update node */ { node->value = new->value; })
|
||||
|
||||
/*
|
||||
* Getter
|
||||
|
@ -50,7 +50,7 @@ SKIPLIST_DECL(
|
|||
* extract data from within your nodes.
|
||||
*/
|
||||
SKIPLIST_GETTERS(
|
||||
slex, api_, int, int, { query.key = key; }, { return node->value; })
|
||||
slex, api_, int, int, { query.key = key; }, { return node->value; })
|
||||
|
||||
/*
|
||||
* Now we need a way to compare the nodes you defined above.
|
||||
|
@ -76,13 +76,13 @@ SKIPLIST_GETTERS(
|
|||
int
|
||||
__slm_key_compare(slex_t *list, slex_node_t *a, slex_node_t *b, void *aux)
|
||||
{
|
||||
(void)list;
|
||||
(void)aux;
|
||||
if (a->key < b->key)
|
||||
return -1;
|
||||
if (a->key > b->key)
|
||||
return 1;
|
||||
return 0;
|
||||
(void)list;
|
||||
(void)aux;
|
||||
if (a->key < b->key)
|
||||
return -1;
|
||||
if (a->key > b->key)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define DOT
|
||||
|
@ -93,71 +93,71 @@ SKIPLIST_DECL_DOT(slex, api_, entries)
|
|||
void
|
||||
sprintf_slex_node(slex_node_t *node, char *buf)
|
||||
{
|
||||
sprintf(buf, "%d:%d", node->key, node->value);
|
||||
sprintf(buf, "%d:%d", node->key, node->value);
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
int rc = 0;
|
||||
/* Allocate and initialize a Skiplist. */
|
||||
slex_t *list = (slex_t *)malloc(sizeof(slex_t));
|
||||
if (list == NULL) {
|
||||
rc = ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
rc = api_skip_init_slex(list, 12, __slm_key_compare);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
struct slex_node *n;
|
||||
|
||||
/* Insert 7 key/value pairs into the list. */
|
||||
for (int i = -200; i <= 200; i++) {
|
||||
int v;
|
||||
slex_node_t new;
|
||||
rc = api_skip_alloc_node_slex(list, &n);
|
||||
int rc = 0;
|
||||
/* Allocate and initialize a Skiplist. */
|
||||
slex_t *list = (slex_t *)malloc(sizeof(slex_t));
|
||||
if (list == NULL) {
|
||||
rc = ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
rc = api_skip_init_slex(list, 12, __slm_key_compare);
|
||||
if (rc)
|
||||
return rc;
|
||||
n->key = i;
|
||||
n->value = i;
|
||||
api_skip_insert_slex(list, n);
|
||||
v = api_skip_get_slex(list, i);
|
||||
((void)v);
|
||||
new.key = n->key;
|
||||
new.value = n->value * 10;
|
||||
api_skip_update_slex(list, &new);
|
||||
}
|
||||
return rc;
|
||||
|
||||
slex_node_t q;
|
||||
q.key = 0;
|
||||
api_skip_remove_slex(list, &q);
|
||||
struct slex_node *n;
|
||||
|
||||
// assert(api_skip_gte_slex(list, -3000000) == -20);
|
||||
assert(api_skip_gte_slex(list, -2) == -20);
|
||||
assert(api_skip_gte_slex(list, 0) == 10);
|
||||
// assert(api_skip_gte_slex(list, 0) == 0);
|
||||
assert(api_skip_gte_slex(list, 2) == 20);
|
||||
assert(api_skip_gte_slex(list, 30000000) == 0);
|
||||
/* Insert 7 key/value pairs into the list. */
|
||||
for (int i = -50; i <= 50; i++) {
|
||||
int v;
|
||||
slex_node_t new;
|
||||
rc = api_skip_alloc_node_slex(list, &n);
|
||||
if (rc)
|
||||
return rc;
|
||||
n->key = i;
|
||||
n->value = i;
|
||||
api_skip_insert_slex(list, n);
|
||||
v = api_skip_get_slex(list, i);
|
||||
((void)v);
|
||||
new.key = n->key;
|
||||
new.value = n->value * 10;
|
||||
api_skip_update_slex(list, &new);
|
||||
}
|
||||
|
||||
assert(api_skip_lte_slex(list, -3000000) == 0);
|
||||
assert(api_skip_lte_slex(list, -2) == -20);
|
||||
assert(api_skip_lte_slex(list, 0) == -10);
|
||||
// assert(api_skip_lte_slex(list, 0) == 0);
|
||||
assert(api_skip_lte_slex(list, 2) == 20);
|
||||
// assert(api_skip_lte_slex(list, 30000000) == 20);
|
||||
slex_node_t q;
|
||||
q.key = 0;
|
||||
api_skip_remove_slex(list, &q);
|
||||
|
||||
FILE *of = fopen("/tmp/slm.dot", "w");
|
||||
if (!of) {
|
||||
perror("Failed to open file /tmp/slm.dot");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
api_skip_dot_slex(of, list, 0, sprintf_slex_node);
|
||||
fclose(of);
|
||||
// assert(api_skip_gte_slex(list, -3000000) == -20);
|
||||
assert(api_skip_gte_slex(list, -2) == -20);
|
||||
assert(api_skip_gte_slex(list, 0) == 10);
|
||||
// assert(api_skip_gte_slex(list, 0) == 0);
|
||||
assert(api_skip_gte_slex(list, 2) == 20);
|
||||
assert(api_skip_gte_slex(list, 30000000) == 0);
|
||||
|
||||
api_skip_destroy_slex(list);
|
||||
assert(api_skip_lte_slex(list, -3000000) == 0);
|
||||
assert(api_skip_lte_slex(list, -2) == -20);
|
||||
assert(api_skip_lte_slex(list, 0) == -10);
|
||||
// assert(api_skip_lte_slex(list, 0) == 0);
|
||||
assert(api_skip_lte_slex(list, 2) == 20);
|
||||
// assert(api_skip_lte_slex(list, 30000000) == 20);
|
||||
|
||||
FILE *of = fopen("/tmp/slm.dot", "w");
|
||||
if (!of) {
|
||||
perror("Failed to open file /tmp/slm.dot");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
api_skip_dot_slex(of, list, 0, sprintf_slex_node);
|
||||
fclose(of);
|
||||
|
||||
api_skip_destroy_slex(list);
|
||||
|
||||
fail:;
|
||||
return rc;
|
||||
return rc;
|
||||
}
|
||||
|
|
48
include/sl.h
48
include/sl.h
|
@ -104,14 +104,16 @@
|
|||
struct type *slh_tail; \
|
||||
}
|
||||
|
||||
#define SKIP_ENTRY(type) \
|
||||
struct { \
|
||||
struct __sle { \
|
||||
struct type **next; \
|
||||
size_t cap; \
|
||||
size_t len; \
|
||||
} sle; \
|
||||
struct type *sle_prev; \
|
||||
#define SKIP_ENTRY(type) \
|
||||
struct __skiplist_entry { \
|
||||
struct __skiplist_idx { \
|
||||
struct type *prev, **next; \
|
||||
size_t cap, len; \
|
||||
} sle; \
|
||||
struct __skiplist_revs { \
|
||||
struct __skiplist_idx **rev; \
|
||||
size_t ref; \
|
||||
} **slr; \
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -120,7 +122,7 @@
|
|||
#define SKIP_FIRST(head) ((head)->slh_head)
|
||||
#define SKIP_LAST(head) ((head)->slh_tail)
|
||||
#define SKIP_NEXT(elm, field) ((elm)->field.sle.next[0])
|
||||
#define SKIP_PREV(elm, field) ((elm)->field.sle_prev)
|
||||
#define SKIP_PREV(elm, field) ((elm)->field.sle.prev)
|
||||
#define SKIP_EMPTY(head) ((head)->length == 0)
|
||||
|
||||
/*
|
||||
|
@ -204,8 +206,8 @@
|
|||
{ \
|
||||
decl##_node_t *n; \
|
||||
/* Calculate the size of the struct sle within decl##_node_t, multiply \
|
||||
by array size. */ \
|
||||
size_t sle_arr_sz = (sizeof(size_t) + offsetof(struct __sle, len)) * slist->max; \
|
||||
by array size. (16/24 bytes on 32/64 bit systems) */ \
|
||||
size_t sle_arr_sz = sizeof(struct __skiplist_idx) * slist->max; \
|
||||
n = (decl##_node_t *)calloc(1, sizeof(decl##_node_t) + sle_arr_sz); \
|
||||
if (n == NULL) \
|
||||
return ENOMEM; \
|
||||
|
@ -239,11 +241,11 @@
|
|||
slist->slh_head->field.sle.len = slist->max; \
|
||||
for (i = 0; i < slist->max; i++) \
|
||||
slist->slh_head->field.sle.next[i] = slist->slh_tail; \
|
||||
slist->slh_head->field.sle_prev = NULL; \
|
||||
slist->slh_head->field.sle.prev = NULL; \
|
||||
slist->slh_tail->field.sle.len = slist->max; \
|
||||
for (i = 0; i < slist->max; i++) \
|
||||
slist->slh_tail->field.sle.next[i] = NULL; \
|
||||
slist->slh_head->field.sle_prev = slist->slh_tail; \
|
||||
slist->slh_head->field.sle.prev = slist->slh_tail; \
|
||||
/* NOTE: Here's a testing aid, simply set `max` to a negative number to \
|
||||
* seed the PRNG in a predictable way and have reproducible random numbers. \
|
||||
*/ \
|
||||
|
@ -283,7 +285,7 @@
|
|||
/* -- skip_tail_ */ \
|
||||
decl##_node_t *prefix##skip_tail_##decl(decl##_t *slist) \
|
||||
{ \
|
||||
return slist->slh_tail->field.sle_prev; \
|
||||
return slist->slh_tail->field.sle.prev; \
|
||||
} \
|
||||
\
|
||||
/* -- __skip_locate_ \
|
||||
|
@ -350,9 +352,9 @@
|
|||
n->field.sle.next[i] = slist->slh_tail; \
|
||||
} \
|
||||
} \
|
||||
n->field.sle_prev = path[1]; \
|
||||
n->field.sle.prev = path[1]; \
|
||||
if (n->field.sle.next[0] == slist->slh_tail) { \
|
||||
slist->slh_tail->field.sle_prev = n; \
|
||||
slist->slh_tail->field.sle.prev = n; \
|
||||
} \
|
||||
if (level > slist->level) { \
|
||||
slist->level = level; \
|
||||
|
@ -453,7 +455,7 @@
|
|||
return elm; \
|
||||
} else { \
|
||||
do { \
|
||||
elm = elm->field.sle_prev; \
|
||||
elm = elm->field.sle.prev; \
|
||||
cmp = __skip_key_compare_##decl(slist, elm, n, slist->aux); \
|
||||
} while (cmp > 0); \
|
||||
} \
|
||||
|
@ -503,7 +505,7 @@
|
|||
len = __skip_locate_##decl(slist, n, path); \
|
||||
node = path[0]; \
|
||||
if (node) { \
|
||||
node->field.sle.next[0]->field.sle_prev = node->field.sle_prev; \
|
||||
node->field.sle.next[0]->field.sle.prev = node->field.sle.prev; \
|
||||
for (i = 1; i <= len; i++) { \
|
||||
if (path[i]->field.sle.next[i - 1] != node) \
|
||||
break; \
|
||||
|
@ -546,9 +548,9 @@
|
|||
{ \
|
||||
if (slist == NULL || n == NULL) \
|
||||
return NULL; \
|
||||
if (n->field.sle_prev == slist->slh_head) \
|
||||
if (n->field.sle.prev == slist->slh_head) \
|
||||
return NULL; \
|
||||
return n->field.sle_prev; \
|
||||
return n->field.sle.prev; \
|
||||
} \
|
||||
\
|
||||
/* -- skip_destroy_ */ \
|
||||
|
@ -769,10 +771,10 @@
|
|||
fprintf(os, "\"node%zu %p\" [label = \"", nsg, (void *)slist->slh_tail); \
|
||||
level = tail->field.sle.len - 1; \
|
||||
do { \
|
||||
fprintf(os, "<w%zu> %p", level, (void *)node->field.sle_prev); \
|
||||
if (level && node->field.sle_prev != slist->slh_head) \
|
||||
fprintf(os, "<w%zu> %p", level, (void *)node->field.sle.prev); \
|
||||
if (level && node->field.sle.prev != slist->slh_head) \
|
||||
fprintf(os, " | "); \
|
||||
} while (level-- && node->field.sle_prev != slist->slh_head); \
|
||||
} while (level-- && node->field.sle.prev != slist->slh_head); \
|
||||
fprintf(os, "\" shape = \"record\"];\n"); \
|
||||
} \
|
||||
\
|
||||
|
|
Loading…
Reference in a new issue