integrity p1
This commit is contained in:
parent
5481b99725
commit
64ac937a6a
2 changed files with 119 additions and 17 deletions
|
@ -56,6 +56,13 @@ SKIPLIST_DECL(
|
||||||
/* size in bytes of the content stored in an entry by you */
|
/* size in bytes of the content stored in an entry by you */
|
||||||
{ size = strlen(node->value) + 1; })
|
{ size = strlen(node->value) + 1; })
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Optional: Create a function that validates as much as possible the
|
||||||
|
* integrity of a Skiplist. This is called by the DOT function to
|
||||||
|
* ensure that it's possible to generate a graph.
|
||||||
|
*/
|
||||||
|
SKIPLIST_INTEGRITY_CHECK(slex, api_, entries)
|
||||||
|
|
||||||
/* Optional: Create the functions used to visualize a Skiplist (DOT/Graphviz) */
|
/* Optional: Create the functions used to visualize a Skiplist (DOT/Graphviz) */
|
||||||
SKIPLIST_DECL_DOT(slex, api_, entries)
|
SKIPLIST_DECL_DOT(slex, api_, entries)
|
||||||
|
|
||||||
|
|
129
include/sl.h
129
include/sl.h
|
@ -148,19 +148,13 @@
|
||||||
* levels).
|
* levels).
|
||||||
*/
|
*/
|
||||||
#define SKIPLIST_ENTRY(type) \
|
#define SKIPLIST_ENTRY(type) \
|
||||||
struct __skiplist_entry { \
|
struct __skiplist_##decl_entry { \
|
||||||
struct __skiplist_idx { \
|
struct __skiplist_##decl_idx { \
|
||||||
struct type *prev, **next; \
|
struct type *prev, **next; \
|
||||||
size_t height; \
|
size_t height; \
|
||||||
} sle; \
|
} sle; \
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Skip List access methods.
|
|
||||||
*/
|
|
||||||
#define SKIP_FIRST(head) ((head)->slh_head)
|
|
||||||
#define SKIP_LAST(head) ((head)->slh_tail)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Skip List node comparison function. This macro builds a function used when
|
* Skip List node comparison function. This macro builds a function used when
|
||||||
* comparing two nodes for equality. A portion of this function, `fn_blk`, is
|
* comparing two nodes for equality. A portion of this function, `fn_blk`, is
|
||||||
|
@ -306,7 +300,7 @@
|
||||||
decl##_node_t *n; \
|
decl##_node_t *n; \
|
||||||
/* Calculate the size of the struct sle within decl##_node_t, multiply \
|
/* Calculate the size of the struct sle within decl##_node_t, multiply \
|
||||||
by array size. (16/24 bytes on 32/64 bit systems) */ \
|
by array size. (16/24 bytes on 32/64 bit systems) */ \
|
||||||
size_t sle_arr_sz = sizeof(struct __skiplist_idx) * slist->max; \
|
size_t sle_arr_sz = sizeof(struct __skiplist_##decl_idx) * slist->max; \
|
||||||
n = (decl##_node_t *)calloc(1, sizeof(decl##_node_t) + sle_arr_sz); \
|
n = (decl##_node_t *)calloc(1, sizeof(decl##_node_t) + sle_arr_sz); \
|
||||||
if (n == NULL) \
|
if (n == NULL) \
|
||||||
return ENOMEM; \
|
return ENOMEM; \
|
||||||
|
@ -975,13 +969,114 @@
|
||||||
if (slist->slh_tail) \
|
if (slist->slh_tail) \
|
||||||
free(slist->slh_tail); \
|
free(slist->slh_tail); \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
} \
|
}
|
||||||
\
|
|
||||||
/* -- __skip_integrity_check_ TODO */ \
|
#define SKIPLIST_INTEGRITY_CHECK(decl, prefix, field) \
|
||||||
static int __skip_integrity_check_##decl(decl##_t *slist) \
|
/* -- __skip_integrity_check_ */ \
|
||||||
{ \
|
static int __skip_integrity_check_##decl(decl##_t *slist, int flags) \
|
||||||
((void)slist); \
|
{ \
|
||||||
return 0; \
|
unsigned nth, n_err = 0; \
|
||||||
|
size_t size; \
|
||||||
|
FILE *of = stderr; \
|
||||||
|
decl##_node_t *node; \
|
||||||
|
struct __skiplist_##decl_idx *this, *that, *prev, *next; \
|
||||||
|
\
|
||||||
|
if (slist == NULL) { \
|
||||||
|
fprintf(of, "slist was NULL, nothing to check"); \
|
||||||
|
n_err++; \
|
||||||
|
return n_err; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* Check the Skiplist header (slh) */ \
|
||||||
|
\
|
||||||
|
if (slist->slh_head == NULL) { \
|
||||||
|
fprintf(of, "skiplist slh_head is NULL"); \
|
||||||
|
n_err++; \
|
||||||
|
return n_err; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
if (slist->slh_tail == NULL) { \
|
||||||
|
fprintf(of, "skiplist slh_tail is NULL"); \
|
||||||
|
n_err++; \
|
||||||
|
return n_err; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
if (slist->cmp == NULL) { \
|
||||||
|
fprintf(of, "skiplist comparison function (cmp) is NULL"); \
|
||||||
|
n_err++; \
|
||||||
|
return n_err; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
if (slist->level >= slist->max) { \
|
||||||
|
/* level is 0-based, max of 12 means level cannot be > 11 */ \
|
||||||
|
fprintf(of, "skiplist level in header was >= max"); \
|
||||||
|
n_err++; \
|
||||||
|
if (flags) \
|
||||||
|
return n_err; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
if (SKIPLIST_MAX_HEIGHT < 1) { \
|
||||||
|
fprintf(of, "SKIPLIST_MAX_HEIGHT cannot be less than 1"); \
|
||||||
|
n_err++; \
|
||||||
|
if (flags) \
|
||||||
|
return n_err; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
if (SKIPLIST_MAX_HEIGHT > 0 && slist->max > SKIPLIST_MAX_HEIGHT) { \
|
||||||
|
fprintf(of, "slist->max cannot be greater than SKIPLIST_MAX_HEIGHT"); \
|
||||||
|
n_err++; \
|
||||||
|
if (flags) \
|
||||||
|
return n_err; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
if (slist->length > 0 && slist->slh_head->field.sle.next[0] != slist->slh_tail) { \
|
||||||
|
fprintf(of, "slist->length is 0, but head->next == tail, not an internal node"); \
|
||||||
|
n_err++; \
|
||||||
|
if (flags) \
|
||||||
|
return n_err; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
if (slist->length > 0 && slist->slh_tail->field.sle.prev != slist->slh_head) { \
|
||||||
|
fprintf(of, "slist->length is 0, but tail->prev == head, not an internal node"); \
|
||||||
|
n_err++; \
|
||||||
|
if (flags) \
|
||||||
|
return n_err; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* Validate the head node */ \
|
||||||
|
\
|
||||||
|
/* Validate the tail node */ \
|
||||||
|
\
|
||||||
|
/* Validate each node */ \
|
||||||
|
nth = 0; \
|
||||||
|
size = prefix##skip_size_##decl(slist); \
|
||||||
|
node = prefix##skip_head_##decl(slist); \
|
||||||
|
do { \
|
||||||
|
this = &node->field.sle; \
|
||||||
|
if (this->next == NULL) { \
|
||||||
|
fprintf(of, "the %u node's [%p] next field should never NULL", nth, (void *)node); \
|
||||||
|
n_err++; \
|
||||||
|
if (flags) \
|
||||||
|
return n_err; \
|
||||||
|
} \
|
||||||
|
if (this->prev == NULL) { \
|
||||||
|
fprintf(of, "the %u node [%p] prev field should never NULL", nth, (void *)node); \
|
||||||
|
n_err++; \
|
||||||
|
if (flags) \
|
||||||
|
return n_err; \
|
||||||
|
} \
|
||||||
|
if (*this->next != node + (sizeof(struct __skiplist_##decl_idx) * slist->max)) { \
|
||||||
|
fprintf(of, "the %u node's [%p] next field isn't at the proper offset relative to the node", nth, (void *)node); \
|
||||||
|
n_err++; \
|
||||||
|
if (flags) \
|
||||||
|
return n_err; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
node = prefix##skip_next_node_##decl(slist, node); \
|
||||||
|
nth++; \
|
||||||
|
} while (node != NULL); \
|
||||||
|
\
|
||||||
|
return 0; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SKIPLIST_KV_ACCESS(decl, prefix, ktype, vtype, qblk, rblk) \
|
#define SKIPLIST_KV_ACCESS(decl, prefix, ktype, vtype, qblk, rblk) \
|
||||||
|
@ -1177,7 +1272,7 @@
|
||||||
\
|
\
|
||||||
if (slist == NULL || fn == NULL) \
|
if (slist == NULL || fn == NULL) \
|
||||||
return nsg; \
|
return nsg; \
|
||||||
if (__skip_integrity_check_##decl(slist) != 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; \
|
||||||
} \
|
} \
|
||||||
|
|
Loading…
Reference in a new issue