mirror of
https://gitee.com/anod/open_agb_firm.git
synced 2025-05-06 13:54:09 +08:00
110 lines
2.5 KiB
C
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 |