From ded941b5eed5a33beed184e895a388d054fefa7a Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Sun, 26 May 2024 21:37:16 -0400 Subject: [PATCH] WIP --- examples/ex1.c | 304 +++++++++++++++++-------------------------------- examples/ex2.c | 28 ++--- include/sl.h | 62 +++++----- 3 files changed, 148 insertions(+), 246 deletions(-) diff --git a/examples/ex1.c b/examples/ex1.c index b357b27..ce8435d 100644 --- a/examples/ex1.c +++ b/examples/ex1.c @@ -5,12 +5,6 @@ // --------------------------------------------------------------------------- #define DEBUG #define SKIPLIST_DIAGNOSTIC -/* Setting SKIPLIST_MAX_HEIGHT will do two things: - * 1) limit our max height across all instances of this data structure. - * 2) remove a heap allocation on frequently used paths, insert/remove/etc. - * so, use it when you need it. - */ -#define SKIPLIST_MAX_HEIGHT 12 // Include our monolithic ADT, the Skiplist! // --------------------------------------------------------------------------- @@ -20,8 +14,8 @@ // --------------------------------------------------------------------------- #define TEST_ARRAY_SIZE 10 #define VALIDATE -//define SNAPSHOTS -//define TODO_RESTORE_SNAPSHOTS +// define SNAPSHOTS +// define TODO_RESTORE_SNAPSHOTS #define STABLE_SEED #define DOT @@ -181,7 +175,7 @@ SKIPLIST_DECL_VALIDATE(ex, api_, entries) */ SKIPLIST_DECL_DOT(ex, api_, entries) -void +static void sprintf_ex_node(ex_node_t *node, char *buf) { sprintf(buf, "%d:%s", node->key, node->value); @@ -189,51 +183,8 @@ sprintf_ex_node(ex_node_t *node, char *buf) // Function for this demo application. // --------------------------------------------------------------------------- -int __xorshift32_state = 0; - -// Xorshift algorithm for PRNG -uint32_t -xorshift32() -{ - uint32_t x = __xorshift32_state; - if (x == 0) - x = 123456789; - x ^= x << 13; - x ^= x >> 17; - x ^= x << 5; - __xorshift32_state = x; - return x; -} - -void -xorshift32_seed() -{ - // Seed the PRNG -#ifdef STABLE_SEED - __xorshift32_state = 8675309; -#else - __xorshift32_state = (unsigned int)time(NULL) ^ getpid(); -#endif -} - -static char * -to_lower(char *str) -{ - char *p = str; - for (; *p; ++p) - *p = (char)(*p >= 'A' && *p <= 'Z' ? *p | 0x60 : *p); - return str; -} - -static char * -to_upper(char *str) -{ - char *p = str; - for (; *p; ++p) - *p = (char)(*p >= 'a' && *p <= 'z' ? *p & ~0x20 : *p); - return str; -} +/* convert a number into the Roman numeral equivalent, allocates a string caller must free */ static char * int_to_roman_numeral(int num) { @@ -266,18 +217,11 @@ int_to_roman_numeral(int num) return res; } -void -shuffle(int *array, size_t n) +/* calculate the floor of the log base 2 of a number m (⌊log2(m)⌋) */ +static int +floor_log2(unsigned int m) { - if (n > 1) { - size_t i; - for (i = n - 1; i > 0; i--) { - size_t j = (unsigned int)(xorshift32() % (i + 1)); /* NOLINT(*-msc50-cpp) */ - int t = array[j]; - array[j] = array[i]; - array[i] = t; - } - } + return (int)floor(log(m) / log(2)); } #ifdef TODO_RESTORE_SNAPSHOTS @@ -289,17 +233,25 @@ typedef struct { #endif // --------------------------------------------------------------------------- + +/* The head node's height is always 1 more than the tallest node, that location + is where we store the total hits, or "m". */ +#define splay_list_m(m) list->slh_head->entries.sle_levels[list->slh_head->entries.sle_height].hits + int main() { int rc; + char *numeral; +#ifdef DOT + char msg[1024]; + memset(msg, 0, 1024); +#endif #ifdef TODO_RESTORE_SNAPSHOTS size_t n_snaps = 0; snap_info_t snaps[TEST_ARRAY_SIZE * 2 + 1]; #endif - xorshift32_seed(); - #ifdef DOT of = fopen("/tmp/ex1.dot", "w"); if (!of) { @@ -314,162 +266,114 @@ main() return ENOMEM; rc = api_skip_init_ex(list); - list->slh_prng_state = 12; if (rc) return rc; + + /* Set the PRNG state to a known constant for reproducible generation, easing debugging. */ + list->slh_prng_state = 12; +#ifdef SNAPSHOTS api_skip_snapshots_init_ex(list); +#endif #ifdef DOT api_skip_dot_ex(of, list, gen++, "init", sprintf_ex_node); #endif - if (api_skip_get_ex(list, 0) != NULL) - perror("found a non-existent item!"); - api_skip_del_ex(list, 0); - CHECK; - /* Insert TEST_ARRAY_SIZE key/value pairs into the list. */ - int i, j; - char *numeral; -#ifdef DOT - char msg[1024]; - memset(msg, 0, 1024); -#endif - int amt = TEST_ARRAY_SIZE, asz = (amt * 2) + 1; - int array[(TEST_ARRAY_SIZE * 2) + 1]; - for (j = 0, i = -amt; i <= amt; i++, j++) - array[j] = i; - shuffle(array, asz); + /* This example mirrors the example given in the paper about splay-lists + to test implementation against research. */ - for (i = 0; i < asz; i++) { -#ifdef SNAPSHOTS - api_skip_snapshot_ex(list); -#elif defined(TODO_RESTORE_SNAPSHOTS) - /* Snapshot the first iteration, and then every 5th after that. */ - if (i % 5 == 0) { - snaps[i].length = api_skip_length_ex(list); - snaps[i].key = array[i]; - snaps[i].snap_id = api_skip_snapshot_ex(list); - n_snaps++; - CHECK; - } -#endif - numeral = to_lower(int_to_roman_numeral(array[i])); - rc = api_skip_put_ex(list, array[i], numeral); - CHECK; + for (int i = 1; i < 8; i++) { + numeral = int_to_roman_numeral(i); + if ((rc = api_skip_put_ex(list, i, numeral))) + perror("put failed"); #ifdef DOT sprintf(msg, "put key: %d value: %s", i, numeral); api_skip_dot_ex(of, list, gen++, msg, sprintf_ex_node); #endif - char *v = api_skip_get_ex(list, array[i]); - CHECK; - char *upper_numeral = calloc(1, strlen(v) + 1); - strncpy(upper_numeral, v, strlen(v)); - assert(strncmp(v, upper_numeral, strlen(upper_numeral)) == 0); - to_upper(upper_numeral); - api_skip_set_ex(list, array[i], upper_numeral); - CHECK; } - numeral = int_to_roman_numeral(-1); - api_skip_dup_ex(list, -1, numeral); CHECK; -#ifdef DOT - sprintf(msg, "put dup key: %d value: %s", i, numeral); - api_skip_dot_ex(of, list, gen++, msg, sprintf_ex_node); -#endif - numeral = int_to_roman_numeral(1); - api_skip_dup_ex(list, 1, numeral); - CHECK; -#ifdef DOT - sprintf(msg, "put dup key: %d value: %s", i, numeral); - api_skip_dot_ex(of, list, gen++, msg, sprintf_ex_node); -#endif - api_skip_del_ex(list, 0); - CHECK; - if (api_skip_get_ex(list, 0) != NULL) - perror("found a deleted item!"); - api_skip_del_ex(list, 0); - CHECK; - if (api_skip_get_ex(list, 0) != NULL) - perror("found a deleted item!"); - int key = TEST_ARRAY_SIZE + 1; - api_skip_del_ex(list, key); - CHECK; - key = -(TEST_ARRAY_SIZE)-1; - api_skip_del_ex(list, key); + /* Now we're going to poke around the internals a bit to set things up. + This first time around we're going to build the list by hand, later + we'll ensure that we can build this shape using only API calls. */ + + ex_node_t *head = list->slh_head; + ex_node_t *tail = list->slh_tail; + ex_node_t *node_1 = head->entries.sle_levels[0].next; + ex_node_t *node_2 = node_1->entries.sle_levels[0].next; + ex_node_t *node_3 = node_2->entries.sle_levels[0].next; + ex_node_t *node_4 = node_3->entries.sle_levels[0].next; + ex_node_t *node_5 = node_4->entries.sle_levels[0].next; + ex_node_t *node_6 = node_5->entries.sle_levels[0].next; + + // Head/Tail-nodes are height 3, ... + head->entries.sle_height = tail->entries.sle_height = 3; + + // Head-node + head->entries.sle_levels[3].hits = 10; + head->entries.sle_levels[2].hits = 5; + head->entries.sle_levels[1].hits = 1; + head->entries.sle_levels[0].hits = 1; + head->entries.sle_levels[1].next = node_2; + head->entries.sle_levels[2].next = node_6; + head->entries.sle_levels[3].next = tail; + + // Tail-node + tail->entries.sle_levels[3].hits = 0; + tail->entries.sle_levels[2].hits = 0; + tail->entries.sle_levels[1].hits = 0; + tail->entries.sle_levels[0].hits = 1; + tail->entries.sle_levels[1].next = tail; + tail->entries.sle_levels[2].next = tail; + tail->entries.sle_levels[3].next = tail; + + // First node has key "1", height "0", hits(0) = 1 + node_1->entries.sle_height = 0; + node_1->entries.sle_levels[0].hits = 1; + + // Second node has key "2", height "1", hits(0) = 1, hits(1) = 0 + node_2->entries.sle_height = 1; + node_2->entries.sle_levels[0].hits = 1; + node_2->entries.sle_levels[1].hits = 0; + node_2->entries.sle_levels[1].next = node_3; + + // Third node has key "3", height "1", hits(0) = 1, hits(1) = 2 + node_3->entries.sle_height = 1; + node_3->entries.sle_levels[0].hits = 1; + node_3->entries.sle_levels[1].hits = 2; + node_3->entries.sle_levels[1].next = node_6; + + // Fourth node has key "4", height "0", hits(0) = 1 + node_4->entries.sle_height = 0; + node_4->entries.sle_levels[0].hits = 1; + + // Fifth node has key "5", height "0", hits(0) = 1 + node_5->entries.sle_height = 0; + node_5->entries.sle_levels[0].hits = 1; + + // Sixth node has key "6", height "2", hits(0) = 5, hits(1) = 0, hits(2) = 0 + node_6->entries.sle_height = 2; + node_6->entries.sle_levels[0].hits = 5; + node_6->entries.sle_levels[1].hits = 0; + node_6->entries.sle_levels[2].hits = 0; + node_6->entries.sle_levels[1].next = tail; + node_6->entries.sle_levels[2].next = tail; + CHECK; #ifdef DOT - sprintf(msg, "deleted key: %d, value: %s", 0, numeral); + sprintf(msg, "manually adjusted"); api_skip_dot_ex(of, list, gen++, msg, sprintf_ex_node); #endif - numeral = int_to_roman_numeral(-(TEST_ARRAY_SIZE)); - assert(strcmp(api_skip_pos_ex(list, SKIP_GTE, -(TEST_ARRAY_SIZE)-1)->value, numeral) == 0); - free(numeral); - numeral = int_to_roman_numeral(-2); - assert(strcmp(api_skip_pos_ex(list, SKIP_GTE, -2)->value, numeral) == 0); - free(numeral); - numeral = int_to_roman_numeral(1); - assert(strcmp(api_skip_pos_ex(list, SKIP_GTE, 0)->value, numeral) == 0); - free(numeral); - numeral = int_to_roman_numeral(2); - assert(strcmp(api_skip_pos_ex(list, SKIP_GTE, 2)->value, numeral) == 0); - free(numeral); - assert(api_skip_pos_ex(list, SKIP_GTE, (TEST_ARRAY_SIZE + 1)) == NULL); + printf("m = %ld\n", splay_list_m(list)); + printf("(⌊log2(m)⌋) = %d\n", floor_log2(splay_list_m(list))); - numeral = int_to_roman_numeral(-(TEST_ARRAY_SIZE)); - assert(strcmp(api_skip_pos_ex(list, SKIP_GT, -(TEST_ARRAY_SIZE)-1)->value, numeral) == 0); - free(numeral); - numeral = int_to_roman_numeral(-1); - assert(strcmp(api_skip_pos_ex(list, SKIP_GT, -2)->value, numeral) == 0); - free(numeral); - numeral = int_to_roman_numeral(1); - assert(strcmp(api_skip_pos_ex(list, SKIP_GT, 0)->value, numeral) == 0); - free(numeral); - numeral = int_to_roman_numeral(2); - assert(strcmp(api_skip_pos_ex(list, SKIP_GT, 1)->value, numeral) == 0); - free(numeral); - assert(api_skip_pos_ex(list, SKIP_GT, TEST_ARRAY_SIZE) == NULL); - - assert(api_skip_pos_ex(list, SKIP_LT, -(TEST_ARRAY_SIZE)) == NULL); - numeral = int_to_roman_numeral(-2); - assert(strcmp(api_skip_pos_ex(list, SKIP_LT, -1)->value, numeral) == 0); - free(numeral); - numeral = int_to_roman_numeral(-1); - assert(strcmp(api_skip_pos_ex(list, SKIP_LT, 0)->value, numeral) == 0); - free(numeral); - numeral = int_to_roman_numeral(1); - assert(strcmp(api_skip_pos_ex(list, SKIP_LT, 2)->value, numeral) == 0); - free(numeral); - numeral = int_to_roman_numeral(TEST_ARRAY_SIZE); - assert(strcmp(api_skip_pos_ex(list, SKIP_LT, (TEST_ARRAY_SIZE + 1))->value, numeral) == 0); - free(numeral); - - assert(api_skip_pos_ex(list, SKIP_LTE, -(TEST_ARRAY_SIZE)-1) == NULL); - numeral = int_to_roman_numeral(-2); - assert(strcmp(api_skip_pos_ex(list, SKIP_LTE, -2)->value, numeral) == 0); - free(numeral); - numeral = int_to_roman_numeral(-1); - assert(strcmp(api_skip_pos_ex(list, SKIP_LTE, 0)->value, numeral) == 0); - free(numeral); - numeral = int_to_roman_numeral(2); - assert(strcmp(api_skip_pos_ex(list, SKIP_LTE, 2)->value, numeral) == 0); - free(numeral); - numeral = int_to_roman_numeral(TEST_ARRAY_SIZE); - assert(strcmp(api_skip_pos_ex(list, SKIP_LTE, (TEST_ARRAY_SIZE + 1))->value, numeral) == 0); - free(numeral); - -#ifdef TODO_RESTORE_SNAPSHOTS - // Walk backward by 2 and test snapshot restore. - for (i = n_snaps; i > 0; i -= 2) { - api_skip_restore_snapshot_ex(list, snaps[i].snap_id); - CHECK; - assert(api_skip_length_ex(list) == snaps[i].length); - numeral = int_to_roman_numeral(snaps[i].key); - assert(strncmp(api_skip_get_ex(list, snaps[i].key), numeral, strlen(numeral)) == 0); - free(numeral); - } - api_skip_release_snapshots_ex(list); + if (!(rc = api_skip_contains_ex(list, 5))) + perror("missing element 5"); + CHECK; +#ifdef DOT + sprintf(msg, "contains(5)"); + api_skip_dot_ex(of, list, gen++, msg, sprintf_ex_node); #endif #ifdef DOT diff --git a/examples/ex2.c b/examples/ex2.c index b357b27..fb24c4b 100644 --- a/examples/ex2.c +++ b/examples/ex2.c @@ -5,12 +5,6 @@ // --------------------------------------------------------------------------- #define DEBUG #define SKIPLIST_DIAGNOSTIC -/* Setting SKIPLIST_MAX_HEIGHT will do two things: - * 1) limit our max height across all instances of this data structure. - * 2) remove a heap allocation on frequently used paths, insert/remove/etc. - * so, use it when you need it. - */ -#define SKIPLIST_MAX_HEIGHT 12 // Include our monolithic ADT, the Skiplist! // --------------------------------------------------------------------------- @@ -181,7 +175,7 @@ SKIPLIST_DECL_VALIDATE(ex, api_, entries) */ SKIPLIST_DECL_DOT(ex, api_, entries) -void +static void sprintf_ex_node(ex_node_t *node, char *buf) { sprintf(buf, "%d:%s", node->key, node->value); @@ -192,7 +186,7 @@ sprintf_ex_node(ex_node_t *node, char *buf) int __xorshift32_state = 0; // Xorshift algorithm for PRNG -uint32_t +static uint32_t xorshift32() { uint32_t x = __xorshift32_state; @@ -205,7 +199,7 @@ xorshift32() return x; } -void +static void xorshift32_seed() { // Seed the PRNG @@ -216,6 +210,7 @@ xorshift32_seed() #endif } +/* convert upper case characters to lower case */ static char * to_lower(char *str) { @@ -225,6 +220,7 @@ to_lower(char *str) return str; } +/* convert lower case characters to upper case */ static char * to_upper(char *str) { @@ -234,6 +230,7 @@ to_upper(char *str) return str; } +/* convert a number into the Roman numeral equivalent, allocates a string caller must free */ static char * int_to_roman_numeral(int num) { @@ -266,7 +263,8 @@ int_to_roman_numeral(int num) return res; } -void +/* shuffle an array of length n */ +static void shuffle(int *array, size_t n) { if (n > 1) { @@ -301,9 +299,9 @@ main() xorshift32_seed(); #ifdef DOT - of = fopen("/tmp/ex1.dot", "w"); + of = fopen("/tmp/ex2.dot", "w"); if (!of) { - perror("Failed to open file /tmp/ex1.dot"); + perror("Failed to open file /tmp/ex2.dot"); return 1; } #endif @@ -314,10 +312,14 @@ main() return ENOMEM; rc = api_skip_init_ex(list); - list->slh_prng_state = 12; if (rc) return rc; + + /* Set the PRNG state to a known constant for reproducible generation, easing debugging. */ + list->slh_prng_state = 12; +#ifdef SNAPSHOTS api_skip_snapshots_init_ex(list); +#endif #ifdef DOT api_skip_dot_ex(of, list, gen++, "init", sprintf_ex_node); #endif diff --git a/include/sl.h b/include/sl.h index ada9558..8fdd752 100644 --- a/include/sl.h +++ b/include/sl.h @@ -205,10 +205,10 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li #endif /* - * Every Skiplist node has to hvae an additional section of data used to manage + * Every Skiplist node has to have an additional section of data used to manage * nodes in the list. The rest of the datastructure is defined by the use case. * This housekeeping portion is the SKIPLIST_ENTRY, see below. It maintains the - * array of forward pointers to nodes and has a height, this height is a a + * array of forward pointers to nodes and has a height, this height is a * zero-based count of levels, so a height of `0` means one (1) level and a * height of `4` means five (5) forward pointers (levels) in the node, [0-4). */ @@ -241,11 +241,14 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li #define __SKIP_ENTRIES_B2T_FROM(field, elm, off) for (size_t lvl = off; lvl <= elm->field.sle_height; lvl++) #define __SKIP_IS_LAST_ENTRY_B2T() if (lvl + 1 == elm->field.sle_height) -/* Iterate over the subtree to the left (v, or 'lt') and right (u, or 'gt') or "CHu" and "CHv". */ +/* Iterate over the left (v) subtree or right (u) subtree or "CHu" and "CHv". */ #define __SKIP_SUBTREE_CHv(decl, field, list, path, nth) \ for (decl##_node_t *elm = path[nth].node; elm->field.sle_levels[path[nth].in].next == path[nth].node; elm = elm->field.sle_prev) #define __SKIP_SUBTREE_CHu(decl, field, list, path, nth) \ for (decl##_node_t *elm = path[nth].node; elm != path[nth].node->field.sle_levels[0].next; elm = elm->field.sle_levels[0].next) +#define __SKIP_SUBTREE_CHhx(decl, field, list, path, nth) \ + for (decl##_node_t *elm = path[nth].node->field.sle_levels[path[nth].in].next->field.sle_prev; elm != path[nth].node->field.sle_prev; \ + elm = elm->field.sle_prev) /* * Skiplist declarations and access methods. @@ -639,8 +642,8 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li /* Total hits, `k`, across all nodes. */ \ m_total_hits = slist->slh_head->field.sle_levels[slist->slh_head->field.sle_height].hits; \ \ - /* Height of the head node, should be close to floor(log(m_total_hits)). */ \ - k_threshold = slist->slh_head->field.sle_height + 1; \ + /* Height of the head node, should be equal to floor(log(m_total_hits)). */ \ + k_threshold = slist->slh_head->field.sle_height; \ \ /* Moving backwards along the path... \ * - path[0] contains a match, if there was one \ @@ -648,17 +651,19 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li * - path[len] is where the locate() terminated, just before path[0] \ * if there was a match \ */ \ - for (i = 1; i <= len; i++) { \ + i = 0; \ + do { \ + hits_CHu = hits_CHv = 0; \ if (path[i].node == slist->slh_head || path[i].node == slist->slh_tail) \ continue; \ \ - __SKIP_SUBTREE_CHu(decl, field, slist, path, i) \ + __SKIP_SUBTREE_CHhx(decl, field, slist, path, i) \ { \ - hits_CHu += elm->field.sle_levels[i].hits; \ + hits_CHu += elm->field.sle_levels[0].hits; \ } \ - __SKIP_SUBTREE_CHv(decl, field, slist, path, i) \ + __SKIP_SUBTREE_CHhx(decl, field, slist, path, i + 1) \ { \ - hits_CHv += elm->field.sle_levels[i].hits; \ + hits_CHv += elm->field.sle_levels[0].hits; \ } \ u_hits = hits_CHu + hits_CHv; \ \ @@ -710,7 +715,7 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li if (path[i - 1].in != 0) \ path[i - 1].node->field.sle_levels[path[i - 1].in].next->field.sle_levels[path[i - 1].in].next = path[i].node; \ } \ - } \ + } while (i++ < len); \ } \ \ /** \ @@ -743,7 +748,8 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li path[i + 1].pu += elm->field.sle_levels[path[i + 1].in].hits; \ } \ path[i + 1].node = elm; \ - path[i + 1].node->field.sle_levels[path[i + 1].in].hits++; \ + if (path[i + 1].in > 0) \ + path[i + 1].node->field.sle_levels[path[i + 1].in].hits++; \ len++; \ } while (i--); \ elm = elm->field.sle_levels[0].next; \ @@ -776,16 +782,6 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li \ memset(path, 0, sizeof(__skiplist_path_##decl##_t) * SKIPLIST_MAX_HEIGHT + 1); \ \ - /* First element in path should be NULL, rest should start pointing at tail. */ \ - path[0].node = NULL; \ - path[0].in = 0; \ - path[0].pu = 0; \ - for (i = 1; i < slist->slh_head->entries.sle_height + 1; i++) { \ - path[i].node = slist->slh_tail; \ - path[i].in = 0; \ - path[i].pu = 0; \ - } \ - \ /* Find a `path` to `new` in the list and a match (`path[0]`) if it exists. */ \ len = __skip_locate_##decl(slist, new, path); \ node = path[0].node; \ @@ -1074,7 +1070,7 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li if (np > 0) \ return np; \ \ - /* Increase the the list's era/age. */ \ + /* Increase the list's era/age. */ \ slist->slh_snap.cur_era++; \ } \ \ @@ -1116,7 +1112,7 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li if (np > 0) \ return np; \ \ - /* Increase the the list's era/age. */ \ + /* Increase the list's era/age. */ \ slist->slh_snap.cur_era++; \ } \ /* We found it, set the next->prev to the node->prev keeping in mind \ @@ -1129,8 +1125,8 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li break; \ /* ... adjust the next pointer at that level. */ \ path[i + 1].node->field.sle_levels[i].next = node->field.sle_levels[i].next; \ - /* Adjust the height so we're only pointing at the tail once at \ - the top so we don't waste steps later when searching. */ \ + /* Adjust the height such that we're only pointing at the tail once at \ + the top that way we don't waste steps later when searching. */ \ if (path[i + 1].node->field.sle_levels[i].next == slist->slh_tail) { \ height = path[i + 1].node->field.sle_height; \ path[i + 1].node->field.sle_height = height - 1; \ @@ -1843,7 +1839,6 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li static void __skip_dot_node_##decl(FILE *os, decl##_t *slist, decl##_node_t *node, size_t nsg, skip_sprintf_node_##decl##_t fn) \ { \ char buf[2048]; \ - size_t width; \ decl##_node_t *next; \ \ __skip_dot_write_node_##decl(os, nsg, node); \ @@ -1852,8 +1847,9 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li __SKIP_ENTRIES_T2B(field, node) \ { \ next = (node->field.sle_levels[lvl].next == slist->slh_tail) ? NULL : node->field.sle_levels[lvl].next; \ - width = __skip_dot_width_##decl(slist, node, next ? next : slist->slh_tail); \ - fprintf(os, " { %lu | ", lvl, width, lvl); \ + (void)__skip_dot_width_##decl; \ + /* size_t width = __skip_dot_width_##decl(slist, node, next ? next : slist->slh_tail); */ \ + fprintf(os, " { %lu | ", lvl, node->field.sle_levels[lvl].hits, lvl); \ if (next) \ fprintf(os, "%p } |", (void *)next); \ else \ @@ -1862,7 +1858,7 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li } \ if (fn) { \ fn(node, buf); \ - fprintf(os, " \u219F %lu \u226B %s \"\n", node->field.sle_height + 1, buf); \ + fprintf(os, " \u219F %lu \u226B %s \"\n", node->field.sle_height, buf); \ } else { \ fprintf(os, " \u219F %lu \"\n", node->field.sle_height); \ } \ @@ -1927,7 +1923,7 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li int prefix##skip_dot_##decl(FILE *os, decl##_t *slist, size_t nsg, char *msg, skip_sprintf_node_##decl##_t fn) \ { \ int letitgo = 0; \ - size_t width, i; \ + size_t i; \ decl##_node_t *node, *next; \ \ if (slist == NULL || fn == NULL) \ @@ -1961,8 +1957,8 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li __SKIP_ENTRIES_T2B(field, node) \ { \ next = (node->field.sle_levels[lvl].next == slist->slh_tail) ? NULL : node->field.sle_levels[lvl].next; \ - width = __skip_dot_width_##decl(slist, node, next ? next : slist->slh_tail); \ - fprintf(os, "{ %lu | ", width, lvl); \ + /* size_t width = __skip_dot_width_##decl(slist, node, next ? next : slist->slh_tail); */ \ + fprintf(os, "{ %lu | ", node->field.sle_levels[lvl].hits, lvl); \ if (next) \ fprintf(os, "%p }", (void *)next); \ else \