WIP: implement the splay-list algorithm #2
2 changed files with 929 additions and 924 deletions
|
@ -365,12 +365,12 @@ main()
|
||||||
api_skip_dot_ex(of, list, gen++, msg, sprintf_ex_node);
|
api_skip_dot_ex(of, list, gen++, msg, sprintf_ex_node);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
printf("m = %ld\n", splay_list_m(list));
|
printf("m = %ld; ", splay_list_m(list));
|
||||||
printf("(⌊log2(m)⌋) = %d\n", floor_log2(splay_list_m(list)));
|
printf("(⌊log2(m)⌋) = %d\n", floor_log2(splay_list_m(list)));
|
||||||
|
|
||||||
if (!(rc = api_skip_contains_ex(list, 5)))
|
if (!(rc = api_skip_contains_ex(list, 5)))
|
||||||
perror("missing element 5");
|
perror("missing element 5");
|
||||||
CHECK;
|
|
||||||
#ifdef DOT
|
#ifdef DOT
|
||||||
sprintf(msg, "contains(5)");
|
sprintf(msg, "contains(5)");
|
||||||
api_skip_dot_ex(of, list, gen++, msg, sprintf_ex_node);
|
api_skip_dot_ex(of, list, gen++, msg, sprintf_ex_node);
|
||||||
|
|
65
include/sl.h
65
include/sl.h
|
@ -246,9 +246,9 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
|
||||||
for (decl##_node_t *elm = path[nth].node; elm->field.sle_levels[path[nth].in].next == path[nth].node; elm = elm->field.sle_prev)
|
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) \
|
#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)
|
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) \
|
/* Iterate over a subtree starting at provided path element, u = path.in */
|
||||||
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; \
|
#define __SKIP_SUBTREE_CHux(decl, field, list, path, level) \
|
||||||
elm = elm->field.sle_prev)
|
for (decl##_node_t *elm = path.node->field.sle_levels[level].next->field.sle_prev; elm != path.node->field.sle_prev; elm = elm->field.sle_prev)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Skiplist declarations and access methods.
|
* Skiplist declarations and access methods.
|
||||||
|
@ -635,9 +635,10 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
|
||||||
*/ \
|
*/ \
|
||||||
static void __skip_rebalance_##decl(decl##_t *slist, size_t len, __skiplist_path_##decl##_t path[]) \
|
static void __skip_rebalance_##decl(decl##_t *slist, size_t len, __skiplist_path_##decl##_t path[]) \
|
||||||
{ \
|
{ \
|
||||||
size_t i, j, u_hits, hits_CHu = 0, hits_CHv = 0, delta_height, new_height, cur_hits, prev_hits; \
|
size_t i, j, u_hits, hits_CHu = 0, hits_CHv = 0, delta_height, cur_hits, prev_hits; \
|
||||||
size_t k_threshold, m_total_hits; \
|
size_t k_threshold, m_total_hits; \
|
||||||
double asc_cond, dsc_cond; \
|
double asc_cond, dsc_cond; \
|
||||||
|
__skiplist_path_##decl##_t cur, prv; \
|
||||||
\
|
\
|
||||||
/* Total hits, `k`, across all nodes. */ \
|
/* Total hits, `k`, across all nodes. */ \
|
||||||
m_total_hits = slist->slh_head->field.sle_levels[slist->slh_head->field.sle_height].hits; \
|
m_total_hits = slist->slh_head->field.sle_levels[slist->slh_head->field.sle_height].hits; \
|
||||||
|
@ -657,11 +658,11 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
|
||||||
if (path[i].node == slist->slh_head || path[i].node == slist->slh_tail) \
|
if (path[i].node == slist->slh_head || path[i].node == slist->slh_tail) \
|
||||||
continue; \
|
continue; \
|
||||||
\
|
\
|
||||||
__SKIP_SUBTREE_CHhx(decl, field, slist, path, i) \
|
__SKIP_SUBTREE_CHux(decl, field, slist, path[i], path[i].in) \
|
||||||
{ \
|
{ \
|
||||||
hits_CHu += elm->field.sle_levels[0].hits; \
|
hits_CHu += elm->field.sle_levels[0].hits; \
|
||||||
} \
|
} \
|
||||||
__SKIP_SUBTREE_CHhx(decl, field, slist, path, i + 1) \
|
__SKIP_SUBTREE_CHux(decl, field, slist, path[i + 1], path[i].in) \
|
||||||
{ \
|
{ \
|
||||||
hits_CHv += elm->field.sle_levels[0].hits; \
|
hits_CHv += elm->field.sle_levels[0].hits; \
|
||||||
} \
|
} \
|
||||||
|
@ -675,24 +676,26 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
|
||||||
* 3) adjust any forward pointers along the way, then... \
|
* 3) adjust any forward pointers along the way, then... \
|
||||||
* 4) lower the path[i]'s node height by 1 \
|
* 4) lower the path[i]'s node height by 1 \
|
||||||
*/ \
|
*/ \
|
||||||
delta_height = k_threshold - path[i].node->field.sle_height + 1; \
|
delta_height = k_threshold - path[i].node->field.sle_height; \
|
||||||
dsc_cond = m_total_hits / pow(2.0, delta_height); \
|
dsc_cond = m_total_hits / pow(2.0, delta_height); \
|
||||||
if (u_hits <= dsc_cond && path[i].node->field.sle_height > 0) { \
|
if (0 && u_hits <= dsc_cond && path[i].node->field.sle_height > 0) { \
|
||||||
if (path[i - 1].node->field.sle_prev != slist->slh_head) { \
|
if (path[i].node->field.sle_prev != slist->slh_head) { \
|
||||||
/* 1) go backwards along path from where we are until head */ \
|
/* 1) go backwards along path from where we are until head */ \
|
||||||
j = i; \
|
j = i; \
|
||||||
cur_hits = path[j].node->field.sle_levels[path[j].in].hits; \
|
cur = path[j]; \
|
||||||
|
prv = path[j + 1]; \
|
||||||
|
cur_hits = cur.node->field.sle_levels[cur.in].hits; \
|
||||||
do { \
|
do { \
|
||||||
/* 2) propagate hits */ \
|
/* 2) propagate hits */ \
|
||||||
prev_hits = path[j - 1].node->field.sle_levels[path[j - 1].in].hits; \
|
prev_hits = prv.node->field.sle_levels[prv.in].hits; \
|
||||||
path[j - 1].node->field.sle_levels[path[j - 1].in].hits += cur_hits; \
|
prv.node->field.sle_levels[prv.in].hits += cur_hits; \
|
||||||
cur_hits = prev_hits; \
|
cur_hits = prev_hits; \
|
||||||
/* 3) adjust forward pointers */ \
|
/* 3) adjust forward pointers */ \
|
||||||
if (path[j - 1].node->field.sle_levels[j].next == path[i].node) \
|
if (prv.node->field.sle_levels[j].next == cur.node) \
|
||||||
path[j - 1].node->field.sle_levels[j].next = path[i].node->field.sle_levels[j].next; \
|
prv.node->field.sle_levels[j].next = cur.node->field.sle_levels[j].next; \
|
||||||
} while (j-- > 1); \
|
} while (j-- > 1); \
|
||||||
/* 4) reduce height by one */ \
|
/* 4) reduce height by one */ \
|
||||||
path[i].node->field.sle_height--; \
|
cur.node->field.sle_height--; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
/* (b) Check the ascent condition: \
|
/* (b) Check the ascent condition: \
|
||||||
|
@ -704,16 +707,19 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
|
||||||
* 4) set prev node hits to 0 and forward to this new level \
|
* 4) set prev node hits to 0 and forward to this new level \
|
||||||
*/ \
|
*/ \
|
||||||
/* 1) check ascent condition */ \
|
/* 1) check ascent condition */ \
|
||||||
asc_cond = m_total_hits / pow(2.0, delta_height == 0 ? 0 : delta_height - 1); \
|
asc_cond = m_total_hits / pow(2.0, delta_height - 1); \
|
||||||
if (path[i - 1].pu > asc_cond && path[i].node->field.sle_height < SKIPLIST_MAX_HEIGHT) { \
|
if (path[i + 1].pu + hits_CHv > asc_cond && path[i].node->field.sle_height < SKIPLIST_MAX_HEIGHT) { \
|
||||||
|
cur = path[i]; \
|
||||||
|
prv = path[i + 1]; \
|
||||||
/* 2) increase height by one */ \
|
/* 2) increase height by one */ \
|
||||||
new_height = path[i].node->field.sle_height++; \
|
cur.node->field.sle_height++; \
|
||||||
/* 3) update hit counter */ \
|
/* 3) update hit counter */ \
|
||||||
path[i].node->field.sle_levels[new_height].hits += path[i - 1].node->field.sle_levels[path[i - 1].in].hits; \
|
cur.node->field.sle_levels[prv.in].hits = prv.node->field.sle_levels[prv.in].hits; \
|
||||||
/* 4) reset the prev node hits to 0 */ \
|
/* 4) reset the prev node hits to 0 */ \
|
||||||
path[i - 1].node->field.sle_levels[path[i - 1].in].hits = 0; \
|
prv.node->field.sle_levels[prv.in].hits = 0; \
|
||||||
if (path[i - 1].in != 0) \
|
/* 5) update forward pointers in the level */ \
|
||||||
path[i - 1].node->field.sle_levels[path[i - 1].in].next->field.sle_levels[path[i - 1].in].next = path[i].node; \
|
cur.node->field.sle_levels[prv.in].next = prv.node->field.sle_levels[prv.in].next; \
|
||||||
|
prv.node->field.sle_levels[prv.in].next = cur.node; \
|
||||||
} \
|
} \
|
||||||
} while (i++ < len); \
|
} while (i++ < len); \
|
||||||
} \
|
} \
|
||||||
|
@ -740,16 +746,15 @@ 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 - 1; \
|
i = slist->slh_head->field.sle_height - 1; \
|
||||||
do { \
|
do { \
|
||||||
path[i + 1].pu = 0; \
|
__skiplist_path_##decl##_t *pe = &path[i + 1]; \
|
||||||
while (elm != slist->slh_tail && elm->field.sle_levels[i].next && \
|
pe->pu = 0; \
|
||||||
__skip_compare_nodes_##decl(slist, elm->field.sle_levels[i].next, n, slist->slh_aux) < 0) { \
|
while (elm != slist->slh_tail && __skip_compare_nodes_##decl(slist, elm->field.sle_levels[i].next, n, slist->slh_aux) < 0) { \
|
||||||
|
pe->in = i; \
|
||||||
|
pe->pu += elm->field.sle_levels[0].hits; \
|
||||||
elm = elm->field.sle_levels[i].next; \
|
elm = elm->field.sle_levels[i].next; \
|
||||||
path[i + 1].in = i; \
|
|
||||||
path[i + 1].pu += elm->field.sle_levels[path[i + 1].in].hits; \
|
|
||||||
} \
|
} \
|
||||||
path[i + 1].node = elm; \
|
pe->node = elm; \
|
||||||
if (path[i + 1].in > 0) \
|
pe->node->field.sle_levels[pe->in].hits += i ? 1 : 0; \
|
||||||
path[i + 1].node->field.sle_levels[path[i + 1].in].hits++; \
|
|
||||||
len++; \
|
len++; \
|
||||||
} while (i--); \
|
} while (i--); \
|
||||||
elm = elm->field.sle_levels[0].next; \
|
elm = elm->field.sle_levels[0].next; \
|
||||||
|
|
Loading…
Reference in a new issue