moving more to decl
This commit is contained in:
parent
a1c08f6fd8
commit
e8d3645ed4
12 changed files with 3071 additions and 3018 deletions
|
@ -99,9 +99,9 @@ IndentPPDirectives: None
|
||||||
Language: Cpp
|
Language: Cpp
|
||||||
NamespaceIndentation: None
|
NamespaceIndentation: None
|
||||||
PointerAlignment: Right
|
PointerAlignment: Right
|
||||||
ContinuationIndentWidth: 4
|
ContinuationIndentWidth: 2
|
||||||
IndentWidth: 4
|
IndentWidth: 2
|
||||||
TabWidth: 4
|
TabWidth: 2
|
||||||
ColumnLimit: 80
|
ColumnLimit: 80
|
||||||
UseTab: Never
|
UseTab: Never
|
||||||
SpaceAfterCStyleCast: false
|
SpaceAfterCStyleCast: false
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
# Generated from CLion Inspection settings
|
# Generated from CLion Inspection settings
|
||||||
#bugprone-reserved-identifier,
|
#bugprone-reserved-identifier,
|
||||||
|
#misc-no-recursion,
|
||||||
---
|
---
|
||||||
Checks: '-*,
|
Checks: '-*,
|
||||||
-deprecated-non-prototype
|
-deprecated-non-prototype
|
||||||
|
@ -74,7 +75,6 @@ hicpp-exception-baseclass,
|
||||||
hicpp-multiway-paths-covered,
|
hicpp-multiway-paths-covered,
|
||||||
misc-misplaced-const,
|
misc-misplaced-const,
|
||||||
misc-new-delete-overloads,
|
misc-new-delete-overloads,
|
||||||
misc-no-recursion,
|
|
||||||
misc-non-copyable-objects,
|
misc-non-copyable-objects,
|
||||||
misc-throw-by-value-catch-by-reference,
|
misc-throw-by-value-catch-by-reference,
|
||||||
misc-unconventional-assign-operator,
|
misc-unconventional-assign-operator,
|
||||||
|
|
6
Makefile
6
Makefile
|
@ -44,7 +44,7 @@ clean:
|
||||||
rm -f $(EXAMPLES)
|
rm -f $(EXAMPLES)
|
||||||
|
|
||||||
format:
|
format:
|
||||||
clang-format -i include/*.h src/*.c tests/*.c tests/*.h
|
clang-format -i include/*.h src/*.c tests/*.c tests/*.h examples/*.c
|
||||||
|
|
||||||
%.o: src/%.c
|
%.o: src/%.c
|
||||||
$(CC) $(CFLAGS) -c -o $@ $^
|
$(CC) $(CFLAGS) -c -o $@ $^
|
||||||
|
@ -60,3 +60,7 @@ examples/mls.c: examples/slm.c
|
||||||
|
|
||||||
examples/mls: examples/mls.o $(STATIC_LIB)
|
examples/mls: examples/mls.o $(STATIC_LIB)
|
||||||
$(CC) $^ -o $@ $(CFLAGS) $(TEST_FLAGS) -pthread
|
$(CC) $^ -o $@ $(CFLAGS) $(TEST_FLAGS) -pthread
|
||||||
|
|
||||||
|
#dot:
|
||||||
|
# ./examples/mls
|
||||||
|
# dot -Tpdf /tmp/slm.dot -o /tmp/slm.pdf >/dev/null 2>&1
|
||||||
|
|
238
examples/skip.c
238
examples/skip.c
|
@ -8,30 +8,30 @@
|
||||||
|
|
||||||
// Define a node that contains key and value pair.
|
// Define a node that contains key and value pair.
|
||||||
struct my_node {
|
struct my_node {
|
||||||
// Metadata for skiplist node.
|
// Metadata for skiplist node.
|
||||||
sl_node snode;
|
sl_node snode;
|
||||||
// My data here: {int, int} pair.
|
// My data here: {int, int} pair.
|
||||||
int key;
|
int key;
|
||||||
int value;
|
int value;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Define a comparison function for `my_node`.
|
// Define a comparison function for `my_node`.
|
||||||
static int
|
static int
|
||||||
my_cmp(sl_node *a, sl_node *b, void *aux)
|
my_cmp(sl_node *a, sl_node *b, void *aux)
|
||||||
{
|
{
|
||||||
// Get `my_node` from skiplist node `a` and `b`.
|
// Get `my_node` from skiplist node `a` and `b`.
|
||||||
struct my_node *aa, *bb;
|
struct my_node *aa, *bb;
|
||||||
aa = sl_get_entry(a, struct my_node, snode);
|
aa = sl_get_entry(a, struct my_node, snode);
|
||||||
bb = sl_get_entry(b, struct my_node, snode);
|
bb = sl_get_entry(b, struct my_node, snode);
|
||||||
|
|
||||||
// aa < bb: return neg
|
// aa < bb: return neg
|
||||||
// aa == bb: return 0
|
// aa == bb: return 0
|
||||||
// aa > bb: return pos
|
// aa > bb: return pos
|
||||||
if (aa->key < bb->key)
|
if (aa->key < bb->key)
|
||||||
return -1;
|
return -1;
|
||||||
if (aa->key > bb->key)
|
if (aa->key > bb->key)
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define NUM_NODES 10000
|
#define NUM_NODES 10000
|
||||||
|
@ -39,118 +39,116 @@ my_cmp(sl_node *a, sl_node *b, void *aux)
|
||||||
int
|
int
|
||||||
main()
|
main()
|
||||||
{
|
{
|
||||||
// seed the PRNG
|
// seed the PRNG
|
||||||
srandom((unsigned)(time(NULL) | getpid()));
|
srandom((unsigned)(time(NULL) | getpid()));
|
||||||
|
|
||||||
sl_raw slist;
|
sl_raw slist;
|
||||||
|
|
||||||
// Initialize skiplist.
|
// Initialize skiplist.
|
||||||
sl_init(&slist, my_cmp);
|
sl_init(&slist, my_cmp);
|
||||||
|
|
||||||
// << Insertion >>
|
// << Insertion >>
|
||||||
// Allocate & insert NUM_NODES KV pairs: {0, 0}, {1, 10}, {2, 20}.
|
// Allocate & insert NUM_NODES KV pairs: {0, 0}, {1, 10}, {2, 20}.
|
||||||
struct my_node *nodes[NUM_NODES];
|
struct my_node *nodes[NUM_NODES];
|
||||||
for (int i = 0; i < NUM_NODES; ++i) {
|
for (int i = 0; i < NUM_NODES; ++i) {
|
||||||
// Allocate memory.
|
// Allocate memory.
|
||||||
nodes[i] = (struct my_node *)malloc(sizeof(struct my_node));
|
nodes[i] = (struct my_node *)malloc(sizeof(struct my_node));
|
||||||
// Initialize node.
|
// Initialize node.
|
||||||
sl_init_node(&nodes[i]->snode);
|
sl_init_node(&nodes[i]->snode);
|
||||||
// Assign key and value.
|
// Assign key and value.
|
||||||
nodes[i]->key = i;
|
nodes[i]->key = i;
|
||||||
nodes[i]->value = i * 10;
|
nodes[i]->value = i * 10;
|
||||||
// Insert into skiplist.
|
// Insert into skiplist.
|
||||||
sl_insert(&slist, &nodes[i]->snode);
|
sl_insert(&slist, &nodes[i]->snode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// << Point lookup >>
|
||||||
|
for (int i = 0; i < NUM_NODES; ++i) {
|
||||||
|
// Define a query.
|
||||||
|
struct my_node query;
|
||||||
|
int min = 1, max = NUM_NODES - 1;
|
||||||
|
int k = min + (int)random() / (RAND_MAX / (max - min + 1) + 1);
|
||||||
|
query.key = k;
|
||||||
|
// Find a skiplist node `cursor`.
|
||||||
|
sl_node *cursor = sl_find(&slist, &query.snode);
|
||||||
|
// If `cursor` is NULL, key doesn't exist.
|
||||||
|
if (!cursor)
|
||||||
|
continue;
|
||||||
|
// Get `my_node` from `cursor`.
|
||||||
|
// Note: found->snode == *cursor
|
||||||
|
struct my_node *found = sl_get_entry(cursor, struct my_node, snode);
|
||||||
|
printf("[point lookup] key: %d, value: %d\n", found->key, found->value);
|
||||||
|
if (found->key != found->value / 10) {
|
||||||
|
printf("FAILURE: key: %d * 10 != value: %d\n", found->key, found->value);
|
||||||
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
// Release `cursor` (== &found->snode).
|
||||||
|
// Other thread cannot free `cursor` until `cursor` is released.
|
||||||
|
sl_release_node(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
// << Point lookup >>
|
// << Erase >>
|
||||||
for (int i = 0; i < NUM_NODES; ++i) {
|
// Erase the KV pair for key 1: {1, 10}.
|
||||||
// Define a query.
|
{
|
||||||
struct my_node query;
|
// Define a query.
|
||||||
int min = 1, max = NUM_NODES - 1;
|
struct my_node query;
|
||||||
int k = min + (int)random() / (RAND_MAX / (max - min + 1) + 1);
|
query.key = 1;
|
||||||
query.key = k;
|
// Find a skiplist node `cursor`.
|
||||||
// Find a skiplist node `cursor`.
|
sl_node *cursor = sl_find(&slist, &query.snode);
|
||||||
sl_node *cursor = sl_find(&slist, &query.snode);
|
// Get `my_node` from `cursor`.
|
||||||
// If `cursor` is NULL, key doesn't exist.
|
// Note: found->snode == *cursor
|
||||||
if (!cursor)
|
struct my_node *found = sl_get_entry(cursor, struct my_node, snode);
|
||||||
continue;
|
printf("[erase] key: %d, value: %d\n", found->key, found->value);
|
||||||
// Get `my_node` from `cursor`.
|
|
||||||
// Note: found->snode == *cursor
|
// Detach `found` from skiplist.
|
||||||
struct my_node *found = sl_get_entry(cursor, struct my_node, snode);
|
sl_erase_node(&slist, &found->snode);
|
||||||
printf("[point lookup] key: %d, value: %d\n", found->key, found->value);
|
// Release `found`, to free its memory.
|
||||||
if (found->key != found->value / 10) {
|
sl_release_node(&found->snode);
|
||||||
printf("FAILURE: key: %d * 10 != value: %d\n", found->key,
|
// Free `found` after it becomes safe.
|
||||||
found->value);
|
sl_wait_for_free(&found->snode);
|
||||||
exit(-1);
|
sl_free_node(&found->snode);
|
||||||
}
|
free(found);
|
||||||
// Release `cursor` (== &found->snode).
|
}
|
||||||
// Other thread cannot free `cursor` until `cursor` is released.
|
|
||||||
sl_release_node(cursor);
|
// << Iteration >>
|
||||||
|
{
|
||||||
|
// Get the first cursor.
|
||||||
|
sl_node *cursor = sl_begin(&slist);
|
||||||
|
while (cursor) {
|
||||||
|
// Get `entry` from `cursor`.
|
||||||
|
// Note: entry->snode == *cursor
|
||||||
|
struct my_node *entry = sl_get_entry(cursor, struct my_node, snode);
|
||||||
|
printf("[iteration] key: %d, value: %d\n", entry->key, entry->value);
|
||||||
|
// Get next `cursor`.
|
||||||
|
cursor = sl_next(&slist, cursor);
|
||||||
|
// Release `entry`.
|
||||||
|
sl_release_node(&entry->snode);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// << Erase >>
|
// << Destroy >>
|
||||||
// Erase the KV pair for key 1: {1, 10}.
|
{
|
||||||
{
|
// Iterate and free all nodes.
|
||||||
// Define a query.
|
sl_node *cursor = sl_begin(&slist);
|
||||||
struct my_node query;
|
while (cursor) {
|
||||||
query.key = 1;
|
struct my_node *entry = sl_get_entry(cursor, struct my_node, snode);
|
||||||
// Find a skiplist node `cursor`.
|
printf("[destroy] key: %d, value: %d\n", entry->key, entry->value);
|
||||||
sl_node *cursor = sl_find(&slist, &query.snode);
|
// Get next `cursor`.
|
||||||
// Get `my_node` from `cursor`.
|
cursor = sl_next(&slist, cursor);
|
||||||
// Note: found->snode == *cursor
|
|
||||||
struct my_node *found = sl_get_entry(cursor, struct my_node, snode);
|
|
||||||
printf("[erase] key: %d, value: %d\n", found->key, found->value);
|
|
||||||
|
|
||||||
// Detach `found` from skiplist.
|
// Detach `entry` from skiplist.
|
||||||
sl_erase_node(&slist, &found->snode);
|
sl_erase_node(&slist, &entry->snode);
|
||||||
// Release `found`, to free its memory.
|
// Release `entry`, to free its memory.
|
||||||
sl_release_node(&found->snode);
|
sl_release_node(&entry->snode);
|
||||||
// Free `found` after it becomes safe.
|
// Free `entry` after it becomes safe.
|
||||||
sl_wait_for_free(&found->snode);
|
sl_wait_for_free(&entry->snode);
|
||||||
sl_free_node(&found->snode);
|
sl_free_node(&entry->snode);
|
||||||
free(found);
|
free(entry);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// << Iteration >>
|
// Free skiplist.
|
||||||
{
|
sl_free(&slist);
|
||||||
// Get the first cursor.
|
|
||||||
sl_node *cursor = sl_begin(&slist);
|
|
||||||
while (cursor) {
|
|
||||||
// Get `entry` from `cursor`.
|
|
||||||
// Note: entry->snode == *cursor
|
|
||||||
struct my_node *entry = sl_get_entry(cursor, struct my_node, snode);
|
|
||||||
printf("[iteration] key: %d, value: %d\n", entry->key,
|
|
||||||
entry->value);
|
|
||||||
// Get next `cursor`.
|
|
||||||
cursor = sl_next(&slist, cursor);
|
|
||||||
// Release `entry`.
|
|
||||||
sl_release_node(&entry->snode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// << Destroy >>
|
return 0;
|
||||||
{
|
|
||||||
// Iterate and free all nodes.
|
|
||||||
sl_node *cursor = sl_begin(&slist);
|
|
||||||
while (cursor) {
|
|
||||||
struct my_node *entry = sl_get_entry(cursor, struct my_node, snode);
|
|
||||||
printf("[destroy] key: %d, value: %d\n", entry->key, entry->value);
|
|
||||||
// Get next `cursor`.
|
|
||||||
cursor = sl_next(&slist, cursor);
|
|
||||||
|
|
||||||
// Detach `entry` from skiplist.
|
|
||||||
sl_erase_node(&slist, &entry->snode);
|
|
||||||
// Release `entry`, to free its memory.
|
|
||||||
sl_release_node(&entry->snode);
|
|
||||||
// Free `entry` after it becomes safe.
|
|
||||||
sl_wait_for_free(&entry->snode);
|
|
||||||
sl_free_node(&entry->snode);
|
|
||||||
free(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Free skiplist.
|
|
||||||
sl_free(&slist);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#include <stdio.h>
|
#include <errno.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <errno.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "../include/sl.h"
|
#include "../include/sl.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -49,54 +49,61 @@ struct slex_node {
|
||||||
* list or when `a == b`. In those cases the comparison function
|
* list or when `a == b`. In those cases the comparison function
|
||||||
* returns before using the code in your block, don't panic. :)
|
* returns before using the code in your block, don't panic. :)
|
||||||
*/
|
*/
|
||||||
SKIPLIST_DECL(slex, api_, entries, {
|
SKIPLIST_DECL(slex, api_, entries)
|
||||||
(void)aux;
|
int
|
||||||
if (a->key < b->key)
|
__slm_key_compare(slex_t *list, slex_node_t *a, slex_node_t *b, void *aux)
|
||||||
return -1;
|
{
|
||||||
if (a->key > b->key)
|
(void)list;
|
||||||
return 1;
|
(void)aux;
|
||||||
return 0;
|
if (a->key < b->key)
|
||||||
})
|
return -1;
|
||||||
|
if (a->key > b->key)
|
||||||
void sprintf_slex_node(slex_node_t *node, char *buf) {
|
return 1;
|
||||||
sprintf(buf, "%d", node->key);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
#define DOT
|
||||||
/* Allocate and initialize a Skiplist. */
|
#ifdef DOT
|
||||||
slex_t _list = SKIP_HEAD_DEFAULT_INITIALIZER(__skip_key_compare_slex);
|
/* Also declare the functions used to visualize a Sliplist (DOT/Graphviz) */
|
||||||
_list.slh_tail = (struct slex_node *)&_list.slh_head; // TODO...
|
SKIPLIST_DECL_DOT(slex, api_, entries)
|
||||||
/* Dynamic allocation, init. */
|
|
||||||
slex_t *list = (slex_t *)malloc(sizeof(slex_t));
|
void
|
||||||
SKIP_DEFAULT_INIT(list, __skip_key_compare_slex, slex_node, entries);
|
sprintf_slex_node(slex_node_t *node, char *buf)
|
||||||
#ifdef STATIC_INIT
|
{
|
||||||
free(list);
|
sprintf(buf, "%d:%d", node->key, node->value);
|
||||||
slex_t *list = &_list;
|
}
|
||||||
#else
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct slex_node *n;
|
int
|
||||||
SKIP_ALLOC_NODE(list, n, slex_node, entries);
|
main()
|
||||||
n->key = -1;
|
{
|
||||||
n->value = -1;
|
int rc = 0;
|
||||||
api_skip_insert_slex(list, n);
|
/* Allocate and initialize a Skiplist. */
|
||||||
|
slex_t *list = (slex_t *)malloc(sizeof(slex_t));
|
||||||
|
if (list == NULL) {
|
||||||
|
rc = ENOMEM;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
rc = api_skip_init_slex(list, 12, 4, __slm_key_compare);
|
||||||
|
|
||||||
FILE* of = fopen("/tmp/slm.dot", "w");
|
struct slex_node *n;
|
||||||
|
|
||||||
|
/* Insert 7 key/value pairs into the list. */
|
||||||
|
for (int i = -2; i <= 2; i++) {
|
||||||
|
SKIP_ALLOC_NODE(list, n, slex_node, entries);
|
||||||
|
n->key = i;
|
||||||
|
n->value = i;
|
||||||
|
api_skip_insert_slex(list, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *of = fopen("/tmp/slm.dot", "w");
|
||||||
if (!of) {
|
if (!of) {
|
||||||
perror("Failed to open file /tmp/slm.dot");
|
perror("Failed to open file /tmp/slm.dot");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
api_skip_dot_slex(of, list, sprintf_slex_node);
|
api_skip_dot_slex(of, list, sprintf_slex_node);
|
||||||
fclose(of);
|
fclose(of);
|
||||||
|
|
||||||
/* Insert 10 key/value pairs into the list. */
|
|
||||||
for (int i = 0; i < 10; i++) {
|
|
||||||
SKIP_ALLOC_NODE(list, n, slex_node, entries);
|
|
||||||
n->key = i;
|
|
||||||
n->value = i;
|
|
||||||
api_skip_insert_slex(list, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/* Delete a specific element in the list. */
|
/* Delete a specific element in the list. */
|
||||||
struct slex_node query;
|
struct slex_node query;
|
||||||
|
@ -124,5 +131,6 @@ int main() {
|
||||||
}
|
}
|
||||||
SKIP_INIT(&head);
|
SKIP_INIT(&head);
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
fail:;
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,13 +50,13 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct _sl_node {
|
typedef struct _sl_node {
|
||||||
atm_node_ptr *next;
|
atm_node_ptr *next;
|
||||||
atm_bool is_fully_linked;
|
atm_bool is_fully_linked;
|
||||||
atm_bool being_modified;
|
atm_bool being_modified;
|
||||||
atm_bool removed;
|
atm_bool removed;
|
||||||
uint8_t top_layer; /* 0: bottom */
|
uint8_t top_layer; /* 0: bottom */
|
||||||
atm_uint16_t ref_count;
|
atm_uint16_t ref_count;
|
||||||
atm_uint32_t accessing_next;
|
atm_uint32_t accessing_next;
|
||||||
} sl_node;
|
} sl_node;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -67,26 +67,26 @@ typedef struct _sl_node {
|
||||||
typedef int sl_cmp_t(sl_node *a, sl_node *b, void *aux);
|
typedef int sl_cmp_t(sl_node *a, sl_node *b, void *aux);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
size_t fanout;
|
size_t fanout;
|
||||||
size_t maxLayer;
|
size_t maxLayer;
|
||||||
void *aux;
|
void *aux;
|
||||||
} sl_raw_config;
|
} sl_raw_config;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
sl_node head;
|
sl_node head;
|
||||||
sl_node tail;
|
sl_node tail;
|
||||||
sl_cmp_t *cmp_func;
|
sl_cmp_t *cmp_func;
|
||||||
void *aux;
|
void *aux;
|
||||||
atm_uint32_t num_entries;
|
atm_uint32_t num_entries;
|
||||||
atm_uint32_t *layer_entries;
|
atm_uint32_t *layer_entries;
|
||||||
atm_uint8_t top_layer;
|
atm_uint8_t top_layer;
|
||||||
uint8_t fanout;
|
uint8_t fanout;
|
||||||
uint8_t max_layer;
|
uint8_t max_layer;
|
||||||
} sl_raw;
|
} sl_raw;
|
||||||
|
|
||||||
#ifndef sl_get_entry
|
#ifndef sl_get_entry
|
||||||
#define sl_get_entry(ELEM, STRUCT, MEMBER) \
|
#define sl_get_entry(ELEM, STRUCT, MEMBER) \
|
||||||
((STRUCT *)((uint8_t *)(ELEM)-offsetof(STRUCT, MEMBER)))
|
((STRUCT *)((uint8_t *)(ELEM)-offsetof(STRUCT, MEMBER)))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void sl_init(sl_raw *slist, sl_cmp_t *cmp_func);
|
void sl_init(sl_raw *slist, sl_cmp_t *cmp_func);
|
||||||
|
|
907
include/sl.h
907
include/sl.h
|
@ -30,8 +30,8 @@
|
||||||
* - async_nif.h
|
* - async_nif.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _SYS_SKIPLIST_H_
|
#ifndef _SYS_SKIPLIST_H_
|
||||||
#define _SYS_SKIPLIST_H_
|
#define _SYS_SKIPLIST_H_
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file defines a skiplist data structure with a similar API to those
|
* This file defines a skiplist data structure with a similar API to those
|
||||||
|
@ -68,40 +68,44 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define SKIPLIST_MACRO_DEBUG 0
|
#define SKIPLIST_MACRO_DEBUG 0
|
||||||
#if SKIPLIST_MACRO_DEBUG
|
#if SKIPLIST_MACRO_DEBUG
|
||||||
/* Store the last 2 places the element or head was altered */
|
/* Store the last 2 places the element or head was altered */
|
||||||
struct sl_trace {
|
struct sl_trace {
|
||||||
char * lastfile;
|
char *lastfile;
|
||||||
int lastline;
|
int lastline;
|
||||||
char * prevfile;
|
char *prevfile;
|
||||||
int prevline;
|
int prevline;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TRACEBUF struct sl_trace trace;
|
#define TRACEBUF struct sl_trace trace;
|
||||||
#define TRASHIT(x) do {(x) = (void *)-1;} while (0)
|
#define TRASHIT(x) \
|
||||||
|
do { \
|
||||||
|
(x) = (void *)-1; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define SLD_TRACE_HEAD(head) do { \
|
#define SLD_TRACE_HEAD(head) \
|
||||||
(head)->trace.prevline = (head)->trace.lastline; \
|
do { \
|
||||||
(head)->trace.prevfile = (head)->trace.lastfile; \
|
(head)->trace.prevline = (head)->trace.lastline; \
|
||||||
(head)->trace.lastline = __LINE__; \
|
(head)->trace.prevfile = (head)->trace.lastfile; \
|
||||||
(head)->trace.lastfile = __FILE__; \
|
(head)->trace.lastline = __LINE__; \
|
||||||
} while (0)
|
(head)->trace.lastfile = __FILE__; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define SLD_TRACE_ELEM(elem) do { \
|
#define SLD_TRACE_ELEM(elem) \
|
||||||
(elem)->trace.prevline = (elem)->trace.lastline; \
|
do { \
|
||||||
(elem)->trace.prevfile = (elem)->trace.lastfile; \
|
(elem)->trace.prevline = (elem)->trace.lastline; \
|
||||||
(elem)->trace.lastline = __LINE__; \
|
(elem)->trace.prevfile = (elem)->trace.lastfile; \
|
||||||
(elem)->trace.lastfile = __FILE__; \
|
(elem)->trace.lastline = __LINE__; \
|
||||||
} while (0)
|
(elem)->trace.lastfile = __FILE__; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define SLD_TRACE_ELEM(elem)
|
#define SLD_TRACE_ELEM(elem)
|
||||||
#define SLD_TRACE_HEAD(head)
|
#define SLD_TRACE_HEAD(head)
|
||||||
#define TRACEBUF
|
#define TRACEBUF
|
||||||
#define TRASHIT(x)
|
#define TRASHIT(x)
|
||||||
#endif /* QUEUE_MACRO_DEBUG */
|
#endif /* QUEUE_MACRO_DEBUG */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Private, internal API.
|
* Private, internal API.
|
||||||
|
@ -113,14 +117,15 @@ struct sl_trace {
|
||||||
* can grow to (`array[-2]`) and the length, or number of elements used in the
|
* can grow to (`array[-2]`) and the length, or number of elements used in the
|
||||||
* array so far (`array[-1]`).
|
* array so far (`array[-1]`).
|
||||||
*/
|
*/
|
||||||
#define ARRAY_ALLOC(var, type, size) do { \
|
#define ARRAY_ALLOC(var, type, size) \
|
||||||
(size) = (size == 0 ? 254 : size); \
|
do { \
|
||||||
(var) = (type**)calloc(sizeof(type*), size + 2); \
|
(size) = (size == 0 ? 254 : size); \
|
||||||
if ((var) != NULL) { \
|
(var) = (type **)calloc(sizeof(type *), size + 2); \
|
||||||
*(var)++ = (type *)size; \
|
if ((var) != NULL) { \
|
||||||
*(var)++ = 0; \
|
*(var)++ = (type *)size; \
|
||||||
} \
|
*(var)++ = 0; \
|
||||||
} while(0)
|
} \
|
||||||
|
} while (0)
|
||||||
#define ARRAY_FREE(var) free((var)-2)
|
#define ARRAY_FREE(var) free((var)-2)
|
||||||
#define ARRAY_SIZE(list) (unsigned int)(uintptr_t)(list)[-2]
|
#define ARRAY_SIZE(list) (unsigned int)(uintptr_t)(list)[-2]
|
||||||
#define ARRAY_SET_SIZE(list, size) (list)[-2] = (void *)(uintptr_t)(size)
|
#define ARRAY_SET_SIZE(list, size) (list)[-2] = (void *)(uintptr_t)(size)
|
||||||
|
@ -130,414 +135,492 @@ struct sl_trace {
|
||||||
/*
|
/*
|
||||||
* Skiplist declarations.
|
* Skiplist declarations.
|
||||||
*/
|
*/
|
||||||
#define SKIP_HEAD(name, type) \
|
#define SKIP_HEAD(name, type) \
|
||||||
struct name { \
|
struct name { \
|
||||||
size_t level, length, max, fanout; \
|
size_t level, length, max, fanout; \
|
||||||
int (*cmp)(struct name *, struct type *, struct type *, void *); \
|
int (*cmp)(struct name *, struct type *, struct type *, void *); \
|
||||||
void *aux; \
|
void *aux; \
|
||||||
struct type *slh_head; \
|
struct type *slh_head; \
|
||||||
struct type *slh_tail; \
|
struct type *slh_tail; \
|
||||||
TRACEBUF \
|
TRACEBUF \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SKIP_HEAD_DEFAULT_INITIALIZER(cmp) \
|
#define SKIP_HEAD_DEFAULT_INITIALIZER(cmp) \
|
||||||
{ 0, 0, 12, 4, cmp, NULL, NULL, NULL }
|
{ \
|
||||||
|
0, 0, 12, 4, cmp, NULL, NULL, NULL \
|
||||||
|
}
|
||||||
|
|
||||||
#define SKIP_HEAD_INITIALIZER(cmp, max, fanout) \
|
#define SKIP_HEAD_INITIALIZER(cmp, max, fanout) \
|
||||||
{ 0, 0, max, fanout, cmp, NULL, NULL, NULL }
|
{ \
|
||||||
|
0, 0, max, fanout, cmp, NULL, NULL, NULL \
|
||||||
|
}
|
||||||
|
|
||||||
#define SKIP_ENTRY(type) \
|
#define SKIP_ENTRY(type) \
|
||||||
struct { \
|
struct { \
|
||||||
struct type **sle_next; \
|
struct type **sle_next; \
|
||||||
struct type *sle_prev; \
|
struct type *sle_prev; \
|
||||||
TRACEBUF \
|
TRACEBUF \
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Skip List access methods.
|
* Skip List access methods.
|
||||||
*/
|
*/
|
||||||
#define SKIP_FIRST(head) ((head)->slh_head)
|
#define SKIP_FIRST(head) ((head)->slh_head)
|
||||||
#define SKIP_LAST(head) ((head)->slh_tail)
|
#define SKIP_LAST(head) ((head)->slh_tail)
|
||||||
#define SKIP_NEXT(elm, field) ((elm)->field.sle_next[0])
|
#define SKIP_NEXT(elm, field) ((elm)->field.sle_next[0])
|
||||||
#define SKIP_PREV(elm, field) ((elm)->field.sle_prev)
|
#define SKIP_PREV(elm, field) ((elm)->field.sle_prev)
|
||||||
#define SKIP_EMPTY(head) ((head)->length == 0)
|
#define SKIP_EMPTY(head) ((head)->length == 0)
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
#define SKIP_FOREACH(var, head, field) \
|
#define SKIP_FOREACH(var, head, field) \
|
||||||
for((var) = SKIP_FIRST(head); \
|
for ((var) = SKIP_FIRST(head); (var) != SKIP_END(head); \
|
||||||
(var)!= SKIP_END(head); \
|
(var) = SKIP_NEXT(var, field))
|
||||||
(var) = SKIP_NEXT(var, field))
|
|
||||||
|
|
||||||
#define SKIP_FOREACH_SAFE(var, head, field, tvar) \
|
#define SKIP_FOREACH_SAFE(var, head, field, tvar) \
|
||||||
for ((var) = SKIP_FIRST(head); \
|
for ((var) = SKIP_FIRST(head); (var) && ((tvar) = SKIP_NEXT(var, field), 1); \
|
||||||
(var) && ((tvar) = SKIP_NEXT(var, field), 1); \
|
(var) = (tvar))
|
||||||
(var) = (tvar))
|
|
||||||
|
|
||||||
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
|
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
|
||||||
for((var) = TAILQ_LAST(head, headname); \
|
for ((var) = TAILQ_LAST(head, headname); (var) != TAILQ_END(head); \
|
||||||
(var) != TAILQ_END(head); \
|
(var) = TAILQ_PREV(var, headname, field))
|
||||||
(var) = TAILQ_PREV(var, headname, field))
|
|
||||||
|
|
||||||
#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
|
#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
|
||||||
for ((var) = TAILQ_LAST(head, headname); \
|
for ((var) = TAILQ_LAST(head, headname); (var) != TAILQ_END(head) && \
|
||||||
(var) != TAILQ_END(head) && \
|
((tvar) = TAILQ_PREV(var, headname, field), 1); \
|
||||||
((tvar) = TAILQ_PREV(var, headname, field), 1); \
|
(var) = (tvar))
|
||||||
(var) = (tvar))
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Skip List functions.
|
* Skip List functions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define SKIP_COMPARATOR(list, type, fn) \
|
#define SKIP_COMPARATOR(list, type, fn) \
|
||||||
int __skip_cmp_##type(struct list *head, struct type *a, struct type *b, void *aux) { \
|
int __skip_cmp_##type(struct list *head, struct type *a, struct type *b, \
|
||||||
if (a == b) \
|
void *aux) \
|
||||||
return 0; \
|
{ \
|
||||||
if (a == (head)->slh_head || b == (head)->slh_tail) \
|
if (a == b) \
|
||||||
return -1; \
|
return 0; \
|
||||||
if (a == (head)->slh_tail || b == (head)->slh_head) \
|
if (a == (head)->slh_head || b == (head)->slh_tail) \
|
||||||
return 1; \
|
return -1; \
|
||||||
fn }
|
if (a == (head)->slh_tail || b == (head)->slh_head) \
|
||||||
|
return 1; \
|
||||||
|
fn \
|
||||||
|
}
|
||||||
|
|
||||||
#define SKIP_INIT(head, max, fanout, type, field, fn) do { \
|
#define SKIP_INIT(head, max, fanout, type, field, fn) \
|
||||||
(head)->level = 0; \
|
do { \
|
||||||
(head)->length = 0; \
|
(head)->level = 0; \
|
||||||
(head)->max = max; \
|
(head)->length = 0; \
|
||||||
(head)->fanout = fanout; \
|
(head)->max = max; \
|
||||||
(head)->cmp = fn; \
|
(head)->fanout = fanout; \
|
||||||
SKIP_ALLOC_NODE(head, (head)->slh_head, type, field); \
|
(head)->cmp = fn; \
|
||||||
SKIP_ALLOC_NODE(head, (head)->slh_tail, type, field); \
|
SKIP_ALLOC_NODE(head, (head)->slh_head, type, field); \
|
||||||
ARRAY_SET_LENGTH((head)->slh_head->field.sle_next, max); \
|
SKIP_ALLOC_NODE(head, (head)->slh_tail, type, field); \
|
||||||
for(size_t __i = 0; __i < ARRAY_SIZE((head)->slh_head->field.sle_next); __i++) { \
|
ARRAY_SET_LENGTH((head)->slh_head->field.sle_next, max); \
|
||||||
(head)->slh_head->field.sle_next[__i] = (head)->slh_tail; \
|
for (size_t __i = 0; __i < ARRAY_SIZE((head)->slh_head->field.sle_next); \
|
||||||
} \
|
__i++) { \
|
||||||
(head)->slh_head->field.sle_prev = NULL; \
|
(head)->slh_head->field.sle_next[__i] = (head)->slh_tail; \
|
||||||
ARRAY_SET_LENGTH((head)->slh_tail->field.sle_next, max); \
|
} \
|
||||||
for(size_t __i = 0; __i < ARRAY_SIZE((head)->slh_tail->field.sle_next); __i++) { \
|
(head)->slh_head->field.sle_prev = NULL; \
|
||||||
(head)->slh_tail->field.sle_next[__i] = NULL; \
|
ARRAY_SET_LENGTH((head)->slh_tail->field.sle_next, max); \
|
||||||
} \
|
for (size_t __i = 0; __i < ARRAY_SIZE((head)->slh_tail->field.sle_next); \
|
||||||
(head)->slh_head->field.sle_prev = (head)->slh_tail; \
|
__i++) { \
|
||||||
SLD_TRACE_HEAD(head); \
|
(head)->slh_tail->field.sle_next[__i] = NULL; \
|
||||||
|
} \
|
||||||
|
(head)->slh_head->field.sle_prev = (head)->slh_tail; \
|
||||||
|
SLD_TRACE_HEAD(head); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define SKIP_DEFAULT_INIT(head, fn, type, field) do { \
|
#define SKIP_DEFAULT_INIT(head, fn, type, field) \
|
||||||
(head)->level = 0; \
|
do { \
|
||||||
(head)->length = 0; \
|
(head)->level = 0; \
|
||||||
(head)->max = 12; \
|
(head)->length = 0; \
|
||||||
(head)->fanout = 4; \
|
(head)->max = 12; \
|
||||||
(head)->cmp = fn; \
|
(head)->fanout = 4; \
|
||||||
SKIP_ALLOC_NODE(head, (head)->slh_head, type, field); \
|
(head)->cmp = fn; \
|
||||||
SKIP_ALLOC_NODE(head, (head)->slh_tail, type, field); \
|
SKIP_ALLOC_NODE(head, (head)->slh_head, type, field); \
|
||||||
ARRAY_SET_LENGTH((head)->slh_head->field.sle_next, (head)->max); \
|
SKIP_ALLOC_NODE(head, (head)->slh_tail, type, field); \
|
||||||
for(size_t __i = 0; __i < ARRAY_SIZE((head)->slh_head->field.sle_next); __i++) { \
|
ARRAY_SET_LENGTH((head)->slh_head->field.sle_next, (head)->max); \
|
||||||
(head)->slh_head->field.sle_next[__i] = (head)->slh_tail; \
|
for (size_t __i = 0; __i < ARRAY_SIZE((head)->slh_head->field.sle_next); \
|
||||||
} \
|
__i++) { \
|
||||||
(head)->slh_head->field.sle_prev = NULL; \
|
(head)->slh_head->field.sle_next[__i] = (head)->slh_tail; \
|
||||||
ARRAY_SET_LENGTH((head)->slh_tail->field.sle_next, (head)->max); \
|
} \
|
||||||
for(size_t __i = 0; __i < ARRAY_SIZE((head)->slh_tail->field.sle_next); __i++) { \
|
(head)->slh_head->field.sle_prev = NULL; \
|
||||||
(head)->slh_tail->field.sle_next[__i] = NULL; \
|
ARRAY_SET_LENGTH((head)->slh_tail->field.sle_next, (head)->max); \
|
||||||
} \
|
for (size_t __i = 0; __i < ARRAY_SIZE((head)->slh_tail->field.sle_next); \
|
||||||
(head)->slh_head->field.sle_prev = (head)->slh_tail; \
|
__i++) { \
|
||||||
SLD_TRACE_HEAD(head); \
|
(head)->slh_tail->field.sle_next[__i] = NULL; \
|
||||||
|
} \
|
||||||
|
(head)->slh_head->field.sle_prev = (head)->slh_tail; \
|
||||||
|
SLD_TRACE_HEAD(head); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#define SKIP_ALLOC_NODE(head, var, type, field) \
|
||||||
#define SKIP_ALLOC_NODE(head, var, type, field) do { \
|
do { \
|
||||||
(var) = (struct type *)calloc(1, sizeof(struct type)); \
|
(var) = (struct type *)calloc(1, sizeof(struct type)); \
|
||||||
ARRAY_ALLOC((var)->field.sle_next, struct type, (head)->max); \
|
ARRAY_ALLOC((var)->field.sle_next, struct type, (head)->max); \
|
||||||
if ((var) && (var)->field.sle_next) { \
|
if ((var) && (var)->field.sle_next) { \
|
||||||
ARRAY_SET_SIZE((var)->field.sle_next, (head)->max); \
|
ARRAY_SET_SIZE((var)->field.sle_next, (head)->max); \
|
||||||
ARRAY_SET_LENGTH((var)->field.sle_next, 0); \
|
ARRAY_SET_LENGTH((var)->field.sle_next, 0); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define SKIP_FREE_NODE(node, field) do { \
|
#define SKIPLIST_DECL(decl, prefix, field) \
|
||||||
free((node)->field.sle_next); \
|
\
|
||||||
free((node)); \
|
/* Skiplist node type */ \
|
||||||
} while (0)
|
typedef struct decl##_node decl##_node_t; \
|
||||||
|
\
|
||||||
|
/* Skiplist type */ \
|
||||||
|
typedef struct decl { \
|
||||||
|
size_t level, length, max, fanout; \
|
||||||
|
int (*cmp)(struct decl *, decl##_node_t *, decl##_node_t *, void *); \
|
||||||
|
void *aux; \
|
||||||
|
decl##_node_t *slh_head; \
|
||||||
|
decl##_node_t *slh_tail; \
|
||||||
|
TRACEBUF \
|
||||||
|
} decl##_t; \
|
||||||
|
\
|
||||||
|
/* -- __skip_key_compare_ \
|
||||||
|
* \
|
||||||
|
* This function takes four arguments: \
|
||||||
|
* - a reference to the Skiplist \
|
||||||
|
* - the two nodes to compare, `a` and `b` \
|
||||||
|
* - `aux` an additional auxiliary argument \
|
||||||
|
* and returns: \
|
||||||
|
* a < b : return -1 \
|
||||||
|
* a == b : return 0 \
|
||||||
|
* a > b : return 1 \
|
||||||
|
*/ \
|
||||||
|
static int __skip_key_compare_##decl(decl##_t *slist, decl##_node_t *a, \
|
||||||
|
decl##_node_t *b, void *aux) \
|
||||||
|
{ \
|
||||||
|
if (a == b) \
|
||||||
|
return 0; \
|
||||||
|
if (a == slist->slh_head || b == slist->slh_tail) \
|
||||||
|
return -1; \
|
||||||
|
if (a == slist->slh_tail || b == slist->slh_head) \
|
||||||
|
return 1; \
|
||||||
|
return slist->cmp(slist, a, b, aux); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* -- __skip_toss_ */ \
|
||||||
|
static int __skip_toss_##decl(size_t max, size_t fanout) \
|
||||||
|
{ \
|
||||||
|
size_t level = 0; \
|
||||||
|
while (level + 1 < max) { \
|
||||||
|
if (rand() % fanout == 0) /* NOLINT(*-msc50-cpp) */ \
|
||||||
|
level++; \
|
||||||
|
else \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
return level; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* -- skip_alloc_node_ */ \
|
||||||
|
int prefix##skip_alloc_node_##decl(decl##_t *slist, decl##_node_t **node) \
|
||||||
|
{ \
|
||||||
|
decl##_node_t *n; \
|
||||||
|
n = (decl##_node_t *)calloc(1, sizeof(decl##_node_t)); \
|
||||||
|
ARRAY_ALLOC(n->field.sle_next, struct decl##_node, slist->max); \
|
||||||
|
if (n && n->field.sle_next) { \
|
||||||
|
ARRAY_SET_SIZE(n->field.sle_next, slist->max); \
|
||||||
|
ARRAY_SET_LENGTH(n->field.sle_next, 0); \
|
||||||
|
*node = n; \
|
||||||
|
return 0; \
|
||||||
|
} \
|
||||||
|
return ENOMEM; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* -- skip_init_ \
|
||||||
|
* max: 12, fanout: 4 are good defaults. \
|
||||||
|
*/ \
|
||||||
|
int prefix##skip_init_##decl(decl##_t *slist, size_t max, size_t fanout, \
|
||||||
|
int (*cmp)(struct decl *, decl##_node_t *, decl##_node_t *, void *)) \
|
||||||
|
{ \
|
||||||
|
int rc = 0; \
|
||||||
|
slist->level = 0; \
|
||||||
|
slist->length = 0; \
|
||||||
|
slist->max = max; \
|
||||||
|
slist->fanout = fanout; \
|
||||||
|
slist->cmp = cmp; \
|
||||||
|
rc = prefix##skip_alloc_node_##decl(slist, &slist->slh_head); \
|
||||||
|
if (rc) \
|
||||||
|
goto fail; \
|
||||||
|
rc = prefix##skip_alloc_node_##decl(slist, &slist->slh_tail); \
|
||||||
|
if (rc) \
|
||||||
|
goto fail; \
|
||||||
|
ARRAY_SET_LENGTH(slist->slh_head->field.sle_next, max); \
|
||||||
|
for (size_t __i = 0; __i < max; __i++) \
|
||||||
|
slist->slh_head->field.sle_next[__i] = slist->slh_tail; \
|
||||||
|
slist->slh_head->field.sle_prev = NULL; \
|
||||||
|
ARRAY_SET_LENGTH(slist->slh_tail->field.sle_next, max); \
|
||||||
|
for (size_t __i = 0; __i < max; __i++) \
|
||||||
|
slist->slh_tail->field.sle_next[__i] = NULL; \
|
||||||
|
slist->slh_head->field.sle_prev = slist->slh_tail; \
|
||||||
|
fail:; \
|
||||||
|
return rc; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* -- skip_free_node_ */ \
|
||||||
|
void prefix##skip_free_node_##decl(decl##_node_t *node) \
|
||||||
|
{ \
|
||||||
|
free(node->field.sle_next); \
|
||||||
|
free(node); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* -- skip_insert_ */ \
|
||||||
|
int prefix##skip_insert_##decl(decl##_t *slist, decl##_node_t *n) \
|
||||||
|
{ \
|
||||||
|
if (n == NULL) \
|
||||||
|
return ENOMEM; \
|
||||||
|
decl##_node_t *prev, *elm = slist->slh_head; \
|
||||||
|
unsigned int i; \
|
||||||
|
decl##_node_t **path; \
|
||||||
|
i = slist->level; \
|
||||||
|
ARRAY_ALLOC(path, decl##_node_t, slist->max); \
|
||||||
|
if (path == NULL) \
|
||||||
|
return ENOMEM; \
|
||||||
|
/* Find the position in the list where this element belongs. */ \
|
||||||
|
do { \
|
||||||
|
while (elm && \
|
||||||
|
__skip_key_compare_##decl(slist, elm->field.sle_next[i], n, \
|
||||||
|
slist->aux) < 0) \
|
||||||
|
elm = elm->field.sle_next[i]; \
|
||||||
|
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; \
|
||||||
|
} \
|
||||||
|
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++) { \
|
||||||
|
path[i] = slist->slh_tail; \
|
||||||
|
} \
|
||||||
|
slist->level = level; \
|
||||||
|
} \
|
||||||
|
for (i = 0; i <= level; i++) { \
|
||||||
|
n->field.sle_next[i] = path[i]->field.sle_next[i]; \
|
||||||
|
path[i]->field.sle_next[i] = n; \
|
||||||
|
} \
|
||||||
|
n->field.sle_prev = prev; \
|
||||||
|
if (n->field.sle_next[0] == slist->slh_tail) { \
|
||||||
|
slist->slh_tail->field.sle_prev = n; \
|
||||||
|
} \
|
||||||
|
slist->length++; \
|
||||||
|
ARRAY_FREE(path); \
|
||||||
|
return 0; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* -- __skip_integrity_check_ */ \
|
||||||
|
static int __skip_integrity_check_##decl(decl##_t *slist) \
|
||||||
|
{ \
|
||||||
|
((void)slist); /* TODO */ \
|
||||||
|
return 0; \
|
||||||
|
}
|
||||||
|
|
||||||
#define SKIPLIST_DECL(decl, prefix, field, key_cmp_logic) \
|
#define SKIPLIST_DECL_DOT(decl, prefix, field) \
|
||||||
\
|
\
|
||||||
/* Skiplist node type */ \
|
/* A type for a function that writes into a char[2048] buffer \
|
||||||
typedef struct decl##_node decl##_node_t; \
|
* a description of the value within the node. */ \
|
||||||
\
|
typedef void (*skip_sprintf_node_##decl##_t)(decl##_node_t *, char *); \
|
||||||
/* Skiplist type */ \
|
\
|
||||||
typedef struct decl { \
|
/* -- __skip_dot_node_ \
|
||||||
size_t level, length, max, fanout; \
|
* Writes out a fragment of a DOT file representing a node. \
|
||||||
int (*cmp)(struct decl *, decl##_node_t *, decl##_node_t *, void *); \
|
*/ \
|
||||||
void *aux; \
|
static void __skip_dot_node_##decl(FILE *os, decl##_t *slist, \
|
||||||
decl##_node_t *slh_head; \
|
decl##_node_t *node, size_t nsg, skip_sprintf_node_##decl##_t fn) \
|
||||||
decl##_node_t *slh_tail; \
|
{ \
|
||||||
TRACEBUF \
|
char buf[2048]; \
|
||||||
}decl##_t; \
|
size_t level, height = ARRAY_LENGTH(node->field.sle_next); \
|
||||||
\
|
fprintf(os, "\"node%zu%p\"", nsg, (void *)node); \
|
||||||
/* -- __skip_key_compare_ \
|
fprintf(os, " [label = \""); \
|
||||||
* \
|
level = height; \
|
||||||
* This function takes four arguments: \
|
do { \
|
||||||
* - a reference to the Skiplist \
|
fprintf(os, " { <w%zu> | <f%zu> %p }", level + 1, level + 1, \
|
||||||
* - the two nodes to compare, `a` and `b` \
|
(void *)node->field.sle_next[level]); \
|
||||||
* - `aux` an additional auxiliary argument \
|
if (level != 0) \
|
||||||
* and returns: \
|
fprintf(os, " | "); \
|
||||||
* a < b : return -1 \
|
} while (level--); \
|
||||||
* a == b : return 0 \
|
if (fn) { \
|
||||||
* a > b : return 1 \
|
fn(node, buf); \
|
||||||
*/ \
|
fprintf(os, " <f0> %s\"\n", buf); \
|
||||||
static int __skip_key_compare_##decl(decl##_t *slist, decl##_node_t *a, decl##_node_t *b, void *aux) { \
|
} else { \
|
||||||
if (a == b) \
|
fprintf(os, " <f0> ?\"\n"); \
|
||||||
return 0; \
|
} \
|
||||||
if (a == slist->slh_head || b == slist->slh_tail) \
|
fprintf(os, "shape = \"record\"\n"); \
|
||||||
return -1; \
|
fprintf(os, "];\n"); \
|
||||||
if (a == slist->slh_tail || b == slist->slh_head) \
|
\
|
||||||
return 1; \
|
/* Now edges */ \
|
||||||
do { key_cmp_logic } while(0); \
|
level = 0; \
|
||||||
} \
|
for (level = 0; level < height; level++) { \
|
||||||
\
|
fprintf(os, "\"node%zu%p\"", nsg, (void *)node); \
|
||||||
/* -- __skip_toss_ */ \
|
fprintf(os, ":f%zu -> ", level + 1); \
|
||||||
static int __skip_toss_##decl(size_t max, size_t fanout) { \
|
fprintf(os, "\"node%zu%p\"", nsg, (void *)node->field.sle_next[level]); \
|
||||||
size_t level = 0; \
|
fprintf(os, ":w%zu [];\n", level + 1); \
|
||||||
while (level + 1 < max) { \
|
} \
|
||||||
if (rand() % fanout == 0) /* NOLINT(*-msc50-cpp) */ \
|
\
|
||||||
level++; \
|
if (node->field.sle_next[0] != SKIP_LAST(slist)) \
|
||||||
else \
|
__skip_dot_node_##decl(os, slist, node->field.sle_next[0], nsg, fn); \
|
||||||
break; \
|
} \
|
||||||
} \
|
\
|
||||||
return level; \
|
/* -- __skip_dot_finish_ \
|
||||||
} \
|
* Finalise the DOT file of the internal representation. \
|
||||||
\
|
*/ \
|
||||||
/* -- skip_insert_ */ \
|
static void __skip_dot_finish_##decl(FILE *os, size_t nsg) \
|
||||||
int prefix##skip_insert_##decl(decl##_t *slist, decl##_node_t *n) { \
|
{ \
|
||||||
if (n == NULL) \
|
size_t i; \
|
||||||
return ENOMEM; \
|
if (nsg > 0) { \
|
||||||
decl##_node_t *prev, *elm = slist->slh_head; \
|
/* Link the nodes together with an invisible node. \
|
||||||
unsigned int i; \
|
* node0 [shape=record, label = "<f0> | <f1> | <f2> | <f3> | \
|
||||||
decl##_node_t **path; \
|
* <f4> | <f5> | <f6> | <f7> | <f8> | ", style=invis, width=0.01]; \
|
||||||
i = slist->level; \
|
*/ \
|
||||||
ARRAY_ALLOC(path, decl##_node_t, slist->max); \
|
fprintf(os, "node0 [shape=record, label = \""); \
|
||||||
if (path == NULL) \
|
for (i = 0; i < nsg; ++i) { \
|
||||||
return ENOMEM; \
|
fprintf(os, "<f%zu> | ", i); \
|
||||||
/* Find the position in the list where this element belongs. */ \
|
} \
|
||||||
do { \
|
fprintf(os, "\", style=invis, width=0.01];\n"); \
|
||||||
while(elm && slist->cmp(slist, elm->field.sle_next[i], n, slist->aux) < 0) \
|
\
|
||||||
elm = elm->field.sle_next[i]; \
|
/* Now connect nodes with invisible edges \
|
||||||
path[i] = elm; \
|
* \
|
||||||
ARRAY_SET_LENGTH(path, ARRAY_LENGTH(path)+1); \
|
* node0:f0 -> HeadNode [style=invis]; \
|
||||||
} while(i--); \
|
* node0:f1 -> HeadNode1 [style=invis]; \
|
||||||
i = 0; \
|
*/ \
|
||||||
prev = elm; \
|
for (i = 0; i < nsg; ++i) { \
|
||||||
elm = elm->field.sle_next[0]; \
|
fprintf(os, "node0:f%zu -> HeadNode%zu [style=invis];\n", i, i); \
|
||||||
if (slist->cmp(slist, elm, n, slist->aux) == 0) { \
|
} \
|
||||||
ARRAY_FREE(path); \
|
nsg = 0; \
|
||||||
/* Don't overwrite, to do that use _REPLACE not _INSERT */ \
|
} \
|
||||||
return -1; \
|
fprintf(os, "}\n"); \
|
||||||
} \
|
} \
|
||||||
size_t level = __skip_toss_##decl(slist->max, slist->fanout); \
|
\
|
||||||
ARRAY_SET_LENGTH(n->field.sle_next, level); \
|
/* -- skip_dot_start_ */ \
|
||||||
if (level > slist->level) { \
|
static int __skip_dot_start_##decl(FILE *os, decl##_t *slist, size_t nsg, \
|
||||||
for (i = slist->level + 1; i <= level; i++) { \
|
skip_sprintf_node_##decl##_t fn) \
|
||||||
path[i] = slist->slh_tail; \
|
{ \
|
||||||
} \
|
size_t level; \
|
||||||
slist->level = level; \
|
decl##_node_t *head; \
|
||||||
} \
|
if (nsg == 0) { \
|
||||||
for (i = 0; i <= level; i++) { \
|
fprintf(os, "digraph Skiplist {\n"); \
|
||||||
n->field.sle_next[i] = path[i]->field.sle_next[i]; \
|
fprintf(os, "label = \"Skiplist.\"\n"); \
|
||||||
path[i]->field.sle_next[i] = n; \
|
fprintf(os, "graph [rankdir = \"LR\"];\n"); \
|
||||||
} \
|
fprintf(os, "node [fontsize = \"12\" shape = \"ellipse\"];\n"); \
|
||||||
n->field.sle_prev = prev; \
|
fprintf(os, "edge [];\n\n"); \
|
||||||
if (n->field.sle_next[0] == slist->slh_tail) { \
|
} \
|
||||||
slist->slh_tail->field.sle_prev = n; \
|
fprintf(os, "subgraph cluster%zu {\n", nsg); \
|
||||||
} \
|
fprintf(os, "style=dashed\n"); \
|
||||||
slist->length++; \
|
fprintf(os, "label=\"Skip list iteration %zu\"\n\n", nsg); \
|
||||||
ARRAY_FREE(path); \
|
fprintf(os, "\"HeadNode%zu\" [\n", nsg); \
|
||||||
return 0; \
|
fprintf(os, "label = \""); \
|
||||||
} \
|
\
|
||||||
\
|
/* Write out the fields */ \
|
||||||
/* -- __skip_integrity_check_ */ \
|
head = slist->slh_head; \
|
||||||
static int __skip_integrity_check_##decl() { \
|
if (SKIP_EMPTY(slist)) \
|
||||||
return 0; \
|
fprintf(os, "Empty HeadNode"); \
|
||||||
} \
|
else { \
|
||||||
\
|
level = ARRAY_LENGTH(head->field.sle_next); \
|
||||||
/* A type for a function that writes into a char[2048] buffer \
|
while (level--) { \
|
||||||
* a description of the value within the node. */ \
|
decl##_node_t *node = head->field.sle_next[level]; \
|
||||||
typedef void (*skip_sprintf_node_##decl##_t)(decl##_node_t *, char *); \
|
fprintf(os, "{ <f%zu> %p }", level + 1, (void *)node); \
|
||||||
\
|
if (level + 1 != 0) \
|
||||||
/* -- __skip_dot_node_ \
|
fprintf(os, " | "); \
|
||||||
* 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) { \
|
fprintf(os, "\"\n"); \
|
||||||
fprintf(os, "\"node%zu%p\"", nsg, (void*)node); \
|
fprintf(os, "shape = \"record\"\n"); \
|
||||||
fprintf(os, " [label = \""); \
|
fprintf(os, "];\n"); \
|
||||||
size_t level = ARRAY_LENGTH(node->field.sle_next); \
|
\
|
||||||
do { \
|
/* Edges for head node */ \
|
||||||
fprintf(os, " { <w%zu> | <f%zu> %p }", level, level, (void*)node->field.sle_next[level]); \
|
decl##_node_t *node = slist->slh_head; \
|
||||||
if (level != 0) fprintf(os, " | "); \
|
level = 0; \
|
||||||
} while(level--); \
|
do { \
|
||||||
if (fn) { \
|
fprintf(os, "\"HeadNode%zu\":f%zu -> ", nsg, level + 1); \
|
||||||
char buf[2048]; \
|
fprintf(os, "\"node%zu%p\"", nsg, (void *)node->field.sle_next[level]); \
|
||||||
fn(node, buf); \
|
fprintf(os, ":w%zu [];\n", level + 1); \
|
||||||
fprintf(os, " <f0> %s\"\n", buf); \
|
} while (level++ < slist->level); \
|
||||||
} else { \
|
fprintf(os, "}\n\n"); \
|
||||||
fprintf(os, " <f0> ?\"\n"); \
|
\
|
||||||
} \
|
/* Now all nodes via level 0, if non-empty */ \
|
||||||
fprintf(os, "shape = \"record\"\n"); \
|
node = slist->slh_head; \
|
||||||
fprintf(os, "];\n"); \
|
if (ARRAY_LENGTH(node->field.sle_next)) \
|
||||||
\
|
__skip_dot_node_##decl(os, slist, node->field.sle_next[0], nsg, fn); \
|
||||||
/* Now edges */ \
|
fprintf(os, "\n"); \
|
||||||
level = 0; \
|
\
|
||||||
size_t size = ARRAY_LENGTH(node->field.sle_next); \
|
/* The tail, sentinal node */ \
|
||||||
for (size_t level = 0; level <= size; level++) { \
|
if (!SKIP_EMPTY(slist)) { \
|
||||||
fprintf(os, "\"node%zu%p\"", nsg, (void*)node); \
|
fprintf(os, "\"node%zu0x0\" [label = \"", nsg); \
|
||||||
fprintf(os, ":f%zu -> ", level); \
|
level = slist->level; \
|
||||||
fprintf(os, "\"node%zu%p\"", nsg, (void*)node->field.sle_next[level]); \
|
do { \
|
||||||
fprintf(os, ":w%zu [];\n", level); \
|
fprintf(os, "<w%zu> NULL", level + 1); \
|
||||||
} \
|
if (level != 0) \
|
||||||
\
|
fprintf(os, " | "); \
|
||||||
if (node->field.sle_next[0]) \
|
} while (level-- > 0); \
|
||||||
__skip_dot_node_##decl(os, slist, node->field.sle_next[0], nsg, fn); \
|
fprintf(os, "\" shape = \"record\"];\n"); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/* -- __skip_dot_finish_ \
|
/* End: "subgraph cluster1 {" */ \
|
||||||
* Finalise the DOT file of the internal representation. \
|
fprintf(os, "}\n\n"); \
|
||||||
*/ \
|
nsg += 1; \
|
||||||
static void __skip_dot_finish_##decl(FILE *os, size_t nsg) { \
|
\
|
||||||
if (nsg > 0) { \
|
return 0; \
|
||||||
/* Link the nodes together with an invisible node. \
|
} \
|
||||||
* node0 [shape=record, label = "<f0> | <f1> | <f2> | <f3> | <f4> | <f5> | <f6> | <f7> | <f8> | ", \
|
\
|
||||||
* style=invis, \
|
/* -- skip_dot_ \
|
||||||
* width=0.01]; \
|
* Create a DOT file of the internal representation of the \
|
||||||
*/ \
|
* Skiplist on the provided file descriptor (default: STDOUT). \
|
||||||
fprintf(os, "node0 [shape=record, label = \""); \
|
* \
|
||||||
for (size_t i = 0; i < nsg; ++i) { \
|
* To view the output: \
|
||||||
fprintf(os, "<f%zu> | ", i); \
|
* $ dot -Tps filename.dot -o outfile.ps \
|
||||||
} \
|
* You can change the output format by varying the value after -T and \
|
||||||
fprintf(os, "\", style=invis, width=0.01];\n"); \
|
* choosing an appropriate filename extension after -o. \
|
||||||
\
|
* See: https://graphviz.org/docs/outputs/ for the format options. \
|
||||||
/* Now connect nodes with invisible edges \
|
* \
|
||||||
* \
|
* https://en.wikipedia.org/wiki/DOT_(graph_description_language) \
|
||||||
* node0:f0 -> HeadNode [style=invis]; \
|
*/ \
|
||||||
* node0:f1 -> HeadNode1 [style=invis]; \
|
int prefix##skip_dot_##decl(FILE *os, decl##_t *slist, \
|
||||||
*/ \
|
skip_sprintf_node_##decl##_t fn) \
|
||||||
for (size_t i = 0; i < nsg; ++i) { \
|
{ \
|
||||||
fprintf(os, "node0:f%zu -> HeadNode%zu [style=invis];\n", i, i);\
|
size_t nsg = 0; \
|
||||||
} \
|
if (__skip_integrity_check_##decl(slist) != 0) { \
|
||||||
nsg = 0; \
|
perror("Skiplist failed integrity checks, impossible to diagram."); \
|
||||||
} \
|
return -1; \
|
||||||
fprintf(os, "}\n"); \
|
} \
|
||||||
} \
|
if (os == NULL) \
|
||||||
\
|
os = stdout; \
|
||||||
/* -- skip_dot_start_ */ \
|
if (!os) { \
|
||||||
static int __skip_dot_start_##decl(FILE *os, decl##_t *slist, size_t nsg, skip_sprintf_node_##decl##_t fn) { \
|
perror("Failed to open output file, unable to write DOT file."); \
|
||||||
if (nsg == 0) { \
|
return -1; \
|
||||||
fprintf(os, "digraph Skiplist {\n"); \
|
} \
|
||||||
fprintf(os, "label = \"Skiplist.\"\n"); \
|
__skip_dot_start_##decl(os, slist, nsg, fn); \
|
||||||
fprintf(os, "graph [rankdir = \"LR\"];\n"); \
|
__skip_dot_finish_##decl(os, nsg); \
|
||||||
fprintf(os, "node [fontsize = \"12\" shape = \"ellipse\"];\n"); \
|
return 0; \
|
||||||
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 head node fields */ \
|
|
||||||
decl##_node_t *head = slist->slh_head; \
|
|
||||||
size_t level; \
|
|
||||||
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 != 0) 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 = slist->slh_head; \
|
|
||||||
if (ARRAY_LENGTH(node->field.sle_next)) \
|
|
||||||
__skip_dot_node_##decl(os, slist, node, nsg, fn); \
|
|
||||||
fprintf(os, "\n"); \
|
|
||||||
\
|
|
||||||
/* The tail, sentinal node */ \
|
|
||||||
if (!SKIP_EMPTY(slist)) { \
|
|
||||||
fprintf(os,"\"node%zu0x0\" [label = \"", nsg); \
|
|
||||||
size_t level = slist->level; \
|
|
||||||
do { \
|
|
||||||
fprintf(os, "<w%zu> NULL", level); \
|
|
||||||
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; \
|
|
||||||
} \
|
|
||||||
/* END */
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
#define SKIP_REMOVE(head, elm, field) do { \
|
#define SKIP_REMOVE(head, elm, field) \
|
||||||
if ((elm)->field.le_next != NULL) \
|
do { \
|
||||||
(elm)->field.le_next->field.le_prev = \
|
if ((elm)->field.le_next != NULL) \
|
||||||
(elm)->field.le_prev; \
|
(elm)->field.le_next->field.le_prev = (elm)->field.le_prev; \
|
||||||
*(elm)->field.le_prev = (elm)->field.le_next; \
|
*(elm)->field.le_prev = (elm)->field.le_next; \
|
||||||
_Q_INVALIDATE((elm)->field.le_prev); \
|
_Q_INVALIDATE((elm)->field.le_prev); \
|
||||||
_Q_INVALIDATE((elm)->field.le_next); \
|
_Q_INVALIDATE((elm)->field.le_next); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define SKIP_REPLACE(elm, elm2, field) do { \
|
#define SKIP_REPLACE(elm, elm2, field) \
|
||||||
if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
|
do { \
|
||||||
(elm2)->field.le_next->field.le_prev = \
|
if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
|
||||||
&(elm2)->field.le_next; \
|
(elm2)->field.le_next->field.le_prev = &(elm2)->field.le_next; \
|
||||||
(elm2)->field.le_prev = (elm)->field.le_prev; \
|
(elm2)->field.le_prev = (elm)->field.le_prev; \
|
||||||
*(elm2)->field.le_prev = (elm2); \
|
*(elm2)->field.le_prev = (elm2); \
|
||||||
_Q_INVALIDATE((elm)->field.le_prev); \
|
_Q_INVALIDATE((elm)->field.le_prev); \
|
||||||
_Q_INVALIDATE((elm)->field.le_next); \
|
_Q_INVALIDATE((elm)->field.le_next); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* _SYS_SKIPLIST_H_ */
|
#endif /* _SYS_SKIPLIST_H_ */
|
||||||
|
|
1336
src/skiplist.c
1336
src/skiplist.c
File diff suppressed because it is too large
Load diff
164
tests/api.c
164
tests/api.c
|
@ -1,196 +1,196 @@
|
||||||
static void *
|
static void *
|
||||||
test_api_setup(const MunitParameter params[], void *user_data)
|
test_api_setup(const MunitParameter params[], void *user_data)
|
||||||
{
|
{
|
||||||
struct test_info *info = (struct test_info *)user_data;
|
struct test_info *info = (struct test_info *)user_data;
|
||||||
(void)info;
|
(void)info;
|
||||||
(void)params;
|
(void)params;
|
||||||
|
|
||||||
ex_sl_t *slist = calloc(sizeof(ex_sl_t), 1);
|
ex_sl_t *slist = calloc(sizeof(ex_sl_t), 1);
|
||||||
if (slist == NULL)
|
if (slist == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
sl_init(slist, uint32_key_cmp);
|
sl_init(slist, uint32_key_cmp);
|
||||||
return (void *)(uintptr_t)slist;
|
return (void *)(uintptr_t)slist;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_api_tear_down(void *fixture)
|
test_api_tear_down(void *fixture)
|
||||||
{
|
{
|
||||||
ex_sl_t *slist = (ex_sl_t *)fixture;
|
ex_sl_t *slist = (ex_sl_t *)fixture;
|
||||||
assert_ptr_not_null(slist);
|
assert_ptr_not_null(slist);
|
||||||
sl_node *cursor = sl_begin(slist);
|
sl_node *cursor = sl_begin(slist);
|
||||||
while (cursor) {
|
while (cursor) {
|
||||||
assert_ptr_not_null(cursor);
|
assert_ptr_not_null(cursor);
|
||||||
ex_node_t *entry = sl_get_entry(cursor, ex_node_t, snode);
|
ex_node_t *entry = sl_get_entry(cursor, ex_node_t, snode);
|
||||||
assert_ptr_not_null(entry);
|
assert_ptr_not_null(entry);
|
||||||
assert_uint32(entry->key, ==, entry->value);
|
assert_uint32(entry->key, ==, entry->value);
|
||||||
cursor = sl_next(slist, cursor);
|
cursor = sl_next(slist, cursor);
|
||||||
sl_erase_node(slist, &entry->snode);
|
sl_erase_node(slist, &entry->snode);
|
||||||
sl_release_node(&entry->snode);
|
sl_release_node(&entry->snode);
|
||||||
sl_wait_for_free(&entry->snode);
|
sl_wait_for_free(&entry->snode);
|
||||||
sl_free_node(&entry->snode);
|
sl_free_node(&entry->snode);
|
||||||
free(entry);
|
free(entry);
|
||||||
}
|
}
|
||||||
sl_free(slist);
|
sl_free(slist);
|
||||||
free(fixture);
|
free(fixture);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
test_api_insert_setup(const MunitParameter params[], void *user_data)
|
test_api_insert_setup(const MunitParameter params[], void *user_data)
|
||||||
{
|
{
|
||||||
return test_api_setup(params, user_data);
|
return test_api_setup(params, user_data);
|
||||||
}
|
}
|
||||||
static void
|
static void
|
||||||
test_api_insert_tear_down(void *fixture)
|
test_api_insert_tear_down(void *fixture)
|
||||||
{
|
{
|
||||||
test_api_tear_down(fixture);
|
test_api_tear_down(fixture);
|
||||||
}
|
}
|
||||||
static MunitResult
|
static MunitResult
|
||||||
test_api_insert(const MunitParameter params[], void *data)
|
test_api_insert(const MunitParameter params[], void *data)
|
||||||
{
|
{
|
||||||
sl_raw *slist = (sl_raw *)data;
|
sl_raw *slist = (sl_raw *)data;
|
||||||
(void)params;
|
(void)params;
|
||||||
assert_ptr_not_null(data);
|
assert_ptr_not_null(data);
|
||||||
int n = munit_rand_int_range(128, 4096);
|
int n = munit_rand_int_range(128, 4096);
|
||||||
int key = munit_rand_int_range(0, (((uint32_t)0) - 1) / 10);
|
int key = munit_rand_int_range(0, (((uint32_t)0) - 1) / 10);
|
||||||
while (n--) {
|
while (n--) {
|
||||||
ex_node_t *node = (ex_node_t *)calloc(sizeof(ex_node_t), 1);
|
ex_node_t *node = (ex_node_t *)calloc(sizeof(ex_node_t), 1);
|
||||||
sl_init_node(&node->snode);
|
sl_init_node(&node->snode);
|
||||||
node->key = key;
|
node->key = key;
|
||||||
node->value = key;
|
node->value = key;
|
||||||
sl_insert(slist, &node->snode);
|
sl_insert(slist, &node->snode);
|
||||||
}
|
}
|
||||||
return MUNIT_OK;
|
return MUNIT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
test_api_remove_setup(const MunitParameter params[], void *user_data)
|
test_api_remove_setup(const MunitParameter params[], void *user_data)
|
||||||
{
|
{
|
||||||
return test_api_setup(params, user_data);
|
return test_api_setup(params, user_data);
|
||||||
}
|
}
|
||||||
static void
|
static void
|
||||||
test_api_remove_tear_down(void *fixture)
|
test_api_remove_tear_down(void *fixture)
|
||||||
{
|
{
|
||||||
test_api_tear_down(fixture);
|
test_api_tear_down(fixture);
|
||||||
}
|
}
|
||||||
static MunitResult
|
static MunitResult
|
||||||
test_api_remove(const MunitParameter params[], void *data)
|
test_api_remove(const MunitParameter params[], void *data)
|
||||||
{
|
{
|
||||||
sl_raw *slist = (sl_raw *)data;
|
sl_raw *slist = (sl_raw *)data;
|
||||||
(void)params;
|
(void)params;
|
||||||
(void)slist;
|
(void)slist;
|
||||||
return MUNIT_OK;
|
return MUNIT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
test_api_find_setup(const MunitParameter params[], void *user_data)
|
test_api_find_setup(const MunitParameter params[], void *user_data)
|
||||||
{
|
{
|
||||||
return test_api_setup(params, user_data);
|
return test_api_setup(params, user_data);
|
||||||
}
|
}
|
||||||
static void
|
static void
|
||||||
test_api_find_tear_down(void *fixture)
|
test_api_find_tear_down(void *fixture)
|
||||||
{
|
{
|
||||||
test_api_tear_down(fixture);
|
test_api_tear_down(fixture);
|
||||||
}
|
}
|
||||||
static MunitResult
|
static MunitResult
|
||||||
test_api_find(const MunitParameter params[], void *data)
|
test_api_find(const MunitParameter params[], void *data)
|
||||||
{
|
{
|
||||||
sl_raw *slist = (sl_raw *)data;
|
sl_raw *slist = (sl_raw *)data;
|
||||||
(void)params;
|
(void)params;
|
||||||
(void)slist;
|
(void)slist;
|
||||||
return MUNIT_OK;
|
return MUNIT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
test_api_update_setup(const MunitParameter params[], void *user_data)
|
test_api_update_setup(const MunitParameter params[], void *user_data)
|
||||||
{
|
{
|
||||||
return test_api_setup(params, user_data);
|
return test_api_setup(params, user_data);
|
||||||
}
|
}
|
||||||
static void
|
static void
|
||||||
test_api_update_tear_down(void *fixture)
|
test_api_update_tear_down(void *fixture)
|
||||||
{
|
{
|
||||||
test_api_tear_down(fixture);
|
test_api_tear_down(fixture);
|
||||||
}
|
}
|
||||||
static MunitResult
|
static MunitResult
|
||||||
test_api_update(const MunitParameter params[], void *data)
|
test_api_update(const MunitParameter params[], void *data)
|
||||||
{
|
{
|
||||||
sl_raw *slist = (sl_raw *)data;
|
sl_raw *slist = (sl_raw *)data;
|
||||||
(void)params;
|
(void)params;
|
||||||
(void)slist;
|
(void)slist;
|
||||||
return MUNIT_OK;
|
return MUNIT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
test_api_delete_setup(const MunitParameter params[], void *user_data)
|
test_api_delete_setup(const MunitParameter params[], void *user_data)
|
||||||
{
|
{
|
||||||
return test_api_setup(params, user_data);
|
return test_api_setup(params, user_data);
|
||||||
}
|
}
|
||||||
static void
|
static void
|
||||||
test_api_delete_tear_down(void *fixture)
|
test_api_delete_tear_down(void *fixture)
|
||||||
{
|
{
|
||||||
test_api_tear_down(fixture);
|
test_api_tear_down(fixture);
|
||||||
}
|
}
|
||||||
static MunitResult
|
static MunitResult
|
||||||
test_api_delete(const MunitParameter params[], void *data)
|
test_api_delete(const MunitParameter params[], void *data)
|
||||||
{
|
{
|
||||||
sl_raw *slist = (sl_raw *)data;
|
sl_raw *slist = (sl_raw *)data;
|
||||||
(void)params;
|
(void)params;
|
||||||
(void)slist;
|
(void)slist;
|
||||||
return MUNIT_OK;
|
return MUNIT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
test_api_duplicates_setup(const MunitParameter params[], void *user_data)
|
test_api_duplicates_setup(const MunitParameter params[], void *user_data)
|
||||||
{
|
{
|
||||||
return test_api_setup(params, user_data);
|
return test_api_setup(params, user_data);
|
||||||
}
|
}
|
||||||
static void
|
static void
|
||||||
test_api_duplicates_tear_down(void *fixture)
|
test_api_duplicates_tear_down(void *fixture)
|
||||||
{
|
{
|
||||||
test_api_tear_down(fixture);
|
test_api_tear_down(fixture);
|
||||||
}
|
}
|
||||||
static MunitResult
|
static MunitResult
|
||||||
test_api_duplicates(const MunitParameter params[], void *data)
|
test_api_duplicates(const MunitParameter params[], void *data)
|
||||||
{
|
{
|
||||||
sl_raw *slist = (sl_raw *)data;
|
sl_raw *slist = (sl_raw *)data;
|
||||||
(void)params;
|
(void)params;
|
||||||
(void)slist;
|
(void)slist;
|
||||||
return MUNIT_OK;
|
return MUNIT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
test_api_size_setup(const MunitParameter params[], void *user_data)
|
test_api_size_setup(const MunitParameter params[], void *user_data)
|
||||||
{
|
{
|
||||||
return test_api_setup(params, user_data);
|
return test_api_setup(params, user_data);
|
||||||
}
|
}
|
||||||
static void
|
static void
|
||||||
test_api_size_tear_down(void *fixture)
|
test_api_size_tear_down(void *fixture)
|
||||||
{
|
{
|
||||||
test_api_tear_down(fixture);
|
test_api_tear_down(fixture);
|
||||||
}
|
}
|
||||||
static MunitResult
|
static MunitResult
|
||||||
test_api_size(const MunitParameter params[], void *data)
|
test_api_size(const MunitParameter params[], void *data)
|
||||||
{
|
{
|
||||||
sl_raw *slist = (sl_raw *)data;
|
sl_raw *slist = (sl_raw *)data;
|
||||||
(void)params;
|
(void)params;
|
||||||
(void)slist;
|
(void)slist;
|
||||||
return MUNIT_OK;
|
return MUNIT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
test_api_iterators_setup(const MunitParameter params[], void *user_data)
|
test_api_iterators_setup(const MunitParameter params[], void *user_data)
|
||||||
{
|
{
|
||||||
return test_api_setup(params, user_data);
|
return test_api_setup(params, user_data);
|
||||||
}
|
}
|
||||||
static void
|
static void
|
||||||
test_api_iterators_tear_down(void *fixture)
|
test_api_iterators_tear_down(void *fixture)
|
||||||
{
|
{
|
||||||
test_api_tear_down(fixture);
|
test_api_tear_down(fixture);
|
||||||
}
|
}
|
||||||
static MunitResult
|
static MunitResult
|
||||||
test_api_iterators(const MunitParameter params[], void *data)
|
test_api_iterators(const MunitParameter params[], void *data)
|
||||||
{
|
{
|
||||||
sl_raw *slist = (sl_raw *)data;
|
sl_raw *slist = (sl_raw *)data;
|
||||||
(void)params;
|
(void)params;
|
||||||
(void)slist;
|
(void)slist;
|
||||||
return MUNIT_OK;
|
return MUNIT_OK;
|
||||||
}
|
}
|
||||||
|
|
2508
tests/munit.c
2508
tests/munit.c
File diff suppressed because it is too large
Load diff
349
tests/munit.h
349
tests/munit.h
|
@ -29,7 +29,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#define MUNIT_VERSION(major, minor, revision) \
|
#define MUNIT_VERSION(major, minor, revision) \
|
||||||
(((major) << 16) | ((minor) << 8) | (revision))
|
(((major) << 16) | ((minor) << 8) | (revision))
|
||||||
|
|
||||||
#define MUNIT_CURRENT_VERSION MUNIT_VERSION(0, 4, 1)
|
#define MUNIT_CURRENT_VERSION MUNIT_VERSION(0, 4, 1)
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
|
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
|
||||||
!defined(__PGI)
|
!defined(__PGI)
|
||||||
#define MUNIT_ARRAY_PARAM(name) name
|
#define MUNIT_ARRAY_PARAM(name) name
|
||||||
#else
|
#else
|
||||||
#define MUNIT_ARRAY_PARAM(name)
|
#define MUNIT_ARRAY_PARAM(name)
|
||||||
|
@ -164,7 +164,7 @@ extern "C" {
|
||||||
|
|
||||||
#if defined(_MSC_VER) && (_MSC_VER >= 1500)
|
#if defined(_MSC_VER) && (_MSC_VER >= 1500)
|
||||||
#define MUNIT_PUSH_DISABLE_MSVC_C4127_ \
|
#define MUNIT_PUSH_DISABLE_MSVC_C4127_ \
|
||||||
__pragma(warning(push)) __pragma(warning(disable : 4127))
|
__pragma(warning(push)) __pragma(warning(disable : 4127))
|
||||||
#define MUNIT_POP_DISABLE_MSVC_C4127_ __pragma(warning(pop))
|
#define MUNIT_POP_DISABLE_MSVC_C4127_ __pragma(warning(pop))
|
||||||
#else
|
#else
|
||||||
#define MUNIT_PUSH_DISABLE_MSVC_C4127_
|
#define MUNIT_PUSH_DISABLE_MSVC_C4127_
|
||||||
|
@ -172,25 +172,25 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MUNIT_LOG_DEBUG,
|
MUNIT_LOG_DEBUG,
|
||||||
MUNIT_LOG_INFO,
|
MUNIT_LOG_INFO,
|
||||||
MUNIT_LOG_WARNING,
|
MUNIT_LOG_WARNING,
|
||||||
MUNIT_LOG_ERROR
|
MUNIT_LOG_ERROR
|
||||||
} MunitLogLevel;
|
} MunitLogLevel;
|
||||||
|
|
||||||
#if defined(__GNUC__) && !defined(__MINGW32__)
|
#if defined(__GNUC__) && !defined(__MINGW32__)
|
||||||
#define MUNIT_PRINTF(string_index, first_to_check) \
|
#define MUNIT_PRINTF(string_index, first_to_check) \
|
||||||
__attribute__((format(printf, string_index, first_to_check)))
|
__attribute__((format(printf, string_index, first_to_check)))
|
||||||
#else
|
#else
|
||||||
#define MUNIT_PRINTF(string_index, first_to_check)
|
#define MUNIT_PRINTF(string_index, first_to_check)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MUNIT_PRINTF(4, 5)
|
MUNIT_PRINTF(4, 5)
|
||||||
void munit_logf_ex(MunitLogLevel level, const char *filename, int line,
|
void munit_logf_ex(MunitLogLevel level, const char *filename, int line,
|
||||||
const char *format, ...);
|
const char *format, ...);
|
||||||
|
|
||||||
#define munit_logf(level, format, ...) \
|
#define munit_logf(level, format, ...) \
|
||||||
munit_logf_ex(level, __FILE__, __LINE__, format, __VA_ARGS__)
|
munit_logf_ex(level, __FILE__, __LINE__, format, __VA_ARGS__)
|
||||||
|
|
||||||
#define munit_log(level, msg) munit_logf(level, "%s", msg)
|
#define munit_log(level, msg) munit_logf(level, "%s", msg)
|
||||||
|
|
||||||
|
@ -199,170 +199,167 @@ MUNIT_PRINTF(3, 4)
|
||||||
void munit_errorf_ex(const char *filename, int line, const char *format, ...);
|
void munit_errorf_ex(const char *filename, int line, const char *format, ...);
|
||||||
|
|
||||||
#define munit_errorf(format, ...) \
|
#define munit_errorf(format, ...) \
|
||||||
munit_errorf_ex(__FILE__, __LINE__, format, __VA_ARGS__)
|
munit_errorf_ex(__FILE__, __LINE__, format, __VA_ARGS__)
|
||||||
|
|
||||||
#define munit_error(msg) munit_errorf("%s", msg)
|
#define munit_error(msg) munit_errorf("%s", msg)
|
||||||
|
|
||||||
#define munit_assert(expr) \
|
#define munit_assert(expr) \
|
||||||
do { \
|
do { \
|
||||||
if (!MUNIT_LIKELY(expr)) { \
|
if (!MUNIT_LIKELY(expr)) { \
|
||||||
munit_error("assertion failed: " #expr); \
|
munit_error("assertion failed: " #expr); \
|
||||||
} \
|
} \
|
||||||
MUNIT_PUSH_DISABLE_MSVC_C4127_ \
|
MUNIT_PUSH_DISABLE_MSVC_C4127_ \
|
||||||
} while (0) MUNIT_POP_DISABLE_MSVC_C4127_
|
} while (0) MUNIT_POP_DISABLE_MSVC_C4127_
|
||||||
|
|
||||||
#define munit_assert_true(expr) \
|
#define munit_assert_true(expr) \
|
||||||
do { \
|
do { \
|
||||||
if (!MUNIT_LIKELY(expr)) { \
|
if (!MUNIT_LIKELY(expr)) { \
|
||||||
munit_error("assertion failed: " #expr " is not true"); \
|
munit_error("assertion failed: " #expr " is not true"); \
|
||||||
} \
|
} \
|
||||||
MUNIT_PUSH_DISABLE_MSVC_C4127_ \
|
MUNIT_PUSH_DISABLE_MSVC_C4127_ \
|
||||||
} while (0) MUNIT_POP_DISABLE_MSVC_C4127_
|
} while (0) MUNIT_POP_DISABLE_MSVC_C4127_
|
||||||
|
|
||||||
#define munit_assert_false(expr) \
|
#define munit_assert_false(expr) \
|
||||||
do { \
|
do { \
|
||||||
if (!MUNIT_LIKELY(!(expr))) { \
|
if (!MUNIT_LIKELY(!(expr))) { \
|
||||||
munit_error("assertion failed: " #expr " is not false"); \
|
munit_error("assertion failed: " #expr " is not false"); \
|
||||||
} \
|
} \
|
||||||
MUNIT_PUSH_DISABLE_MSVC_C4127_ \
|
MUNIT_PUSH_DISABLE_MSVC_C4127_ \
|
||||||
} while (0) MUNIT_POP_DISABLE_MSVC_C4127_
|
} while (0) MUNIT_POP_DISABLE_MSVC_C4127_
|
||||||
|
|
||||||
#define munit_assert_type_full(prefix, suffix, T, fmt, a, op, b) \
|
#define munit_assert_type_full(prefix, suffix, T, fmt, a, op, b) \
|
||||||
do { \
|
do { \
|
||||||
T munit_tmp_a_ = (a); \
|
T munit_tmp_a_ = (a); \
|
||||||
T munit_tmp_b_ = (b); \
|
T munit_tmp_b_ = (b); \
|
||||||
if (!(munit_tmp_a_ op munit_tmp_b_)) { \
|
if (!(munit_tmp_a_ op munit_tmp_b_)) { \
|
||||||
munit_errorf("assertion failed: %s %s %s (" prefix "%" fmt suffix \
|
munit_errorf("assertion failed: %s %s %s (" prefix "%" fmt suffix \
|
||||||
" %s " prefix "%" fmt suffix ")", \
|
" %s " prefix "%" fmt suffix ")", \
|
||||||
#a, #op, #b, munit_tmp_a_, #op, munit_tmp_b_); \
|
#a, #op, #b, munit_tmp_a_, #op, munit_tmp_b_); \
|
||||||
} \
|
} \
|
||||||
MUNIT_PUSH_DISABLE_MSVC_C4127_ \
|
MUNIT_PUSH_DISABLE_MSVC_C4127_ \
|
||||||
} while (0) MUNIT_POP_DISABLE_MSVC_C4127_
|
} while (0) MUNIT_POP_DISABLE_MSVC_C4127_
|
||||||
|
|
||||||
#define munit_assert_type(T, fmt, a, op, b) \
|
#define munit_assert_type(T, fmt, a, op, b) \
|
||||||
munit_assert_type_full("", "", T, fmt, a, op, b)
|
munit_assert_type_full("", "", T, fmt, a, op, b)
|
||||||
|
|
||||||
#define munit_assert_char(a, op, b) \
|
#define munit_assert_char(a, op, b) \
|
||||||
munit_assert_type_full("'\\x", "'", char, "02" MUNIT_CHAR_MODIFIER "x", a, \
|
munit_assert_type_full("'\\x", "'", char, "02" MUNIT_CHAR_MODIFIER "x", a, \
|
||||||
op, b)
|
op, b)
|
||||||
#define munit_assert_uchar(a, op, b) \
|
#define munit_assert_uchar(a, op, b) \
|
||||||
munit_assert_type_full("'\\x", "'", unsigned char, \
|
munit_assert_type_full("'\\x", "'", unsigned char, \
|
||||||
"02" MUNIT_CHAR_MODIFIER "x", a, op, b)
|
"02" MUNIT_CHAR_MODIFIER "x", a, op, b)
|
||||||
#define munit_assert_short(a, op, b) \
|
#define munit_assert_short(a, op, b) \
|
||||||
munit_assert_type(short, MUNIT_SHORT_MODIFIER "d", a, op, b)
|
munit_assert_type(short, MUNIT_SHORT_MODIFIER "d", a, op, b)
|
||||||
#define munit_assert_ushort(a, op, b) \
|
#define munit_assert_ushort(a, op, b) \
|
||||||
munit_assert_type(unsigned short, MUNIT_SHORT_MODIFIER "u", a, op, b)
|
munit_assert_type(unsigned short, MUNIT_SHORT_MODIFIER "u", a, op, b)
|
||||||
#define munit_assert_int(a, op, b) munit_assert_type(int, "d", a, op, b)
|
#define munit_assert_int(a, op, b) munit_assert_type(int, "d", a, op, b)
|
||||||
#define munit_assert_uint(a, op, b) \
|
#define munit_assert_uint(a, op, b) \
|
||||||
munit_assert_type(unsigned int, "u", a, op, b)
|
munit_assert_type(unsigned int, "u", a, op, b)
|
||||||
#define munit_assert_long(a, op, b) munit_assert_type(long int, "ld", a, op, b)
|
#define munit_assert_long(a, op, b) munit_assert_type(long int, "ld", a, op, b)
|
||||||
#define munit_assert_ulong(a, op, b) \
|
#define munit_assert_ulong(a, op, b) \
|
||||||
munit_assert_type(unsigned long int, "lu", a, op, b)
|
munit_assert_type(unsigned long int, "lu", a, op, b)
|
||||||
#define munit_assert_llong(a, op, b) \
|
#define munit_assert_llong(a, op, b) \
|
||||||
munit_assert_type(long long int, "lld", a, op, b)
|
munit_assert_type(long long int, "lld", a, op, b)
|
||||||
#define munit_assert_ullong(a, op, b) \
|
#define munit_assert_ullong(a, op, b) \
|
||||||
munit_assert_type(unsigned long long int, "llu", a, op, b)
|
munit_assert_type(unsigned long long int, "llu", a, op, b)
|
||||||
|
|
||||||
#define munit_assert_size(a, op, b) \
|
#define munit_assert_size(a, op, b) \
|
||||||
munit_assert_type(size_t, MUNIT_SIZE_MODIFIER "u", a, op, b)
|
munit_assert_type(size_t, MUNIT_SIZE_MODIFIER "u", a, op, b)
|
||||||
|
|
||||||
#define munit_assert_float(a, op, b) munit_assert_type(float, "f", a, op, b)
|
#define munit_assert_float(a, op, b) munit_assert_type(float, "f", a, op, b)
|
||||||
#define munit_assert_double(a, op, b) munit_assert_type(double, "g", a, op, b)
|
#define munit_assert_double(a, op, b) munit_assert_type(double, "g", a, op, b)
|
||||||
#define munit_assert_ptr(a, op, b) \
|
#define munit_assert_ptr(a, op, b) \
|
||||||
munit_assert_type(const void *, "p", a, op, b)
|
munit_assert_type(const void *, "p", a, op, b)
|
||||||
|
|
||||||
#define munit_assert_int8(a, op, b) \
|
#define munit_assert_int8(a, op, b) \
|
||||||
munit_assert_type(munit_int8_t, PRIi8, a, op, b)
|
munit_assert_type(munit_int8_t, PRIi8, a, op, b)
|
||||||
#define munit_assert_uint8(a, op, b) \
|
#define munit_assert_uint8(a, op, b) \
|
||||||
munit_assert_type(munit_uint8_t, PRIu8, a, op, b)
|
munit_assert_type(munit_uint8_t, PRIu8, a, op, b)
|
||||||
#define munit_assert_int16(a, op, b) \
|
#define munit_assert_int16(a, op, b) \
|
||||||
munit_assert_type(munit_int16_t, PRIi16, a, op, b)
|
munit_assert_type(munit_int16_t, PRIi16, a, op, b)
|
||||||
#define munit_assert_uint16(a, op, b) \
|
#define munit_assert_uint16(a, op, b) \
|
||||||
munit_assert_type(munit_uint16_t, PRIu16, a, op, b)
|
munit_assert_type(munit_uint16_t, PRIu16, a, op, b)
|
||||||
#define munit_assert_int32(a, op, b) \
|
#define munit_assert_int32(a, op, b) \
|
||||||
munit_assert_type(munit_int32_t, PRIi32, a, op, b)
|
munit_assert_type(munit_int32_t, PRIi32, a, op, b)
|
||||||
#define munit_assert_uint32(a, op, b) \
|
#define munit_assert_uint32(a, op, b) \
|
||||||
munit_assert_type(munit_uint32_t, PRIu32, a, op, b)
|
munit_assert_type(munit_uint32_t, PRIu32, a, op, b)
|
||||||
#define munit_assert_int64(a, op, b) \
|
#define munit_assert_int64(a, op, b) \
|
||||||
munit_assert_type(munit_int64_t, PRIi64, a, op, b)
|
munit_assert_type(munit_int64_t, PRIi64, a, op, b)
|
||||||
#define munit_assert_uint64(a, op, b) \
|
#define munit_assert_uint64(a, op, b) \
|
||||||
munit_assert_type(munit_uint64_t, PRIu64, a, op, b)
|
munit_assert_type(munit_uint64_t, PRIu64, a, op, b)
|
||||||
|
|
||||||
#define munit_assert_double_equal(a, b, precision) \
|
#define munit_assert_double_equal(a, b, precision) \
|
||||||
do { \
|
do { \
|
||||||
const double munit_tmp_a_ = (a); \
|
const double munit_tmp_a_ = (a); \
|
||||||
const double munit_tmp_b_ = (b); \
|
const double munit_tmp_b_ = (b); \
|
||||||
const double munit_tmp_diff_ = ((munit_tmp_a_ - munit_tmp_b_) < 0) ? \
|
const double munit_tmp_diff_ = ((munit_tmp_a_ - munit_tmp_b_) < 0) ? \
|
||||||
-(munit_tmp_a_ - munit_tmp_b_) : \
|
-(munit_tmp_a_ - munit_tmp_b_) : \
|
||||||
(munit_tmp_a_ - munit_tmp_b_); \
|
(munit_tmp_a_ - munit_tmp_b_); \
|
||||||
if (MUNIT_UNLIKELY(munit_tmp_diff_ > 1e-##precision)) { \
|
if (MUNIT_UNLIKELY(munit_tmp_diff_ > 1e-##precision)) { \
|
||||||
munit_errorf("assertion failed: %s == %s (%0." #precision \
|
munit_errorf("assertion failed: %s == %s (%0." #precision \
|
||||||
"g == %0." #precision "g)", \
|
"g == %0." #precision "g)", \
|
||||||
#a, #b, munit_tmp_a_, munit_tmp_b_); \
|
#a, #b, munit_tmp_a_, munit_tmp_b_); \
|
||||||
} \
|
} \
|
||||||
MUNIT_PUSH_DISABLE_MSVC_C4127_ \
|
MUNIT_PUSH_DISABLE_MSVC_C4127_ \
|
||||||
} while (0) MUNIT_POP_DISABLE_MSVC_C4127_
|
} while (0) MUNIT_POP_DISABLE_MSVC_C4127_
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#define munit_assert_string_equal(a, b) \
|
#define munit_assert_string_equal(a, b) \
|
||||||
do { \
|
do { \
|
||||||
const char *munit_tmp_a_ = a; \
|
const char *munit_tmp_a_ = a; \
|
||||||
const char *munit_tmp_b_ = b; \
|
const char *munit_tmp_b_ = b; \
|
||||||
if (MUNIT_UNLIKELY(strcmp(munit_tmp_a_, munit_tmp_b_) != 0)) { \
|
if (MUNIT_UNLIKELY(strcmp(munit_tmp_a_, munit_tmp_b_) != 0)) { \
|
||||||
munit_errorf( \
|
munit_errorf("assertion failed: string %s == %s (\"%s\" == \"%s\")", #a, \
|
||||||
"assertion failed: string %s == %s (\"%s\" == \"%s\")", #a, \
|
#b, munit_tmp_a_, munit_tmp_b_); \
|
||||||
#b, munit_tmp_a_, munit_tmp_b_); \
|
} \
|
||||||
} \
|
MUNIT_PUSH_DISABLE_MSVC_C4127_ \
|
||||||
MUNIT_PUSH_DISABLE_MSVC_C4127_ \
|
} while (0) MUNIT_POP_DISABLE_MSVC_C4127_
|
||||||
} while (0) MUNIT_POP_DISABLE_MSVC_C4127_
|
|
||||||
|
|
||||||
#define munit_assert_string_not_equal(a, b) \
|
#define munit_assert_string_not_equal(a, b) \
|
||||||
do { \
|
do { \
|
||||||
const char *munit_tmp_a_ = a; \
|
const char *munit_tmp_a_ = a; \
|
||||||
const char *munit_tmp_b_ = b; \
|
const char *munit_tmp_b_ = b; \
|
||||||
if (MUNIT_UNLIKELY(strcmp(munit_tmp_a_, munit_tmp_b_) == 0)) { \
|
if (MUNIT_UNLIKELY(strcmp(munit_tmp_a_, munit_tmp_b_) == 0)) { \
|
||||||
munit_errorf( \
|
munit_errorf("assertion failed: string %s != %s (\"%s\" == \"%s\")", #a, \
|
||||||
"assertion failed: string %s != %s (\"%s\" == \"%s\")", #a, \
|
#b, munit_tmp_a_, munit_tmp_b_); \
|
||||||
#b, munit_tmp_a_, munit_tmp_b_); \
|
} \
|
||||||
} \
|
MUNIT_PUSH_DISABLE_MSVC_C4127_ \
|
||||||
MUNIT_PUSH_DISABLE_MSVC_C4127_ \
|
} while (0) MUNIT_POP_DISABLE_MSVC_C4127_
|
||||||
} while (0) MUNIT_POP_DISABLE_MSVC_C4127_
|
|
||||||
|
|
||||||
#define munit_assert_memory_equal(size, a, b) \
|
#define munit_assert_memory_equal(size, a, b) \
|
||||||
do { \
|
do { \
|
||||||
const unsigned char *munit_tmp_a_ = (const unsigned char *)(a); \
|
const unsigned char *munit_tmp_a_ = (const unsigned char *)(a); \
|
||||||
const unsigned char *munit_tmp_b_ = (const unsigned char *)(b); \
|
const unsigned char *munit_tmp_b_ = (const unsigned char *)(b); \
|
||||||
const size_t munit_tmp_size_ = (size); \
|
const size_t munit_tmp_size_ = (size); \
|
||||||
if (MUNIT_UNLIKELY( \
|
if (MUNIT_UNLIKELY(memcmp(munit_tmp_a_, munit_tmp_b_, munit_tmp_size_)) != \
|
||||||
memcmp(munit_tmp_a_, munit_tmp_b_, munit_tmp_size_)) != 0) { \
|
0) { \
|
||||||
size_t munit_tmp_pos_; \
|
size_t munit_tmp_pos_; \
|
||||||
for (munit_tmp_pos_ = 0; munit_tmp_pos_ < munit_tmp_size_; \
|
for (munit_tmp_pos_ = 0; munit_tmp_pos_ < munit_tmp_size_; \
|
||||||
munit_tmp_pos_++) { \
|
munit_tmp_pos_++) { \
|
||||||
if (munit_tmp_a_[munit_tmp_pos_] != \
|
if (munit_tmp_a_[munit_tmp_pos_] != munit_tmp_b_[munit_tmp_pos_]) { \
|
||||||
munit_tmp_b_[munit_tmp_pos_]) { \
|
munit_errorf( \
|
||||||
munit_errorf( \
|
"assertion failed: memory %s == %s, at offset %" MUNIT_SIZE_MODIFIER \
|
||||||
"assertion failed: memory %s == %s, at offset %" MUNIT_SIZE_MODIFIER \
|
"u", \
|
||||||
"u", \
|
#a, #b, munit_tmp_pos_); \
|
||||||
#a, #b, munit_tmp_pos_); \
|
break; \
|
||||||
break; \
|
} \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
} \
|
MUNIT_PUSH_DISABLE_MSVC_C4127_ \
|
||||||
MUNIT_PUSH_DISABLE_MSVC_C4127_ \
|
} while (0) MUNIT_POP_DISABLE_MSVC_C4127_
|
||||||
} while (0) MUNIT_POP_DISABLE_MSVC_C4127_
|
|
||||||
|
|
||||||
#define munit_assert_memory_not_equal(size, a, b) \
|
#define munit_assert_memory_not_equal(size, a, b) \
|
||||||
do { \
|
do { \
|
||||||
const unsigned char *munit_tmp_a_ = (const unsigned char *)(a); \
|
const unsigned char *munit_tmp_a_ = (const unsigned char *)(a); \
|
||||||
const unsigned char *munit_tmp_b_ = (const unsigned char *)(b); \
|
const unsigned char *munit_tmp_b_ = (const unsigned char *)(b); \
|
||||||
const size_t munit_tmp_size_ = (size); \
|
const size_t munit_tmp_size_ = (size); \
|
||||||
if (MUNIT_UNLIKELY( \
|
if (MUNIT_UNLIKELY(memcmp(munit_tmp_a_, munit_tmp_b_, munit_tmp_size_)) == \
|
||||||
memcmp(munit_tmp_a_, munit_tmp_b_, munit_tmp_size_)) == 0) { \
|
0) { \
|
||||||
munit_errorf("assertion failed: memory %s != %s (%zu bytes)", #a, \
|
munit_errorf("assertion failed: memory %s != %s (%zu bytes)", #a, #b, \
|
||||||
#b, munit_tmp_size_); \
|
munit_tmp_size_); \
|
||||||
} \
|
} \
|
||||||
MUNIT_PUSH_DISABLE_MSVC_C4127_ \
|
MUNIT_PUSH_DISABLE_MSVC_C4127_ \
|
||||||
} while (0) MUNIT_POP_DISABLE_MSVC_C4127_
|
} while (0) MUNIT_POP_DISABLE_MSVC_C4127_
|
||||||
|
|
||||||
#define munit_assert_ptr_equal(a, b) munit_assert_ptr(a, ==, b)
|
#define munit_assert_ptr_equal(a, b) munit_assert_ptr(a, ==, b)
|
||||||
#define munit_assert_ptr_not_equal(a, b) munit_assert_ptr(a, !=, b)
|
#define munit_assert_ptr_not_equal(a, b) munit_assert_ptr(a, !=, b)
|
||||||
|
@ -390,54 +387,54 @@ munit_uint32_t munit_rand_uint32(void);
|
||||||
int munit_rand_int_range(int min, int max);
|
int munit_rand_int_range(int min, int max);
|
||||||
double munit_rand_double(void);
|
double munit_rand_double(void);
|
||||||
void munit_rand_memory(size_t size,
|
void munit_rand_memory(size_t size,
|
||||||
munit_uint8_t buffer[MUNIT_ARRAY_PARAM(size)]);
|
munit_uint8_t buffer[MUNIT_ARRAY_PARAM(size)]);
|
||||||
|
|
||||||
/*** Tests and Suites ***/
|
/*** Tests and Suites ***/
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
/* Test successful */
|
/* Test successful */
|
||||||
MUNIT_OK,
|
MUNIT_OK,
|
||||||
/* Test failed */
|
/* Test failed */
|
||||||
MUNIT_FAIL,
|
MUNIT_FAIL,
|
||||||
/* Test was skipped */
|
/* Test was skipped */
|
||||||
MUNIT_SKIP,
|
MUNIT_SKIP,
|
||||||
/* Test failed due to circumstances not intended to be tested
|
/* Test failed due to circumstances not intended to be tested
|
||||||
* (things like network errors, invalid parameter value, failure to
|
* (things like network errors, invalid parameter value, failure to
|
||||||
* allocate memory in the test harness, etc.). */
|
* allocate memory in the test harness, etc.). */
|
||||||
MUNIT_ERROR
|
MUNIT_ERROR
|
||||||
} MunitResult;
|
} MunitResult;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *name;
|
char *name;
|
||||||
char **values;
|
char **values;
|
||||||
} MunitParameterEnum;
|
} MunitParameterEnum;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *name;
|
char *name;
|
||||||
char *value;
|
char *value;
|
||||||
} MunitParameter;
|
} MunitParameter;
|
||||||
|
|
||||||
const char *munit_parameters_get(const MunitParameter params[],
|
const char *munit_parameters_get(const MunitParameter params[],
|
||||||
const char *key);
|
const char *key);
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MUNIT_TEST_OPTION_NONE = 0,
|
MUNIT_TEST_OPTION_NONE = 0,
|
||||||
MUNIT_TEST_OPTION_SINGLE_ITERATION = 1 << 0,
|
MUNIT_TEST_OPTION_SINGLE_ITERATION = 1 << 0,
|
||||||
MUNIT_TEST_OPTION_TODO = 1 << 1
|
MUNIT_TEST_OPTION_TODO = 1 << 1
|
||||||
} MunitTestOptions;
|
} MunitTestOptions;
|
||||||
|
|
||||||
typedef MunitResult (
|
typedef MunitResult (
|
||||||
*MunitTestFunc)(const MunitParameter params[], void *user_data_or_fixture);
|
*MunitTestFunc)(const MunitParameter params[], void *user_data_or_fixture);
|
||||||
typedef void *(*MunitTestSetup)(const MunitParameter params[], void *user_data);
|
typedef void *(*MunitTestSetup)(const MunitParameter params[], void *user_data);
|
||||||
typedef void (*MunitTestTearDown)(void *fixture);
|
typedef void (*MunitTestTearDown)(void *fixture);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *name;
|
char *name;
|
||||||
MunitTestFunc test;
|
MunitTestFunc test;
|
||||||
MunitTestSetup setup;
|
MunitTestSetup setup;
|
||||||
MunitTestTearDown tear_down;
|
MunitTestTearDown tear_down;
|
||||||
MunitTestOptions options;
|
MunitTestOptions options;
|
||||||
MunitParameterEnum *parameters;
|
MunitParameterEnum *parameters;
|
||||||
} MunitTest;
|
} MunitTest;
|
||||||
|
|
||||||
typedef enum { MUNIT_SUITE_OPTION_NONE = 0 } MunitSuiteOptions;
|
typedef enum { MUNIT_SUITE_OPTION_NONE = 0 } MunitSuiteOptions;
|
||||||
|
@ -445,15 +442,15 @@ typedef enum { MUNIT_SUITE_OPTION_NONE = 0 } MunitSuiteOptions;
|
||||||
typedef struct MunitSuite_ MunitSuite;
|
typedef struct MunitSuite_ MunitSuite;
|
||||||
|
|
||||||
struct MunitSuite_ {
|
struct MunitSuite_ {
|
||||||
char *prefix;
|
char *prefix;
|
||||||
MunitTest *tests;
|
MunitTest *tests;
|
||||||
MunitSuite *suites;
|
MunitSuite *suites;
|
||||||
unsigned int iterations;
|
unsigned int iterations;
|
||||||
MunitSuiteOptions options;
|
MunitSuiteOptions options;
|
||||||
};
|
};
|
||||||
|
|
||||||
int munit_suite_main(const MunitSuite *suite, void *user_data, int argc,
|
int munit_suite_main(const MunitSuite *suite, void *user_data, int argc,
|
||||||
char *const argv[MUNIT_ARRAY_PARAM(argc + 1)]);
|
char *const argv[MUNIT_ARRAY_PARAM(argc + 1)]);
|
||||||
|
|
||||||
/* Note: I'm not very happy with this API; it's likely to change if I
|
/* Note: I'm not very happy with this API; it's likely to change if I
|
||||||
* figure out something better. Suggestions welcome. */
|
* figure out something better. Suggestions welcome. */
|
||||||
|
@ -461,15 +458,15 @@ int munit_suite_main(const MunitSuite *suite, void *user_data, int argc,
|
||||||
typedef struct MunitArgument_ MunitArgument;
|
typedef struct MunitArgument_ MunitArgument;
|
||||||
|
|
||||||
struct MunitArgument_ {
|
struct MunitArgument_ {
|
||||||
char *name;
|
char *name;
|
||||||
munit_bool (*parse_argument)(const MunitSuite *suite, void *user_data,
|
munit_bool (*parse_argument)(const MunitSuite *suite, void *user_data,
|
||||||
int *arg, int argc, char *const argv[MUNIT_ARRAY_PARAM(argc + 1)]);
|
int *arg, int argc, char *const argv[MUNIT_ARRAY_PARAM(argc + 1)]);
|
||||||
void (*write_help)(const MunitArgument *argument, void *user_data);
|
void (*write_help)(const MunitArgument *argument, void *user_data);
|
||||||
};
|
};
|
||||||
|
|
||||||
int munit_suite_main_custom(const MunitSuite *suite, void *user_data, int argc,
|
int munit_suite_main_custom(const MunitSuite *suite, void *user_data, int argc,
|
||||||
char *const argv[MUNIT_ARRAY_PARAM(argc + 1)],
|
char *const argv[MUNIT_ARRAY_PARAM(argc + 1)],
|
||||||
const MunitArgument arguments[]);
|
const MunitArgument arguments[]);
|
||||||
|
|
||||||
#if defined(MUNIT_ENABLE_ASSERT_ALIASES)
|
#if defined(MUNIT_ENABLE_ASSERT_ALIASES)
|
||||||
|
|
||||||
|
@ -500,12 +497,12 @@ int munit_suite_main_custom(const MunitSuite *suite, void *user_data, int argc,
|
||||||
#define assert_uint64(a, op, b) munit_assert_uint64(a, op, b)
|
#define assert_uint64(a, op, b) munit_assert_uint64(a, op, b)
|
||||||
|
|
||||||
#define assert_double_equal(a, b, precision) \
|
#define assert_double_equal(a, b, precision) \
|
||||||
munit_assert_double_equal(a, b, precision)
|
munit_assert_double_equal(a, b, precision)
|
||||||
#define assert_string_equal(a, b) munit_assert_string_equal(a, b)
|
#define assert_string_equal(a, b) munit_assert_string_equal(a, b)
|
||||||
#define assert_string_not_equal(a, b) munit_assert_string_not_equal(a, b)
|
#define assert_string_not_equal(a, b) munit_assert_string_not_equal(a, b)
|
||||||
#define assert_memory_equal(size, a, b) munit_assert_memory_equal(size, a, b)
|
#define assert_memory_equal(size, a, b) munit_assert_memory_equal(size, a, b)
|
||||||
#define assert_memory_not_equal(size, a, b) \
|
#define assert_memory_not_equal(size, a, b) \
|
||||||
munit_assert_memory_not_equal(size, a, b)
|
munit_assert_memory_not_equal(size, a, b)
|
||||||
#define assert_ptr_equal(a, b) munit_assert_ptr_equal(a, b)
|
#define assert_ptr_equal(a, b) munit_assert_ptr_equal(a, b)
|
||||||
#define assert_ptr_not_equal(a, b) munit_assert_ptr_not_equal(a, b)
|
#define assert_ptr_not_equal(a, b) munit_assert_ptr_not_equal(a, b)
|
||||||
#define assert_ptr_null(ptr) munit_assert_null_equal(ptr)
|
#define assert_ptr_null(ptr) munit_assert_null_equal(ptr)
|
||||||
|
|
439
tests/test.c
439
tests/test.c
|
@ -29,55 +29,55 @@
|
||||||
#define __SLD_P(...) printf(__VA_ARGS__)
|
#define __SLD_P(...) printf(__VA_ARGS__)
|
||||||
#elif __SL_DEBUG >= 3
|
#elif __SL_DEBUG >= 3
|
||||||
typedef struct dbg_node {
|
typedef struct dbg_node {
|
||||||
sl_node snode;
|
sl_node snode;
|
||||||
int value;
|
int value;
|
||||||
} dbg_node_t;
|
} dbg_node_t;
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
__sld_rt_ins(int error_code, sl_node *node, int top_layer, int cur_layer)
|
__sld_rt_ins(int error_code, sl_node *node, int top_layer, int cur_layer)
|
||||||
{
|
{
|
||||||
dbg_node_t *ddd = sl_get_entry(node, dbg_node_t, snode);
|
dbg_node_t *ddd = sl_get_entry(node, dbg_node_t, snode);
|
||||||
printf("[INS] retry (code %d) "
|
printf("[INS] retry (code %d) "
|
||||||
"%p (top %d, cur %d) %d\n",
|
"%p (top %d, cur %d) %d\n",
|
||||||
error_code, node, top_layer, cur_layer, ddd->value);
|
error_code, node, top_layer, cur_layer, ddd->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
__sld_nc_ins(sl_node *node, sl_node *next_node, int top_layer, int cur_layer)
|
__sld_nc_ins(sl_node *node, sl_node *next_node, int top_layer, int cur_layer)
|
||||||
{
|
{
|
||||||
dbg_node_t *ddd = sl_get_entry(node, dbg_node_t, snode);
|
dbg_node_t *ddd = sl_get_entry(node, dbg_node_t, snode);
|
||||||
dbg_node_t *ddd_next = sl_get_entry(next_node, dbg_node_t, snode);
|
dbg_node_t *ddd_next = sl_get_entry(next_node, dbg_node_t, snode);
|
||||||
|
|
||||||
printf("[INS] next node changed, "
|
printf("[INS] next node changed, "
|
||||||
"%p %p (top %d, cur %d) %d %d\n",
|
"%p %p (top %d, cur %d) %d %d\n",
|
||||||
node, next_node, top_layer, cur_layer, ddd->value, ddd_next->value);
|
node, next_node, top_layer, cur_layer, ddd->value, ddd_next->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
__sld_rt_rmv(int error_code, sl_node *node, int top_layer, int cur_layer)
|
__sld_rt_rmv(int error_code, sl_node *node, int top_layer, int cur_layer)
|
||||||
{
|
{
|
||||||
dbg_node_t *ddd = sl_get_entry(node, dbg_node_t, snode);
|
dbg_node_t *ddd = sl_get_entry(node, dbg_node_t, snode);
|
||||||
printf("[RMV] retry (code %d) "
|
printf("[RMV] retry (code %d) "
|
||||||
"%p (top %d, cur %d) %d\n",
|
"%p (top %d, cur %d) %d\n",
|
||||||
error_code, node, top_layer, cur_layer, ddd->value);
|
error_code, node, top_layer, cur_layer, ddd->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
__sld_nc_rmv(sl_node *node, sl_node *next_node, int top_layer, int cur_layer)
|
__sld_nc_rmv(sl_node *node, sl_node *next_node, int top_layer, int cur_layer)
|
||||||
{
|
{
|
||||||
dbg_node_t *ddd = sl_get_entry(node, dbg_node_t, snode);
|
dbg_node_t *ddd = sl_get_entry(node, dbg_node_t, snode);
|
||||||
dbg_node_t *ddd_next = sl_get_entry(next_node, dbg_node_t, snode);
|
dbg_node_t *ddd_next = sl_get_entry(next_node, dbg_node_t, snode);
|
||||||
|
|
||||||
printf("[RMV] next node changed, "
|
printf("[RMV] next node changed, "
|
||||||
"%p %p (top %d, cur %d) %d %d\n",
|
"%p %p (top %d, cur %d) %d %d\n",
|
||||||
node, next_node, top_layer, cur_layer, ddd->value, ddd_next->value);
|
node, next_node, top_layer, cur_layer, ddd->value, ddd_next->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
__sld_bm(sl_node *node)
|
__sld_bm(sl_node *node)
|
||||||
{
|
{
|
||||||
dbg_node_t *ddd = sl_get_entry(node, dbg_node_t, snode);
|
dbg_node_t *ddd = sl_get_entry(node, dbg_node_t, snode);
|
||||||
printf("[RMV] node is being modified %d\n", ddd->value);
|
printf("[RMV] node is being modified %d\n", ddd->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define __SLD_RT_INS(e, n, t, c) __sld_rt_ins(e, n, t, c)
|
#define __SLD_RT_INS(e, n, t, c) __sld_rt_ins(e, n, t, c)
|
||||||
|
@ -95,13 +95,13 @@ __sld_bm(sl_node *node)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct user_data {
|
struct user_data {
|
||||||
size_t n_ele;
|
size_t n_ele;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct ex_node {
|
typedef struct ex_node {
|
||||||
sl_node snode;
|
sl_node snode;
|
||||||
uint32_t key;
|
uint32_t key;
|
||||||
uint32_t value;
|
uint32_t value;
|
||||||
} ex_node_t;
|
} ex_node_t;
|
||||||
|
|
||||||
typedef sl_raw ex_sl_t;
|
typedef sl_raw ex_sl_t;
|
||||||
|
@ -109,340 +109,341 @@ typedef sl_raw ex_sl_t;
|
||||||
static int
|
static int
|
||||||
uint32_key_cmp(sl_node *a, sl_node *b, void *aux)
|
uint32_key_cmp(sl_node *a, sl_node *b, void *aux)
|
||||||
{
|
{
|
||||||
ex_node_t *aa, *bb;
|
ex_node_t *aa, *bb;
|
||||||
(void)aux;
|
(void)aux;
|
||||||
aa = sl_get_entry(a, ex_node_t, snode);
|
aa = sl_get_entry(a, ex_node_t, snode);
|
||||||
bb = sl_get_entry(b, ex_node_t, snode);
|
bb = sl_get_entry(b, ex_node_t, snode);
|
||||||
|
|
||||||
if (aa->key < bb->key)
|
if (aa->key < bb->key)
|
||||||
return -1;
|
return -1;
|
||||||
if (aa->key > bb->key)
|
if (aa->key > bb->key)
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
__populate_slist(ex_sl_t *slist){
|
__populate_slist(ex_sl_t *slist)
|
||||||
size_t inserted = 0;
|
{
|
||||||
uint32_t n, key;
|
size_t inserted = 0;
|
||||||
ex_node_t *node;
|
uint32_t n, key;
|
||||||
|
ex_node_t *node;
|
||||||
|
|
||||||
n = munit_rand_int_range(1024, 4196);
|
n = munit_rand_int_range(1024, 4196);
|
||||||
while (n--) {
|
while (n--) {
|
||||||
key = munit_rand_int_range(0, (((uint32_t)0) - 1) / 10);
|
key = munit_rand_int_range(0, (((uint32_t)0) - 1) / 10);
|
||||||
node = (ex_node_t *)calloc(sizeof(ex_node_t), 1);
|
node = (ex_node_t *)calloc(sizeof(ex_node_t), 1);
|
||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
return MUNIT_ERROR;
|
return MUNIT_ERROR;
|
||||||
sl_init_node(&node->snode);
|
sl_init_node(&node->snode);
|
||||||
node->key = key;
|
node->key = key;
|
||||||
node->value = key;
|
node->value = key;
|
||||||
if (sl_insert_nodup(slist, &node->snode) == -1)
|
if (sl_insert_nodup(slist, &node->snode) == -1)
|
||||||
continue; /* a random duplicate appeared */
|
continue; /* a random duplicate appeared */
|
||||||
else
|
else
|
||||||
inserted++;
|
inserted++;
|
||||||
}
|
}
|
||||||
return inserted;
|
return inserted;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
test_api_setup(const MunitParameter params[], void *user_data)
|
test_api_setup(const MunitParameter params[], void *user_data)
|
||||||
{
|
{
|
||||||
struct test_info *info = (struct test_info *)user_data;
|
struct test_info *info = (struct test_info *)user_data;
|
||||||
(void)info;
|
(void)info;
|
||||||
(void)params;
|
(void)params;
|
||||||
|
|
||||||
ex_sl_t *slist = calloc(sizeof(ex_sl_t), 1);
|
ex_sl_t *slist = calloc(sizeof(ex_sl_t), 1);
|
||||||
if (slist == NULL)
|
if (slist == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
sl_init(slist, uint32_key_cmp);
|
sl_init(slist, uint32_key_cmp);
|
||||||
return (void *)(uintptr_t)slist;
|
return (void *)(uintptr_t)slist;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_api_tear_down(void *fixture)
|
test_api_tear_down(void *fixture)
|
||||||
{
|
{
|
||||||
ex_sl_t *slist = (ex_sl_t *)fixture;
|
ex_sl_t *slist = (ex_sl_t *)fixture;
|
||||||
assert_ptr_not_null(slist);
|
assert_ptr_not_null(slist);
|
||||||
sl_node *cursor = sl_begin(slist);
|
sl_node *cursor = sl_begin(slist);
|
||||||
while (cursor) {
|
while (cursor) {
|
||||||
assert_ptr_not_null(cursor);
|
assert_ptr_not_null(cursor);
|
||||||
ex_node_t *entry = sl_get_entry(cursor, ex_node_t, snode);
|
ex_node_t *entry = sl_get_entry(cursor, ex_node_t, snode);
|
||||||
assert_ptr_not_null(entry);
|
assert_ptr_not_null(entry);
|
||||||
assert_uint32(entry->key, ==, entry->value);
|
assert_uint32(entry->key, ==, entry->value);
|
||||||
cursor = sl_next(slist, cursor);
|
cursor = sl_next(slist, cursor);
|
||||||
sl_erase_node(slist, &entry->snode);
|
sl_erase_node(slist, &entry->snode);
|
||||||
sl_release_node(&entry->snode);
|
sl_release_node(&entry->snode);
|
||||||
sl_wait_for_free(&entry->snode);
|
sl_wait_for_free(&entry->snode);
|
||||||
sl_free_node(&entry->snode);
|
sl_free_node(&entry->snode);
|
||||||
free(entry);
|
free(entry);
|
||||||
}
|
}
|
||||||
sl_free(slist);
|
sl_free(slist);
|
||||||
free(fixture);
|
free(fixture);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
test_api_insert_setup(const MunitParameter params[], void *user_data)
|
test_api_insert_setup(const MunitParameter params[], void *user_data)
|
||||||
{
|
{
|
||||||
return test_api_setup(params, user_data);
|
return test_api_setup(params, user_data);
|
||||||
}
|
}
|
||||||
static void
|
static void
|
||||||
test_api_insert_tear_down(void *fixture)
|
test_api_insert_tear_down(void *fixture)
|
||||||
{
|
{
|
||||||
test_api_tear_down(fixture);
|
test_api_tear_down(fixture);
|
||||||
}
|
}
|
||||||
static MunitResult
|
static MunitResult
|
||||||
test_api_insert(const MunitParameter params[], void *data)
|
test_api_insert(const MunitParameter params[], void *data)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
size_t inserted = 0;
|
size_t inserted = 0;
|
||||||
uint32_t n, key;
|
uint32_t n, key;
|
||||||
sl_raw *slist = (sl_raw *)data;
|
sl_raw *slist = (sl_raw *)data;
|
||||||
ex_node_t *node;
|
ex_node_t *node;
|
||||||
(void)params;
|
(void)params;
|
||||||
|
|
||||||
assert_ptr_not_null(slist);
|
assert_ptr_not_null(slist);
|
||||||
n = munit_rand_int_range(4096, 8192);
|
n = munit_rand_int_range(4096, 8192);
|
||||||
while (n--) {
|
while (n--) {
|
||||||
key = munit_rand_int_range(0, ((uint32_t)0-1) / 10);
|
key = munit_rand_int_range(0, ((uint32_t)0 - 1) / 10);
|
||||||
node = (ex_node_t *)calloc(sizeof(ex_node_t), 1);
|
node = (ex_node_t *)calloc(sizeof(ex_node_t), 1);
|
||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
return MUNIT_ERROR;
|
return MUNIT_ERROR;
|
||||||
sl_init_node(&node->snode);
|
sl_init_node(&node->snode);
|
||||||
node->key = key;
|
node->key = key;
|
||||||
node->value = key;
|
node->value = key;
|
||||||
if ((ret = sl_insert_nodup(slist, &node->snode)) == -1)
|
if ((ret = sl_insert_nodup(slist, &node->snode)) == -1)
|
||||||
continue; /* a random duplicate appeared */
|
continue; /* a random duplicate appeared */
|
||||||
else {
|
else {
|
||||||
assert_int(ret, ==, 0);
|
assert_int(ret, ==, 0);
|
||||||
inserted++;
|
inserted++;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
assert_size(inserted, ==, sl_get_size(slist));
|
}
|
||||||
return MUNIT_OK;
|
assert_size(inserted, ==, sl_get_size(slist));
|
||||||
|
return MUNIT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
test_api_remove_setup(const MunitParameter params[], void *user_data)
|
test_api_remove_setup(const MunitParameter params[], void *user_data)
|
||||||
{
|
{
|
||||||
sl_raw *slist = (sl_raw *)test_api_setup(params, user_data);
|
sl_raw *slist = (sl_raw *)test_api_setup(params, user_data);
|
||||||
__populate_slist(slist);
|
__populate_slist(slist);
|
||||||
return (void *)slist;
|
return (void *)slist;
|
||||||
}
|
}
|
||||||
static void
|
static void
|
||||||
test_api_remove_tear_down(void *fixture)
|
test_api_remove_tear_down(void *fixture)
|
||||||
{
|
{
|
||||||
test_api_tear_down(fixture);
|
test_api_tear_down(fixture);
|
||||||
}
|
}
|
||||||
static MunitResult
|
static MunitResult
|
||||||
test_api_remove(const MunitParameter params[], void *data)
|
test_api_remove(const MunitParameter params[], void *data)
|
||||||
{
|
{
|
||||||
uint32_t key;
|
uint32_t key;
|
||||||
sl_raw *slist = (sl_raw *)data;
|
sl_raw *slist = (sl_raw *)data;
|
||||||
ex_node_t *node;
|
ex_node_t *node;
|
||||||
(void)params;
|
(void)params;
|
||||||
|
|
||||||
assert_ptr_not_null(slist);
|
assert_ptr_not_null(slist);
|
||||||
key = munit_rand_int_range((((uint32_t)0-1) / 10) + 1, ((uint32_t)0-1));
|
key = munit_rand_int_range((((uint32_t)0 - 1) / 10) + 1, ((uint32_t)0 - 1));
|
||||||
node = (ex_node_t *)calloc(sizeof(ex_node_t), 1);
|
node = (ex_node_t *)calloc(sizeof(ex_node_t), 1);
|
||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
return MUNIT_ERROR;
|
return MUNIT_ERROR;
|
||||||
sl_init_node(&node->snode);
|
sl_init_node(&node->snode);
|
||||||
node->key = key;
|
node->key = key;
|
||||||
node->value = key;
|
node->value = key;
|
||||||
if (sl_insert_nodup(slist, &node->snode) == -1)
|
if (sl_insert_nodup(slist, &node->snode) == -1)
|
||||||
return MUNIT_ERROR;
|
return MUNIT_ERROR;
|
||||||
else {
|
else {
|
||||||
ex_node_t query;
|
ex_node_t query;
|
||||||
query.key = key;
|
query.key = key;
|
||||||
sl_node *cursor = sl_find(slist, &query.snode);
|
sl_node *cursor = sl_find(slist, &query.snode);
|
||||||
assert_ptr_not_null(cursor);
|
assert_ptr_not_null(cursor);
|
||||||
ex_node_t *entry = sl_get_entry(cursor, ex_node_t, snode);
|
ex_node_t *entry = sl_get_entry(cursor, ex_node_t, snode);
|
||||||
sl_erase_node(slist, &entry->snode);
|
sl_erase_node(slist, &entry->snode);
|
||||||
sl_release_node(&entry->snode);
|
sl_release_node(&entry->snode);
|
||||||
sl_wait_for_free(&entry->snode);
|
sl_wait_for_free(&entry->snode);
|
||||||
sl_free_node(&entry->snode);
|
sl_free_node(&entry->snode);
|
||||||
free(entry);
|
free(entry);
|
||||||
}
|
}
|
||||||
return MUNIT_OK;
|
return MUNIT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
test_api_find_setup(const MunitParameter params[], void *user_data)
|
test_api_find_setup(const MunitParameter params[], void *user_data)
|
||||||
{
|
{
|
||||||
sl_raw *slist = (sl_raw *)test_api_setup(params, user_data);
|
sl_raw *slist = (sl_raw *)test_api_setup(params, user_data);
|
||||||
ex_node_t *node;
|
ex_node_t *node;
|
||||||
for (int i = 1; i <= 100; ++i) {
|
for (int i = 1; i <= 100; ++i) {
|
||||||
node = calloc(sizeof(ex_node_t), 1);
|
node = calloc(sizeof(ex_node_t), 1);
|
||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
node = (ex_node_t *)calloc(sizeof(ex_node_t), 1);
|
node = (ex_node_t *)calloc(sizeof(ex_node_t), 1);
|
||||||
sl_init_node(&node->snode);
|
sl_init_node(&node->snode);
|
||||||
node->key = i;
|
node->key = i;
|
||||||
node->value = i;
|
node->value = i;
|
||||||
sl_insert(slist, &node->snode);
|
sl_insert(slist, &node->snode);
|
||||||
}
|
}
|
||||||
return (void *)slist;
|
return (void *)slist;
|
||||||
}
|
}
|
||||||
static void
|
static void
|
||||||
test_api_find_tear_down(void *fixture)
|
test_api_find_tear_down(void *fixture)
|
||||||
{
|
{
|
||||||
test_api_tear_down(fixture);
|
test_api_tear_down(fixture);
|
||||||
}
|
}
|
||||||
static MunitResult
|
static MunitResult
|
||||||
test_api_find(const MunitParameter params[], void *data)
|
test_api_find(const MunitParameter params[], void *data)
|
||||||
{
|
{
|
||||||
sl_raw *slist = (sl_raw *)data;
|
sl_raw *slist = (sl_raw *)data;
|
||||||
(void)params;
|
(void)params;
|
||||||
|
|
||||||
/* find equal every value */
|
/* find equal every value */
|
||||||
assert_ptr_not_null(data);
|
assert_ptr_not_null(data);
|
||||||
for (int i = 1; i <= 100; i++) {
|
for (int i = 1; i <= 100; i++) {
|
||||||
ex_node_t query;
|
ex_node_t query;
|
||||||
query.key = i;
|
query.key = i;
|
||||||
sl_node *cursor = sl_find(slist, &query.snode);
|
sl_node *cursor = sl_find(slist, &query.snode);
|
||||||
assert_ptr_not_null(cursor);
|
assert_ptr_not_null(cursor);
|
||||||
ex_node_t *entry = sl_get_entry(cursor, ex_node_t, snode);
|
ex_node_t *entry = sl_get_entry(cursor, ex_node_t, snode);
|
||||||
assert_uint32(entry->key, ==, i);
|
assert_uint32(entry->key, ==, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* */
|
/* */
|
||||||
return MUNIT_OK;
|
return MUNIT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
test_api_update_setup(const MunitParameter params[], void *user_data)
|
test_api_update_setup(const MunitParameter params[], void *user_data)
|
||||||
{
|
{
|
||||||
return test_api_setup(params, user_data);
|
return test_api_setup(params, user_data);
|
||||||
}
|
}
|
||||||
static void
|
static void
|
||||||
test_api_update_tear_down(void *fixture)
|
test_api_update_tear_down(void *fixture)
|
||||||
{
|
{
|
||||||
test_api_tear_down(fixture);
|
test_api_tear_down(fixture);
|
||||||
}
|
}
|
||||||
static MunitResult
|
static MunitResult
|
||||||
test_api_update(const MunitParameter params[], void *data)
|
test_api_update(const MunitParameter params[], void *data)
|
||||||
{
|
{
|
||||||
sl_raw *slist = (sl_raw *)data;
|
sl_raw *slist = (sl_raw *)data;
|
||||||
(void)params;
|
(void)params;
|
||||||
(void)slist;
|
(void)slist;
|
||||||
return MUNIT_OK;
|
return MUNIT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
test_api_delete_setup(const MunitParameter params[], void *user_data)
|
test_api_delete_setup(const MunitParameter params[], void *user_data)
|
||||||
{
|
{
|
||||||
return test_api_setup(params, user_data);
|
return test_api_setup(params, user_data);
|
||||||
}
|
}
|
||||||
static void
|
static void
|
||||||
test_api_delete_tear_down(void *fixture)
|
test_api_delete_tear_down(void *fixture)
|
||||||
{
|
{
|
||||||
test_api_tear_down(fixture);
|
test_api_tear_down(fixture);
|
||||||
}
|
}
|
||||||
static MunitResult
|
static MunitResult
|
||||||
test_api_delete(const MunitParameter params[], void *data)
|
test_api_delete(const MunitParameter params[], void *data)
|
||||||
{
|
{
|
||||||
sl_raw *slist = (sl_raw *)data;
|
sl_raw *slist = (sl_raw *)data;
|
||||||
(void)params;
|
(void)params;
|
||||||
(void)slist;
|
(void)slist;
|
||||||
return MUNIT_OK;
|
return MUNIT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
test_api_duplicates_setup(const MunitParameter params[], void *user_data)
|
test_api_duplicates_setup(const MunitParameter params[], void *user_data)
|
||||||
{
|
{
|
||||||
return test_api_setup(params, user_data);
|
return test_api_setup(params, user_data);
|
||||||
}
|
}
|
||||||
static void
|
static void
|
||||||
test_api_duplicates_tear_down(void *fixture)
|
test_api_duplicates_tear_down(void *fixture)
|
||||||
{
|
{
|
||||||
test_api_tear_down(fixture);
|
test_api_tear_down(fixture);
|
||||||
}
|
}
|
||||||
static MunitResult
|
static MunitResult
|
||||||
test_api_duplicates(const MunitParameter params[], void *data)
|
test_api_duplicates(const MunitParameter params[], void *data)
|
||||||
{
|
{
|
||||||
sl_raw *slist = (sl_raw *)data;
|
sl_raw *slist = (sl_raw *)data;
|
||||||
(void)params;
|
(void)params;
|
||||||
(void)slist;
|
(void)slist;
|
||||||
return MUNIT_OK;
|
return MUNIT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
test_api_size_setup(const MunitParameter params[], void *user_data)
|
test_api_size_setup(const MunitParameter params[], void *user_data)
|
||||||
{
|
{
|
||||||
return test_api_setup(params, user_data);
|
return test_api_setup(params, user_data);
|
||||||
}
|
}
|
||||||
static void
|
static void
|
||||||
test_api_size_tear_down(void *fixture)
|
test_api_size_tear_down(void *fixture)
|
||||||
{
|
{
|
||||||
test_api_tear_down(fixture);
|
test_api_tear_down(fixture);
|
||||||
}
|
}
|
||||||
static MunitResult
|
static MunitResult
|
||||||
test_api_size(const MunitParameter params[], void *data)
|
test_api_size(const MunitParameter params[], void *data)
|
||||||
{
|
{
|
||||||
sl_raw *slist = (sl_raw *)data;
|
sl_raw *slist = (sl_raw *)data;
|
||||||
(void)params;
|
(void)params;
|
||||||
(void)slist;
|
(void)slist;
|
||||||
return MUNIT_OK;
|
return MUNIT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
test_api_iterators_setup(const MunitParameter params[], void *user_data)
|
test_api_iterators_setup(const MunitParameter params[], void *user_data)
|
||||||
{
|
{
|
||||||
return test_api_setup(params, user_data);
|
return test_api_setup(params, user_data);
|
||||||
}
|
}
|
||||||
static void
|
static void
|
||||||
test_api_iterators_tear_down(void *fixture)
|
test_api_iterators_tear_down(void *fixture)
|
||||||
{
|
{
|
||||||
test_api_tear_down(fixture);
|
test_api_tear_down(fixture);
|
||||||
}
|
}
|
||||||
static MunitResult
|
static MunitResult
|
||||||
test_api_iterators(const MunitParameter params[], void *data)
|
test_api_iterators(const MunitParameter params[], void *data)
|
||||||
{
|
{
|
||||||
sl_raw *slist = (sl_raw *)data;
|
sl_raw *slist = (sl_raw *)data;
|
||||||
(void)params;
|
(void)params;
|
||||||
(void)slist;
|
(void)slist;
|
||||||
return MUNIT_OK;
|
return MUNIT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MunitTest api_test_suite[] = {
|
static MunitTest api_test_suite[] = {
|
||||||
{ (char *)"/api/insert", test_api_insert, test_api_insert_setup,
|
{ (char *)"/api/insert", test_api_insert, test_api_insert_setup,
|
||||||
test_api_insert_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
test_api_insert_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
||||||
{ (char *)"/api/remove", test_api_remove, test_api_remove_setup,
|
{ (char *)"/api/remove", test_api_remove, test_api_remove_setup,
|
||||||
test_api_remove_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
test_api_remove_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
||||||
{ (char *)"/api/find", test_api_find, test_api_find_setup,
|
{ (char *)"/api/find", test_api_find, test_api_find_setup,
|
||||||
test_api_find_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
test_api_find_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
||||||
{ (char *)"/api/update", test_api_update, test_api_update_setup,
|
{ (char *)"/api/update", test_api_update, test_api_update_setup,
|
||||||
test_api_update_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
test_api_update_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
||||||
{ (char *)"/api/delete", test_api_delete, test_api_delete_setup,
|
{ (char *)"/api/delete", test_api_delete, test_api_delete_setup,
|
||||||
test_api_delete_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
test_api_delete_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
||||||
{ (char *)"/api/duplicates", test_api_duplicates, test_api_duplicates_setup,
|
{ (char *)"/api/duplicates", test_api_duplicates, test_api_duplicates_setup,
|
||||||
test_api_duplicates_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
test_api_duplicates_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
||||||
{ (char *)"/api/size", test_api_size, test_api_size_setup,
|
{ (char *)"/api/size", test_api_size, test_api_size_setup,
|
||||||
test_api_size_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
test_api_size_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
||||||
{ (char *)"/api/iterators", test_api_iterators, test_api_iterators_setup,
|
{ (char *)"/api/iterators", test_api_iterators, test_api_iterators_setup,
|
||||||
test_api_iterators_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
test_api_iterators_tear_down, MUNIT_TEST_OPTION_NONE, NULL },
|
||||||
{ NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }
|
{ NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static MunitTest mt_tests[] = { { NULL, NULL, NULL, NULL,
|
static MunitTest mt_tests[] = { { NULL, NULL, NULL, NULL,
|
||||||
MUNIT_TEST_OPTION_NONE, NULL } };
|
MUNIT_TEST_OPTION_NONE, NULL } };
|
||||||
|
|
||||||
static MunitTest scale_tests[] = { { NULL, NULL, NULL, NULL,
|
static MunitTest scale_tests[] = { { NULL, NULL, NULL, NULL,
|
||||||
MUNIT_TEST_OPTION_NONE, NULL } };
|
MUNIT_TEST_OPTION_NONE, NULL } };
|
||||||
|
|
||||||
static MunitSuite other_test_suite[] = { { "/mt", mt_tests, NULL, 1,
|
static MunitSuite other_test_suite[] = { { "/mt", mt_tests, NULL, 1,
|
||||||
MUNIT_SUITE_OPTION_NONE },
|
MUNIT_SUITE_OPTION_NONE },
|
||||||
{ "/scale", scale_tests, NULL, 1, MUNIT_SUITE_OPTION_NONE },
|
{ "/scale", scale_tests, NULL, 1, MUNIT_SUITE_OPTION_NONE },
|
||||||
{ NULL, NULL, NULL, 0, MUNIT_SUITE_OPTION_NONE } };
|
{ NULL, NULL, NULL, 0, MUNIT_SUITE_OPTION_NONE } };
|
||||||
|
|
||||||
static const MunitSuite main_test_suite = { (char *)"/api", api_test_suite,
|
static const MunitSuite main_test_suite = { (char *)"/api", api_test_suite,
|
||||||
other_test_suite, 1, MUNIT_SUITE_OPTION_NONE };
|
other_test_suite, 1, MUNIT_SUITE_OPTION_NONE };
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[MUNIT_ARRAY_PARAM(argc + 1)])
|
main(int argc, char *argv[MUNIT_ARRAY_PARAM(argc + 1)])
|
||||||
{
|
{
|
||||||
struct user_data info;
|
struct user_data info;
|
||||||
return munit_suite_main(&main_test_suite, (void *)&info, argc, argv);
|
return munit_suite_main(&main_test_suite, (void *)&info, argc, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ARGS: --no-fork --seed 8675309 */
|
/* ARGS: --no-fork --seed 8675309 */
|
||||||
|
|
Loading…
Reference in a new issue