#if !defined(__OCS_LIST_H__)
#define __OCS_LIST_H__
#define OCS_LIST_DEBUG
#if defined(OCS_LIST_DEBUG)
#define ocs_list_magic_decl uint32_t magic;
#define OCS_LIST_LIST_MAGIC 0xcafe0000
#define OCS_LIST_LINK_MAGIC 0xcafe0001
#define ocs_list_set_list_magic list->magic = OCS_LIST_LIST_MAGIC
#define ocs_list_set_link_magic list->magic = OCS_LIST_LINK_MAGIC
#define ocs_list_assert(cond, ...) \
if (!(cond)) { \
return __VA_ARGS__; \
}
#else
#define ocs_list_magic_decl
#define ocs_list_assert(cond, ...)
#define ocs_list_set_list_magic
#define ocs_list_set_link_magic
#endif
typedef struct ocs_list_s ocs_list_t;
struct ocs_list_s {
ocs_list_magic_decl
ocs_list_t *next;
ocs_list_t *prev;
uint32_t offset;
};
typedef ocs_list_t ocs_list_link_t;
#define item2link(list, item) ((ocs_list_t*) (((uint8_t*)(item)) + (list)->offset))
#define link2item(list, link) ((void*) (((uint8_t*)(link)) - (list)->offset))
static inline void
_ocs_list_init(ocs_list_t *list, uint32_t offset)
{
ocs_list_assert(list);
ocs_list_set_list_magic;
list->next = list;
list->prev = list;
list->offset = offset;
}
#define ocs_list_init(head, type, link) _ocs_list_init(head, offsetof(type, link))
static inline int32_t
ocs_list_empty(ocs_list_t *list)
{
ocs_list_assert(list, 1);
ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, 1);
return list->next == list;
}
static inline int
ocs_list_valid(ocs_list_t *list)
{
return (list->magic == OCS_LIST_LIST_MAGIC);
}
static inline void
_ocs_list_insert_link(ocs_list_t *a, ocs_list_t *b, ocs_list_t *c)
{
ocs_list_assert(a);
ocs_list_assert((a->magic == OCS_LIST_LIST_MAGIC) || (a->magic == OCS_LIST_LINK_MAGIC));
ocs_list_assert(a->next);
ocs_list_assert(a->prev);
ocs_list_assert(b);
ocs_list_assert((b->magic == OCS_LIST_LIST_MAGIC) || (b->magic == OCS_LIST_LINK_MAGIC));
ocs_list_assert(b->next);
ocs_list_assert(b->prev);
ocs_list_assert(c);
ocs_list_assert((c->magic == OCS_LIST_LIST_MAGIC) || (c->magic == OCS_LIST_LINK_MAGIC));
ocs_list_assert(!c->next);
ocs_list_assert(!c->prev);
ocs_list_assert(a->offset == b->offset);
ocs_list_assert(b->offset == c->offset);
c->next = a->next;
c->prev = b->prev;
a->next = c;
b->prev = c;
}
#if defined(OCS_LIST_DEBUG)
static inline void
ocs_list_init_link(ocs_list_t *list, ocs_list_t *link)
{
ocs_list_assert(list);
ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC);
ocs_list_assert(link);
if (link->magic == 0) {
link->magic = OCS_LIST_LINK_MAGIC;
link->offset = list->offset;
link->next = NULL;
link->prev = NULL;
}
}
#else
#define ocs_list_init_link(...)
#endif
static inline void
ocs_list_add_head(ocs_list_t *list, void *item)
{
ocs_list_t *link;
ocs_list_assert(list);
ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC);
ocs_list_assert(item);
link = item2link(list, item);
ocs_list_init_link(list, link);
ocs_list_assert(link->magic == OCS_LIST_LINK_MAGIC);
ocs_list_assert(link->offset == list->offset);
ocs_list_assert(link->next == NULL);
ocs_list_assert(link->prev == NULL);
_ocs_list_insert_link(list, list->next, item2link(list, item));
}
static inline void
ocs_list_add_tail(ocs_list_t *list, void *item)
{
ocs_list_t *link;
ocs_list_assert(list);
ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC);
ocs_list_assert(item);
link = item2link(list, item);
ocs_list_init_link(list, link);
ocs_list_assert(link->magic == OCS_LIST_LINK_MAGIC);
ocs_list_assert(link->offset == list->offset);
ocs_list_assert(link->next == NULL);
ocs_list_assert(link->prev == NULL);
_ocs_list_insert_link(list->prev, list, link);
}
static inline void *
ocs_list_get_head(ocs_list_t *list)
{
ocs_list_assert(list, NULL);
ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, NULL);
return ocs_list_empty(list) ? NULL : link2item(list, list->next);
}
static inline void *
ocs_list_get_tail(ocs_list_t *list)
{
ocs_list_assert(list, NULL);
ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, NULL);
return ocs_list_empty(list) ? NULL : link2item(list, list->prev);
}
static inline void *ocs_list_tail(ocs_list_t *list)
{
ocs_list_assert(list, NULL);
ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, NULL);
return ocs_list_empty(list) ? NULL : link2item(list, list->prev);
}
static inline void *ocs_list_next(ocs_list_t *list, void *item)
{
ocs_list_t *link;
if (item == NULL) {
return NULL;
}
ocs_list_assert(list, NULL);
ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, NULL);
ocs_list_assert(item, NULL);
link = item2link(list, item);
ocs_list_assert(link->magic == OCS_LIST_LINK_MAGIC, NULL);
ocs_list_assert(link->offset == list->offset, NULL);
ocs_list_assert(link->next, NULL);
ocs_list_assert(link->prev, NULL);
if ((link->next) == list) {
return NULL;
}
return link2item(list, link->next);
}
#define ocs_list_remove_head(list) ocs_list_remove(list, ocs_list_get_head(list))
static inline void *ocs_list_remove(ocs_list_t *list, void *item)
{
ocs_list_t *link;
ocs_list_t *prev;
ocs_list_t *next;
if (item == NULL) {
return NULL;
}
ocs_list_assert(list, NULL);
ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, NULL);
link = item2link(list, item);
ocs_list_assert(link->magic == OCS_LIST_LINK_MAGIC, NULL);
ocs_list_assert(link->offset == list->offset, NULL);
ocs_list_assert(link->next, NULL);
ocs_list_assert(link->prev, NULL);
prev = link->prev;
next = link->next;
prev->next = next;
next->prev = prev;
link->next = link->prev = NULL;
return item;
}
#define ocs_list_foreach(list, item) \
for (item = ocs_list_get_head((list)); item; item = ocs_list_next((list), item) )
#define ocs_list_foreach_safe(list, item, nxt) \
for (item = ocs_list_get_head(list), nxt = item ? ocs_list_next(list, item) : NULL; item; \
item = nxt, nxt = ocs_list_next(list, item))
static inline int32_t
ocs_list_on_list(ocs_list_link_t *link)
{
return (link->next != NULL);
}
#endif