splay v1/p5; rebalence desc cond
This commit is contained in:
parent
8703fbb5a9
commit
64c68c2283
4
Makefile
4
Makefile
|
@ -3,9 +3,11 @@ OBJS = skiplist.o
|
||||||
STATIC_LIB = libskiplist.a
|
STATIC_LIB = libskiplist.a
|
||||||
SHARED_LIB = libskiplist.so
|
SHARED_LIB = libskiplist.so
|
||||||
|
|
||||||
|
# https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
|
||||||
|
#CFLAGS = -Wall -Wextra -Wpedantic -Of -std=c99 -Iinclude/ -fPIC
|
||||||
CFLAGS = -Wall -Wextra -Wpedantic -Og -g -std=c99 -Iinclude/ -fPIC
|
CFLAGS = -Wall -Wextra -Wpedantic -Og -g -std=c99 -Iinclude/ -fPIC
|
||||||
|
#CFLAGS = -Wall -Wextra -Wpedantic -Og -g -fsanitize=address,undefined -std=c99 -Iinclude/ -fPIC
|
||||||
TEST_FLAGS = -Itests/
|
TEST_FLAGS = -Itests/
|
||||||
#-fsanitize=address,undefined
|
|
||||||
|
|
||||||
TESTS = tests/test
|
TESTS = tests/test
|
||||||
TEST_OBJS = tests/test.o tests/munit.o
|
TEST_OBJS = tests/test.o tests/munit.o
|
||||||
|
|
132
examples/slm.c
132
examples/slm.c
|
@ -19,11 +19,11 @@
|
||||||
#define VALIDATE
|
#define VALIDATE
|
||||||
#define SNAPSHOTS
|
#define SNAPSHOTS
|
||||||
#define DOT
|
#define DOT
|
||||||
#define TEST_ARRAY_SIZE 10
|
#define TEST_ARRAY_SIZE 50
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
#ifdef VALIDATE
|
#ifdef VALIDATE
|
||||||
#define CHECK __skip_integrity_check_sample(list, 0)
|
#define CHECK __skip_integrity_check_esempio(list, 0)
|
||||||
#else
|
#else
|
||||||
#define CHECK ((void)0)
|
#define CHECK ((void)0)
|
||||||
#endif
|
#endif
|
||||||
|
@ -31,10 +31,8 @@
|
||||||
/*
|
/*
|
||||||
* SKIPLIST EXAMPLE:
|
* SKIPLIST EXAMPLE:
|
||||||
*
|
*
|
||||||
* This example creates a "sample" Skiplist where keys are integers, values are
|
* This example creates an "esempio" (example in Italian) Skiplist where keys
|
||||||
* strings allocated on the heap.
|
* are integers, values are strings allocated on the heap.
|
||||||
*
|
|
||||||
* 'sample' - meaning: EXample
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -45,17 +43,17 @@
|
||||||
* node against another, logic you'll provide in SKIP_DECL as a
|
* node against another, logic you'll provide in SKIP_DECL as a
|
||||||
* block below.
|
* block below.
|
||||||
*/
|
*/
|
||||||
struct sample_node {
|
struct esempio_node {
|
||||||
int key;
|
int key;
|
||||||
char *value;
|
char *value;
|
||||||
SKIPLIST_ENTRY(sample) entries;
|
SKIPLIST_ENTRY(esempio) 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(
|
||||||
sample, api_, entries,
|
esempio, api_, entries,
|
||||||
/* compare entries: list, a, b, aux */
|
/* compare entries: list, a, b, aux */
|
||||||
{
|
{
|
||||||
(void)list;
|
(void)list;
|
||||||
|
@ -109,7 +107,7 @@ SKIPLIST_DECL(
|
||||||
* list or when `a == b`. In those cases the comparison function
|
* list or when `a == b`. In those cases the comparison function
|
||||||
* returns before using the code in your block, don't panic. :)
|
* returns before using the code in your block, don't panic. :)
|
||||||
int
|
int
|
||||||
__sample_key_compare(sample_t *list, sample_node_t *a, sample_node_t *b, void *aux)
|
__esempio_key_compare(esempio_t *list, esempio_node_t *a, esempio_node_t *b, void *aux)
|
||||||
{
|
{
|
||||||
(void)list;
|
(void)list;
|
||||||
(void)aux;
|
(void)aux;
|
||||||
|
@ -130,7 +128,7 @@ __sample_key_compare(sample_t *list, sample_node_t *a, sample_node_t *b, void *a
|
||||||
* extract data from within your nodes.
|
* extract data from within your nodes.
|
||||||
*/
|
*/
|
||||||
SKIPLIST_DECL_ACCESS(
|
SKIPLIST_DECL_ACCESS(
|
||||||
sample, api_, key, int, value, char *,
|
esempio, api_, key, int, value, char *,
|
||||||
/* query blk */ { query.key = key; },
|
/* query blk */ { query.key = key; },
|
||||||
/* return blk */ { return node->value; })
|
/* return blk */ { return node->value; })
|
||||||
|
|
||||||
|
@ -140,7 +138,7 @@ SKIPLIST_DECL_ACCESS(
|
||||||
* Enable functions that enable returning to an earlier point in
|
* Enable functions that enable returning to an earlier point in
|
||||||
* time when a snapshot was created.
|
* time when a snapshot was created.
|
||||||
*/
|
*/
|
||||||
SKIPLIST_DECL_SNAPSHOTS(sample, api_, entries)
|
SKIPLIST_DECL_SNAPSHOTS(esempio, api_, entries)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Optional: Archive to/from bytes
|
* Optional: Archive to/from bytes
|
||||||
|
@ -148,30 +146,30 @@ SKIPLIST_DECL_SNAPSHOTS(sample, api_, entries)
|
||||||
* Enable functions that can write/read the content of your Skiplist
|
* Enable functions that can write/read the content of your Skiplist
|
||||||
* out/in to/from an array of bytes.
|
* out/in to/from an array of bytes.
|
||||||
*/
|
*/
|
||||||
SKIPLIST_DECL_ARCHIVE(sample, api_, entries)
|
SKIPLIST_DECL_ARCHIVE(esempio, api_, entries)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Optional: As Hashtable
|
* Optional: As Hashtable
|
||||||
*
|
*
|
||||||
* Turn your Skiplist into a hash table.
|
* Turn your Skiplist into a hash table.
|
||||||
*/
|
*/
|
||||||
//TODO SKIPLIST_DECL_HASHTABLE(sample, api_, entries, snaps)
|
//TODO SKIPLIST_DECL_HASHTABLE(esempio, api_, entries, snaps)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Optional: Check Skiplists at runtime
|
* Optional: Check Skiplists at runtime
|
||||||
*
|
*
|
||||||
* Create a functions that validate the integrity of a Skiplist.
|
* Create a functions that validate the integrity of a Skiplist.
|
||||||
*/
|
*/
|
||||||
SKIPLIST_DECL_VALIDATE(sample, api_, entries)
|
SKIPLIST_DECL_VALIDATE(esempio, api_, entries)
|
||||||
|
|
||||||
/* Optional: Visualize your Skiplist using DOT/Graphviz in PDF
|
/* Optional: Visualize your Skiplist using DOT/Graphviz in PDF
|
||||||
*
|
*
|
||||||
* Create the functions used to annotate a visualization of a Skiplist.
|
* Create the functions used to annotate a visualization of a Skiplist.
|
||||||
*/
|
*/
|
||||||
SKIPLIST_DECL_DOT(sample, api_, entries)
|
SKIPLIST_DECL_DOT(esempio, api_, entries)
|
||||||
|
|
||||||
void
|
void
|
||||||
sprintf_sample_node(sample_node_t *node, char *buf)
|
sprintf_esempio_node(esempio_node_t *node, char *buf)
|
||||||
{
|
{
|
||||||
// sprintf(buf, "%d:%s (hits: %lu)", node->key, node->value, node->entries.sle_hits);
|
// sprintf(buf, "%d:%s (hits: %lu)", node->key, node->value, node->entries.sle_hits);
|
||||||
sprintf(buf, "%d:%s", node->key, node->value);
|
sprintf(buf, "%d:%s", node->key, node->value);
|
||||||
|
@ -259,25 +257,25 @@ main()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Allocate and initialize a Skiplist. */
|
/* Allocate and initialize a Skiplist. */
|
||||||
sample_t *list = (sample_t *)malloc(sizeof(sample_t));
|
esempio_t *list = (esempio_t *)malloc(sizeof(esempio_t));
|
||||||
if (list == NULL)
|
if (list == NULL)
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
|
|
||||||
rc = api_skip_init_sample(list, -12);
|
rc = api_skip_init_esempio(list, -12);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
api_skip_snapshots_init_sample(list);
|
api_skip_snapshots_init_esempio(list);
|
||||||
#ifdef DOT
|
#ifdef DOT
|
||||||
api_skip_dot_sample(of, list, gen++, "init", sprintf_sample_node);
|
api_skip_dot_esempio(of, list, gen++, "init", sprintf_esempio_node);
|
||||||
#endif
|
#endif
|
||||||
if (api_skip_get_sample(list, 0) != NULL)
|
if (api_skip_get_esempio(list, 0) != NULL)
|
||||||
perror("found a non-existent item!");
|
perror("found a non-existent item!");
|
||||||
api_skip_del_sample(list, 0);
|
api_skip_del_esempio(list, 0);
|
||||||
CHECK;
|
CHECK;
|
||||||
|
|
||||||
#ifdef SNAPSHOTS
|
#ifdef SNAPSHOTS
|
||||||
/* Test creating a snapshot of an empty Skiplist */
|
/* Test creating a snapshot of an empty Skiplist */
|
||||||
snap_ids[snap_i++] = api_skip_snapshot_sample(list);
|
snap_ids[snap_i++] = api_skip_snapshot_esempio(list);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Insert 7 key/value pairs into the list. */
|
/* Insert 7 key/value pairs into the list. */
|
||||||
|
@ -295,98 +293,104 @@ main()
|
||||||
|
|
||||||
for (i = 0; i < asz; i++) {
|
for (i = 0; i < asz; i++) {
|
||||||
numeral = to_lower(int_to_roman_numeral(array[i]));
|
numeral = to_lower(int_to_roman_numeral(array[i]));
|
||||||
rc = api_skip_put_sample(list, array[i], numeral);
|
rc = api_skip_put_esempio(list, array[i], numeral);
|
||||||
CHECK;
|
CHECK;
|
||||||
#ifdef SNAPSHOTS
|
#ifdef SNAPSHOTS
|
||||||
if (i > TEST_ARRAY_SIZE + 1) {
|
if (i > TEST_ARRAY_SIZE + 1) {
|
||||||
snap_ids[snap_i++] = api_skip_snapshot_sample(list);
|
snap_ids[snap_i++] = api_skip_snapshot_esempio(list);
|
||||||
CHECK;
|
CHECK;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef DOT
|
#ifdef DOT
|
||||||
sprintf(msg, "put key: %d value: %s", i, numeral);
|
sprintf(msg, "put key: %d value: %s", i, numeral);
|
||||||
api_skip_dot_sample(of, list, gen++, msg, sprintf_sample_node);
|
api_skip_dot_esempio(of, list, gen++, msg, sprintf_esempio_node);
|
||||||
CHECK;
|
CHECK;
|
||||||
#endif
|
#endif
|
||||||
char *v = api_skip_get_sample(list, array[i]);
|
char *v = api_skip_get_esempio(list, array[i]);
|
||||||
CHECK;
|
CHECK;
|
||||||
char *upper_numeral = calloc(1, strlen(v) + 1);
|
char *upper_numeral = calloc(1, strlen(v) + 1);
|
||||||
strncpy(upper_numeral, v, strlen(v));
|
strncpy(upper_numeral, v, strlen(v));
|
||||||
to_upper(upper_numeral);
|
to_upper(upper_numeral);
|
||||||
api_skip_set_sample(list, array[i], upper_numeral);
|
api_skip_set_esempio(list, array[i], upper_numeral);
|
||||||
CHECK;
|
CHECK;
|
||||||
|
if (i == 8) {
|
||||||
|
api_skip_get_esempio(list, -2);
|
||||||
|
api_skip_get_esempio(list, -2);
|
||||||
|
api_skip_get_esempio(list, -2);
|
||||||
|
api_skip_get_esempio(list, -2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
numeral = int_to_roman_numeral(-1);
|
numeral = int_to_roman_numeral(-1);
|
||||||
api_skip_dup_sample(list, -1, numeral);
|
api_skip_dup_esempio(list, -1, numeral);
|
||||||
CHECK;
|
CHECK;
|
||||||
#ifdef DOT
|
#ifdef DOT
|
||||||
sprintf(msg, "put dup key: %d value: %s", i, numeral);
|
sprintf(msg, "put dup key: %d value: %s", i, numeral);
|
||||||
api_skip_dot_sample(of, list, gen++, msg, sprintf_sample_node);
|
api_skip_dot_esempio(of, list, gen++, msg, sprintf_esempio_node);
|
||||||
CHECK;
|
CHECK;
|
||||||
#endif
|
#endif
|
||||||
numeral = int_to_roman_numeral(1);
|
numeral = int_to_roman_numeral(1);
|
||||||
api_skip_dup_sample(list, 1, numeral);
|
api_skip_dup_esempio(list, 1, numeral);
|
||||||
CHECK;
|
CHECK;
|
||||||
#ifdef DOT
|
#ifdef DOT
|
||||||
sprintf(msg, "put dup key: %d value: %s", i, numeral);
|
sprintf(msg, "put dup key: %d value: %s", i, numeral);
|
||||||
api_skip_dot_sample(of, list, gen++, msg, sprintf_sample_node);
|
api_skip_dot_esempio(of, list, gen++, msg, sprintf_esempio_node);
|
||||||
CHECK;
|
CHECK;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
api_skip_del_sample(list, 0);
|
api_skip_del_esempio(list, 0);
|
||||||
CHECK;
|
CHECK;
|
||||||
if (api_skip_get_sample(list, 0) != NULL)
|
if (api_skip_get_esempio(list, 0) != NULL)
|
||||||
perror("found a deleted item!");
|
perror("found a deleted item!");
|
||||||
api_skip_del_sample(list, 0);
|
api_skip_del_esempio(list, 0);
|
||||||
CHECK;
|
CHECK;
|
||||||
if (api_skip_get_sample(list, 0) != NULL)
|
if (api_skip_get_esempio(list, 0) != NULL)
|
||||||
perror("found a deleted item!");
|
perror("found a deleted item!");
|
||||||
int key = TEST_ARRAY_SIZE + 1;
|
int key = TEST_ARRAY_SIZE + 1;
|
||||||
api_skip_del_sample(list, key);
|
api_skip_del_esempio(list, key);
|
||||||
CHECK;
|
CHECK;
|
||||||
key = -(TEST_ARRAY_SIZE)-1;
|
key = -(TEST_ARRAY_SIZE)-1;
|
||||||
numeral = int_to_roman_numeral(key);
|
numeral = int_to_roman_numeral(key);
|
||||||
api_skip_del_sample(list, key);
|
api_skip_del_esempio(list, key);
|
||||||
CHECK;
|
CHECK;
|
||||||
|
|
||||||
#ifdef DOT
|
#ifdef DOT
|
||||||
sprintf(msg, "deleted key: %d, value: %s", 0, numeral);
|
sprintf(msg, "deleted key: %d, value: %s", 0, numeral);
|
||||||
api_skip_dot_sample(of, list, gen++, msg, sprintf_sample_node);
|
api_skip_dot_esempio(of, list, gen++, msg, sprintf_esempio_node);
|
||||||
CHECK;
|
CHECK;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SNAPSHOTS
|
#ifdef SNAPSHOTS
|
||||||
//api_skip_restore_snapshot_sample(list, snap_ids[snap_i - 1]);
|
api_skip_restore_snapshot_esempio(list, snap_ids[snap_i - 1]);
|
||||||
//api_skip_release_snapshots_sample(list);
|
api_skip_release_snapshots_esempio(list);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
assert(strcmp(api_skip_pos_sample(list, SKIP_GTE, -(TEST_ARRAY_SIZE)-1)->value, int_to_roman_numeral(-(TEST_ARRAY_SIZE))) == 0);
|
assert(strcmp(api_skip_pos_esempio(list, SKIP_GTE, -(TEST_ARRAY_SIZE)-1)->value, int_to_roman_numeral(-(TEST_ARRAY_SIZE))) == 0);
|
||||||
assert(strcmp(api_skip_pos_sample(list, SKIP_GTE, -2)->value, int_to_roman_numeral(-2)) == 0);
|
assert(strcmp(api_skip_pos_esempio(list, SKIP_GTE, -2)->value, int_to_roman_numeral(-2)) == 0);
|
||||||
assert(strcmp(api_skip_pos_sample(list, SKIP_GTE, 0)->value, int_to_roman_numeral(1)) == 0);
|
assert(strcmp(api_skip_pos_esempio(list, SKIP_GTE, 0)->value, int_to_roman_numeral(1)) == 0);
|
||||||
assert(strcmp(api_skip_pos_sample(list, SKIP_GTE, 2)->value, int_to_roman_numeral(2)) == 0);
|
assert(strcmp(api_skip_pos_esempio(list, SKIP_GTE, 2)->value, int_to_roman_numeral(2)) == 0);
|
||||||
assert(api_skip_pos_sample(list, SKIP_GTE, (TEST_ARRAY_SIZE + 1)) == NULL);
|
assert(api_skip_pos_esempio(list, SKIP_GTE, (TEST_ARRAY_SIZE + 1)) == NULL);
|
||||||
|
|
||||||
assert(strcmp(api_skip_pos_sample(list, SKIP_GT, -(TEST_ARRAY_SIZE)-1)->value, int_to_roman_numeral(-(TEST_ARRAY_SIZE))) == 0);
|
assert(strcmp(api_skip_pos_esempio(list, SKIP_GT, -(TEST_ARRAY_SIZE)-1)->value, int_to_roman_numeral(-(TEST_ARRAY_SIZE))) == 0);
|
||||||
assert(strcmp(api_skip_pos_sample(list, SKIP_GT, -2)->value, int_to_roman_numeral(-1)) == 0);
|
assert(strcmp(api_skip_pos_esempio(list, SKIP_GT, -2)->value, int_to_roman_numeral(-1)) == 0);
|
||||||
assert(strcmp(api_skip_pos_sample(list, SKIP_GT, 0)->value, int_to_roman_numeral(1)) == 0);
|
assert(strcmp(api_skip_pos_esempio(list, SKIP_GT, 0)->value, int_to_roman_numeral(1)) == 0);
|
||||||
assert(strcmp(api_skip_pos_sample(list, SKIP_GT, 1)->value, int_to_roman_numeral(2)) == 0);
|
assert(strcmp(api_skip_pos_esempio(list, SKIP_GT, 1)->value, int_to_roman_numeral(2)) == 0);
|
||||||
assert(api_skip_pos_sample(list, SKIP_GT, TEST_ARRAY_SIZE) == NULL);
|
assert(api_skip_pos_esempio(list, SKIP_GT, TEST_ARRAY_SIZE) == NULL);
|
||||||
|
|
||||||
assert(api_skip_pos_sample(list, SKIP_LT, -(TEST_ARRAY_SIZE)) == NULL);
|
assert(api_skip_pos_esempio(list, SKIP_LT, -(TEST_ARRAY_SIZE)) == NULL);
|
||||||
assert(strcmp(api_skip_pos_sample(list, SKIP_LT, -1)->value, int_to_roman_numeral(-2)) == 0);
|
assert(strcmp(api_skip_pos_esempio(list, SKIP_LT, -1)->value, int_to_roman_numeral(-2)) == 0);
|
||||||
assert(strcmp(api_skip_pos_sample(list, SKIP_LT, 0)->value, int_to_roman_numeral(-1)) == 0);
|
assert(strcmp(api_skip_pos_esempio(list, SKIP_LT, 0)->value, int_to_roman_numeral(-1)) == 0);
|
||||||
assert(strcmp(api_skip_pos_sample(list, SKIP_LT, 2)->value, int_to_roman_numeral(1)) == 0);
|
assert(strcmp(api_skip_pos_esempio(list, SKIP_LT, 2)->value, int_to_roman_numeral(1)) == 0);
|
||||||
assert(strcmp(api_skip_pos_sample(list, SKIP_LT, (TEST_ARRAY_SIZE + 1))->value, int_to_roman_numeral(TEST_ARRAY_SIZE)) == 0);
|
assert(strcmp(api_skip_pos_esempio(list, SKIP_LT, (TEST_ARRAY_SIZE + 1))->value, int_to_roman_numeral(TEST_ARRAY_SIZE)) == 0);
|
||||||
|
|
||||||
assert(api_skip_pos_sample(list, SKIP_LTE, -(TEST_ARRAY_SIZE)-1) == NULL);
|
assert(api_skip_pos_esempio(list, SKIP_LTE, -(TEST_ARRAY_SIZE)-1) == NULL);
|
||||||
assert(strcmp(api_skip_pos_sample(list, SKIP_LTE, -2)->value, int_to_roman_numeral(-2)) == 0);
|
assert(strcmp(api_skip_pos_esempio(list, SKIP_LTE, -2)->value, int_to_roman_numeral(-2)) == 0);
|
||||||
assert(strcmp(api_skip_pos_sample(list, SKIP_LTE, 0)->value, int_to_roman_numeral(-1)) == 0);
|
assert(strcmp(api_skip_pos_esempio(list, SKIP_LTE, 0)->value, int_to_roman_numeral(-1)) == 0);
|
||||||
assert(strcmp(api_skip_pos_sample(list, SKIP_LTE, 2)->value, int_to_roman_numeral(2)) == 0);
|
assert(strcmp(api_skip_pos_esempio(list, SKIP_LTE, 2)->value, int_to_roman_numeral(2)) == 0);
|
||||||
assert(strcmp(api_skip_pos_sample(list, SKIP_LTE, (TEST_ARRAY_SIZE + 1))->value, int_to_roman_numeral(TEST_ARRAY_SIZE)) == 0);
|
assert(strcmp(api_skip_pos_esempio(list, SKIP_LTE, (TEST_ARRAY_SIZE + 1))->value, int_to_roman_numeral(TEST_ARRAY_SIZE)) == 0);
|
||||||
|
|
||||||
api_skip_free_sample(list);
|
api_skip_free_esempio(list);
|
||||||
#ifdef DOT
|
#ifdef DOT
|
||||||
api_skip_dot_end_sample(of, gen);
|
api_skip_dot_end_esempio(of, gen);
|
||||||
fclose(of);
|
fclose(of);
|
||||||
#endif
|
#endif
|
||||||
return rc;
|
return rc;
|
||||||
|
|
583
include/sl.h
583
include/sl.h
|
@ -276,6 +276,7 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
|
||||||
typedef struct __skiplist_path_##decl { \
|
typedef struct __skiplist_path_##decl { \
|
||||||
decl##_node_t *node; /* node traversed in the act of location */ \
|
decl##_node_t *node; /* node traversed in the act of location */ \
|
||||||
size_t intersection; /* level at which the node was intersected */ \
|
size_t intersection; /* level at which the node was intersected */ \
|
||||||
|
size_t par_hit_sum; /* sum of hits from intersection to level[1] */ \
|
||||||
} __skiplist_path_##decl##_t; \
|
} __skiplist_path_##decl##_t; \
|
||||||
\
|
\
|
||||||
/** \
|
/** \
|
||||||
|
@ -597,35 +598,58 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/** \
|
/** \
|
||||||
* -- __skip_rebalence_ TODO \
|
* -- __skip_rebalence_ TODO/WIP \
|
||||||
|
* \
|
||||||
|
* Restore balance to our list by adjusting heights and forward pointers \
|
||||||
|
* according to the algorithm put forth in "The Splay-List: A \
|
||||||
|
* Distribution-Adaptive Concurrent Skip-List". \
|
||||||
* \
|
* \
|
||||||
*/ \
|
*/ \
|
||||||
static void __skip_rebalence_##decl(decl##_t *slist, size_t len, __skiplist_path_##decl##_t path[], size_t par_sum) \
|
static void __skip_rebalence_##decl(decl##_t *slist, size_t len, __skiplist_path_##decl##_t path[]) \
|
||||||
{ \
|
{ \
|
||||||
size_t i; \
|
size_t i, j, cur_hits, prev_hits; \
|
||||||
double asc_cond, dsc_cond; \
|
double asc_cond, dsc_cond; \
|
||||||
\
|
\
|
||||||
return; /* TODO GSB */ \
|
/* Moving backwards along the path... \
|
||||||
/* Moving backwards along the path... */ \
|
* - path[0] contains a match, if there was one \
|
||||||
|
* - path[1..len] will be the nodes traversed along the way \
|
||||||
|
* - path[len] is where the locate() terminated, just before path[0] \
|
||||||
|
* if there was a match \
|
||||||
|
*/ \
|
||||||
for (i = 1; i < len; i++) { \
|
for (i = 1; i < len; i++) { \
|
||||||
if (par_sum > 0) { \
|
/* (a) Check the decent condition: \
|
||||||
/* check the decent condition: \
|
* path[i].par_hit_sum <= hits total / (2 ^ (height of head - height of node)) \
|
||||||
* par_sum <= hits total / (2 ^ (height of head - height of node)) \
|
* When met should induce: \
|
||||||
*/ \
|
* 1) traverse the path backward, and ... \
|
||||||
dsc_cond = pow(2.0, slist->slh_head->field.sle_height - path[i].node->field.sle_height); \
|
* 2) propagate path[i].level[i] hits backward along path, and ... \
|
||||||
if (par_sum <= dsc_cond) { \
|
* 3) adjust any forward pointers along the way, then. \
|
||||||
/* reduce height by one, change forward pointer */ \
|
* 4) lower the path[i]'s node height by 1 \
|
||||||
path[i - 1].node->field.sle_next[i] = path[i].node->field.sle_next[i]; \
|
*/ \
|
||||||
path[i].node->field.sle_next[i] = slist->slh_tail; \
|
dsc_cond = pow(2.0, slist->slh_head->field.sle_height - path[i].node->field.sle_height); \
|
||||||
|
if (path[i].par_hit_sum <= dsc_cond) { \
|
||||||
|
if (path[i - 1].node->field.sle_prev != slist->slh_head) { \
|
||||||
|
/* 1) go backwards along path from where we are until head */ \
|
||||||
|
j = i; \
|
||||||
|
cur_hits = path[j].node->field.sle_next[path[j].intersection]->field.sle_hits; \
|
||||||
|
do { \
|
||||||
|
/* 2) propagate hits */ \
|
||||||
|
prev_hits = path[j - 1].node->field.sle_next[path[j - 1].intersection]->field.sle_hits; \
|
||||||
|
path[j - 1].node->field.sle_next[path[j - 1].intersection]->field.sle_hits += cur_hits; \
|
||||||
|
cur_hits = prev_hits; \
|
||||||
|
/* 3) adjust any forward pointers */ \
|
||||||
|
path[j - 1].node->field.sle_next[j] = path[j].node->field.sle_next[j]; \
|
||||||
|
} while (j-- > 1); \
|
||||||
|
/* 4) reduce height by one */ \
|
||||||
path[i].node->field.sle_height--; \
|
path[i].node->field.sle_height--; \
|
||||||
|
path[i].node->field.sle_next[i] = slist->slh_tail; \
|
||||||
} \
|
} \
|
||||||
/* check the ascent condition: \
|
} \
|
||||||
* par_sum + node_hits > hits total / (2 ^ (height of head - height of node - 1)) \
|
/* (b) Check the ascent condition: \
|
||||||
*/ \
|
* path[i].par_hit_sum + node_hits > hits total / (2 ^ (height of head - height of node - 1)) \
|
||||||
asc_cond = pow(2.0, slist->slh_head->field.sle_height - path[i].node->field.sle_height - 1); \
|
*/ \
|
||||||
if (path[i].node->field.sle_hits > asc_cond) { \
|
asc_cond = pow(2.0, slist->slh_head->field.sle_height - path[i].node->field.sle_height - 1); \
|
||||||
((void)0); \
|
if (path[i].node->field.sle_hits > asc_cond) { \
|
||||||
} \
|
((void)0); \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
|
@ -641,7 +665,7 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
|
||||||
static size_t __skip_locate_##decl(decl##_t *slist, decl##_node_t *n, __skiplist_path_##decl##_t path[]) \
|
static size_t __skip_locate_##decl(decl##_t *slist, decl##_node_t *n, __skiplist_path_##decl##_t path[]) \
|
||||||
{ \
|
{ \
|
||||||
unsigned int i; \
|
unsigned int i; \
|
||||||
size_t par_sum = 0, len = 0; \
|
size_t len = 0; \
|
||||||
decl##_node_t *elm = slist->slh_head; \
|
decl##_node_t *elm = slist->slh_head; \
|
||||||
\
|
\
|
||||||
if (slist == NULL || n == NULL) \
|
if (slist == NULL || n == NULL) \
|
||||||
|
@ -650,19 +674,21 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
|
||||||
/* Find the node that matches `node` or NULL. */ \
|
/* Find the node that matches `node` or NULL. */ \
|
||||||
i = slist->slh_head->field.sle_height; \
|
i = slist->slh_head->field.sle_height; \
|
||||||
do { \
|
do { \
|
||||||
|
path[i + 1].par_hit_sum = 0; \
|
||||||
while (elm != slist->slh_tail && elm->field.sle_next[i] && __skip_compare_nodes_##decl(slist, elm->field.sle_next[i], n, slist->slh_aux) < 0) { \
|
while (elm != slist->slh_tail && elm->field.sle_next[i] && __skip_compare_nodes_##decl(slist, elm->field.sle_next[i], n, slist->slh_aux) < 0) { \
|
||||||
elm = elm->field.sle_next[i]; \
|
elm = elm->field.sle_next[i]; \
|
||||||
path[i + 1].intersection = i; \
|
path[i + 1].intersection = i; \
|
||||||
|
path[i + 1].par_hit_sum += elm->field.sle_hits; \
|
||||||
} \
|
} \
|
||||||
path[i + 1].node = elm; \
|
path[i + 1].node = elm; \
|
||||||
par_sum += elm->field.sle_hits; \
|
path[i + 1].node->field.sle_hits++; \
|
||||||
len++; \
|
len++; \
|
||||||
} while (i--); \
|
} while (i--); \
|
||||||
elm = elm->field.sle_next[0]; \
|
elm = elm->field.sle_next[0]; \
|
||||||
if (__skip_compare_nodes_##decl(slist, elm, n, slist->slh_aux) == 0) { \
|
if (__skip_compare_nodes_##decl(slist, elm, n, slist->slh_aux) == 0) { \
|
||||||
path[0].node = elm; \
|
path[0].node = elm; \
|
||||||
path[0].node->field.sle_hits++; \
|
path[0].node->field.sle_hits++; \
|
||||||
__skip_rebalence_##decl(slist, len, path, par_sum); \
|
__skip_rebalence_##decl(slist, len, path); \
|
||||||
} \
|
} \
|
||||||
return len; \
|
return len; \
|
||||||
} \
|
} \
|
||||||
|
@ -753,6 +779,8 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
|
||||||
/* Record the era for this node to enable snapshots. */ \
|
/* Record the era for this node to enable snapshots. */ \
|
||||||
if (slist->slh_fns.snapshot_record_era) \
|
if (slist->slh_fns.snapshot_record_era) \
|
||||||
slist->slh_fns.snapshot_record_era(slist, new); \
|
slist->slh_fns.snapshot_record_era(slist, new); \
|
||||||
|
/* Set hits for rebalencing to 1 when new born. */ \
|
||||||
|
new->field.sle_hits = 1; \
|
||||||
/* Increase our list length (aka. size, count, etc.) by one. */ \
|
/* Increase our list length (aka. size, count, etc.) by one. */ \
|
||||||
slist->slh_length++; \
|
slist->slh_length++; \
|
||||||
\
|
\
|
||||||
|
@ -1499,260 +1527,259 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
|
||||||
return NULL; \
|
return NULL; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SKIPLIST_DECL_VALIDATE(decl, prefix, field) \
|
#define SKIPLIST_DECL_VALIDATE(decl, prefix, field) \
|
||||||
/** \
|
/** \
|
||||||
* -- __skip_integrity_failure_ \
|
* -- __skip_integrity_failure_ \
|
||||||
*/ \
|
*/ \
|
||||||
static void __attribute__((format(printf, 1, 2))) __skip_integrity_failure_##decl(const char *format, ...) \
|
static void __attribute__((format(printf, 1, 2))) __skip_integrity_failure_##decl(const char *format, ...) \
|
||||||
{ \
|
{ \
|
||||||
va_list args; \
|
va_list args; \
|
||||||
va_start(args, format); \
|
va_start(args, format); \
|
||||||
vfprintf(stderr, format, args); \
|
vfprintf(stderr, format, args); \
|
||||||
va_end(args); \
|
va_end(args); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/** \
|
/** \
|
||||||
* -- __skip_integrity_check_ \
|
* -- __skip_integrity_check_ \
|
||||||
*/ \
|
*/ \
|
||||||
static int __skip_integrity_check_##decl(decl##_t *slist, int flags) \
|
static int __skip_integrity_check_##decl(decl##_t *slist, int flags) \
|
||||||
{ \
|
{ \
|
||||||
size_t n = 0; \
|
size_t n = 0; \
|
||||||
unsigned long nth, n_err = 0; \
|
unsigned long nth, n_err = 0; \
|
||||||
decl##_node_t *node, *prev, *next; \
|
decl##_node_t *node, *prev, *next; \
|
||||||
struct __skiplist_##decl##_entry *this; \
|
struct __skiplist_##decl##_entry *this; \
|
||||||
\
|
\
|
||||||
if (slist == NULL) { \
|
if (slist == NULL) { \
|
||||||
__skip_integrity_failure_##decl("slist was NULL, nothing to check\n"); \
|
__skip_integrity_failure_##decl("slist was NULL, nothing to check\n"); \
|
||||||
n_err++; \
|
n_err++; \
|
||||||
return n_err; \
|
return n_err; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/* Check the Skiplist header (slh) */ \
|
/* Check the Skiplist header (slh) */ \
|
||||||
\
|
\
|
||||||
if (slist->slh_head == NULL) { \
|
if (slist->slh_head == NULL) { \
|
||||||
__skip_integrity_failure_##decl("skiplist slh_head is NULL\n"); \
|
__skip_integrity_failure_##decl("skiplist slh_head is NULL\n"); \
|
||||||
n_err++; \
|
n_err++; \
|
||||||
return n_err; \
|
return n_err; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
if (slist->slh_tail == NULL) { \
|
if (slist->slh_tail == NULL) { \
|
||||||
__skip_integrity_failure_##decl("skiplist slh_tail is NULL\n"); \
|
__skip_integrity_failure_##decl("skiplist slh_tail is NULL\n"); \
|
||||||
n_err++; \
|
n_err++; \
|
||||||
return n_err; \
|
return n_err; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
if (slist->slh_fns.free_entry == NULL) { \
|
if (slist->slh_fns.free_entry == NULL) { \
|
||||||
__skip_integrity_failure_##decl("skiplist free_entry fn is NULL\n"); \
|
__skip_integrity_failure_##decl("skiplist free_entry fn is NULL\n"); \
|
||||||
n_err++; \
|
n_err++; \
|
||||||
return n_err; \
|
return n_err; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
if (slist->slh_fns.update_entry == NULL) { \
|
if (slist->slh_fns.update_entry == NULL) { \
|
||||||
__skip_integrity_failure_##decl("skiplist update_entry fn is NULL\n"); \
|
__skip_integrity_failure_##decl("skiplist update_entry fn is NULL\n"); \
|
||||||
n_err++; \
|
n_err++; \
|
||||||
return n_err; \
|
return n_err; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
if (slist->slh_fns.archive_entry == NULL) { \
|
if (slist->slh_fns.archive_entry == NULL) { \
|
||||||
__skip_integrity_failure_##decl("skiplist archive_entry fn is NULL\n"); \
|
__skip_integrity_failure_##decl("skiplist archive_entry fn is NULL\n"); \
|
||||||
n_err++; \
|
n_err++; \
|
||||||
return n_err; \
|
return n_err; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
if (slist->slh_fns.sizeof_entry == NULL) { \
|
if (slist->slh_fns.sizeof_entry == NULL) { \
|
||||||
__skip_integrity_failure_##decl("skiplist sizeof_entry fn is NULL\n"); \
|
__skip_integrity_failure_##decl("skiplist sizeof_entry fn is NULL\n"); \
|
||||||
n_err++; \
|
n_err++; \
|
||||||
return n_err; \
|
return n_err; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
if (slist->slh_fns.compare_entries == NULL) { \
|
if (slist->slh_fns.compare_entries == NULL) { \
|
||||||
__skip_integrity_failure_##decl("skiplist compare_entries fn is NULL\n"); \
|
__skip_integrity_failure_##decl("skiplist compare_entries fn is NULL\n"); \
|
||||||
n_err++; \
|
n_err++; \
|
||||||
return n_err; \
|
return n_err; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
if (slist->slh_max_height < 1) { \
|
if (slist->slh_max_height < 1) { \
|
||||||
__skip_integrity_failure_##decl("skiplist max level must be 1 at minimum\n"); \
|
__skip_integrity_failure_##decl("skiplist max level must be 1 at minimum\n"); \
|
||||||
n_err++; \
|
n_err++; \
|
||||||
if (flags) \
|
if (flags) \
|
||||||
return n_err; \
|
return n_err; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
if (slist->slh_height >= slist->slh_max_height) { \
|
if (slist->slh_height >= slist->slh_max_height) { \
|
||||||
/* level is 0-based, max of 12 means level cannot be > 11 */ \
|
/* level is 0-based, max of 12 means level cannot be > 11 */ \
|
||||||
__skip_integrity_failure_##decl("skiplist level %lu in header was >= max %lu\n", slist->slh_height, slist->slh_max_height); \
|
__skip_integrity_failure_##decl("skiplist level %lu in header was >= max %lu\n", slist->slh_height, slist->slh_max_height); \
|
||||||
n_err++; \
|
n_err++; \
|
||||||
if (flags) \
|
if (flags) \
|
||||||
return n_err; \
|
return n_err; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
if (SKIPLIST_MAX_HEIGHT < 1) { \
|
if (SKIPLIST_MAX_HEIGHT < 1) { \
|
||||||
__skip_integrity_failure_##decl("SKIPLIST_MAX_HEIGHT cannot be less than 1\n"); \
|
__skip_integrity_failure_##decl("SKIPLIST_MAX_HEIGHT cannot be less than 1\n"); \
|
||||||
n_err++; \
|
n_err++; \
|
||||||
if (flags) \
|
if (flags) \
|
||||||
return n_err; \
|
return n_err; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
if (SKIPLIST_MAX_HEIGHT > 1 && slist->slh_max_height > SKIPLIST_MAX_HEIGHT) { \
|
if (SKIPLIST_MAX_HEIGHT > 1 && slist->slh_max_height > SKIPLIST_MAX_HEIGHT) { \
|
||||||
__skip_integrity_failure_##decl("slist->slh_max_height %lu cannot be greater than SKIPLIST_MAX_HEIGHT %lu\n", slist->slh_max_height, \
|
__skip_integrity_failure_##decl("slist->slh_max_height %lu cannot be greater than SKIPLIST_MAX_HEIGHT %lu\n", slist->slh_max_height, \
|
||||||
(size_t)SKIPLIST_MAX_HEIGHT); \
|
(size_t)SKIPLIST_MAX_HEIGHT); \
|
||||||
n_err++; \
|
n_err++; \
|
||||||
if (flags) \
|
if (flags) \
|
||||||
return n_err; \
|
return n_err; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
node = slist->slh_head; \
|
node = slist->slh_head; \
|
||||||
__SKIP_ENTRIES_B2T(field, node) \
|
__SKIP_ENTRIES_B2T(field, node) \
|
||||||
{ \
|
{ \
|
||||||
if (node->field.sle_next[lvl] == NULL) { \
|
if (node->field.sle_next[lvl] == NULL) { \
|
||||||
__skip_integrity_failure_##decl("the head's %lu next node should not be NULL\n", lvl); \
|
__skip_integrity_failure_##decl("the head's %lu next node should not be NULL\n", lvl); \
|
||||||
n_err++; \
|
n_err++; \
|
||||||
if (flags) \
|
if (flags) \
|
||||||
return n_err; \
|
return n_err; \
|
||||||
} \
|
} \
|
||||||
n = lvl; \
|
n = lvl; \
|
||||||
if (node->field.sle_next[lvl] == slist->slh_tail) \
|
if (node->field.sle_next[lvl] == slist->slh_tail) \
|
||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
n++; \
|
n++; \
|
||||||
__SKIP_ENTRIES_B2T_FROM(field, node, n) \
|
__SKIP_ENTRIES_B2T_FROM(field, node, n) \
|
||||||
{ \
|
{ \
|
||||||
if (node->field.sle_next[lvl] == NULL) { \
|
if (node->field.sle_next[lvl] == NULL) { \
|
||||||
__skip_integrity_failure_##decl("the head's %lu next node should not be NULL\n", lvl); \
|
__skip_integrity_failure_##decl("the head's %lu next node should not be NULL\n", lvl); \
|
||||||
n_err++; \
|
n_err++; \
|
||||||
if (flags) \
|
if (flags) \
|
||||||
return n_err; \
|
return n_err; \
|
||||||
} \
|
} \
|
||||||
if (node->field.sle_next[lvl] != slist->slh_tail) { \
|
if (node->field.sle_next[lvl] != slist->slh_tail) { \
|
||||||
__skip_integrity_failure_##decl("after internal nodes, the head's %lu next node should always be the tail\n", lvl); \
|
__skip_integrity_failure_##decl("after internal nodes, the head's %lu next node should always be the tail\n", lvl); \
|
||||||
n_err++; \
|
n_err++; \
|
||||||
if (flags) \
|
if (flags) \
|
||||||
return n_err; \
|
return n_err; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
if (slist->slh_length > 0 && slist->slh_tail->field.sle_prev == slist->slh_head) { \
|
if (slist->slh_length > 0 && slist->slh_tail->field.sle_prev == slist->slh_head) { \
|
||||||
__skip_integrity_failure_##decl("slist->slh_length is 0, but tail->prev == head, not an internal node\n"); \
|
__skip_integrity_failure_##decl("slist->slh_length is 0, but tail->prev == head, not an internal node\n"); \
|
||||||
n_err++; \
|
n_err++; \
|
||||||
if (flags) \
|
if (flags) \
|
||||||
return n_err; \
|
return n_err; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/* Validate the head node */ \
|
/* Validate the head node */ \
|
||||||
\
|
\
|
||||||
/* Validate the tail node */ \
|
/* Validate the tail node */ \
|
||||||
\
|
\
|
||||||
/* Validate each node */ \
|
/* Validate each node */ \
|
||||||
SKIPLIST_FOREACH_H2T(decl, prefix, slist, node, nth) \
|
SKIPLIST_FOREACH_H2T(decl, prefix, slist, node, nth) \
|
||||||
{ \
|
{ \
|
||||||
this = &node->field; \
|
this = &node->field; \
|
||||||
\
|
\
|
||||||
if (this->sle_height >= slist->slh_max_height) { \
|
if (this->sle_height >= slist->slh_max_height) { \
|
||||||
__skip_integrity_failure_##decl("the %luth node's [%p] height %lu is >= max %lu\n", nth, (void *)node, this->sle_height, \
|
__skip_integrity_failure_##decl("the %lu node's [%p] height %lu is >= max %lu\n", nth, (void *)node, this->sle_height, slist->slh_max_height); \
|
||||||
slist->slh_max_height); \
|
n_err++; \
|
||||||
n_err++; \
|
if (flags) \
|
||||||
if (flags) \
|
return n_err; \
|
||||||
return n_err; \
|
} \
|
||||||
} \
|
\
|
||||||
\
|
if (this->sle_next == NULL) { \
|
||||||
if (this->sle_next == NULL) { \
|
__skip_integrity_failure_##decl("the %lu node's [%p] next field should never NULL\n", nth, (void *)node); \
|
||||||
__skip_integrity_failure_##decl("the %luth node's [%p] next field should never NULL\n", nth, (void *)node); \
|
n_err++; \
|
||||||
n_err++; \
|
if (flags) \
|
||||||
if (flags) \
|
return n_err; \
|
||||||
return n_err; \
|
} \
|
||||||
} \
|
\
|
||||||
\
|
if (this->sle_prev == NULL) { \
|
||||||
if (this->sle_prev == NULL) { \
|
__skip_integrity_failure_##decl("the %lu node [%p] prev field should never NULL\n", nth, (void *)node); \
|
||||||
__skip_integrity_failure_##decl("the %luth node [%p] prev field should never NULL\n", nth, (void *)node); \
|
n_err++; \
|
||||||
n_err++; \
|
if (flags) \
|
||||||
if (flags) \
|
return n_err; \
|
||||||
return n_err; \
|
} \
|
||||||
} \
|
\
|
||||||
\
|
__SKIP_ENTRIES_B2T(field, node) \
|
||||||
__SKIP_ENTRIES_B2T(field, node) \
|
{ \
|
||||||
{ \
|
if (this->sle_next[lvl] == NULL) { \
|
||||||
if (this->sle_next[lvl] == NULL) { \
|
__skip_integrity_failure_##decl("the %lu node's next[%lu] should not be NULL\n", nth, lvl); \
|
||||||
__skip_integrity_failure_##decl("the %luth node's next[%lu] should not be NULL\n", nth, lvl); \
|
n_err++; \
|
||||||
n_err++; \
|
if (flags) \
|
||||||
if (flags) \
|
return n_err; \
|
||||||
return n_err; \
|
} \
|
||||||
} \
|
n = lvl; \
|
||||||
n = lvl; \
|
if (this->sle_next[lvl] == slist->slh_tail) \
|
||||||
if (this->sle_next[lvl] == slist->slh_tail) \
|
break; \
|
||||||
break; \
|
} \
|
||||||
} \
|
n++; \
|
||||||
n++; \
|
__SKIP_ENTRIES_B2T_FROM(field, node, n) \
|
||||||
__SKIP_ENTRIES_B2T_FROM(field, node, n) \
|
{ \
|
||||||
{ \
|
if (this->sle_next[lvl] == NULL) { \
|
||||||
if (this->sle_next[lvl] == NULL) { \
|
__skip_integrity_failure_##decl("after the %lunth the %lu node's next[%lu] should not be NULL\n", n, nth, lvl); \
|
||||||
__skip_integrity_failure_##decl("after the %lunth the %luth node's next[%lu] should not be NULL\n", n, nth, lvl); \
|
n_err++; \
|
||||||
n_err++; \
|
if (flags) \
|
||||||
if (flags) \
|
return n_err; \
|
||||||
return n_err; \
|
} else if (this->sle_next[lvl] != slist->slh_tail) { \
|
||||||
} else if (this->sle_next[lvl] != slist->slh_tail) { \
|
__skip_integrity_failure_##decl("after the %lunth the %lu node's next[%lu] should point to the tail\n", n, nth, lvl); \
|
||||||
__skip_integrity_failure_##decl("after the %lunth the %luth node's next[%lu] should point to the tail\n", n, nth, lvl); \
|
n_err++; \
|
||||||
n_err++; \
|
if (flags) \
|
||||||
if (flags) \
|
return n_err; \
|
||||||
return n_err; \
|
} \
|
||||||
} \
|
} \
|
||||||
} \
|
\
|
||||||
\
|
decl##_node_t *a = (decl##_node_t *)(uintptr_t)this->sle_next; \
|
||||||
decl##_node_t *a = (decl##_node_t *)(uintptr_t)this->sle_next; \
|
decl##_node_t *b = (decl##_node_t *)(intptr_t)((uintptr_t)node + sizeof(decl##_node_t)); \
|
||||||
decl##_node_t *b = (decl##_node_t *)(intptr_t)((uintptr_t)node + sizeof(decl##_node_t)); \
|
if (a != b) { \
|
||||||
if (a != b) { \
|
__skip_integrity_failure_##decl("the %lu node's [%p] next field isn't at the proper offset relative to the node\n", nth, (void *)node); \
|
||||||
__skip_integrity_failure_##decl("the %luth node's [%p] next field isn't at the proper offset relative to the node\n", nth, (void *)node); \
|
n_err++; \
|
||||||
n_err++; \
|
if (flags) \
|
||||||
if (flags) \
|
return n_err; \
|
||||||
return n_err; \
|
} \
|
||||||
} \
|
\
|
||||||
\
|
next = this->sle_next[0]; \
|
||||||
next = this->sle_next[0]; \
|
prev = this->sle_prev; \
|
||||||
prev = this->sle_prev; \
|
if (__skip_compare_nodes_##decl(slist, node, node, slist->slh_aux) != 0) { \
|
||||||
if (__skip_compare_nodes_##decl(slist, node, node, slist->slh_aux) != 0) { \
|
__skip_integrity_failure_##decl("the %lu node [%p] is not equal to itself\n", nth, (void *)node); \
|
||||||
__skip_integrity_failure_##decl("the %luth node [%p] is not equal to itself\n", nth, (void *)node); \
|
n_err++; \
|
||||||
n_err++; \
|
if (flags) \
|
||||||
if (flags) \
|
return n_err; \
|
||||||
return n_err; \
|
} \
|
||||||
} \
|
\
|
||||||
\
|
if (__skip_compare_nodes_##decl(slist, node, prev, slist->slh_aux) < 0) { \
|
||||||
if (__skip_compare_nodes_##decl(slist, node, prev, slist->slh_aux) < 0) { \
|
__skip_integrity_failure_##decl("the %lu node [%p] is not greater than the prev node [%p]\n", nth, (void *)node, (void *)prev); \
|
||||||
__skip_integrity_failure_##decl("the %luth node [%p] is not greater than the prev node [%p]\n", nth, (void *)node, (void *)prev); \
|
n_err++; \
|
||||||
n_err++; \
|
if (flags) \
|
||||||
if (flags) \
|
return n_err; \
|
||||||
return n_err; \
|
} \
|
||||||
} \
|
\
|
||||||
\
|
if (__skip_compare_nodes_##decl(slist, node, next, slist->slh_aux) > 0) { \
|
||||||
if (__skip_compare_nodes_##decl(slist, node, next, slist->slh_aux) > 0) { \
|
__skip_integrity_failure_##decl("the %lu node [%p] is not less than the next node [%p]\n", nth, (void *)node, (void *)next); \
|
||||||
__skip_integrity_failure_##decl("the %luth node [%p] is not less than the next node [%p]\n", nth, (void *)node, (void *)next); \
|
n_err++; \
|
||||||
n_err++; \
|
if (flags) \
|
||||||
if (flags) \
|
return n_err; \
|
||||||
return n_err; \
|
} \
|
||||||
} \
|
\
|
||||||
\
|
if (__skip_compare_nodes_##decl(slist, prev, node, slist->slh_aux) > 0) { \
|
||||||
if (__skip_compare_nodes_##decl(slist, prev, node, slist->slh_aux) > 0) { \
|
__skip_integrity_failure_##decl("the prev node [%p] is not less than the %lu node [%p]\n", (void *)prev, nth, (void *)node); \
|
||||||
__skip_integrity_failure_##decl("the prev node [%p] is not less than the %luth node [%p]\n", (void *)prev, nth, (void *)node); \
|
n_err++; \
|
||||||
n_err++; \
|
if (flags) \
|
||||||
if (flags) \
|
return n_err; \
|
||||||
return n_err; \
|
} \
|
||||||
} \
|
\
|
||||||
\
|
if (__skip_compare_nodes_##decl(slist, next, node, slist->slh_aux) < 0) { \
|
||||||
if (__skip_compare_nodes_##decl(slist, next, node, slist->slh_aux) < 0) { \
|
__skip_integrity_failure_##decl("the next node [%p] is not greater than the %lu node [%p]\n", (void *)next, nth, (void *)node); \
|
||||||
__skip_integrity_failure_##decl("the next node [%p] is not greater than the %luth node [%p]\n", (void *)next, nth, (void *)node); \
|
n_err++; \
|
||||||
n_err++; \
|
if (flags) \
|
||||||
if (flags) \
|
return n_err; \
|
||||||
return n_err; \
|
} \
|
||||||
} \
|
} \
|
||||||
} \
|
\
|
||||||
\
|
if (slist->slh_length != nth) { \
|
||||||
if (slist->slh_length != nth) { \
|
__skip_integrity_failure_##decl("slist->slh_length (%lu) doesn't match the count (%lu) of nodes between the head and tail\n", slist->slh_length, \
|
||||||
__skip_integrity_failure_##decl("slist->slh_length (%lu) doesn't match the count (%lu) of nodes between the head and tail\n", slist->slh_length, \
|
nth); \
|
||||||
nth); \
|
n_err++; \
|
||||||
n_err++; \
|
if (flags) \
|
||||||
if (flags) \
|
return n_err; \
|
||||||
return n_err; \
|
} \
|
||||||
} \
|
\
|
||||||
\
|
return 0; \
|
||||||
return 0; \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SKIPLIST_DECL_ACCESS(decl, prefix, key, ktype, value, vtype, qblk, rblk) \
|
#define SKIPLIST_DECL_ACCESS(decl, prefix, key, ktype, value, vtype, qblk, rblk) \
|
||||||
|
|
Loading…
Reference in a new issue