2024-10-02 22:07:21 +08:00

110 lines
2.5 KiB
C

#pragma once
#include <stddef.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C"
{
#endif
// Based on https://github.com/torvalds/linux/blob/master/include/linux/list.h
#define LIST_INIT_VAL(name) ((ListNode){&(name), &(name)})
#define LIST_ENTRY(ptr, type, member) \
({ \
u8 *__mptr = (void*)(ptr); \
(type*)(__mptr - (size_t)&((type*)0)->member); \
})
#define LIST_FIRST_ENTRY(ptr, type, member) \
LIST_ENTRY((ptr)->next, type, member)
#define LIST_NEXT_ENTRY(pos, member) \
LIST_ENTRY((pos)->member.next, typeof(*(pos)), member)
#define LIST_FOR_EACH_ENTRY(pos, start, member) \
for(pos = LIST_FIRST_ENTRY(start, typeof(*pos), member); \
&pos->member != (start); \
pos = LIST_NEXT_ENTRY(pos, member))
typedef struct ListNode ListNode;
struct ListNode
{
ListNode *next;
ListNode *prev;
};
//static_assert(offsetof(ListNode, next) == 0, "Error: Member next of ListNode is not at offset 0!");
static inline void listInit(ListNode *start)
{
*start = LIST_INIT_VAL(*start);
}
static inline bool listEmpty(const ListNode *start)
{
return start->next == start;
}
// Internal function. Don't use unless you know what you are doing!
static inline void _listAdd(ListNode *node, ListNode *next, ListNode *prev)
{
node->next = next;
node->prev = prev;
next->prev = node;
prev->next = node;
}
static inline void listAddBefore(ListNode *entry, ListNode *node)
{
_listAdd(node, entry, entry->prev);
}
static inline void listAddAfter(ListNode *entry, ListNode *node)
{
_listAdd(node, entry->next, entry);
}
// Internal function. Don't use unless you know what you are doing!
static inline void _listDelete(ListNode *next, ListNode *prev)
{
next->prev = prev;
prev->next = next;
}
static inline void listDelete(ListNode *entry)
{
_listDelete(entry->next, entry->prev);
}
static inline ListNode* listRemoveTail(ListNode *start)
{
ListNode *const node = start->next;
listDelete(node);
return node;
}
static inline ListNode* listRemoveHead(ListNode *start)
{
ListNode *const node = start->prev;
listDelete(node);
return node;
}
// Some function aliases for queues.
#define listPush(start, node) listAddBefore((start), (node))
#define listPop(start) listRemoveTail((start))
#define listPushTail(start, node) listAddAfter((start), (node))
#define listPopHead(start) listRemoveHead((start))
#ifdef __cplusplus
} // extern "C"
#endif