WIP: implement the splay-list algorithm #2
2 changed files with 53 additions and 38 deletions
|
@ -16,7 +16,7 @@
|
||||||
#define VALIDATE
|
#define VALIDATE
|
||||||
// define SNAPSHOTS
|
// define SNAPSHOTS
|
||||||
// define TODO_RESTORE_SNAPSHOTS
|
// define TODO_RESTORE_SNAPSHOTS
|
||||||
#define STABLE_SEED
|
//define STABLE_SEED
|
||||||
#define DOT
|
#define DOT
|
||||||
|
|
||||||
#ifdef DOT
|
#ifdef DOT
|
||||||
|
@ -362,23 +362,31 @@ 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
|
||||||
char *v = api_skip_get_ex(list, array[i]);
|
char *v = api_skip_get_ex(list, array[i]);
|
||||||
|
#ifdef DOT
|
||||||
|
sprintf(msg, "get key: %d", array[i]);
|
||||||
|
api_skip_dot_ex(of, list, gen++, msg, sprintf_ex_node);
|
||||||
|
#endif
|
||||||
CHECK;
|
CHECK;
|
||||||
char *upper_numeral = calloc(1, strlen(v) + 1);
|
char *upper_numeral = calloc(1, strlen(v) + 1);
|
||||||
strncpy(upper_numeral, v, strlen(v));
|
strncpy(upper_numeral, v, strlen(v));
|
||||||
assert(strncmp(v, upper_numeral, strlen(upper_numeral)) == 0);
|
assert(strncmp(v, upper_numeral, strlen(upper_numeral)) == 0);
|
||||||
to_upper(upper_numeral);
|
to_upper(upper_numeral);
|
||||||
api_skip_set_ex(list, array[i], upper_numeral);
|
api_skip_set_ex(list, array[i], upper_numeral);
|
||||||
|
#ifdef DOT
|
||||||
|
sprintf(msg, "set key: %d value: %s", array[i], upper_numeral);
|
||||||
|
api_skip_dot_ex(of, list, gen++, msg, sprintf_ex_node);
|
||||||
|
#endif
|
||||||
CHECK;
|
CHECK;
|
||||||
|
|
||||||
for (size_t j = 0; j < api_skip_length_ex(list); j++) {
|
for (size_t j = 0; j < api_skip_length_ex(list); j++) {
|
||||||
int n = xorshift32() % api_skip_length_ex(list);
|
int n = xorshift32() % api_skip_length_ex(list);
|
||||||
api_skip_contains_ex(list, n);
|
api_skip_contains_ex(list, n);
|
||||||
CHECK;
|
CHECK;
|
||||||
#if 0
|
|
||||||
sprintf(msg, "locate key: %d", n);
|
|
||||||
api_skip_dot_ex(of, list, gen++, msg, sprintf_ex_node);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#ifdef DOT
|
||||||
|
sprintf(msg, "locate all the keys!!!");
|
||||||
|
api_skip_dot_ex(of, list, gen++, msg, sprintf_ex_node);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
numeral = int_to_roman_numeral(-1);
|
numeral = int_to_roman_numeral(-1);
|
||||||
api_skip_dup_ex(list, -1, numeral);
|
api_skip_dup_ex(list, -1, numeral);
|
||||||
|
|
73
include/sl.h
73
include/sl.h
|
@ -247,8 +247,8 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
|
||||||
#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)
|
||||||
/* Iterate over a subtree starting at provided path element, u = path.in */
|
/* Iterate over a subtree starting at provided path element, u = path.in */
|
||||||
#define __SKIP_SUBTREE_CHux(decl, field, list, path, level) \
|
#define __SKIP_SUBTREE_CHux(decl, field, list, node, level) \
|
||||||
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)
|
for (decl##_node_t *elm = node->field.sle_levels[level].next->field.sle_prev; elm != node->field.sle_prev; elm = elm->field.sle_prev)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Skiplist declarations and access methods.
|
* Skiplist declarations and access methods.
|
||||||
|
@ -638,8 +638,8 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
|
||||||
size_t i, lvl, u_hits, hits_CHu = 0, hits_CHv = 0, delta_height; \
|
size_t i, lvl, u_hits, hits_CHu = 0, hits_CHv = 0, delta_height; \
|
||||||
size_t k_threshold, m_total_hits, expected_height; \
|
size_t k_threshold, m_total_hits, expected_height; \
|
||||||
double asc_cond, dsc_cond; \
|
double asc_cond, dsc_cond; \
|
||||||
__skiplist_path_##decl##_t *p, path_u, path_v, *cur; \
|
__skiplist_path_##decl##_t *p, path_u, path_v; \
|
||||||
decl##_node_t *prv_node; \
|
decl##_node_t *node; \
|
||||||
\
|
\
|
||||||
/* 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; \
|
||||||
|
@ -650,6 +650,9 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
|
||||||
if (expected_height > slist->slh_head->field.sle_height && expected_height < SKIPLIST_MAX_HEIGHT - 1) { \
|
if (expected_height > slist->slh_head->field.sle_height && expected_height < SKIPLIST_MAX_HEIGHT - 1) { \
|
||||||
slist->slh_head->field.sle_height++; \
|
slist->slh_head->field.sle_height++; \
|
||||||
slist->slh_head->field.sle_levels[slist->slh_head->field.sle_height].next = slist->slh_tail; \
|
slist->slh_head->field.sle_levels[slist->slh_head->field.sle_height].next = slist->slh_tail; \
|
||||||
|
slist->slh_head->field.sle_levels[slist->slh_head->field.sle_height].hits = \
|
||||||
|
slist->slh_head->field.sle_levels[slist->slh_head->field.sle_height - 1].hits; \
|
||||||
|
slist->slh_head->field.sle_levels[slist->slh_head->field.sle_height - 1].hits = 0; \
|
||||||
slist->slh_tail->field.sle_height = slist->slh_head->field.sle_height; \
|
slist->slh_tail->field.sle_height = slist->slh_head->field.sle_height; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
|
@ -670,18 +673,14 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
|
||||||
if (path_u.node == slist->slh_head || path_u.node == slist->slh_tail) \
|
if (path_u.node == slist->slh_head || path_u.node == slist->slh_tail) \
|
||||||
continue; \
|
continue; \
|
||||||
path_v = *(p + 1); \
|
path_v = *(p + 1); \
|
||||||
if ((*(p + 1)).node->field.sle_levels[path_u.in].next != path_u.node) { \
|
|
||||||
path_v.node = (*(p + 1)).node->field.sle_levels[path_u.in].next; \
|
|
||||||
path_v.pu = 0; \
|
|
||||||
} \
|
|
||||||
\
|
\
|
||||||
/* Evaluate the subtree 'u'. */ \
|
/* Evaluate the subtree 'u'. */ \
|
||||||
__SKIP_SUBTREE_CHux(decl, field, slist, path_u, path_u.in) \
|
__SKIP_SUBTREE_CHux(decl, field, slist, path_u.node, path_u.in) \
|
||||||
{ \
|
{ \
|
||||||
hits_CHu += elm->field.sle_levels[0].hits; \
|
hits_CHu += elm->field.sle_levels[0].hits; \
|
||||||
} \
|
} \
|
||||||
/* Evaluate the subtree 'v' at the same level. */ \
|
/* Evaluate the subtree 'v' at the same level. */ \
|
||||||
__SKIP_SUBTREE_CHux(decl, field, slist, path_v, path_u.in) \
|
__SKIP_SUBTREE_CHux(decl, field, slist, (*(p + 1)).node->field.sle_levels[path_u.in].next, path_u.in) \
|
||||||
{ \
|
{ \
|
||||||
hits_CHv += elm->field.sle_levels[0].hits; \
|
hits_CHv += elm->field.sle_levels[0].hits; \
|
||||||
} \
|
} \
|
||||||
|
@ -689,25 +688,30 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
|
||||||
/* (a) Check the decent condition: \
|
/* (a) Check the decent condition: \
|
||||||
* u_hits <= m_total_hits / (2 ^ (k_threshold - height of node)) \
|
* u_hits <= m_total_hits / (2 ^ (k_threshold - height of node)) \
|
||||||
* When met we: \
|
* When met we: \
|
||||||
* 1) traverse the path backward, and... \
|
* 1) go backwards along path from where we are until head \
|
||||||
* 2) propagate path[i].level[i] hits backward along path, and... \
|
* 2) adjust any forward pointers, then... \
|
||||||
* 3) adjust any forward pointers along the way, then... \
|
* 3) adjust hits, and... \
|
||||||
* 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_u.node->field.sle_height; \
|
delta_height = k_threshold - path_u.node->field.sle_height; \
|
||||||
dsc_cond = m_total_hits / pow(2.0, delta_height); \
|
dsc_cond = m_total_hits / pow(2.0, delta_height); \
|
||||||
u_hits = hits_CHu + hits_CHv; \
|
u_hits = hits_CHu + hits_CHv; \
|
||||||
if (u_hits <= dsc_cond && path_u.node->field.sle_height > 0) { \
|
if (u_hits <= dsc_cond && path_u.node->field.sle_height > 0) { \
|
||||||
|
lvl = path_u.node->field.sle_height; \
|
||||||
/* 1) go backwards along path from where we are until head */ \
|
/* 1) go backwards along path from where we are until head */ \
|
||||||
cur = &path[i]; \
|
node = path_u.node; \
|
||||||
prv_node = (*(p + 1)).node->field.sle_levels[path_u.in].next; \
|
do { \
|
||||||
/* 2) propagate hits */ \
|
node = node->field.sle_prev; \
|
||||||
prv_node->field.sle_levels[cur->in].hits += 1; \
|
/* 2) adjust forward pointers */ \
|
||||||
/* 3) adjust forward pointers */ \
|
if (node->field.sle_height >= lvl && node->field.sle_levels[lvl].next == path_u.node) { \
|
||||||
if (prv_node->field.sle_levels[cur->in].next == cur->node) \
|
node->field.sle_levels[lvl].next = path_u.node->field.sle_levels[lvl].next; \
|
||||||
prv_node->field.sle_levels[cur->in].next = cur->node->field.sle_levels[cur->in].next; \
|
/* 3) adjust hits */ \
|
||||||
|
node->field.sle_levels[lvl].hits += 1; \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
} while (node != slist->slh_head); \
|
||||||
/* 4) reduce height by one */ \
|
/* 4) reduce height by one */ \
|
||||||
cur->node->field.sle_height--; \
|
path_u.node->field.sle_height--; \
|
||||||
} \
|
} \
|
||||||
/* (b) Check the ascent condition: \
|
/* (b) Check the ascent condition: \
|
||||||
* path[i].pu + node_hits > hits total / (2 ^ (height of head - height of node - 1)) \
|
* path[i].pu + node_hits > hits total / (2 ^ (height of head - height of node - 1)) \
|
||||||
|
@ -719,14 +723,16 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
|
||||||
*/ \
|
*/ \
|
||||||
/* 1) check ascent condition */ \
|
/* 1) check ascent condition */ \
|
||||||
asc_cond = m_total_hits / pow(2.0, delta_height - 1); \
|
asc_cond = m_total_hits / pow(2.0, delta_height - 1); \
|
||||||
if (path_u.pu > asc_cond && path_u.node->field.sle_height < SKIPLIST_MAX_HEIGHT - 1) { \
|
if (path_u.pu > asc_cond && path_u.node->entries.sle_height < 64 - 1) { \
|
||||||
/* 2) increase height by one */ \
|
if (path_u.node->field.sle_height + 1 > path_v.node->field.sle_height) { \
|
||||||
|
continue; \
|
||||||
|
} \
|
||||||
lvl = ++path_u.node->field.sle_height; \
|
lvl = ++path_u.node->field.sle_height; \
|
||||||
/* 3) update hit counter */ \
|
/* Don't adjust hits when the previous node on the path is the head. */ \
|
||||||
path_u.node->field.sle_levels[lvl].hits = path_v.node->field.sle_levels[lvl].hits; \
|
if (path_v.node != slist->slh_head) { \
|
||||||
/* 4) reset the prev node hits to 0 */ \
|
path_u.node->field.sle_levels[lvl].hits = path_v.node->entries.sle_levels[lvl].hits; \
|
||||||
path_v.node->field.sle_levels[lvl].hits = 0; \
|
path_v.node->field.sle_levels[lvl].hits = 0; \
|
||||||
/* 5) update forward pointers in the level */ \
|
} \
|
||||||
path_u.node->field.sle_levels[lvl].next = path_v.node->field.sle_levels[lvl].next; \
|
path_u.node->field.sle_levels[lvl].next = path_v.node->field.sle_levels[lvl].next; \
|
||||||
path_v.node->field.sle_levels[lvl].next = path_u.node; \
|
path_v.node->field.sle_levels[lvl].next = path_u.node; \
|
||||||
} \
|
} \
|
||||||
|
@ -1155,6 +1161,7 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
|
||||||
/* Reduce the height of the head/tail nodes. */ \
|
/* Reduce the height of the head/tail nodes. */ \
|
||||||
for (i = 0; slist->slh_head->field.sle_levels[i].next != slist->slh_tail && i < SKIPLIST_MAX_HEIGHT; i++) \
|
for (i = 0; slist->slh_head->field.sle_levels[i].next != slist->slh_tail && i < SKIPLIST_MAX_HEIGHT; i++) \
|
||||||
; \
|
; \
|
||||||
|
slist->slh_head->field.sle_levels[i].hits = slist->slh_head->field.sle_levels[slist->slh_head->field.sle_height].hits; \
|
||||||
slist->slh_head->field.sle_height = slist->slh_tail->field.sle_height = i; \
|
slist->slh_head->field.sle_height = slist->slh_tail->field.sle_height = i; \
|
||||||
\
|
\
|
||||||
slist->slh_length--; \
|
slist->slh_length--; \
|
||||||
|
@ -1937,10 +1944,10 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
|
||||||
\
|
\
|
||||||
if (slist == NULL || fn == NULL) \
|
if (slist == NULL || fn == NULL) \
|
||||||
return nsg; \
|
return nsg; \
|
||||||
if (__skip_integrity_check_##decl(slist, 1) != 0) { \
|
/*if (__skip_integrity_check_##decl(slist, 1) != 0) { \
|
||||||
perror("Skiplist failed integrity checks, impossible to diagram."); \
|
perror("Skiplist failed integrity checks, impossible to diagram."); \
|
||||||
return -1; \
|
return -1; \
|
||||||
} \
|
}*/ \
|
||||||
if (nsg == 0) { \
|
if (nsg == 0) { \
|
||||||
fprintf(os, "digraph Skiplist {\n"); \
|
fprintf(os, "digraph Skiplist {\n"); \
|
||||||
fprintf(os, "label = \"Skiplist.\"\n"); \
|
fprintf(os, "label = \"Skiplist.\"\n"); \
|
||||||
|
@ -1950,9 +1957,9 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
|
||||||
} \
|
} \
|
||||||
fprintf(os, "subgraph cluster%lu {\n", nsg); \
|
fprintf(os, "subgraph cluster%lu {\n", nsg); \
|
||||||
fprintf(os, "style=dashed\n"); \
|
fprintf(os, "style=dashed\n"); \
|
||||||
fprintf(os, "label=\"Skiplist iteration %lu", nsg); \
|
fprintf(os, "label=\"Skiplist [%lu]", nsg); \
|
||||||
if (msg) \
|
if (msg) \
|
||||||
fprintf(os, ", %s", msg); \
|
fprintf(os, " %s", msg); \
|
||||||
fprintf(os, "\"\n\n"); \
|
fprintf(os, "\"\n\n"); \
|
||||||
fprintf(os, "\"HeadNode%lu\" [\n", nsg); \
|
fprintf(os, "\"HeadNode%lu\" [\n", nsg); \
|
||||||
fprintf(os, "label = \""); \
|
fprintf(os, "label = \""); \
|
||||||
|
@ -2011,7 +2018,7 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
|
||||||
} \
|
} \
|
||||||
fflush(os); \
|
fflush(os); \
|
||||||
\
|
\
|
||||||
/* The tail, sentinal node */ \
|
/* The tail, sentinel node */ \
|
||||||
if (letitgo) { \
|
if (letitgo) { \
|
||||||
__skip_dot_write_node_##decl(os, nsg, NULL); \
|
__skip_dot_write_node_##decl(os, nsg, NULL); \
|
||||||
fprintf(os, " [label = \""); \
|
fprintf(os, " [label = \""); \
|
||||||
|
|
Loading…
Reference in a new issue