From 0008d1fa192c8333b18178b352724cfa2ce8ff25 Mon Sep 17 00:00:00 2001 From: "Dmitry E. Oboukhov" <unera@debian.org> Date: Tue, 16 Oct 2012 01:54:28 +0400 Subject: [PATCH] Add rlist library and tests --- include/rlist.h | 183 ++++++++++++++++++++++++++++++++++++++++++++++ include/test.h | 93 +++++++++++++++++++++++ test/unit/rlist.c | 106 +++++++++++++++++++++++++++ 3 files changed, 382 insertions(+) create mode 100644 include/rlist.h create mode 100644 include/test.h create mode 100644 test/unit/rlist.c diff --git a/include/rlist.h b/include/rlist.h new file mode 100644 index 0000000000..e24f1b5d31 --- /dev/null +++ b/include/rlist.h @@ -0,0 +1,183 @@ +#ifndef TARANTOOL_RLIST_H_INCLUDED +#define TARANTOOL_RLIST_H_INCLUDED + +/** + * list entry and head structure + */ + +struct rlist { + struct rlist *prev; + struct rlist *next; +}; + + +/** + * init list head (or list entry as ins't included in list) + */ + +inline static void +rlist_init(struct rlist *list) +{ + list->next = list; + list->prev = list; +} + +/** + * add item to list + */ +inline static void +rlist_add(struct rlist *head, struct rlist *item) +{ + item->prev = head; + item->next = head->next; + item->prev->next = item; + item->next->prev = item; +} + +/** + * add item to list tail + */ +inline static void +rlist_add_tail(struct rlist *head, struct rlist *item) +{ + item->next = head; + item->prev = head->prev; + item->prev->next = item; + item->next->prev = item; +} + +/** + * delete element + */ +inline static void +rlist_del(struct rlist *item) +{ + item->prev->next = item->next; + item->next->prev = item->prev; + rlist_init(item); +} + +/** + * return first element + */ +inline static struct rlist * +rlist_first(struct rlist *head) +{ + return head->next; +} + +/** + * return last element + */ +inline static struct rlist * +rlist_last(struct rlist *head) +{ + return head->prev; +} + +/** + * return next element by element + */ +inline static struct rlist * +rlist_next(struct rlist *item) +{ + return item->next; +} + +/** + * return previous element + */ +inline static struct rlist * +rlist_prev(struct rlist *item) +{ + return item->prev; +} + +/** + * return TRUE if list is empty + */ +inline static int +rlist_empty(struct rlist *item) +{ + return item->next == item->prev && item->next == item; +} + +/** + * allocate and init head of list + */ +#define RLIST_HEAD(name) \ + struct rlist name = { &(name), &(name) } + +/** + * return entry by list item + */ +#define rlist_entry(item, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (item); \ + (type *)( (char *)__mptr - ((size_t) &((type *)0)->member) ); }) + +/** + * return first entry + */ +#define rlist_first_entry(head, type, member) \ + rlist_entry(rlist_first(head), type, member) + +/** + * return last entry + */ +#define rlist_last_entry(head, type, member) \ + rlist_entry(rlist_last(head), type, member) + +/** + * return next entry + */ +#define rlist_next_entry(item, member) \ + rlist_entry(rlist_next(&(item)->member), typeof(*item), member) + +/** + * return previous entry + */ +#define rlist_prev_entry(item, member) \ + rlist_entry(rlist_prev(&(item)->member), typeof(*item), member) + +/** + * add entry to list + */ +#define rlist_add_entry(head, item, member) \ + rlist_add((head), &(item)->member) + +/** + * add entry to list tail + */ +#define rlist_add_tail_entry(head, item, member) \ + rlist_add_tail((head), &(item)->member) + +/** + * foreach through list + */ +#define rlist_foreach(item, head) \ + for(item = rlist_first(head); item != (head); item = rlist_next(item)) + +/** + * foreach backward through list + */ +#define rlist_foreach_reverse(item, head) \ + for(item = rlist_last(head); item != (head); item = rlist_prev(item)) + +/** + * foreach through all list entries + */ +#define rlist_foreach_entry(item, head, member) \ + for(item = rlist_first_entry((head), typeof(*item), member); \ + &item->member != (head); \ + item = rlist_next_entry((item), member)) + +/** + * foreach backward through all list entries + */ +#define rlist_foreach_entry_reverse(item, head, member) \ + for(item = rlist_last_entry((head), typeof(*item), member); \ + &item->member != (head); \ + item = rlist_prev_entry((item), member)) + + +#endif /* TARANTOOL_RLIST_H_INCLUDED */ diff --git a/include/test.h b/include/test.h new file mode 100644 index 0000000000..b12e350a1b --- /dev/null +++ b/include/test.h @@ -0,0 +1,93 @@ +#ifndef TARANTOOL_TEST_H_INCLUDED +#define TARANTOOL_TEST_H_INCLUDED + +#include <stdio.h> +#include <stdarg.h> + +static int tests_done = 0; +static int tests_failed = 0; +static int plan_test = 0; + +static inline void +plan(int count) +{ + plan_test = count; + static showed_plan = 0; + if (!showed_plan) + printf("%d..%d\n", 1, plan_test); + showed_plan = 1; +} + +static inline int +check_plan(void) +{ + int res; + if (tests_done != plan_test) { + fprintf(stderr, + "# Looks like you planned %d tests but ran %d.\n", + plan_test, tests_done); + res = -1; + } + + if (tests_failed) { + fprintf(stderr, + "# Looks like you failed %d test of %d run.\n", + tests_failed, tests_done); + res = tests_failed; + } + return res; +} + +static inline int +__ok(int condition, const char *fmt, ...) +{ + va_list ap; + + printf("%s %d - ", condition ? "ok" : "not ok", ++tests_done); + if (!condition) + tests_failed++; + va_start(ap, fmt); + vprintf(fmt, ap); + printf("\n"); + return condition; +} + +#define ok(condition, fmt, args...) { \ + int res = __ok(condition, fmt, ##args); \ + if (!res) { \ + fprintf(stderr, "# Failed test '"); \ + fprintf(stderr, fmt, ##args); \ + fprintf(stderr, "'\n"); \ + fprintf(stderr, "# in %s at line %d\n", __FILE__, __LINE__); \ + } \ + res; \ +} + +#define is(a, b, fmt, args...) { \ + int res = __ok((a) == (b), fmt, ##args); \ + if (!res) { \ + fprintf(stderr, "# Failed test '"); \ + fprintf(stderr, fmt, ##args); \ + fprintf(stderr, "'\n"); \ + fprintf(stderr, "# in %s at line %d\n", __FILE__, __LINE__); \ + } \ + res; \ +} + +#define isnt(a, b, fmt, args...) { \ + int res = __ok((a) != (b), fmt, ##args); \ + if (!res) { \ + fprintf(stderr, "# Failed test '"); \ + fprintf(stderr, fmt, ##args); \ + fprintf(stderr, "'\n"); \ + fprintf(stderr, "# in %s at line %d\n", __FILE__, __LINE__); \ + } \ + res; \ +} + +#define fail(fmt, args...) \ + ok(0, fmt, ##args) + + +#endif /* TARANTOOL_TEST_H_INCLUDED */ + diff --git a/test/unit/rlist.c b/test/unit/rlist.c new file mode 100644 index 0000000000..68768763fd --- /dev/null +++ b/test/unit/rlist.c @@ -0,0 +1,106 @@ +#include <rlist.h> +#include <stdio.h> +#include <stdarg.h> +#include <test.h> + + +#define PLAN 66 + +#define ITEMS 7 + +struct test { + char ch; + int no; + struct rlist list; +}; + +static struct test items[ITEMS]; + +static RLIST_HEAD(head); + +int +main(void) +{ + int i; + struct test *it; + struct rlist *rlist; + + plan(PLAN); + ok(rlist_empty(&head), "list is empty"); + for (i = 0; i < ITEMS; i++) { + items[i].no = i; + rlist_add_tail(&head, &(items[i].list)); + } + + + is(rlist_first(&head), &items[0].list, "first item"); + isnt(rlist_first(&head), &items[ITEMS - 1].list, "first item"); + + is(rlist_last(&head), &items[ITEMS - 1].list, "last item"); + isnt(rlist_last(&head), &items[0].list, "last item"); + + is(rlist_next(&head), &items[0].list, "rlist_next"); + is(rlist_prev(&head), &items[ITEMS - 1].list, "rlist_prev"); + + i = 0; + rlist_foreach(rlist, &head) { + is(rlist, &items[i].list, "element (foreach) %d", i); + i++; + } + rlist_foreach_reverse(rlist, &head) { + i--; + is(rlist, &items[i].list, "element (foreach_reverse) %d", i); + } + + + is(rlist_entry(&items[0].list, struct test, list), &items[0], + "rlist_entry"); + is(rlist_first_entry(&head, struct test, list), &items[0], + "rlist_first_entry"); + is(rlist_next_entry(&items[0], list), &items[1], "rlist_next_entry"); + is(rlist_prev_entry(&items[2], list), &items[1], "rlist_prev_entry"); + + + i = 0; + rlist_foreach_entry(it, &head, list) { + is(it, items + i, "element (foreach_entry) %d", i); + i++; + } + rlist_foreach_entry_reverse(it, &head, list) { + i--; + is(it, items + i, "element (foreach_entry_reverse) %d", i); + } + + rlist_del(&items[2].list); + rlist_foreach_entry(it, &head, list) { + is(it, items + i, "element (second deleted) %d", i); + i++; + if (i == 2) + i++; + } + rlist_foreach_entry_reverse(it, &head, list) { + i--; + if (i == 2) + i--; + is(it, items + i, "element (second deleted) %d", i); + } + + + rlist_init(&head); + ok(rlist_empty(&head), "list is empty"); + for (i = 0; i < ITEMS; i++) { + items[i].no = i; + rlist_add(&head, &(items[i].list)); + } + i = 0; + rlist_foreach_entry_reverse(it, &head, list) { + is(it, items + i, "element (foreach_entry_reverse) %d", i); + i++; + } + rlist_foreach_entry(it, &head, list) { + i--; + is(it, items + i, "element (foreach_entry) %d", i); + } + return check_plan(); +} + -- GitLab