splay v1/p5; rebalence desc cond

This commit is contained in:
Gregory Burd 2024-04-01 14:26:44 -04:00
parent 8703fbb5a9
commit 64c68c2283
3 changed files with 376 additions and 343 deletions

View file

@ -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

View file

@ -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;

View file

@ -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,37 +598,60 @@ 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 ... \
* 2) propagate path[i].level[i] hits backward along path, and ... \
* 3) adjust any forward pointers along the way, then. \
* 4) lower the path[i]'s node height by 1 \
*/ \ */ \
dsc_cond = pow(2.0, slist->slh_head->field.sle_height - path[i].node->field.sle_height); \ dsc_cond = pow(2.0, slist->slh_head->field.sle_height - path[i].node->field.sle_height); \
if (par_sum <= dsc_cond) { \ if (path[i].par_hit_sum <= dsc_cond) { \
/* reduce height by one, change forward pointer */ \ if (path[i - 1].node->field.sle_prev != slist->slh_head) { \
path[i - 1].node->field.sle_next[i] = path[i].node->field.sle_next[i]; \ /* 1) go backwards along path from where we are until head */ \
path[i].node->field.sle_next[i] = slist->slh_tail; \ 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); \ 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) { \ if (path[i].node->field.sle_hits > asc_cond) { \
((void)0); \ ((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++; \
\ \
@ -1648,22 +1676,21 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
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 %luth node's [%p] next field should never NULL\n", nth, (void *)node); \ __skip_integrity_failure_##decl("the %lu 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 %luth node [%p] prev field should never NULL\n", nth, (void *)node); \ __skip_integrity_failure_##decl("the %lu 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; \
@ -1672,7 +1699,7 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
__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 %luth node's next[%lu] should not be NULL\n", nth, lvl); \ __skip_integrity_failure_##decl("the %lu 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; \
@ -1685,12 +1712,12 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
__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 %luth node's next[%lu] should not be NULL\n", n, nth, lvl); \ __skip_integrity_failure_##decl("after the %lunth the %lu 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 %luth node's next[%lu] should point to the tail\n", n, nth, lvl); \ __skip_integrity_failure_##decl("after the %lunth the %lu 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; \
@ -1700,7 +1727,7 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
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 %luth node's [%p] next field isn't at the proper offset relative to the node\n", nth, (void *)node); \ __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); \
n_err++; \ n_err++; \
if (flags) \ if (flags) \
return n_err; \ return n_err; \
@ -1709,35 +1736,35 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
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 %luth node [%p] is not equal to itself\n", nth, (void *)node); \ __skip_integrity_failure_##decl("the %lu 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 %luth node [%p] is not greater than the prev node [%p]\n", nth, (void *)node, (void *)prev); \ __skip_integrity_failure_##decl("the %lu 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 %luth node [%p] is not less than the next node [%p]\n", nth, (void *)node, (void *)next); \ __skip_integrity_failure_##decl("the %lu 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 %luth node [%p]\n", (void *)prev, nth, (void *)node); \ __skip_integrity_failure_##decl("the prev node [%p] is not less than the %lu 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 %luth node [%p]\n", (void *)next, nth, (void *)node); \ __skip_integrity_failure_##decl("the next node [%p] is not greater than the %lu node [%p]\n", (void *)next, nth, (void *)node); \
n_err++; \ n_err++; \
if (flags) \ if (flags) \
return n_err; \ return n_err; \