splay v1/p5; rebalence asc cond; WIP

This commit is contained in:
Gregory Burd 2024-04-01 17:14:04 -04:00
parent 64c68c2283
commit 1048d0df59
2 changed files with 80 additions and 25 deletions

View file

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

View file

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