#ifndef ILIST_H
#define ILIST_H
typedef struct dlist_node dlist_node;
struct dlist_node
{
dlist_node *prev;
dlist_node *next;
};
typedef struct dlist_head
{
dlist_node head;
} dlist_head;
typedef struct dlist_iter
{
dlist_node *cur;
dlist_node *end;
} dlist_iter;
typedef struct dlist_mutable_iter
{
dlist_node *cur;
dlist_node *next;
dlist_node *end;
} dlist_mutable_iter;
typedef struct dclist_head
{
dlist_head dlist;
uint32 count;
} dclist_head;
typedef struct slist_node slist_node;
struct slist_node
{
slist_node *next;
};
typedef struct slist_head
{
slist_node head;
} slist_head;
typedef struct slist_iter
{
slist_node *cur;
} slist_iter;
typedef struct slist_mutable_iter
{
slist_node *cur;
slist_node *next;
slist_node *prev;
} slist_mutable_iter;
#define DLIST_STATIC_INIT(name) {{&(name).head, &(name).head}}
#define DCLIST_STATIC_INIT(name) {{{&(name).dlist.head, &(name).dlist.head}}, 0}
#define SLIST_STATIC_INIT(name) {{NULL}}
extern void slist_delete(slist_head *head, const slist_node *node);
#ifdef ILIST_DEBUG
extern void dlist_member_check(const dlist_head *head, const dlist_node *node);
extern void dlist_check(const dlist_head *head);
extern void slist_check(const slist_head *head);
#else
#define dlist_member_check(head, node) ((void) (head))
#define dlist_check(head) ((void) (head))
#define slist_check(head) ((void) (head))
#endif
static inline void
dlist_init(dlist_head *head)
{
head->head.next = head->head.prev = &head->head;
}
static inline void
dlist_node_init(dlist_node *node)
{
node->next = node->prev = NULL;
}
static inline bool
dlist_is_empty(const dlist_head *head)
{
dlist_check(head);
return head->head.next == NULL || head->head.next == &(head->head);
}
static inline void
dlist_push_head(dlist_head *head, dlist_node *node)
{
if (head->head.next == NULL)
dlist_init(head);
node->next = head->head.next;
node->prev = &head->head;
node->next->prev = node;
head->head.next = node;
dlist_check(head);
}
static inline void
dlist_push_tail(dlist_head *head, dlist_node *node)
{
if (head->head.next == NULL)
dlist_init(head);
node->next = &head->head;
node->prev = head->head.prev;
node->prev->next = node;
head->head.prev = node;
dlist_check(head);
}
static inline void
dlist_insert_after(dlist_node *after, dlist_node *node)
{
node->prev = after;
node->next = after->next;
after->next = node;
node->next->prev = node;
}
static inline void
dlist_insert_before(dlist_node *before, dlist_node *node)
{
node->prev = before->prev;
node->next = before;
before->prev = node;
node->prev->next = node;
}
static inline void
dlist_delete(dlist_node *node)
{
node->prev->next = node->next;
node->next->prev = node->prev;
}
static inline void
dlist_delete_thoroughly(dlist_node *node)
{
node->prev->next = node->next;
node->next->prev = node->prev;
node->next = NULL;
node->prev = NULL;
}
static inline void
dlist_delete_from(dlist_head *head, dlist_node *node)
{
dlist_member_check(head, node);
dlist_delete(node);
}
static inline void
dlist_delete_from_thoroughly(dlist_head *head, dlist_node *node)
{
dlist_member_check(head, node);
dlist_delete_thoroughly(node);
}
static inline dlist_node *
dlist_pop_head_node(dlist_head *head)
{
dlist_node *node;
Assert(!dlist_is_empty(head));
node = head->head.next;
dlist_delete(node);
return node;
}
static inline void
dlist_move_head(dlist_head *head, dlist_node *node)
{
if (head->head.next == node)
return;
dlist_delete(node);
dlist_push_head(head, node);
dlist_check(head);
}
static inline void
dlist_move_tail(dlist_head *head, dlist_node *node)
{
if (head->head.prev == node)
return;
dlist_delete(node);
dlist_push_tail(head, node);
dlist_check(head);
}
static inline bool
dlist_has_next(const dlist_head *head, const dlist_node *node)
{
return node->next != &head->head;
}
static inline bool
dlist_has_prev(const dlist_head *head, const dlist_node *node)
{
return node->prev != &head->head;
}
static inline bool
dlist_node_is_detached(const dlist_node *node)
{
Assert((node->next == NULL && node->prev == NULL) ||
(node->next != NULL && node->prev != NULL));
return node->next == NULL;
}
static inline dlist_node *
dlist_next_node(dlist_head *head, dlist_node *node)
{
Assert(dlist_has_next(head, node));
return node->next;
}
static inline dlist_node *
dlist_prev_node(dlist_head *head, dlist_node *node)
{
Assert(dlist_has_prev(head, node));
return node->prev;
}
static inline void *
dlist_head_element_off(dlist_head *head, size_t off)
{
Assert(!dlist_is_empty(head));
return (char *) head->head.next - off;
}
static inline dlist_node *
dlist_head_node(dlist_head *head)
{
return (dlist_node *) dlist_head_element_off(head, 0);
}
static inline void *
dlist_tail_element_off(dlist_head *head, size_t off)
{
Assert(!dlist_is_empty(head));
return (char *) head->head.prev - off;
}
static inline dlist_node *
dlist_tail_node(dlist_head *head)
{
return (dlist_node *) dlist_tail_element_off(head, 0);
}
#define dlist_container(type, membername, ptr) \
(AssertVariableIsOfTypeMacro(ptr, dlist_node *), \
AssertVariableIsOfTypeMacro(((type *) NULL)->membername, dlist_node), \
((type *) ((char *) (ptr) - offsetof(type, membername))))
#define dlist_head_element(type, membername, lhead) \
(AssertVariableIsOfTypeMacro(((type *) NULL)->membername, dlist_node), \
(type *) dlist_head_element_off(lhead, offsetof(type, membername)))
#define dlist_tail_element(type, membername, lhead) \
(AssertVariableIsOfTypeMacro(((type *) NULL)->membername, dlist_node), \
((type *) dlist_tail_element_off(lhead, offsetof(type, membername))))
#define dlist_foreach(iter, lhead) \
for (AssertVariableIsOfTypeMacro(iter, dlist_iter), \
AssertVariableIsOfTypeMacro(lhead, dlist_head *), \
(iter).end = &(lhead)->head, \
(iter).cur = (iter).end->next ? (iter).end->next : (iter).end; \
(iter).cur != (iter).end; \
(iter).cur = (iter).cur->next)
#define dlist_foreach_modify(iter, lhead) \
for (AssertVariableIsOfTypeMacro(iter, dlist_mutable_iter), \
AssertVariableIsOfTypeMacro(lhead, dlist_head *), \
(iter).end = &(lhead)->head, \
(iter).cur = (iter).end->next ? (iter).end->next : (iter).end, \
(iter).next = (iter).cur->next; \
(iter).cur != (iter).end; \
(iter).cur = (iter).next, (iter).next = (iter).cur->next)
#define dlist_reverse_foreach(iter, lhead) \
for (AssertVariableIsOfTypeMacro(iter, dlist_iter), \
AssertVariableIsOfTypeMacro(lhead, dlist_head *), \
(iter).end = &(lhead)->head, \
(iter).cur = (iter).end->prev ? (iter).end->prev : (iter).end; \
(iter).cur != (iter).end; \
(iter).cur = (iter).cur->prev)
static inline void
dclist_init(dclist_head *head)
{
dlist_init(&head->dlist);
head->count = 0;
}
static inline bool
dclist_is_empty(const dclist_head *head)
{
Assert(dlist_is_empty(&head->dlist) == (head->count == 0));
return (head->count == 0);
}
static inline void
dclist_push_head(dclist_head *head, dlist_node *node)
{
if (head->dlist.head.next == NULL)
dclist_init(head);
dlist_push_head(&head->dlist, node);
head->count++;
Assert(head->count > 0);
}
static inline void
dclist_push_tail(dclist_head *head, dlist_node *node)
{
if (head->dlist.head.next == NULL)
dclist_init(head);
dlist_push_tail(&head->dlist, node);
head->count++;
Assert(head->count > 0);
}
static inline void
dclist_insert_after(dclist_head *head, dlist_node *after, dlist_node *node)
{
dlist_member_check(&head->dlist, after);
Assert(head->count > 0);
dlist_insert_after(after, node);
head->count++;
Assert(head->count > 0);
}
static inline void
dclist_insert_before(dclist_head *head, dlist_node *before, dlist_node *node)
{
dlist_member_check(&head->dlist, before);
Assert(head->count > 0);
dlist_insert_before(before, node);
head->count++;
Assert(head->count > 0);
}
static inline void
dclist_delete_from(dclist_head *head, dlist_node *node)
{
Assert(head->count > 0);
dlist_delete_from(&head->dlist, node);
head->count--;
}
static inline void
dclist_delete_from_thoroughly(dclist_head *head, dlist_node *node)
{
Assert(head->count > 0);
dlist_delete_from_thoroughly(&head->dlist, node);
head->count--;
}
static inline dlist_node *
dclist_pop_head_node(dclist_head *head)
{
dlist_node *node;
Assert(head->count > 0);
node = dlist_pop_head_node(&head->dlist);
head->count--;
return node;
}
static inline void
dclist_move_head(dclist_head *head, dlist_node *node)
{
dlist_member_check(&head->dlist, node);
Assert(head->count > 0);
dlist_move_head(&head->dlist, node);
}
static inline void
dclist_move_tail(dclist_head *head, dlist_node *node)
{
dlist_member_check(&head->dlist, node);
Assert(head->count > 0);
dlist_move_tail(&head->dlist, node);
}
static inline bool
dclist_has_next(const dclist_head *head, const dlist_node *node)
{
dlist_member_check(&head->dlist, node);
Assert(head->count > 0);
return dlist_has_next(&head->dlist, node);
}
static inline bool
dclist_has_prev(const dclist_head *head, const dlist_node *node)
{
dlist_member_check(&head->dlist, node);
Assert(head->count > 0);
return dlist_has_prev(&head->dlist, node);
}
static inline dlist_node *
dclist_next_node(dclist_head *head, dlist_node *node)
{
Assert(head->count > 0);
return dlist_next_node(&head->dlist, node);
}
static inline dlist_node *
dclist_prev_node(dclist_head *head, dlist_node *node)
{
Assert(head->count > 0);
return dlist_prev_node(&head->dlist, node);
}
static inline void *
dclist_head_element_off(dclist_head *head, size_t off)
{
Assert(!dclist_is_empty(head));
return (char *) head->dlist.head.next - off;
}
static inline dlist_node *
dclist_head_node(dclist_head *head)
{
Assert(head->count > 0);
return (dlist_node *) dlist_head_element_off(&head->dlist, 0);
}
static inline void *
dclist_tail_element_off(dclist_head *head, size_t off)
{
Assert(!dclist_is_empty(head));
return (char *) head->dlist.head.prev - off;
}
static inline dlist_node *
dclist_tail_node(dclist_head *head)
{
Assert(head->count > 0);
return (dlist_node *) dlist_tail_element_off(&head->dlist, 0);
}
static inline uint32
dclist_count(const dclist_head *head)
{
Assert(dlist_is_empty(&head->dlist) == (head->count == 0));
return head->count;
}
#define dclist_container(type, membername, ptr) \
dlist_container(type, membername, ptr)
#define dclist_head_element(type, membername, lhead) \
(AssertVariableIsOfTypeMacro(((type *) NULL)->membername, dlist_node), \
(type *) dclist_head_element_off(lhead, offsetof(type, membername)))
#define dclist_tail_element(type, membername, lhead) \
(AssertVariableIsOfTypeMacro(((type *) NULL)->membername, dlist_node), \
((type *) dclist_tail_element_off(lhead, offsetof(type, membername))))
#define dclist_foreach(iter, lhead) \
dlist_foreach(iter, &((lhead)->dlist))
#define dclist_foreach_modify(iter, lhead) \
dlist_foreach_modify(iter, &((lhead)->dlist))
#define dclist_reverse_foreach(iter, lhead) \
dlist_reverse_foreach(iter, &((lhead)->dlist))
static inline void
slist_init(slist_head *head)
{
head->head.next = NULL;
}
static inline bool
slist_is_empty(const slist_head *head)
{
slist_check(head);
return head->head.next == NULL;
}
static inline void
slist_push_head(slist_head *head, slist_node *node)
{
node->next = head->head.next;
head->head.next = node;
slist_check(head);
}
static inline void
slist_insert_after(slist_node *after, slist_node *node)
{
node->next = after->next;
after->next = node;
}
static inline slist_node *
slist_pop_head_node(slist_head *head)
{
slist_node *node;
Assert(!slist_is_empty(head));
node = head->head.next;
head->head.next = node->next;
slist_check(head);
return node;
}
static inline bool
slist_has_next(const slist_head *head, const slist_node *node)
{
slist_check(head);
return node->next != NULL;
}
static inline slist_node *
slist_next_node(slist_head *head, slist_node *node)
{
Assert(slist_has_next(head, node));
return node->next;
}
static inline void *
slist_head_element_off(slist_head *head, size_t off)
{
Assert(!slist_is_empty(head));
return (char *) head->head.next - off;
}
static inline slist_node *
slist_head_node(slist_head *head)
{
return (slist_node *) slist_head_element_off(head, 0);
}
static inline void
slist_delete_current(slist_mutable_iter *iter)
{
iter->prev->next = iter->next;
iter->cur = iter->prev;
}
#define slist_container(type, membername, ptr) \
(AssertVariableIsOfTypeMacro(ptr, slist_node *), \
AssertVariableIsOfTypeMacro(((type *) NULL)->membername, slist_node), \
((type *) ((char *) (ptr) - offsetof(type, membername))))
#define slist_head_element(type, membername, lhead) \
(AssertVariableIsOfTypeMacro(((type *) NULL)->membername, slist_node), \
(type *) slist_head_element_off(lhead, offsetof(type, membername)))
#define slist_foreach(iter, lhead) \
for (AssertVariableIsOfTypeMacro(iter, slist_iter), \
AssertVariableIsOfTypeMacro(lhead, slist_head *), \
(iter).cur = (lhead)->head.next; \
(iter).cur != NULL; \
(iter).cur = (iter).cur->next)
#define slist_foreach_modify(iter, lhead) \
for (AssertVariableIsOfTypeMacro(iter, slist_mutable_iter), \
AssertVariableIsOfTypeMacro(lhead, slist_head *), \
(iter).prev = &(lhead)->head, \
(iter).cur = (iter).prev->next, \
(iter).next = (iter).cur ? (iter).cur->next : NULL; \
(iter).cur != NULL; \
(iter).prev = (iter).cur, \
(iter).cur = (iter).next, \
(iter).next = (iter).next ? (iter).next->next : NULL)
#endif