splay v1/p5; rebalence asc cond; WIP
This commit is contained in:
parent
64c68c2283
commit
1048d0df59
|
@ -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;
|
||||
|
|
85
include/sl.h
85
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 */ \
|
||||
/* 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; \
|
||||
|
|
Loading…
Reference in a new issue