moving more to decl
This commit is contained in:
parent
a1c08f6fd8
commit
e8d3645ed4
|
@ -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
|
||||||
|
|
|
@ -79,8 +79,7 @@ main()
|
||||||
struct my_node *found = sl_get_entry(cursor, struct my_node, snode);
|
struct my_node *found = sl_get_entry(cursor, struct my_node, snode);
|
||||||
printf("[point lookup] key: %d, value: %d\n", found->key, found->value);
|
printf("[point lookup] key: %d, value: %d\n", found->key, found->value);
|
||||||
if (found->key != found->value / 10) {
|
if (found->key != found->value / 10) {
|
||||||
printf("FAILURE: key: %d * 10 != value: %d\n", found->key,
|
printf("FAILURE: key: %d * 10 != value: %d\n", found->key, found->value);
|
||||||
found->value);
|
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
// Release `cursor` (== &found->snode).
|
// Release `cursor` (== &found->snode).
|
||||||
|
@ -119,8 +118,7 @@ main()
|
||||||
// Get `entry` from `cursor`.
|
// Get `entry` from `cursor`.
|
||||||
// Note: entry->snode == *cursor
|
// Note: entry->snode == *cursor
|
||||||
struct my_node *entry = sl_get_entry(cursor, struct my_node, snode);
|
struct my_node *entry = sl_get_entry(cursor, struct my_node, snode);
|
||||||
printf("[iteration] key: %d, value: %d\n", entry->key,
|
printf("[iteration] key: %d, value: %d\n", entry->key, entry->value);
|
||||||
entry->value);
|
|
||||||
// Get next `cursor`.
|
// Get next `cursor`.
|
||||||
cursor = sl_next(&slist, cursor);
|
cursor = sl_next(&slist, cursor);
|
||||||
// Release `entry`.
|
// Release `entry`.
|
||||||
|
|
|
@ -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,37 +49,52 @@ 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)
|
||||||
|
int
|
||||||
|
__slm_key_compare(slex_t *list, slex_node_t *a, slex_node_t *b, void *aux)
|
||||||
|
{
|
||||||
|
(void)list;
|
||||||
(void)aux;
|
(void)aux;
|
||||||
if (a->key < b->key)
|
if (a->key < b->key)
|
||||||
return -1;
|
return -1;
|
||||||
if (a->key > b->key)
|
if (a->key > b->key)
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
})
|
|
||||||
|
|
||||||
void sprintf_slex_node(slex_node_t *node, char *buf) {
|
|
||||||
sprintf(buf, "%d", node->key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
/* 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);
|
||||||
|
|
||||||
struct slex_node *n;
|
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);
|
SKIP_ALLOC_NODE(list, n, slex_node, entries);
|
||||||
n->key = -1;
|
n->key = i;
|
||||||
n->value = -1;
|
n->value = i;
|
||||||
api_skip_insert_slex(list, n);
|
api_skip_insert_slex(list, n);
|
||||||
|
}
|
||||||
|
|
||||||
FILE *of = fopen("/tmp/slm.dot", "w");
|
FILE *of = fopen("/tmp/slm.dot", "w");
|
||||||
if (!of) {
|
if (!of) {
|
||||||
|
@ -89,14 +104,6 @@ int main() {
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
243
include/sl.h
243
include/sl.h
|
@ -79,16 +79,21 @@ struct sl_trace {
|
||||||
};
|
};
|
||||||
|
|
||||||
#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) \
|
||||||
|
do { \
|
||||||
(head)->trace.prevline = (head)->trace.lastline; \
|
(head)->trace.prevline = (head)->trace.lastline; \
|
||||||
(head)->trace.prevfile = (head)->trace.lastfile; \
|
(head)->trace.prevfile = (head)->trace.lastfile; \
|
||||||
(head)->trace.lastline = __LINE__; \
|
(head)->trace.lastline = __LINE__; \
|
||||||
(head)->trace.lastfile = __FILE__; \
|
(head)->trace.lastfile = __FILE__; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define SLD_TRACE_ELEM(elem) do { \
|
#define SLD_TRACE_ELEM(elem) \
|
||||||
|
do { \
|
||||||
(elem)->trace.prevline = (elem)->trace.lastline; \
|
(elem)->trace.prevline = (elem)->trace.lastline; \
|
||||||
(elem)->trace.prevfile = (elem)->trace.lastfile; \
|
(elem)->trace.prevfile = (elem)->trace.lastfile; \
|
||||||
(elem)->trace.lastline = __LINE__; \
|
(elem)->trace.lastline = __LINE__; \
|
||||||
|
@ -102,7 +107,6 @@ struct sl_trace {
|
||||||
#define TRASHIT(x)
|
#define TRASHIT(x)
|
||||||
#endif /* QUEUE_MACRO_DEBUG */
|
#endif /* QUEUE_MACRO_DEBUG */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Private, internal API.
|
* Private, internal API.
|
||||||
*/
|
*/
|
||||||
|
@ -113,7 +117,8 @@ 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) \
|
||||||
|
do { \
|
||||||
(size) = (size == 0 ? 254 : size); \
|
(size) = (size == 0 ? 254 : size); \
|
||||||
(var) = (type **)calloc(sizeof(type *), size + 2); \
|
(var) = (type **)calloc(sizeof(type *), size + 2); \
|
||||||
if ((var) != NULL) { \
|
if ((var) != NULL) { \
|
||||||
|
@ -141,10 +146,14 @@ struct sl_trace {
|
||||||
}
|
}
|
||||||
|
|
||||||
#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 { \
|
||||||
|
@ -164,23 +173,19 @@ struct sl_trace {
|
||||||
|
|
||||||
#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
|
||||||
|
@ -190,16 +195,20 @@ struct sl_trace {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#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, \
|
||||||
|
void *aux) \
|
||||||
|
{ \
|
||||||
if (a == b) \
|
if (a == b) \
|
||||||
return 0; \
|
return 0; \
|
||||||
if (a == (head)->slh_head || b == (head)->slh_tail) \
|
if (a == (head)->slh_head || b == (head)->slh_tail) \
|
||||||
return -1; \
|
return -1; \
|
||||||
if (a == (head)->slh_tail || b == (head)->slh_head) \
|
if (a == (head)->slh_tail || b == (head)->slh_head) \
|
||||||
return 1; \
|
return 1; \
|
||||||
fn }
|
fn \
|
||||||
|
}
|
||||||
|
|
||||||
#define SKIP_INIT(head, max, fanout, type, field, fn) do { \
|
#define SKIP_INIT(head, max, fanout, type, field, fn) \
|
||||||
|
do { \
|
||||||
(head)->level = 0; \
|
(head)->level = 0; \
|
||||||
(head)->length = 0; \
|
(head)->length = 0; \
|
||||||
(head)->max = max; \
|
(head)->max = max; \
|
||||||
|
@ -208,19 +217,22 @@ struct sl_trace {
|
||||||
SKIP_ALLOC_NODE(head, (head)->slh_head, type, field); \
|
SKIP_ALLOC_NODE(head, (head)->slh_head, type, field); \
|
||||||
SKIP_ALLOC_NODE(head, (head)->slh_tail, type, field); \
|
SKIP_ALLOC_NODE(head, (head)->slh_tail, type, field); \
|
||||||
ARRAY_SET_LENGTH((head)->slh_head->field.sle_next, max); \
|
ARRAY_SET_LENGTH((head)->slh_head->field.sle_next, max); \
|
||||||
for(size_t __i = 0; __i < ARRAY_SIZE((head)->slh_head->field.sle_next); __i++) { \
|
for (size_t __i = 0; __i < ARRAY_SIZE((head)->slh_head->field.sle_next); \
|
||||||
|
__i++) { \
|
||||||
(head)->slh_head->field.sle_next[__i] = (head)->slh_tail; \
|
(head)->slh_head->field.sle_next[__i] = (head)->slh_tail; \
|
||||||
} \
|
} \
|
||||||
(head)->slh_head->field.sle_prev = NULL; \
|
(head)->slh_head->field.sle_prev = NULL; \
|
||||||
ARRAY_SET_LENGTH((head)->slh_tail->field.sle_next, max); \
|
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++) { \
|
for (size_t __i = 0; __i < ARRAY_SIZE((head)->slh_tail->field.sle_next); \
|
||||||
|
__i++) { \
|
||||||
(head)->slh_tail->field.sle_next[__i] = NULL; \
|
(head)->slh_tail->field.sle_next[__i] = NULL; \
|
||||||
} \
|
} \
|
||||||
(head)->slh_head->field.sle_prev = (head)->slh_tail; \
|
(head)->slh_head->field.sle_prev = (head)->slh_tail; \
|
||||||
SLD_TRACE_HEAD(head); \
|
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) \
|
||||||
|
do { \
|
||||||
(head)->level = 0; \
|
(head)->level = 0; \
|
||||||
(head)->length = 0; \
|
(head)->length = 0; \
|
||||||
(head)->max = 12; \
|
(head)->max = 12; \
|
||||||
|
@ -229,20 +241,22 @@ struct sl_trace {
|
||||||
SKIP_ALLOC_NODE(head, (head)->slh_head, type, field); \
|
SKIP_ALLOC_NODE(head, (head)->slh_head, type, field); \
|
||||||
SKIP_ALLOC_NODE(head, (head)->slh_tail, type, field); \
|
SKIP_ALLOC_NODE(head, (head)->slh_tail, type, field); \
|
||||||
ARRAY_SET_LENGTH((head)->slh_head->field.sle_next, (head)->max); \
|
ARRAY_SET_LENGTH((head)->slh_head->field.sle_next, (head)->max); \
|
||||||
for(size_t __i = 0; __i < ARRAY_SIZE((head)->slh_head->field.sle_next); __i++) { \
|
for (size_t __i = 0; __i < ARRAY_SIZE((head)->slh_head->field.sle_next); \
|
||||||
|
__i++) { \
|
||||||
(head)->slh_head->field.sle_next[__i] = (head)->slh_tail; \
|
(head)->slh_head->field.sle_next[__i] = (head)->slh_tail; \
|
||||||
} \
|
} \
|
||||||
(head)->slh_head->field.sle_prev = NULL; \
|
(head)->slh_head->field.sle_prev = NULL; \
|
||||||
ARRAY_SET_LENGTH((head)->slh_tail->field.sle_next, (head)->max); \
|
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++) { \
|
for (size_t __i = 0; __i < ARRAY_SIZE((head)->slh_tail->field.sle_next); \
|
||||||
|
__i++) { \
|
||||||
(head)->slh_tail->field.sle_next[__i] = NULL; \
|
(head)->slh_tail->field.sle_next[__i] = NULL; \
|
||||||
} \
|
} \
|
||||||
(head)->slh_head->field.sle_prev = (head)->slh_tail; \
|
(head)->slh_head->field.sle_prev = (head)->slh_tail; \
|
||||||
SLD_TRACE_HEAD(head); \
|
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) { \
|
||||||
|
@ -251,12 +265,7 @@ struct sl_trace {
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define SKIP_FREE_NODE(node, field) do { \
|
#define SKIPLIST_DECL(decl, prefix, field) \
|
||||||
free((node)->field.sle_next); \
|
|
||||||
free((node)); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define SKIPLIST_DECL(decl, prefix, field, key_cmp_logic) \
|
|
||||||
\
|
\
|
||||||
/* Skiplist node type */ \
|
/* Skiplist node type */ \
|
||||||
typedef struct decl##_node decl##_node_t; \
|
typedef struct decl##_node decl##_node_t; \
|
||||||
|
@ -282,18 +291,21 @@ struct sl_trace {
|
||||||
* a == b : return 0 \
|
* a == b : return 0 \
|
||||||
* a > b : return 1 \
|
* a > b : return 1 \
|
||||||
*/ \
|
*/ \
|
||||||
static int __skip_key_compare_##decl(decl##_t *slist, decl##_node_t *a, decl##_node_t *b, void *aux) { \
|
static int __skip_key_compare_##decl(decl##_t *slist, decl##_node_t *a, \
|
||||||
|
decl##_node_t *b, void *aux) \
|
||||||
|
{ \
|
||||||
if (a == b) \
|
if (a == b) \
|
||||||
return 0; \
|
return 0; \
|
||||||
if (a == slist->slh_head || b == slist->slh_tail) \
|
if (a == slist->slh_head || b == slist->slh_tail) \
|
||||||
return -1; \
|
return -1; \
|
||||||
if (a == slist->slh_tail || b == slist->slh_head) \
|
if (a == slist->slh_tail || b == slist->slh_head) \
|
||||||
return 1; \
|
return 1; \
|
||||||
do { key_cmp_logic } while(0); \
|
return slist->cmp(slist, a, b, aux); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/* -- __skip_toss_ */ \
|
/* -- __skip_toss_ */ \
|
||||||
static int __skip_toss_##decl(size_t max, size_t fanout) { \
|
static int __skip_toss_##decl(size_t max, size_t fanout) \
|
||||||
|
{ \
|
||||||
size_t level = 0; \
|
size_t level = 0; \
|
||||||
while (level + 1 < max) { \
|
while (level + 1 < max) { \
|
||||||
if (rand() % fanout == 0) /* NOLINT(*-msc50-cpp) */ \
|
if (rand() % fanout == 0) /* NOLINT(*-msc50-cpp) */ \
|
||||||
|
@ -304,8 +316,61 @@ struct sl_trace {
|
||||||
return level; \
|
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_ */ \
|
/* -- skip_insert_ */ \
|
||||||
int prefix##skip_insert_##decl(decl##_t *slist, decl##_node_t *n) { \
|
int prefix##skip_insert_##decl(decl##_t *slist, decl##_node_t *n) \
|
||||||
|
{ \
|
||||||
if (n == NULL) \
|
if (n == NULL) \
|
||||||
return ENOMEM; \
|
return ENOMEM; \
|
||||||
decl##_node_t *prev, *elm = slist->slh_head; \
|
decl##_node_t *prev, *elm = slist->slh_head; \
|
||||||
|
@ -317,7 +382,9 @@ struct sl_trace {
|
||||||
return ENOMEM; \
|
return ENOMEM; \
|
||||||
/* Find the position in the list where this element belongs. */ \
|
/* Find the position in the list where this element belongs. */ \
|
||||||
do { \
|
do { \
|
||||||
while(elm && slist->cmp(slist, elm->field.sle_next[i], n, slist->aux) < 0) \
|
while (elm && \
|
||||||
|
__skip_key_compare_##decl(slist, elm->field.sle_next[i], n, \
|
||||||
|
slist->aux) < 0) \
|
||||||
elm = elm->field.sle_next[i]; \
|
elm = elm->field.sle_next[i]; \
|
||||||
path[i] = elm; \
|
path[i] = elm; \
|
||||||
ARRAY_SET_LENGTH(path, ARRAY_LENGTH(path) + 1); \
|
ARRAY_SET_LENGTH(path, ARRAY_LENGTH(path) + 1); \
|
||||||
|
@ -325,9 +392,9 @@ struct sl_trace {
|
||||||
i = 0; \
|
i = 0; \
|
||||||
prev = elm; \
|
prev = elm; \
|
||||||
elm = elm->field.sle_next[0]; \
|
elm = elm->field.sle_next[0]; \
|
||||||
if (slist->cmp(slist, elm, n, slist->aux) == 0) { \
|
if (__skip_key_compare_##decl(slist, elm, n, slist->aux) == 0) { \
|
||||||
ARRAY_FREE(path); \
|
|
||||||
/* Don't overwrite, to do that use _REPLACE not _INSERT */ \
|
/* Don't overwrite, to do that use _REPLACE not _INSERT */ \
|
||||||
|
ARRAY_FREE(path); \
|
||||||
return -1; \
|
return -1; \
|
||||||
} \
|
} \
|
||||||
size_t level = __skip_toss_##decl(slist->max, slist->fanout); \
|
size_t level = __skip_toss_##decl(slist->max, slist->fanout); \
|
||||||
|
@ -352,9 +419,13 @@ struct sl_trace {
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/* -- __skip_integrity_check_ */ \
|
/* -- __skip_integrity_check_ */ \
|
||||||
static int __skip_integrity_check_##decl() { \
|
static int __skip_integrity_check_##decl(decl##_t *slist) \
|
||||||
|
{ \
|
||||||
|
((void)slist); /* TODO */ \
|
||||||
return 0; \
|
return 0; \
|
||||||
} \
|
}
|
||||||
|
|
||||||
|
#define SKIPLIST_DECL_DOT(decl, prefix, field) \
|
||||||
\
|
\
|
||||||
/* A type for a function that writes into a char[2048] buffer \
|
/* A type for a function that writes into a char[2048] buffer \
|
||||||
* a description of the value within the node. */ \
|
* a description of the value within the node. */ \
|
||||||
|
@ -363,16 +434,21 @@ struct sl_trace {
|
||||||
/* -- __skip_dot_node_ \
|
/* -- __skip_dot_node_ \
|
||||||
* Writes out a fragment of a DOT file representing a node. \
|
* Writes out a fragment of a DOT file representing a node. \
|
||||||
*/ \
|
*/ \
|
||||||
static void __skip_dot_node_##decl(FILE *os, decl##_t *slist, decl##_node_t *node, size_t nsg, skip_sprintf_node_##decl##_t fn) { \
|
static void __skip_dot_node_##decl(FILE *os, decl##_t *slist, \
|
||||||
|
decl##_node_t *node, size_t nsg, skip_sprintf_node_##decl##_t fn) \
|
||||||
|
{ \
|
||||||
|
char buf[2048]; \
|
||||||
|
size_t level, height = ARRAY_LENGTH(node->field.sle_next); \
|
||||||
fprintf(os, "\"node%zu%p\"", nsg, (void *)node); \
|
fprintf(os, "\"node%zu%p\"", nsg, (void *)node); \
|
||||||
fprintf(os, " [label = \""); \
|
fprintf(os, " [label = \""); \
|
||||||
size_t level = ARRAY_LENGTH(node->field.sle_next); \
|
level = height; \
|
||||||
do { \
|
do { \
|
||||||
fprintf(os, " { <w%zu> | <f%zu> %p }", level, level, (void*)node->field.sle_next[level]); \
|
fprintf(os, " { <w%zu> | <f%zu> %p }", level + 1, level + 1, \
|
||||||
if (level != 0) fprintf(os, " | "); \
|
(void *)node->field.sle_next[level]); \
|
||||||
|
if (level != 0) \
|
||||||
|
fprintf(os, " | "); \
|
||||||
} while (level--); \
|
} while (level--); \
|
||||||
if (fn) { \
|
if (fn) { \
|
||||||
char buf[2048]; \
|
|
||||||
fn(node, buf); \
|
fn(node, buf); \
|
||||||
fprintf(os, " <f0> %s\"\n", buf); \
|
fprintf(os, " <f0> %s\"\n", buf); \
|
||||||
} else { \
|
} else { \
|
||||||
|
@ -383,30 +459,30 @@ struct sl_trace {
|
||||||
\
|
\
|
||||||
/* Now edges */ \
|
/* Now edges */ \
|
||||||
level = 0; \
|
level = 0; \
|
||||||
size_t size = ARRAY_LENGTH(node->field.sle_next); \
|
for (level = 0; level < height; level++) { \
|
||||||
for (size_t level = 0; level <= size; level++) { \
|
|
||||||
fprintf(os, "\"node%zu%p\"", nsg, (void *)node); \
|
fprintf(os, "\"node%zu%p\"", nsg, (void *)node); \
|
||||||
fprintf(os, ":f%zu -> ", level); \
|
fprintf(os, ":f%zu -> ", level + 1); \
|
||||||
fprintf(os, "\"node%zu%p\"", nsg, (void *)node->field.sle_next[level]); \
|
fprintf(os, "\"node%zu%p\"", nsg, (void *)node->field.sle_next[level]); \
|
||||||
fprintf(os, ":w%zu [];\n", level); \
|
fprintf(os, ":w%zu [];\n", level + 1); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
if (node->field.sle_next[0]) \
|
if (node->field.sle_next[0] != SKIP_LAST(slist)) \
|
||||||
__skip_dot_node_##decl(os, slist, node->field.sle_next[0], nsg, fn); \
|
__skip_dot_node_##decl(os, slist, node->field.sle_next[0], nsg, fn); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/* -- __skip_dot_finish_ \
|
/* -- __skip_dot_finish_ \
|
||||||
* Finalise the DOT file of the internal representation. \
|
* Finalise the DOT file of the internal representation. \
|
||||||
*/ \
|
*/ \
|
||||||
static void __skip_dot_finish_##decl(FILE *os, size_t nsg) { \
|
static void __skip_dot_finish_##decl(FILE *os, size_t nsg) \
|
||||||
|
{ \
|
||||||
|
size_t i; \
|
||||||
if (nsg > 0) { \
|
if (nsg > 0) { \
|
||||||
/* Link the nodes together with an invisible node. \
|
/* Link the nodes together with an invisible node. \
|
||||||
* node0 [shape=record, label = "<f0> | <f1> | <f2> | <f3> | <f4> | <f5> | <f6> | <f7> | <f8> | ", \
|
* node0 [shape=record, label = "<f0> | <f1> | <f2> | <f3> | \
|
||||||
* style=invis, \
|
* <f4> | <f5> | <f6> | <f7> | <f8> | ", style=invis, width=0.01]; \
|
||||||
* width=0.01]; \
|
|
||||||
*/ \
|
*/ \
|
||||||
fprintf(os, "node0 [shape=record, label = \""); \
|
fprintf(os, "node0 [shape=record, label = \""); \
|
||||||
for (size_t i = 0; i < nsg; ++i) { \
|
for (i = 0; i < nsg; ++i) { \
|
||||||
fprintf(os, "<f%zu> | ", i); \
|
fprintf(os, "<f%zu> | ", i); \
|
||||||
} \
|
} \
|
||||||
fprintf(os, "\", style=invis, width=0.01];\n"); \
|
fprintf(os, "\", style=invis, width=0.01];\n"); \
|
||||||
|
@ -416,7 +492,7 @@ struct sl_trace {
|
||||||
* node0:f0 -> HeadNode [style=invis]; \
|
* node0:f0 -> HeadNode [style=invis]; \
|
||||||
* node0:f1 -> HeadNode1 [style=invis]; \
|
* node0:f1 -> HeadNode1 [style=invis]; \
|
||||||
*/ \
|
*/ \
|
||||||
for (size_t i = 0; i < nsg; ++i) { \
|
for (i = 0; i < nsg; ++i) { \
|
||||||
fprintf(os, "node0:f%zu -> HeadNode%zu [style=invis];\n", i, i); \
|
fprintf(os, "node0:f%zu -> HeadNode%zu [style=invis];\n", i, i); \
|
||||||
} \
|
} \
|
||||||
nsg = 0; \
|
nsg = 0; \
|
||||||
|
@ -425,7 +501,11 @@ struct sl_trace {
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/* -- skip_dot_start_ */ \
|
/* -- skip_dot_start_ */ \
|
||||||
static int __skip_dot_start_##decl(FILE *os, decl##_t *slist, size_t nsg, skip_sprintf_node_##decl##_t fn) { \
|
static int __skip_dot_start_##decl(FILE *os, decl##_t *slist, size_t nsg, \
|
||||||
|
skip_sprintf_node_##decl##_t fn) \
|
||||||
|
{ \
|
||||||
|
size_t level; \
|
||||||
|
decl##_node_t *head; \
|
||||||
if (nsg == 0) { \
|
if (nsg == 0) { \
|
||||||
fprintf(os, "digraph Skiplist {\n"); \
|
fprintf(os, "digraph Skiplist {\n"); \
|
||||||
fprintf(os, "label = \"Skiplist.\"\n"); \
|
fprintf(os, "label = \"Skiplist.\"\n"); \
|
||||||
|
@ -439,16 +519,18 @@ struct sl_trace {
|
||||||
fprintf(os, "\"HeadNode%zu\" [\n", nsg); \
|
fprintf(os, "\"HeadNode%zu\" [\n", nsg); \
|
||||||
fprintf(os, "label = \""); \
|
fprintf(os, "label = \""); \
|
||||||
\
|
\
|
||||||
/* Write out the head node fields */ \
|
/* Write out the fields */ \
|
||||||
decl##_node_t *head = slist->slh_head; \
|
head = slist->slh_head; \
|
||||||
size_t level; \
|
if (SKIP_EMPTY(slist)) \
|
||||||
if (SKIP_EMPTY(slist)) fprintf(os, "Empty HeadNode"); else { \
|
fprintf(os, "Empty HeadNode"); \
|
||||||
level = ARRAY_LENGTH(head->field.sle_next) - 1; \
|
else { \
|
||||||
do { \
|
level = ARRAY_LENGTH(head->field.sle_next); \
|
||||||
|
while (level--) { \
|
||||||
decl##_node_t *node = head->field.sle_next[level]; \
|
decl##_node_t *node = head->field.sle_next[level]; \
|
||||||
fprintf(os, "{ <f%zu> %p }", level, (void *)node); \
|
fprintf(os, "{ <f%zu> %p }", level + 1, (void *)node); \
|
||||||
if (level != 0) fprintf(os, " | "); \
|
if (level + 1 != 0) \
|
||||||
} while(level--); \
|
fprintf(os, " | "); \
|
||||||
|
} \
|
||||||
} \
|
} \
|
||||||
fprintf(os, "\"\n"); \
|
fprintf(os, "\"\n"); \
|
||||||
fprintf(os, "shape = \"record\"\n"); \
|
fprintf(os, "shape = \"record\"\n"); \
|
||||||
|
@ -458,24 +540,24 @@ struct sl_trace {
|
||||||
decl##_node_t *node = slist->slh_head; \
|
decl##_node_t *node = slist->slh_head; \
|
||||||
level = 0; \
|
level = 0; \
|
||||||
do { \
|
do { \
|
||||||
fprintf(os, "\"HeadNode%zu\":f%zu -> ", nsg, level); \
|
fprintf(os, "\"HeadNode%zu\":f%zu -> ", nsg, level + 1); \
|
||||||
fprintf(os, "\"node%zu%p\"", nsg, (void *)node->field.sle_next[level]); \
|
fprintf(os, "\"node%zu%p\"", nsg, (void *)node->field.sle_next[level]); \
|
||||||
fprintf(os, ":w%zu [];\n", level); \
|
fprintf(os, ":w%zu [];\n", level + 1); \
|
||||||
} while (level++ < slist->level); \
|
} while (level++ < slist->level); \
|
||||||
fprintf(os, "}\n\n"); \
|
fprintf(os, "}\n\n"); \
|
||||||
\
|
\
|
||||||
/* Now all nodes via level 0, if non-empty */ \
|
/* Now all nodes via level 0, if non-empty */ \
|
||||||
node = slist->slh_head; \
|
node = slist->slh_head; \
|
||||||
if (ARRAY_LENGTH(node->field.sle_next)) \
|
if (ARRAY_LENGTH(node->field.sle_next)) \
|
||||||
__skip_dot_node_##decl(os, slist, node, nsg, fn); \
|
__skip_dot_node_##decl(os, slist, node->field.sle_next[0], nsg, fn); \
|
||||||
fprintf(os, "\n"); \
|
fprintf(os, "\n"); \
|
||||||
\
|
\
|
||||||
/* The tail, sentinal node */ \
|
/* The tail, sentinal node */ \
|
||||||
if (!SKIP_EMPTY(slist)) { \
|
if (!SKIP_EMPTY(slist)) { \
|
||||||
fprintf(os, "\"node%zu0x0\" [label = \"", nsg); \
|
fprintf(os, "\"node%zu0x0\" [label = \"", nsg); \
|
||||||
size_t level = slist->level; \
|
level = slist->level; \
|
||||||
do { \
|
do { \
|
||||||
fprintf(os, "<w%zu> NULL", level); \
|
fprintf(os, "<w%zu> NULL", level + 1); \
|
||||||
if (level != 0) \
|
if (level != 0) \
|
||||||
fprintf(os, " | "); \
|
fprintf(os, " | "); \
|
||||||
} while (level-- > 0); \
|
} while (level-- > 0); \
|
||||||
|
@ -501,7 +583,9 @@ struct sl_trace {
|
||||||
* \
|
* \
|
||||||
* https://en.wikipedia.org/wiki/DOT_(graph_description_language) \
|
* 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) { \
|
int prefix##skip_dot_##decl(FILE *os, decl##_t *slist, \
|
||||||
|
skip_sprintf_node_##decl##_t fn) \
|
||||||
|
{ \
|
||||||
size_t nsg = 0; \
|
size_t nsg = 0; \
|
||||||
if (__skip_integrity_check_##decl(slist) != 0) { \
|
if (__skip_integrity_check_##decl(slist) != 0) { \
|
||||||
perror("Skiplist failed integrity checks, impossible to diagram."); \
|
perror("Skiplist failed integrity checks, impossible to diagram."); \
|
||||||
|
@ -516,23 +600,22 @@ struct sl_trace {
|
||||||
__skip_dot_start_##decl(os, slist, nsg, fn); \
|
__skip_dot_start_##decl(os, slist, nsg, fn); \
|
||||||
__skip_dot_finish_##decl(os, nsg); \
|
__skip_dot_finish_##decl(os, nsg); \
|
||||||
return 0; \
|
return 0; \
|
||||||
} \
|
}
|
||||||
/* END */
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
#define SKIP_REMOVE(head, elm, field) do { \
|
#define SKIP_REMOVE(head, elm, field) \
|
||||||
|
do { \
|
||||||
if ((elm)->field.le_next != NULL) \
|
if ((elm)->field.le_next != NULL) \
|
||||||
(elm)->field.le_next->field.le_prev = \
|
(elm)->field.le_next->field.le_prev = (elm)->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) \
|
||||||
|
do { \
|
||||||
if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
|
if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
|
||||||
(elm2)->field.le_next->field.le_prev = \
|
(elm2)->field.le_next->field.le_prev = &(elm2)->field.le_next; \
|
||||||
&(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); \
|
||||||
|
|
|
@ -585,16 +585,14 @@ insert_retry:;
|
||||||
|
|
||||||
/* check if prev node is duplicated with upper
|
/* check if prev node is duplicated with upper
|
||||||
* layer */
|
* layer */
|
||||||
if (cur_layer < top_layer &&
|
if (cur_layer < top_layer && prev[cur_layer] == prev[cur_layer + 1]) {
|
||||||
prev[cur_layer] == prev[cur_layer + 1]) {
|
|
||||||
/* duplicate
|
/* duplicate
|
||||||
=> which means that
|
=> which means that
|
||||||
'being_modified' flag is already true
|
'being_modified' flag is already true
|
||||||
=> do nothing */
|
=> do nothing */
|
||||||
} else {
|
} else {
|
||||||
bool expected = false;
|
bool expected = false;
|
||||||
if (ATM_CAS(prev[cur_layer]->being_modified, expected,
|
if (ATM_CAS(prev[cur_layer]->being_modified, expected, bool_true)) {
|
||||||
bool_true)) {
|
|
||||||
locked_layer = cur_layer;
|
locked_layer = cur_layer;
|
||||||
} else {
|
} else {
|
||||||
error_code = -1;
|
error_code = -1;
|
||||||
|
@ -645,13 +643,13 @@ insert_retry:;
|
||||||
__sl_write_lock_an(prev[layer]);
|
__sl_write_lock_an(prev[layer]);
|
||||||
exp = next[layer];
|
exp = next[layer];
|
||||||
if (!ATM_CAS(prev[layer]->next[layer], exp, node)) {
|
if (!ATM_CAS(prev[layer]->next[layer], exp, node)) {
|
||||||
__SLD_P("%02x ASSERT ins %p[%d] -> %p (expected %p)\n",
|
__SLD_P("%02x ASSERT ins %p[%d] -> %p (expected %p)\n", (int)tid_hash,
|
||||||
(int)tid_hash, prev[layer], cur_layer,
|
prev[layer], cur_layer, ATM_GET(prev[layer]->next[layer]),
|
||||||
ATM_GET(prev[layer]->next[layer]), next[layer]);
|
next[layer]);
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
__SLD_P("%02x ins %p[%d] -> %p -> %p\n", (int)tid_hash,
|
__SLD_P("%02x ins %p[%d] -> %p -> %p\n", (int)tid_hash, prev[layer],
|
||||||
prev[layer], layer, node, ATM_GET(node->next[layer]));
|
layer, node, ATM_GET(node->next[layer]));
|
||||||
__sl_write_unlock_an(prev[layer]);
|
__sl_write_unlock_an(prev[layer]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -929,16 +927,14 @@ erase_node_retry:
|
||||||
/* check if prev node duplicates with upper layer */
|
/* check if prev node duplicates with upper layer */
|
||||||
error_code = 0;
|
error_code = 0;
|
||||||
locked_layer = cur_layer + 1;
|
locked_layer = cur_layer + 1;
|
||||||
if (cur_layer < top_layer &&
|
if (cur_layer < top_layer && prev[cur_layer] == prev[cur_layer + 1]) {
|
||||||
prev[cur_layer] == prev[cur_layer + 1]) {
|
|
||||||
/* duplicate with upper layer
|
/* duplicate with upper layer
|
||||||
=> which means that 'being_modified'
|
=> which means that 'being_modified'
|
||||||
flag is already true
|
flag is already true
|
||||||
=> do nothing. */
|
=> do nothing. */
|
||||||
} else {
|
} else {
|
||||||
expected = false;
|
expected = false;
|
||||||
if (ATM_CAS(prev[cur_layer]->being_modified, expected,
|
if (ATM_CAS(prev[cur_layer]->being_modified, expected, bool_true)) {
|
||||||
bool_true)) {
|
|
||||||
locked_layer = cur_layer;
|
locked_layer = cur_layer;
|
||||||
} else {
|
} else {
|
||||||
error_code = -1;
|
error_code = -1;
|
||||||
|
@ -958,13 +954,11 @@ erase_node_retry:
|
||||||
goto erase_node_retry;
|
goto erase_node_retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
next_node_again = __sl_fnd_next(cur_node, cur_layer, node,
|
next_node_again = __sl_fnd_next(cur_node, cur_layer, node, NULL);
|
||||||
NULL);
|
|
||||||
ATM_FETCH_SUB(next_node_again->ref_count, 1);
|
ATM_FETCH_SUB(next_node_again->ref_count, 1);
|
||||||
if (next_node_again != next[cur_layer]) {
|
if (next_node_again != next[cur_layer]) {
|
||||||
/* `next` pointer has been changed, retry */
|
/* `next` pointer has been changed, retry */
|
||||||
__SLD_NC_RMV(cur_node, next[cur_layer], top_layer,
|
__SLD_NC_RMV(cur_node, next[cur_layer], top_layer, cur_layer);
|
||||||
cur_layer);
|
|
||||||
__sl_clr_flags(prev, cur_layer, top_layer);
|
__sl_clr_flags(prev, cur_layer, top_layer);
|
||||||
ATM_FETCH_SUB(cur_node->ref_count, 1);
|
ATM_FETCH_SUB(cur_node->ref_count, 1);
|
||||||
YIELD();
|
YIELD();
|
||||||
|
@ -994,13 +988,13 @@ erase_node_retry:
|
||||||
assert(next[cur_layer]->is_fully_linked);
|
assert(next[cur_layer]->is_fully_linked);
|
||||||
if (!ATM_CAS(prev[cur_layer]->next[cur_layer], exp, next[cur_layer])) {
|
if (!ATM_CAS(prev[cur_layer]->next[cur_layer], exp, next[cur_layer])) {
|
||||||
__SLD_P("%02x ASSERT rmv %p[%d] -> %p (node %p)\n", (int)tid_hash,
|
__SLD_P("%02x ASSERT rmv %p[%d] -> %p (node %p)\n", (int)tid_hash,
|
||||||
prev[cur_layer], cur_layer,
|
prev[cur_layer], cur_layer, ATM_GET(prev[cur_layer]->next[cur_layer]),
|
||||||
ATM_GET(prev[cur_layer]->next[cur_layer]), node);
|
node);
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
assert(next[cur_layer]->top_layer >= cur_layer);
|
assert(next[cur_layer]->top_layer >= cur_layer);
|
||||||
__SLD_P("%02x rmv %p[%d] -> %p (node %p)\n", (int)tid_hash,
|
__SLD_P("%02x rmv %p[%d] -> %p (node %p)\n", (int)tid_hash, prev[cur_layer],
|
||||||
prev[cur_layer], cur_layer, next[cur_layer], node);
|
cur_layer, next[cur_layer], node);
|
||||||
__sl_write_unlock_an(prev[cur_layer]);
|
__sl_write_unlock_an(prev[cur_layer]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
124
tests/munit.c
124
tests/munit.c
|
@ -513,8 +513,7 @@ struct PsnipClockTimespec {
|
||||||
(defined(PSNIP_CLOCK_WALL_METHOD) && \
|
(defined(PSNIP_CLOCK_WALL_METHOD) && \
|
||||||
(PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETPROCESSTIMES)) || \
|
(PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETPROCESSTIMES)) || \
|
||||||
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && \
|
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && \
|
||||||
(PSNIP_CLOCK_MONOTONIC_METHOD == \
|
(PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETPROCESSTIMES)) || \
|
||||||
PSNIP_CLOCK_METHOD_GETPROCESSTIMES)) || \
|
|
||||||
(defined(PSNIP_CLOCK_CPU_METHOD) && \
|
(defined(PSNIP_CLOCK_CPU_METHOD) && \
|
||||||
(PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64)) || \
|
(PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64)) || \
|
||||||
(defined(PSNIP_CLOCK_WALL_METHOD) && \
|
(defined(PSNIP_CLOCK_WALL_METHOD) && \
|
||||||
|
@ -539,8 +538,7 @@ struct PsnipClockTimespec {
|
||||||
(defined(PSNIP_CLOCK_WALL_METHOD) && \
|
(defined(PSNIP_CLOCK_WALL_METHOD) && \
|
||||||
(PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME)) || \
|
(PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME)) || \
|
||||||
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && \
|
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && \
|
||||||
(PSNIP_CLOCK_MONOTONIC_METHOD == \
|
(PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME))
|
||||||
PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME))
|
|
||||||
#include <CoreServices/CoreServices.h>
|
#include <CoreServices/CoreServices.h>
|
||||||
#include <mach/mach.h>
|
#include <mach/mach.h>
|
||||||
#include <mach/mach_time.h>
|
#include <mach/mach_time.h>
|
||||||
|
@ -832,8 +830,7 @@ static psnip_uint64_t
|
||||||
munit_clock_get_elapsed(struct PsnipClockTimespec *start,
|
munit_clock_get_elapsed(struct PsnipClockTimespec *start,
|
||||||
struct PsnipClockTimespec *end)
|
struct PsnipClockTimespec *end)
|
||||||
{
|
{
|
||||||
psnip_uint64_t r = (end->seconds - start->seconds) *
|
psnip_uint64_t r = (end->seconds - start->seconds) * PSNIP_CLOCK_NSEC_PER_SEC;
|
||||||
PSNIP_CLOCK_NSEC_PER_SEC;
|
|
||||||
if (end->nanoseconds < start->nanoseconds) {
|
if (end->nanoseconds < start->nanoseconds) {
|
||||||
r -= (start->nanoseconds - end->nanoseconds);
|
r -= (start->nanoseconds - end->nanoseconds);
|
||||||
} else {
|
} else {
|
||||||
|
@ -943,8 +940,8 @@ munit_atomic_cas(ATOMIC_UINT32_T *dest, ATOMIC_UINT32_T *expected,
|
||||||
__c11_atomic_store(dest, value, __ATOMIC_SEQ_CST)
|
__c11_atomic_store(dest, value, __ATOMIC_SEQ_CST)
|
||||||
#define munit_atomic_load(src) __c11_atomic_load(src, __ATOMIC_SEQ_CST)
|
#define munit_atomic_load(src) __c11_atomic_load(src, __ATOMIC_SEQ_CST)
|
||||||
#define munit_atomic_cas(dest, expected, value) \
|
#define munit_atomic_cas(dest, expected, value) \
|
||||||
__c11_atomic_compare_exchange_weak(dest, expected, value, \
|
__c11_atomic_compare_exchange_weak(dest, expected, value, __ATOMIC_SEQ_CST, \
|
||||||
__ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
|
__ATOMIC_SEQ_CST)
|
||||||
#elif defined(__GNUC__) && (__GNUC__ > 4) || \
|
#elif defined(__GNUC__) && (__GNUC__ > 4) || \
|
||||||
(__GNUC__ == 4 && __GNUC_MINOR__ >= 7)
|
(__GNUC__ == 4 && __GNUC_MINOR__ >= 7)
|
||||||
#define munit_atomic_store(dest, value) \
|
#define munit_atomic_store(dest, value) \
|
||||||
|
@ -1001,8 +998,7 @@ munit_rand_next_state(munit_uint32_t state)
|
||||||
static munit_uint32_t
|
static munit_uint32_t
|
||||||
munit_rand_from_state(munit_uint32_t state)
|
munit_rand_from_state(munit_uint32_t state)
|
||||||
{
|
{
|
||||||
munit_uint32_t res = ((state >> ((state >> 28) + 4)) ^ state) *
|
munit_uint32_t res = ((state >> ((state >> 28) + 4)) ^ state) * (277803737U);
|
||||||
(277803737U);
|
|
||||||
res ^= res >> 22;
|
res ^= res >> 22;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -1147,8 +1143,7 @@ munit_rand_double(void)
|
||||||
/* See http://mumble.net/~campbell/tmp/random_real.c for how to do
|
/* See http://mumble.net/~campbell/tmp/random_real.c for how to do
|
||||||
* this right. Patches welcome if you feel that this is too
|
* this right. Patches welcome if you feel that this is too
|
||||||
* biased. */
|
* biased. */
|
||||||
retval = munit_rand_state_uint32(&state) /
|
retval = munit_rand_state_uint32(&state) / ((~((munit_uint32_t)0U)) + 1.0);
|
||||||
((~((munit_uint32_t)0U)) + 1.0);
|
|
||||||
} while (!munit_atomic_cas(&munit_rand_state, &old, state));
|
} while (!munit_atomic_cas(&munit_rand_state, &old, state));
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
|
@ -1325,8 +1320,7 @@ munit_test_runner_exec(MunitTestRunner *runner, const MunitTest *test,
|
||||||
munit_rand_seed(runner->seed);
|
munit_rand_seed(runner->seed);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
void *data = (test->setup == NULL) ?
|
void *data = (test->setup == NULL) ? runner->user_data :
|
||||||
runner->user_data :
|
|
||||||
test->setup(params, runner->user_data);
|
test->setup(params, runner->user_data);
|
||||||
|
|
||||||
#if defined(MUNIT_ENABLE_TIMING)
|
#if defined(MUNIT_ENABLE_TIMING)
|
||||||
|
@ -1522,8 +1516,7 @@ munit_test_runner_run_test_with_params(MunitTestRunner *runner,
|
||||||
sizeof(report) - bytes_written);
|
sizeof(report) - bytes_written);
|
||||||
if (write_res < 0) {
|
if (write_res < 0) {
|
||||||
if (stderr_buf != NULL) {
|
if (stderr_buf != NULL) {
|
||||||
munit_log_errno(MUNIT_LOG_ERROR, stderr,
|
munit_log_errno(MUNIT_LOG_ERROR, stderr, "unable to write to pipe");
|
||||||
"unable to write to pipe");
|
|
||||||
}
|
}
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
@ -1546,8 +1539,7 @@ munit_test_runner_run_test_with_params(MunitTestRunner *runner,
|
||||||
} else {
|
} else {
|
||||||
close(pipefd[1]);
|
close(pipefd[1]);
|
||||||
do {
|
do {
|
||||||
read_res = read(pipefd[0],
|
read_res = read(pipefd[0], ((munit_uint8_t *)(&report)) + bytes_read,
|
||||||
((munit_uint8_t *)(&report)) + bytes_read,
|
|
||||||
sizeof(report) - bytes_read);
|
sizeof(report) - bytes_read);
|
||||||
if (read_res < 1)
|
if (read_res < 1)
|
||||||
break;
|
break;
|
||||||
|
@ -1560,8 +1552,7 @@ munit_test_runner_run_test_with_params(MunitTestRunner *runner,
|
||||||
MUNIT_LIKELY(WIFEXITED(status))) {
|
MUNIT_LIKELY(WIFEXITED(status))) {
|
||||||
if (bytes_read != sizeof(report)) {
|
if (bytes_read != sizeof(report)) {
|
||||||
munit_logf_internal(MUNIT_LOG_ERROR, stderr_buf,
|
munit_logf_internal(MUNIT_LOG_ERROR, stderr_buf,
|
||||||
"child exited unexpectedly with status %d",
|
"child exited unexpectedly with status %d", WEXITSTATUS(status));
|
||||||
WEXITSTATUS(status));
|
|
||||||
report.errored++;
|
report.errored++;
|
||||||
} else if (WEXITSTATUS(status) != EXIT_SUCCESS) {
|
} else if (WEXITSTATUS(status) != EXIT_SUCCESS) {
|
||||||
munit_logf_internal(MUNIT_LOG_ERROR, stderr_buf,
|
munit_logf_internal(MUNIT_LOG_ERROR, stderr_buf,
|
||||||
|
@ -1621,12 +1612,10 @@ print_result:
|
||||||
fputs("[ ", MUNIT_OUTPUT_FILE);
|
fputs("[ ", MUNIT_OUTPUT_FILE);
|
||||||
if ((test->options & MUNIT_TEST_OPTION_TODO) == MUNIT_TEST_OPTION_TODO) {
|
if ((test->options & MUNIT_TEST_OPTION_TODO) == MUNIT_TEST_OPTION_TODO) {
|
||||||
if (report.failed != 0 || report.errored != 0 || report.skipped != 0) {
|
if (report.failed != 0 || report.errored != 0 || report.skipped != 0) {
|
||||||
munit_test_runner_print_color(runner, MUNIT_RESULT_STRING_TODO,
|
munit_test_runner_print_color(runner, MUNIT_RESULT_STRING_TODO, '3');
|
||||||
'3');
|
|
||||||
result = MUNIT_OK;
|
result = MUNIT_OK;
|
||||||
} else {
|
} else {
|
||||||
munit_test_runner_print_color(runner, MUNIT_RESULT_STRING_ERROR,
|
munit_test_runner_print_color(runner, MUNIT_RESULT_STRING_ERROR, '1');
|
||||||
'1');
|
|
||||||
if (MUNIT_LIKELY(stderr_buf != NULL))
|
if (MUNIT_LIKELY(stderr_buf != NULL))
|
||||||
munit_log_internal(MUNIT_LOG_ERROR, stderr_buf,
|
munit_log_internal(MUNIT_LOG_ERROR, stderr_buf,
|
||||||
"Test marked TODO, but was successful.");
|
"Test marked TODO, but was successful.");
|
||||||
|
@ -1649,14 +1638,11 @@ print_result:
|
||||||
munit_test_runner_print_color(runner, MUNIT_RESULT_STRING_OK, '2');
|
munit_test_runner_print_color(runner, MUNIT_RESULT_STRING_OK, '2');
|
||||||
#if defined(MUNIT_ENABLE_TIMING)
|
#if defined(MUNIT_ENABLE_TIMING)
|
||||||
fputs(" ] [ ", MUNIT_OUTPUT_FILE);
|
fputs(" ] [ ", MUNIT_OUTPUT_FILE);
|
||||||
munit_print_time(MUNIT_OUTPUT_FILE,
|
munit_print_time(MUNIT_OUTPUT_FILE, report.wall_clock / report.successful);
|
||||||
report.wall_clock / report.successful);
|
|
||||||
fputs(" / ", MUNIT_OUTPUT_FILE);
|
fputs(" / ", MUNIT_OUTPUT_FILE);
|
||||||
munit_print_time(MUNIT_OUTPUT_FILE,
|
munit_print_time(MUNIT_OUTPUT_FILE, report.cpu_clock / report.successful);
|
||||||
report.cpu_clock / report.successful);
|
|
||||||
fprintf(MUNIT_OUTPUT_FILE,
|
fprintf(MUNIT_OUTPUT_FILE,
|
||||||
" CPU ]\n %-" MUNIT_XSTRINGIFY(MUNIT_TEST_NAME_LEN) "s Total: [ ",
|
" CPU ]\n %-" MUNIT_XSTRINGIFY(MUNIT_TEST_NAME_LEN) "s Total: [ ", "");
|
||||||
"");
|
|
||||||
munit_print_time(MUNIT_OUTPUT_FILE, report.wall_clock);
|
munit_print_time(MUNIT_OUTPUT_FILE, report.wall_clock);
|
||||||
fputs(" / ", MUNIT_OUTPUT_FILE);
|
fputs(" / ", MUNIT_OUTPUT_FILE);
|
||||||
munit_print_time(MUNIT_OUTPUT_FILE, report.cpu_clock);
|
munit_print_time(MUNIT_OUTPUT_FILE, report.cpu_clock);
|
||||||
|
@ -1679,8 +1665,7 @@ print_result:
|
||||||
fputs(" ]\n", MUNIT_OUTPUT_FILE);
|
fputs(" ]\n", MUNIT_OUTPUT_FILE);
|
||||||
|
|
||||||
if (stderr_buf != NULL) {
|
if (stderr_buf != NULL) {
|
||||||
if (result == MUNIT_FAIL || result == MUNIT_ERROR ||
|
if (result == MUNIT_FAIL || result == MUNIT_ERROR || runner->show_stderr) {
|
||||||
runner->show_stderr) {
|
|
||||||
fflush(MUNIT_OUTPUT_FILE);
|
fflush(MUNIT_OUTPUT_FILE);
|
||||||
|
|
||||||
rewind(stderr_buf);
|
rewind(stderr_buf);
|
||||||
|
@ -1715,8 +1700,7 @@ munit_test_runner_run_test_wild(MunitTestRunner *runner, const MunitTest *test,
|
||||||
if (next->name == NULL) {
|
if (next->name == NULL) {
|
||||||
munit_test_runner_run_test_with_params(runner, test, params);
|
munit_test_runner_run_test_with_params(runner, test, params);
|
||||||
} else {
|
} else {
|
||||||
munit_test_runner_run_test_wild(runner, test, test_name, params,
|
munit_test_runner_run_test_wild(runner, test, test_name, params, next);
|
||||||
next);
|
|
||||||
}
|
}
|
||||||
if (runner->fatal_failures &&
|
if (runner->fatal_failures &&
|
||||||
(runner->report.failed != 0 || runner->report.errored != 0))
|
(runner->report.failed != 0 || runner->report.errored != 0))
|
||||||
|
@ -1767,11 +1751,11 @@ munit_test_runner_run_test(MunitTestRunner *runner, const MunitTest *test,
|
||||||
for (pe = test->parameters; pe != NULL && pe->name != NULL; pe++) {
|
for (pe = test->parameters; pe != NULL && pe->name != NULL; pe++) {
|
||||||
/* Did we received a value for this parameter from the CLI? */
|
/* Did we received a value for this parameter from the CLI? */
|
||||||
filled = 0;
|
filled = 0;
|
||||||
for (cli_p = runner->parameters;
|
for (cli_p = runner->parameters; cli_p != NULL && cli_p->name != NULL;
|
||||||
cli_p != NULL && cli_p->name != NULL; cli_p++) {
|
cli_p++) {
|
||||||
if (strcmp(cli_p->name, pe->name) == 0) {
|
if (strcmp(cli_p->name, pe->name) == 0) {
|
||||||
if (MUNIT_UNLIKELY(munit_parameters_add(¶ms_l, ¶ms,
|
if (MUNIT_UNLIKELY(munit_parameters_add(¶ms_l, ¶ms, pe->name,
|
||||||
pe->name, cli_p->value) != MUNIT_OK))
|
cli_p->value) != MUNIT_OK))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
filled = 1;
|
filled = 1;
|
||||||
break;
|
break;
|
||||||
|
@ -1795,16 +1779,14 @@ munit_test_runner_run_test(MunitTestRunner *runner, const MunitTest *test,
|
||||||
* running a single test, but we don't want every test with
|
* running a single test, but we don't want every test with
|
||||||
* the same number of parameters to choose the same parameter
|
* the same number of parameters to choose the same parameter
|
||||||
* number, so use the test name as a primitive salt. */
|
* number, so use the test name as a primitive salt. */
|
||||||
pidx = munit_rand_at_most(munit_str_hash(test_name),
|
pidx = munit_rand_at_most(munit_str_hash(test_name), possible - 1);
|
||||||
possible - 1);
|
if (MUNIT_UNLIKELY(munit_parameters_add(¶ms_l, ¶ms, pe->name,
|
||||||
if (MUNIT_UNLIKELY(munit_parameters_add(¶ms_l, ¶ms,
|
pe->values[pidx]) != MUNIT_OK))
|
||||||
pe->name, pe->values[pidx]) != MUNIT_OK))
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
} else {
|
} else {
|
||||||
/* We want to try every permutation. Put in a placeholder
|
/* We want to try every permutation. Put in a placeholder
|
||||||
* entry, we'll iterate through them later. */
|
* entry, we'll iterate through them later. */
|
||||||
if (MUNIT_UNLIKELY(
|
if (MUNIT_UNLIKELY(munit_parameters_add(&wild_params_l, &wild_params,
|
||||||
munit_parameters_add(&wild_params_l, &wild_params,
|
|
||||||
pe->name, NULL) != MUNIT_OK))
|
pe->name, NULL) != MUNIT_OK))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
@ -1814,11 +1796,9 @@ munit_test_runner_run_test(MunitTestRunner *runner, const MunitTest *test,
|
||||||
first_wild = params_l;
|
first_wild = params_l;
|
||||||
for (wp = wild_params; wp != NULL && wp->name != NULL; wp++) {
|
for (wp = wild_params; wp != NULL && wp->name != NULL; wp++) {
|
||||||
for (pe = test->parameters;
|
for (pe = test->parameters;
|
||||||
pe != NULL && pe->name != NULL && pe->values != NULL;
|
pe != NULL && pe->name != NULL && pe->values != NULL; pe++) {
|
||||||
pe++) {
|
|
||||||
if (strcmp(wp->name, pe->name) == 0) {
|
if (strcmp(wp->name, pe->name) == 0) {
|
||||||
if (MUNIT_UNLIKELY(
|
if (MUNIT_UNLIKELY(munit_parameters_add(¶ms_l, ¶ms,
|
||||||
munit_parameters_add(¶ms_l, ¶ms,
|
|
||||||
pe->name, pe->values[0]) != MUNIT_OK))
|
pe->name, pe->values[0]) != MUNIT_OK))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
@ -1847,25 +1827,22 @@ munit_test_runner_run_suite(MunitTestRunner *runner, const MunitSuite *suite,
|
||||||
const char *prefix)
|
const char *prefix)
|
||||||
{
|
{
|
||||||
size_t pre_l;
|
size_t pre_l;
|
||||||
char *pre = munit_maybe_concat(&pre_l, (char *)prefix,
|
char *pre = munit_maybe_concat(&pre_l, (char *)prefix, (char *)suite->prefix);
|
||||||
(char *)suite->prefix);
|
|
||||||
const MunitTest *test;
|
const MunitTest *test;
|
||||||
const char **test_name;
|
const char **test_name;
|
||||||
const MunitSuite *child_suite;
|
const MunitSuite *child_suite;
|
||||||
|
|
||||||
/* Run the tests. */
|
/* Run the tests. */
|
||||||
for (test = suite->tests; test != NULL && test->test != NULL; test++) {
|
for (test = suite->tests; test != NULL && test->test != NULL; test++) {
|
||||||
if (runner->tests !=
|
if (runner->tests != NULL) { /* Specific tests were requested on the CLI */
|
||||||
NULL) { /* Specific tests were requested on the CLI */
|
for (test_name = runner->tests; test_name != NULL && *test_name != NULL;
|
||||||
for (test_name = runner->tests;
|
test_name++) {
|
||||||
test_name != NULL && *test_name != NULL; test_name++) {
|
|
||||||
if ((pre_l == 0 || strncmp(pre, *test_name, pre_l) == 0) &&
|
if ((pre_l == 0 || strncmp(pre, *test_name, pre_l) == 0) &&
|
||||||
strncmp(test->name, *test_name + pre_l,
|
strncmp(test->name, *test_name + pre_l, strlen(*test_name + pre_l)) ==
|
||||||
strlen(*test_name + pre_l)) == 0) {
|
0) {
|
||||||
munit_test_runner_run_test(runner, test, pre);
|
munit_test_runner_run_test(runner, test, pre);
|
||||||
if (runner->fatal_failures &&
|
if (runner->fatal_failures &&
|
||||||
(runner->report.failed != 0 ||
|
(runner->report.failed != 0 || runner->report.errored != 0))
|
||||||
runner->report.errored != 0))
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1946,8 +1923,7 @@ munit_print_help(int argc, char *const argv[MUNIT_ARRAY_PARAM(argc + 1)],
|
||||||
#endif
|
#endif
|
||||||
printf(" %d.%d.%d\n"
|
printf(" %d.%d.%d\n"
|
||||||
"Full documentation at: https://nemequ.github.io/munit/\n",
|
"Full documentation at: https://nemequ.github.io/munit/\n",
|
||||||
(MUNIT_CURRENT_VERSION >> 16) & 0xff,
|
(MUNIT_CURRENT_VERSION >> 16) & 0xff, (MUNIT_CURRENT_VERSION >> 8) & 0xff,
|
||||||
(MUNIT_CURRENT_VERSION >> 8) & 0xff,
|
|
||||||
(MUNIT_CURRENT_VERSION >> 0) & 0xff);
|
(MUNIT_CURRENT_VERSION >> 0) & 0xff);
|
||||||
for (arg = arguments; arg != NULL && arg->name != NULL; arg++)
|
for (arg = arguments; arg != NULL && arg->name != NULL; arg++)
|
||||||
arg->write_help(arg, user_data);
|
arg->write_help(arg, user_data);
|
||||||
|
@ -1970,8 +1946,7 @@ munit_suite_list_tests(const MunitSuite *suite, munit_bool show_params,
|
||||||
const char *prefix)
|
const char *prefix)
|
||||||
{
|
{
|
||||||
size_t pre_l;
|
size_t pre_l;
|
||||||
char *pre = munit_maybe_concat(&pre_l, (char *)prefix,
|
char *pre = munit_maybe_concat(&pre_l, (char *)prefix, (char *)suite->prefix);
|
||||||
(char *)suite->prefix);
|
|
||||||
const MunitTest *test;
|
const MunitTest *test;
|
||||||
const MunitParameterEnum *params;
|
const MunitParameterEnum *params;
|
||||||
munit_bool first;
|
munit_bool first;
|
||||||
|
@ -1984,8 +1959,8 @@ munit_suite_list_tests(const MunitSuite *suite, munit_bool show_params,
|
||||||
puts(test->name);
|
puts(test->name);
|
||||||
|
|
||||||
if (show_params) {
|
if (show_params) {
|
||||||
for (params = test->parameters;
|
for (params = test->parameters; params != NULL && params->name != NULL;
|
||||||
params != NULL && params->name != NULL; params++) {
|
params++) {
|
||||||
fprintf(stdout, " - %s: ", params->name);
|
fprintf(stdout, " - %s: ", params->name);
|
||||||
if (params->values == NULL) {
|
if (params->values == NULL) {
|
||||||
puts("Any");
|
puts("Any");
|
||||||
|
@ -2101,8 +2076,7 @@ munit_suite_main_custom(const MunitSuite *suite, void *user_data, int argc,
|
||||||
ts = strtoul(argv[arg + 1], &envptr, 0);
|
ts = strtoul(argv[arg + 1], &envptr, 0);
|
||||||
if (*envptr != '\0' || ts > (~((munit_uint32_t)0U))) {
|
if (*envptr != '\0' || ts > (~((munit_uint32_t)0U))) {
|
||||||
munit_logf_internal(MUNIT_LOG_ERROR, stderr,
|
munit_logf_internal(MUNIT_LOG_ERROR, stderr,
|
||||||
"invalid value ('%s') passed to %s", argv[arg + 1],
|
"invalid value ('%s') passed to %s", argv[arg + 1], argv[arg]);
|
||||||
argv[arg]);
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
runner.seed = (munit_uint32_t)ts;
|
runner.seed = (munit_uint32_t)ts;
|
||||||
|
@ -2119,8 +2093,7 @@ munit_suite_main_custom(const MunitSuite *suite, void *user_data, int argc,
|
||||||
iterations = strtoul(argv[arg + 1], &endptr, 0);
|
iterations = strtoul(argv[arg + 1], &endptr, 0);
|
||||||
if (*endptr != '\0' || iterations > UINT_MAX) {
|
if (*endptr != '\0' || iterations > UINT_MAX) {
|
||||||
munit_logf_internal(MUNIT_LOG_ERROR, stderr,
|
munit_logf_internal(MUNIT_LOG_ERROR, stderr,
|
||||||
"invalid value ('%s') passed to %s", argv[arg + 1],
|
"invalid value ('%s') passed to %s", argv[arg + 1], argv[arg]);
|
||||||
argv[arg]);
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2142,8 +2115,7 @@ munit_suite_main_custom(const MunitSuite *suite, void *user_data, int argc,
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
runner.parameters[parameters_size].name = (char *)argv[arg + 1];
|
runner.parameters[parameters_size].name = (char *)argv[arg + 1];
|
||||||
runner.parameters[parameters_size].value = (char *)
|
runner.parameters[parameters_size].value = (char *)argv[arg + 2];
|
||||||
argv[arg + 2];
|
|
||||||
parameters_size++;
|
parameters_size++;
|
||||||
runner.parameters[parameters_size].name = NULL;
|
runner.parameters[parameters_size].name = NULL;
|
||||||
runner.parameters[parameters_size].value = NULL;
|
runner.parameters[parameters_size].value = NULL;
|
||||||
|
@ -2160,12 +2132,10 @@ munit_suite_main_custom(const MunitSuite *suite, void *user_data, int argc,
|
||||||
else if (strcmp(argv[arg + 1], "never") == 0)
|
else if (strcmp(argv[arg + 1], "never") == 0)
|
||||||
runner.colorize = 0;
|
runner.colorize = 0;
|
||||||
else if (strcmp(argv[arg + 1], "auto") == 0)
|
else if (strcmp(argv[arg + 1], "auto") == 0)
|
||||||
runner.colorize = munit_stream_supports_ansi(
|
runner.colorize = munit_stream_supports_ansi(MUNIT_OUTPUT_FILE);
|
||||||
MUNIT_OUTPUT_FILE);
|
|
||||||
else {
|
else {
|
||||||
munit_logf_internal(MUNIT_LOG_ERROR, stderr,
|
munit_logf_internal(MUNIT_LOG_ERROR, stderr,
|
||||||
"invalid value ('%s') passed to %s", argv[arg + 1],
|
"invalid value ('%s') passed to %s", argv[arg + 1], argv[arg]);
|
||||||
argv[arg]);
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2202,8 +2172,7 @@ munit_suite_main_custom(const MunitSuite *suite, void *user_data, int argc,
|
||||||
level = MUNIT_LOG_ERROR;
|
level = MUNIT_LOG_ERROR;
|
||||||
else {
|
else {
|
||||||
munit_logf_internal(MUNIT_LOG_ERROR, stderr,
|
munit_logf_internal(MUNIT_LOG_ERROR, stderr,
|
||||||
"invalid value ('%s') passed to %s", argv[arg + 1],
|
"invalid value ('%s') passed to %s", argv[arg + 1], argv[arg]);
|
||||||
argv[arg]);
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2229,8 +2198,7 @@ munit_suite_main_custom(const MunitSuite *suite, void *user_data, int argc,
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!argument->parse_argument(suite, user_data, &arg, argc,
|
if (!argument->parse_argument(suite, user_data, &arg, argc, argv))
|
||||||
argv))
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -309,8 +309,7 @@ void munit_errorf_ex(const char *filename, int line, const char *format, ...);
|
||||||
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_ \
|
||||||
|
@ -321,8 +320,7 @@ void munit_errorf_ex(const char *filename, int line, const char *format, ...);
|
||||||
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_ \
|
||||||
|
@ -333,13 +331,12 @@ void munit_errorf_ex(const char *filename, int line, const char *format, ...);
|
||||||
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", \
|
||||||
|
@ -356,10 +353,10 @@ void munit_errorf_ex(const char *filename, int line, const char *format, ...);
|
||||||
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_
|
||||||
|
|
|
@ -122,7 +122,8 @@ uint32_key_cmp(sl_node *a, sl_node *b, void *aux)
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
__populate_slist(ex_sl_t *slist){
|
__populate_slist(ex_sl_t *slist)
|
||||||
|
{
|
||||||
size_t inserted = 0;
|
size_t inserted = 0;
|
||||||
uint32_t n, key;
|
uint32_t n, key;
|
||||||
ex_node_t *node;
|
ex_node_t *node;
|
||||||
|
|
Loading…
Reference in a new issue