working on it...
This commit is contained in:
parent
6e97787aa3
commit
03790de272
|
@ -143,7 +143,7 @@ main()
|
|||
perror("Failed to open file /tmp/slm.dot");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
api_skip_dot_slex(of, list, sprintf_slex_node);
|
||||
api_skip_dot_slex(of, list, 0, sprintf_slex_node);
|
||||
fclose(of);
|
||||
|
||||
api_skip_destroy_slex(list);
|
||||
|
|
407
include/sl.h
407
include/sl.h
|
@ -277,8 +277,9 @@
|
|||
return NULL; \
|
||||
} \
|
||||
\
|
||||
/* -- skip_insert_ */ \
|
||||
int prefix##skip_insert_##decl(decl##_t *slist, decl##_node_t *n) \
|
||||
/* -- __skip_insert_ */ \
|
||||
static int __skip_insert_##decl(decl##_t *slist, decl##_node_t *n, \
|
||||
int flags) \
|
||||
{ \
|
||||
unsigned int i; \
|
||||
decl##_node_t *prev, *elm = slist->slh_head; \
|
||||
|
@ -298,26 +299,28 @@
|
|||
__skip_key_compare_##decl(slist, elm->field.sle_next[i], n, \
|
||||
slist->aux) < 0) \
|
||||
elm = elm->field.sle_next[i]; \
|
||||
path[i] = elm; \
|
||||
path[i] = elm; \
|
||||
ARRAY_SET_LENGTH(path, ARRAY_LENGTH(path) + 1); \
|
||||
} while (i--); \
|
||||
i = 0; \
|
||||
prev = elm; \
|
||||
elm = elm->field.sle_next[0]; \
|
||||
if (__skip_key_compare_##decl(slist, elm, n, slist->aux) == 0) { \
|
||||
/* Don't overwrite, to do that use _REPLACE not _INSERT */ \
|
||||
ARRAY_FREE(path); \
|
||||
return -1; \
|
||||
if (flags == 0) { \
|
||||
/* Don't overwrite, to do that use _REPLACE not _INSERT */ \
|
||||
ARRAY_FREE(path); \
|
||||
return -1; \
|
||||
} \
|
||||
} \
|
||||
size_t level = __skip_toss_##decl(slist->max, slist->fanout); \
|
||||
ARRAY_SET_LENGTH(n->field.sle_next, level); \
|
||||
if (level > slist->level) { \
|
||||
for (i = slist->level + 1; i <= level; i++) { \
|
||||
for (i = slist->level + 1; i <= level; i++) { \
|
||||
path[i] = slist->slh_tail; \
|
||||
} \
|
||||
slist->level = level; \
|
||||
} \
|
||||
for (i = 0; i <= level; i++) { \
|
||||
for (i = 0; i <= level; i++) { \
|
||||
n->field.sle_next[i] = path[i]->field.sle_next[i]; \
|
||||
path[i]->field.sle_next[i] = n; \
|
||||
} \
|
||||
|
@ -330,14 +333,17 @@
|
|||
return 0; \
|
||||
} \
|
||||
\
|
||||
/* -- skip_insert_dup_ TODO \
|
||||
/* -- skip_insert_ */ \
|
||||
int prefix##skip_insert_##decl(decl##_t *slist, decl##_node_t *n) \
|
||||
{ \
|
||||
return __skip_insert_##decl(slist, n, 0); \
|
||||
} \
|
||||
\
|
||||
/* -- skip_insert_dup_ */ \
|
||||
int prefix##skip_insert_dup_##decl(decl##_t *slist, decl##_node_t *n) \
|
||||
{ \
|
||||
((void)slist); \
|
||||
((void)n); \
|
||||
return 0; \
|
||||
return __skip_insert_##decl(slist, n, 1); \
|
||||
} \
|
||||
*/ \
|
||||
\
|
||||
/* -- skip_find_ \
|
||||
* Find a node that matches another node. This differs from the locate() \
|
||||
|
@ -477,7 +483,7 @@
|
|||
ARRAY_FREE(path); \
|
||||
free_node_blk; \
|
||||
/* Find all levels in the first element in the list that point \
|
||||
at the tail and shrink the level*/ \
|
||||
at the tail and shrink the level. */ \
|
||||
while (slist->level > 0 && \
|
||||
slist->slh_head->field.sle_next[slist->level] == slist->slh_tail) { \
|
||||
slist->level--; \
|
||||
|
@ -531,6 +537,31 @@
|
|||
return 0; \
|
||||
} \
|
||||
\
|
||||
/* -- skip_snapshot_ \
|
||||
* A snapshot is a read-only view of a Skiplist at a point in \
|
||||
* time. Once taken, a snapshot must be restored or disposed. \
|
||||
* Any number of snapshots can be created. \
|
||||
*/ \
|
||||
int prefix##skip_snapshot_##decl(decl##_t *slist) \
|
||||
{ \
|
||||
((void)slist); /* TODO */ \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
/* -- skip_restore_snapshot_ */ \
|
||||
int prefix##skip_restore_snapshot_##decl(decl##_t *slist) \
|
||||
{ \
|
||||
((void)slist); /* TODO */ \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
/* -- skip_dispose_snapshot_ */ \
|
||||
int prefix##skip_dispose_snapshot_##decl(decl##_t *slist) \
|
||||
{ \
|
||||
((void)slist); /* TODO */ \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
/* -- __skip_integrity_check_ */ \
|
||||
static int __skip_integrity_check_##decl(decl##_t *slist) \
|
||||
{ \
|
||||
|
@ -573,181 +604,179 @@
|
|||
return (vtype)0; \
|
||||
}
|
||||
|
||||
#define SKIPLIST_DECL_DOT(decl, prefix, field) \
|
||||
\
|
||||
/* A type for a function that writes into a char[2048] buffer \
|
||||
* a description of the value within the node. */ \
|
||||
typedef void (*skip_sprintf_node_##decl##_t)(decl##_node_t *, char *); \
|
||||
\
|
||||
/* -- __skip_dot_node_ \
|
||||
* Writes out a fragment of a DOT file representing a node. \
|
||||
*/ \
|
||||
static void __skip_dot_node_##decl(FILE *os, decl##_t *slist, \
|
||||
decl##_node_t *node, size_t nsg, skip_sprintf_node_##decl##_t fn) \
|
||||
{ \
|
||||
char buf[2048]; \
|
||||
size_t level, height = ARRAY_LENGTH(node->field.sle_next); \
|
||||
fprintf(os, "\"node%zu%p\"", nsg, (void *)node); \
|
||||
fprintf(os, " [label = \""); \
|
||||
level = height; \
|
||||
do { \
|
||||
fprintf(os, " { <w%zu> | <f%zu> %p }", level + 1, level + 1, \
|
||||
(void *)node->field.sle_next[level]); \
|
||||
if (level != 0) \
|
||||
fprintf(os, " | "); \
|
||||
} while (level--); \
|
||||
if (fn) { \
|
||||
fn(node, buf); \
|
||||
fprintf(os, " <f0> %s\"\n", buf); \
|
||||
} else { \
|
||||
fprintf(os, " <f0> ?\"\n"); \
|
||||
} \
|
||||
fprintf(os, "shape = \"record\"\n"); \
|
||||
fprintf(os, "];\n"); \
|
||||
\
|
||||
/* Now edges */ \
|
||||
level = 0; \
|
||||
for (level = 0; level < height; level++) { \
|
||||
fprintf(os, "\"node%zu%p\"", nsg, (void *)node); \
|
||||
fprintf(os, ":f%zu -> ", level + 1); \
|
||||
fprintf(os, "\"node%zu%p\"", nsg, (void *)node->field.sle_next[level]); \
|
||||
fprintf(os, ":w%zu [];\n", level + 1); \
|
||||
} \
|
||||
\
|
||||
if (node->field.sle_next[0] != SKIP_LAST(slist)) \
|
||||
__skip_dot_node_##decl(os, slist, node->field.sle_next[0], nsg, fn); \
|
||||
} \
|
||||
\
|
||||
/* -- __skip_dot_finish_ \
|
||||
* Finalise the DOT file of the internal representation. \
|
||||
*/ \
|
||||
static void __skip_dot_finish_##decl(FILE *os, size_t nsg) \
|
||||
{ \
|
||||
size_t i; \
|
||||
if (nsg > 0) { \
|
||||
/* Link the nodes together with an invisible node. \
|
||||
* node0 [shape=record, label = "<f0> | <f1> | <f2> | <f3> | \
|
||||
* <f4> | <f5> | <f6> | <f7> | <f8> | ", style=invis, width=0.01]; \
|
||||
*/ \
|
||||
fprintf(os, "node0 [shape=record, label = \""); \
|
||||
for (i = 0; i < nsg; ++i) { \
|
||||
fprintf(os, "<f%zu> | ", i); \
|
||||
} \
|
||||
fprintf(os, "\", style=invis, width=0.01];\n"); \
|
||||
\
|
||||
/* Now connect nodes with invisible edges \
|
||||
* \
|
||||
* node0:f0 -> HeadNode [style=invis]; \
|
||||
* node0:f1 -> HeadNode1 [style=invis]; \
|
||||
*/ \
|
||||
for (i = 0; i < nsg; ++i) { \
|
||||
fprintf(os, "node0:f%zu -> HeadNode%zu [style=invis];\n", i, i); \
|
||||
} \
|
||||
nsg = 0; \
|
||||
} \
|
||||
fprintf(os, "}\n"); \
|
||||
} \
|
||||
\
|
||||
/* -- skip_dot_start_ */ \
|
||||
static int __skip_dot_start_##decl(FILE *os, decl##_t *slist, size_t nsg, \
|
||||
skip_sprintf_node_##decl##_t fn) \
|
||||
{ \
|
||||
size_t level; \
|
||||
decl##_node_t *head; \
|
||||
if (nsg == 0) { \
|
||||
fprintf(os, "digraph Skiplist {\n"); \
|
||||
fprintf(os, "label = \"Skiplist.\"\n"); \
|
||||
fprintf(os, "graph [rankdir = \"LR\"];\n"); \
|
||||
fprintf(os, "node [fontsize = \"12\" shape = \"ellipse\"];\n"); \
|
||||
fprintf(os, "edge [];\n\n"); \
|
||||
} \
|
||||
fprintf(os, "subgraph cluster%zu {\n", nsg); \
|
||||
fprintf(os, "style=dashed\n"); \
|
||||
fprintf(os, "label=\"Skip list iteration %zu\"\n\n", nsg); \
|
||||
fprintf(os, "\"HeadNode%zu\" [\n", nsg); \
|
||||
fprintf(os, "label = \""); \
|
||||
\
|
||||
/* Write out the fields */ \
|
||||
head = slist->slh_head; \
|
||||
if (SKIP_EMPTY(slist)) \
|
||||
fprintf(os, "Empty HeadNode"); \
|
||||
else { \
|
||||
level = ARRAY_LENGTH(head->field.sle_next); \
|
||||
while (level--) { \
|
||||
decl##_node_t *node = head->field.sle_next[level]; \
|
||||
fprintf(os, "{ <f%zu> %p }", level + 1, (void *)node); \
|
||||
if (level + 1 != 0) \
|
||||
fprintf(os, " | "); \
|
||||
} \
|
||||
} \
|
||||
fprintf(os, "\"\n"); \
|
||||
fprintf(os, "shape = \"record\"\n"); \
|
||||
fprintf(os, "];\n"); \
|
||||
\
|
||||
/* Edges for head node */ \
|
||||
decl##_node_t *node = slist->slh_head; \
|
||||
level = 0; \
|
||||
do { \
|
||||
fprintf(os, "\"HeadNode%zu\":f%zu -> ", nsg, level + 1); \
|
||||
fprintf(os, "\"node%zu%p\"", nsg, (void *)node->field.sle_next[level]); \
|
||||
fprintf(os, ":w%zu [];\n", level + 1); \
|
||||
} while (level++ < slist->level); \
|
||||
fprintf(os, "}\n\n"); \
|
||||
\
|
||||
/* Now all nodes via level 0, if non-empty */ \
|
||||
node = slist->slh_head; \
|
||||
if (ARRAY_LENGTH(node->field.sle_next)) \
|
||||
__skip_dot_node_##decl(os, slist, node->field.sle_next[0], nsg, fn); \
|
||||
fprintf(os, "\n"); \
|
||||
\
|
||||
/* The tail, sentinal node */ \
|
||||
if (!SKIP_EMPTY(slist)) { \
|
||||
fprintf(os, "\"node%zu0x0\" [label = \"", nsg); \
|
||||
level = slist->level; \
|
||||
do { \
|
||||
fprintf(os, "<w%zu> NULL", level + 1); \
|
||||
if (level != 0) \
|
||||
fprintf(os, " | "); \
|
||||
} while (level-- > 0); \
|
||||
fprintf(os, "\" shape = \"record\"];\n"); \
|
||||
} \
|
||||
\
|
||||
/* End: "subgraph cluster1 {" */ \
|
||||
fprintf(os, "}\n\n"); \
|
||||
nsg += 1; \
|
||||
\
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
/* -- skip_dot_ \
|
||||
* Create a DOT file of the internal representation of the \
|
||||
* Skiplist on the provided file descriptor (default: STDOUT). \
|
||||
* \
|
||||
* To view the output: \
|
||||
* $ dot -Tps filename.dot -o outfile.ps \
|
||||
* You can change the output format by varying the value after -T and \
|
||||
* choosing an appropriate filename extension after -o. \
|
||||
* See: https://graphviz.org/docs/outputs/ for the format options. \
|
||||
* \
|
||||
* https://en.wikipedia.org/wiki/DOT_(graph_description_language) \
|
||||
*/ \
|
||||
int prefix##skip_dot_##decl(FILE *os, decl##_t *slist, \
|
||||
skip_sprintf_node_##decl##_t fn) \
|
||||
{ \
|
||||
size_t nsg = 0; \
|
||||
if (__skip_integrity_check_##decl(slist) != 0) { \
|
||||
perror("Skiplist failed integrity checks, impossible to diagram."); \
|
||||
return -1; \
|
||||
} \
|
||||
if (os == NULL) \
|
||||
os = stdout; \
|
||||
if (!os) { \
|
||||
perror("Failed to open output file, unable to write DOT file."); \
|
||||
return -1; \
|
||||
} \
|
||||
__skip_dot_start_##decl(os, slist, nsg, fn); \
|
||||
__skip_dot_finish_##decl(os, nsg); \
|
||||
return 0; \
|
||||
#define SKIPLIST_DECL_DOT(decl, prefix, field) \
|
||||
\
|
||||
/* A type for a function that writes into a char[2048] buffer \
|
||||
* a description of the value within the node. */ \
|
||||
typedef void (*skip_sprintf_node_##decl##_t)(decl##_node_t *, char *); \
|
||||
\
|
||||
/* -- __skip_dot_node_ \
|
||||
* Writes out a fragment of a DOT file representing a node. \
|
||||
*/ \
|
||||
static void __skip_dot_node_##decl(FILE *os, decl##_t *slist, \
|
||||
decl##_node_t *node, size_t nsg, skip_sprintf_node_##decl##_t fn) \
|
||||
{ \
|
||||
char buf[2048]; \
|
||||
size_t level, height = ARRAY_LENGTH(node->field.sle_next) - 1; \
|
||||
decl##_node_t *next; \
|
||||
\
|
||||
fprintf(os, "\"node%zu %p\"", nsg, (void *)node); \
|
||||
fprintf(os, " [label = \""); \
|
||||
level = height; \
|
||||
do { \
|
||||
fprintf(os, " { <w%zu> | <f%zu> %p } |", level, level, \
|
||||
(void *)node->field.sle_next[level]); \
|
||||
} while (level--); \
|
||||
if (fn) { \
|
||||
fn(node, buf); \
|
||||
fprintf(os, " <f0> %s\"\n", buf); \
|
||||
} else { \
|
||||
fprintf(os, " <f0> ?\"\n"); \
|
||||
} \
|
||||
fprintf(os, "shape = \"record\"\n"); \
|
||||
fprintf(os, "];\n"); \
|
||||
\
|
||||
/* Now edges */ \
|
||||
level = 0; \
|
||||
for (level = 0; level < height; level++) { \
|
||||
fprintf(os, "\"node%zu %p\"", nsg, (void *)node); \
|
||||
fprintf(os, ":f%zu -> ", level); \
|
||||
fprintf(os, "\"node%zu %p\"", nsg, (void *)node->field.sle_next[level]); \
|
||||
fprintf(os, ":w%zu [];\n", level); \
|
||||
} \
|
||||
next = prefix##skip_next_node_##decl(slist, node); \
|
||||
if (next) \
|
||||
__skip_dot_node_##decl(os, slist, next, nsg, fn); \
|
||||
} \
|
||||
\
|
||||
/* -- __skip_dot_finish_ \
|
||||
* Finalize the DOT file of the internal representation. \
|
||||
*/ \
|
||||
static void __skip_dot_finish_##decl(FILE *os, size_t nsg) \
|
||||
{ \
|
||||
size_t i; \
|
||||
if (nsg > 0) { \
|
||||
/* Link the nodes together with an invisible node. \
|
||||
* node0 [shape=record, label = "<f0> | <f1> | <f2> | <f3> | \
|
||||
* <f4> | <f5> | <f6> | <f7> | <f8> | ", style=invis, width=0.01]; \
|
||||
*/ \
|
||||
fprintf(os, "node0 [shape=record, label = \""); \
|
||||
for (i = 0; i < nsg; ++i) { \
|
||||
fprintf(os, "<f%zu> | ", i); \
|
||||
} \
|
||||
fprintf(os, "\", style=invis, width=0.01];\n"); \
|
||||
\
|
||||
/* Now connect nodes with invisible edges \
|
||||
* \
|
||||
* node0:f0 -> HeadNode [style=invis]; \
|
||||
* node0:f1 -> HeadNode1 [style=invis]; \
|
||||
*/ \
|
||||
for (i = 0; i < nsg; ++i) { \
|
||||
fprintf(os, "node0:f%zu -> HeadNode%zu [style=invis];\n", i, i); \
|
||||
} \
|
||||
nsg = 0; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* -- skip_dot_start_ */ \
|
||||
static int __skip_dot_start_##decl(FILE *os, decl##_t *slist, size_t nsg, \
|
||||
skip_sprintf_node_##decl##_t fn) \
|
||||
{ \
|
||||
size_t level; \
|
||||
decl##_node_t *head; \
|
||||
if (nsg == 0) { \
|
||||
fprintf(os, "digraph Skiplist {\n"); \
|
||||
fprintf(os, "label = \"Skiplist.\"\n"); \
|
||||
fprintf(os, "graph [rankdir = \"LR\"];\n"); \
|
||||
fprintf(os, "node [fontsize = \"12\" shape = \"ellipse\"];\n"); \
|
||||
fprintf(os, "edge [];\n\n"); \
|
||||
} \
|
||||
fprintf(os, "subgraph cluster%zu {\n", nsg); \
|
||||
fprintf(os, "style=dashed\n"); \
|
||||
fprintf(os, "label=\"Skip list iteration %zu\"\n\n", nsg); \
|
||||
fprintf(os, "\"HeadNode%zu\" [\n", nsg); \
|
||||
fprintf(os, "label = \""); \
|
||||
\
|
||||
/* Write out the fields */ \
|
||||
head = slist->slh_head; \
|
||||
if (SKIP_EMPTY(slist)) \
|
||||
fprintf(os, "Empty HeadNode"); \
|
||||
else { \
|
||||
level = ARRAY_LENGTH(head->field.sle_next) - 1; \
|
||||
do { \
|
||||
decl##_node_t *node = head->field.sle_next[level]; \
|
||||
fprintf(os, "{ <f%zu> %p }", level, (void *)node); \
|
||||
if (level) \
|
||||
fprintf(os, " | "); \
|
||||
} while (level--); \
|
||||
} \
|
||||
fprintf(os, "\"\n"); \
|
||||
fprintf(os, "shape = \"record\"\n"); \
|
||||
fprintf(os, "];\n"); \
|
||||
\
|
||||
/* Edges for head node */ \
|
||||
decl##_node_t *node = slist->slh_head; \
|
||||
level = 0; \
|
||||
do { \
|
||||
fprintf(os, "\"HeadNode%zu\":f%zu -> ", nsg, level); \
|
||||
fprintf(os, "\"node%zu %p\"", nsg, (void *)node->field.sle_next[level]); \
|
||||
fprintf(os, ":w%zu [];\n", level); \
|
||||
} while (++level < slist->level); \
|
||||
fprintf(os, "}\n\n"); \
|
||||
\
|
||||
/* Now all nodes via level 0, if non-empty */ \
|
||||
node = prefix##skip_head_##decl(slist); \
|
||||
if (node) \
|
||||
__skip_dot_node_##decl(os, slist, node->field.sle_next[0], nsg, fn); \
|
||||
fprintf(os, "\n"); \
|
||||
\
|
||||
/* The tail, sentinal node */ \
|
||||
if (!SKIP_EMPTY(slist)) { \
|
||||
fprintf(os, "\"node%zu 0x0\" [label = \"", nsg); \
|
||||
level = slist->level; \
|
||||
do { \
|
||||
fprintf(os, "<w%zu> NULL", level); \
|
||||
if (level) \
|
||||
fprintf(os, " | "); \
|
||||
} while (--level); \
|
||||
fprintf(os, "\" shape = \"record\"];\n"); \
|
||||
} \
|
||||
\
|
||||
/* End: "subgraph cluster0 {" */ \
|
||||
fprintf(os, "}\n\n"); \
|
||||
nsg += 1; \
|
||||
\
|
||||
return nsg; \
|
||||
} \
|
||||
\
|
||||
/* -- skip_dot_ \
|
||||
* Create a DOT file of the internal representation of the \
|
||||
* Skiplist on the provided file descriptor (default: STDOUT). \
|
||||
* \
|
||||
* To view the output: \
|
||||
* $ dot -Tps filename.dot -o outfile.ps \
|
||||
* You can change the output format by varying the value after -T and \
|
||||
* choosing an appropriate filename extension after -o. \
|
||||
* See: https://graphviz.org/docs/outputs/ for the format options. \
|
||||
* \
|
||||
* https://en.wikipedia.org/wiki/DOT_(graph_description_language) \
|
||||
*/ \
|
||||
int prefix##skip_dot_##decl(FILE *os, decl##_t *slist, size_t nsg, \
|
||||
skip_sprintf_node_##decl##_t fn) \
|
||||
{ \
|
||||
if (__skip_integrity_check_##decl(slist) != 0) { \
|
||||
perror("Skiplist failed integrity checks, impossible to diagram."); \
|
||||
return -1; \
|
||||
} \
|
||||
if (os == NULL) \
|
||||
os = stdout; \
|
||||
if (!os) { \
|
||||
perror("Failed to open output file, unable to write DOT file."); \
|
||||
return -1; \
|
||||
} \
|
||||
__skip_dot_start_##decl(os, slist, nsg, fn); \
|
||||
__skip_dot_finish_##decl(os, nsg); \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
#endif /* _SKIPLIST_H_ */
|
||||
|
|
Loading…
Reference in a new issue