И так, после некоторых экспериментов я пришел к следующей реализации списков, которая включает в себя все лучшее из стандартной реализации и реализации «как в линуксе» :)
Достоинства: нигде не используются преобразования указателей, простая чистая реализация, работа идет сразу с лементами (как в стандартных списках) и не нужно вычислять адрес самой структуры данных (как в списках из линукса).
В настоящий момент в каждую сруктуру, которая может включаться в список нужно добавить служебный элемент для связи (макрос LIST_LINK), который всегда называется link. Если во все макросы добавить название служебного поля как параметр, то можно иметь один и то-же элемент в разных списках (как в линуксе), мне это не нужно, поэтому не делал.
Конструктивная критика приветствуется.
Сама реализация:
#ifndef _LIST_H_
#define _LIST_H_
#define LIST_LINK(type) \
struct { struct type *next; struct type *prev; } link
#define DECLARE_LIST(type, name) \
type name = { .link = { .next = &(name), .prev = &(name) } }
#define LIST_INIT(ptr) \
do { (ptr)->link.next = ptr; (ptr)->link.prev = ptr; } while (0)
#define list_add_after(_item, _new) \
do { \
(_new)->link.next = (_item)->link.next; \
(_new)->link.prev = (_item); \
(_item)->link.next->link.prev = (_new); \
(_item)->link.next = (_new); \
} while (0)
#define list_add_before(_item, _new) \
do { \
(_new)->link.next = (_item); \
(_new)->link.prev = (_item)->link.prev; \
(_item)->link.prev->link.next = (_new); \
(_item)->link.prev = (_new); \
} while (0)
#define list_add(_list, _new) \
list_add_before(_list, _new)
#define list_add_head(_list, _new) \
list_add_after(_list, _new)
#define list_del(_item) \
do { \
(_item)->link.prev->link.next = (_item)->link.next; \
(_item)->link.next->link.prev = (_item)->link.prev; \
(_item)->link.next = NULL; \
(_item)->link.prev = NULL; \
} while (0)
#define list_del_init(_list) \
do { \
list_del(_item); \
LIST_INIT(_item); \
} while (0)
#define list_is_empty(_list) \
((_list)->link.next == (_list))
#define list_foreach(_var, _list) \
for (_var = (_list)->link.next; _var != (_list); _var = _var->link.next)
#define list_foreach_back(_var, _list) \
for (_var = (_list)->link.prev; _var != (_list); _var = _var->link.prev)
#define list_foreach_var(_type, _var, _list) \
for (_type *_var = (_list)->link.next; _var != (_list); _var = _var->link.next)
#define list_foreach_back_var(_type, _var, _list) \
for (_type *_var = (_list)->link.prev; _var != (_list); _var = _var->link.prev)
#define list_foreach_safe(_var, _list, _tmp) \
for (_var = (_list)->link.next, _tmp = (_var)->link.next; _var != (_list); \
_var = _tmp, _tmp = (_var)->link.next)
#define list_foreach_back_safe(_var, _list, _tmp) \
for (_var = (_list)->link.prev, _tmp = (_var)->link.prev; _var != (_list); \
_var = _tmp, _tmp = (_var)->link.prev)
#endif // _LIST_H_
Пример использования:
#include <stdio.h>
#include <stdlib.h>
#include "list.h"
typedef struct num_t
{
int num;
LIST_LINK(num_t);
} num_t;
static DECLARE_LIST(num_t, nums);
int main(void)
{
num_t n1, n2, n3, n4;
num_t *n5;
num_t *ext_var;
n1.num = 1111;
n2.num = 2222;
n3.num = 3333;
n4.num = 4444;
n5 = malloc(sizeof(num_t));
n5->num = 5555;
list_add(&nums, &n1);
list_add(&nums, &n2);
list_add(&nums, &n3);
list_add(&nums, &n4);
list_add(&nums, n5);
list_del(&n2);
printf("Go through list using c99 style for loop declaration:\n");
list_foreach_var (num_t, var, &nums)
{
printf(" %d\n", var->num);
}
printf("Go through list using external variable as loop parameter:\n");
list_foreach (ext_var, &nums)
{
printf(" %d\n", ext_var->num);
}
return 0;
}