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