Skip to content
Snippets Groups Projects
Commit 0008d1fa authored by Dmitry E. Oboukhov's avatar Dmitry E. Oboukhov
Browse files

Add rlist library and tests

parent a249b6c7
No related branches found
No related tags found
No related merge requests found
#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 */
#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 */
#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();
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment