From 35f04e9d593c95ef3b00be66edd8ceae971a0323 Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Fri, 22 Mar 2024 15:03:06 -0400 Subject: [PATCH] integrity p2 --- examples/slm.c | 5 +- include/sl.h | 251 ++++++++++++++++++++++++++++--------------------- 2 files changed, 149 insertions(+), 107 deletions(-) diff --git a/examples/slm.c b/examples/slm.c index 78a2b26..90603d1 100644 --- a/examples/slm.c +++ b/examples/slm.c @@ -1,15 +1,18 @@ -#include #include #include #include #include #include +#include #include #include #include #include +#define DEBUG 1 +#define SKIPLIST_DEBUG slex + /* Setting this will do two things: * 1) limit our max height across all instances of this datastructure. * 2) remove a heap allocation on frequently used paths, insert/remove/etc. diff --git a/include/sl.h b/include/sl.h index 414d230..83d3974 100644 --- a/include/sl.h +++ b/include/sl.h @@ -139,6 +139,21 @@ #define SKIPLIST_MAX_HEIGHT 1 #endif +#if defined(SKIPLIST_DEBUG) +#ifndef SKIP_DEBUGF +#define SKIP_DEBUGF +#if defined(DEBUG) && DEBUG > 0 +#define __skip_debugf(...) \ + do { \ + fprintf(stderr, "%s:%d:%s(): ", __FILE__, __LINE__, __func__); \ + fprintf(stderr, __VA_ARGS__); \ + } while (0) +#else +#define __skip_debugf(fmt, args...) ((void)0) +#endif +#endif +#endif + /* * A Skip List contains elements, a portion of which is used to manage those * elements while the rest is defined by the use case for this declaration. The @@ -971,112 +986,136 @@ return NULL; \ } -#define SKIPLIST_INTEGRITY_CHECK(decl, prefix, field) \ - /* -- __skip_integrity_check_ */ \ - static int __skip_integrity_check_##decl(decl##_t *slist, int flags) \ - { \ - 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_INTEGRITY_CHECK(decl, prefix, field) \ + /* -- __skip_integrity_failure_ */ \ + static void __attribute__((format(printf, 1, 2))) __skip_integrity_failure_##decl(const char *fmt, ...) \ + { \ + va_list args; \ + __skip_debugf(fmt, args); \ + } \ + \ + /* -- __skip_integrity_check_ */ \ + static int __skip_integrity_check_##decl(decl##_t *slist, int flags) \ + { \ + size_t size; \ + unsigned nth, n_err = 0; \ + decl##_node_t *node; \ + struct __skiplist_##decl_idx *this, *that, *prev, *next; \ + \ + if (slist == NULL) { \ + __skip_integrity_failure_##decl("slist was NULL, nothing to check"); \ + n_err++; \ + return n_err; \ + } \ + \ + /* Check the Skiplist header (slh) */ \ + \ + if (slist->slh_head == NULL) { \ + __skip_integrity_failure_##decl("skiplist slh_head is NULL"); \ + n_err++; \ + return n_err; \ + } \ + \ + if (slist->slh_tail == NULL) { \ + __skip_integrity_failure_##decl("skiplist slh_tail is NULL"); \ + n_err++; \ + return n_err; \ + } \ + \ + if (slist->cmp == NULL) { \ + __skip_integrity_failure_##decl("skiplist comparison function (cmp) is NULL"); \ + n_err++; \ + return n_err; \ + } \ + \ + if (slist->max < 2) { \ + __skip_integrity_failure_##decl("skiplist max level must be 1 at minimum"); \ + n_err++; \ + if (flags) \ + return n_err; \ + } \ + \ + if (slist->level >= slist->max) { \ + /* level is 0-based, max of 12 means level cannot be > 11 */ \ + __skip_integrity_failure_##decl("skiplist level in header was >= max"); \ + n_err++; \ + if (flags) \ + return n_err; \ + } \ + \ + if (SKIPLIST_MAX_HEIGHT < 1) { \ + __skip_integrity_failure_##decl("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) { \ + __skip_integrity_failure_##decl("slist->max cannot be greater than SKIPLIST_MAX_HEIGHT"); \ + n_err++; \ + if (flags) \ + return n_err; \ + } \ + \ + node = slist->slh_head; \ + for (nth = 0; nth < node->field.sle.height; nth++) { \ + if (node->field.sle.next[nth] == NULL || node->field.sle.next[nth] == slist->slh_tail) { \ + __skip_integrity_failure_##decl("the head's %u next node reference should not be NULL or pointing to the tail", nth); \ + n_err++; \ + if (flags) \ + return n_err; \ + } \ + } \ + for (; nth < slist->max; nth++) { \ + if (node->field.sle.next[nth] != slist->slh_tail) { \ + __skip_integrity_failure_##decl("the head's %u next node reference above it's current height should always point to the tail", nth); \ + n_err++; \ + if (flags) \ + return n_err; \ + } \ + } \ + \ + if (slist->length > 0 && slist->slh_tail->field.sle.prev != slist->slh_head) { \ + __skip_integrity_failure_##decl("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); \ + while (node) { \ + this = &node->field.sle; \ + if (this->next == NULL) { \ + __skip_integrity_failure_##decl("the %u node's [%p] next field should never NULL", nth, (void *)node); \ + n_err++; \ + if (flags) \ + return n_err; \ + } \ + if (this->prev == NULL) { \ + __skip_integrity_failure_##decl("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)) { \ + __skip_integrity_failure_##decl("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++; \ + } \ + \ + return 0; \ } #define SKIPLIST_KV_ACCESS(decl, prefix, ktype, vtype, qblk, rblk) \