From 1048d0df59812564faa9f8f9a5ab6a183ac800e6 Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Mon, 1 Apr 2024 17:14:04 -0400 Subject: [PATCH] splay v1/p5; rebalence asc cond; WIP --- examples/slm.c | 18 ++++++++--- include/sl.h | 87 ++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 80 insertions(+), 25 deletions(-) diff --git a/examples/slm.c b/examples/slm.c index c888310..3846f5e 100644 --- a/examples/slm.c +++ b/examples/slm.c @@ -16,10 +16,19 @@ // Local demo application OPTIONS: // --------------------------------------------------------------------------- +#define TEST_ARRAY_SIZE 10 #define VALIDATE #define SNAPSHOTS #define DOT -#define TEST_ARRAY_SIZE 50 +#ifdef DOT +size_t gen = 0; +FILE *of = 0; +typedef struct esempio esempio_t; +typedef struct esempio_node esempio_node_t; +static int __skip_integrity_check_esempio(esempio_t *slist, int flags); +int api_skip_dot_esempio(FILE *os, esempio_t *slist, size_t nsg, char *msg, void (*fn)(struct esempio_node *, char *)); +void sprintf_esempio_node(esempio_node_t *node, char *buf); +#endif // --------------------------------------------------------------------------- #ifdef VALIDATE @@ -171,8 +180,8 @@ SKIPLIST_DECL_DOT(esempio, api_, entries) void 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", node->key, node->value); + sprintf(buf, "%d:%s (hits: %lu)", node->key, node->value, node->entries.sle_hits); +//TODO sprintf(buf, "%d:%s", node->key, node->value); } // Function for this demo application. @@ -248,8 +257,7 @@ main() #endif #ifdef DOT - size_t gen = 0; - FILE *of = fopen("/tmp/slm.dot", "w"); + of = fopen("/tmp/slm.dot", "w"); if (!of) { perror("Failed to open file /tmp/slm.dot"); return 1; diff --git a/include/sl.h b/include/sl.h index d5dcc78..f96c3f3 100644 --- a/include/sl.h +++ b/include/sl.h @@ -264,7 +264,7 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li void (*snapshot_record_era)(decl##_t *, decl##_node_t *); \ } slh_fns; \ struct { \ - size_t threshold; /* `k`, the floor of log(max height) */ \ + size_t k; /* threshold, the floor of log(max height) */ \ size_t total_hits; /* total hits across nodes in the list */ \ } slh_splay; \ struct { \ @@ -420,7 +420,7 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li slist->slh_max_height = SKIPLIST_MAX_HEIGHT == 1 ? slist->slh_max_height : SKIPLIST_MAX_HEIGHT; \ if (SKIPLIST_MAX_HEIGHT > 1 && slist->slh_max_height > SKIPLIST_MAX_HEIGHT) \ return -1; \ - slist->slh_splay.threshold = floor(log(max) / M_LOG2E); \ + slist->slh_splay.k = floor(log(0) / M_LOG2E); \ slist->slh_fns.free_entry = __skip_free_entry_fn_##decl; \ slist->slh_fns.update_entry = __skip_update_entry_fn_##decl; \ slist->slh_fns.archive_entry = __skip_archive_entry_fn_##decl; \ @@ -598,7 +598,20 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li } \ \ /** \ - * -- __skip_rebalence_ TODO/WIP \ + * -- __skip_adjust_hit_counts_ TODO \ + * \ + * On delete we check the hit counts across all nodes and next[] pointers \ + * and find the smallest counter then subtract that + 1 from all hit \ + * counters. \ + * \ + */ \ + static void __skip_adjust_hit_counts_##decl(decl##_t *slist) \ + { \ + ((void)slist); \ + } \ + \ + /** \ + * -- __skip_rebalence_ \ * \ * Restore balance to our list by adjusting heights and forward pointers \ * according to the algorithm put forth in "The Splay-List: A \ @@ -607,16 +620,18 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li */ \ static void __skip_rebalence_##decl(decl##_t *slist, size_t len, __skiplist_path_##decl##_t path[]) \ { \ - size_t i, j, cur_hits, prev_hits; \ + size_t i, j, cur_hits, prev_hits, hits, new_height, delta_height; \ double asc_cond, dsc_cond; \ + decl##_node_t *node; \ \ + return; \ /* 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 = 2; i < len; i++) { \ /* (a) Check the decent condition: \ * path[i].par_hit_sum <= hits total / (2 ^ (height of head - height of node)) \ * When met should induce: \ @@ -625,8 +640,9 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li * 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); \ - if (path[i].par_hit_sum <= dsc_cond) { \ + delta_height = slist->slh_head->field.sle_height - path[i].node->field.sle_height; \ + dsc_cond = pow(2.0, delta_height); \ + if (path[i].par_hit_sum <= dsc_cond && path[i].node->field.sle_height > 0) { \ if (path[i - 1].node->field.sle_prev != slist->slh_head) { \ /* 1) go backwards along path from where we are until head */ \ j = i; \ @@ -636,20 +652,50 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li 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]; \ + /* 3) adjust forward pointers */ \ + if (j - 1 > 0) \ + 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_next[i] = slist->slh_tail; \ + /* TODO: remove me */ \ + __skip_integrity_check_##decl(slist, 0); \ + prefix##skip_dot_##decl(of, slist, gen, "dsc_cond", sprintf_##decl##_node); \ } \ } \ /* (b) Check the ascent condition: \ * path[i].par_hit_sum + node_hits > hits total / (2 ^ (height of head - height of node - 1)) \ + * When met should induce: \ + * 1) find the next node with a higher level (or tail), and ... \ + * 2) count the hits at height[0] from there back to this node, and ... \ + * 3) check the ascent condition, then iff true ... \ + * 4) add a level, and ... \ + * 5) set its hits to the prev node at intersection height \ + * 6) set prev node hits to 0 and forward to this new level \ */ \ - 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) { \ - ((void)0); \ + /* 1) find next node taller than this one (or tail) */ \ + hits = 0; \ + node = path[i].node; \ + if (node != slist->slh_tail) { \ + do { \ + /* 2) sum hits along the way */ \ + hits += node->field.sle_hits; \ + node = node->field.sle_next[0]; \ + } while (node->field.sle_height <= path[i].node->field.sle_height && node != slist->slh_tail); \ + } \ + /* 3) check ascent condition */ \ + asc_cond = pow(2.0, delta_height == 0 ? 0 : delta_height - 1); \ + if (hits > asc_cond && path[i].node->field.sle_height < slist->slh_max_height - 1) { \ + /* 4) increase height by one */ \ + new_height = path[i].node->field.sle_height++; \ + /* 5) update hit counter */ \ + path[i].node->field.sle_next[new_height]->field.sle_hits += path[i - 1].node->field.sle_next[path[i - 1].intersection]->field.sle_hits; \ + path[i - 1].node->field.sle_next[path[i - 1].intersection]->field.sle_hits = 0; \ + path[i - 1].node->field.sle_next[path[i - 1].intersection]->field.sle_next[path[i - 1].intersection] = path[i].node; \ + /* TODO: remove me */ \ + __skip_integrity_check_##decl(slist, 0); \ + prefix##skip_dot_##decl(of, slist, gen, "asc_cond", sprintf_##decl##_node); \ } \ } \ } \ @@ -678,10 +724,10 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li 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]; \ path[i + 1].intersection = i; \ - path[i + 1].par_hit_sum += elm->field.sle_hits; \ + path[i + 1].par_hit_sum += elm->field.sle_next[path[i + 1].intersection]->field.sle_hits; \ } \ path[i + 1].node = elm; \ - path[i + 1].node->field.sle_hits++; \ + path[i + 1].node->field.sle_next[path[i + 1].intersection]->field.sle_hits++; \ len++; \ } while (i--); \ elm = elm->field.sle_next[0]; \ @@ -774,8 +820,8 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li slist->slh_head->field.sle_height = new_height; \ slist->slh_tail->field.sle_height = new_height; \ } \ - /* Adjust the splay threshold based on the height. */ \ - slist->slh_splay.threshold = floor(log(slist->slh_head->field.sle_height) / M_LOG2E); \ + /* Adjust the splay threshold, `k`, using the new height. */ \ + slist->slh_splay.k = floor(log(slist->slh_head->field.sle_height) / M_LOG2E); \ /* Record the era for this node to enable snapshots. */ \ if (slist->slh_fns.snapshot_record_era) \ slist->slh_fns.snapshot_record_era(slist, new); \ @@ -1138,10 +1184,11 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li i++; \ slist->slh_head->field.sle_height = i; \ slist->slh_tail->field.sle_height = i; \ - /* Adjust the splay threshold based on the height. */ \ - slist->slh_splay.threshold = floor(log(slist->slh_head->field.sle_height) / M_LOG2E); \ + /* Adjust the splay threshold, `k`, using the new height. */ \ + slist->slh_splay.k = floor(log(slist->slh_head->field.sle_height) / M_LOG2E); \ \ slist->slh_length--; \ + __skip_adjust_hit_counts_##decl(slist); \ } \ return 0; \ } \ @@ -1683,14 +1730,14 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li } \ \ 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 %lu node's [%p] next field should never be NULL\n", nth, (void *)node); \ n_err++; \ if (flags) \ return n_err; \ } \ \ 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 %lu node [%p] prev field should never be NULL\n", nth, (void *)node); \ n_err++; \ if (flags) \ return n_err; \