#pragma once #include #include /// Intrusive node structure definition. typedef struct IntrusiveNode { struct IntrusiveNode *prev; ///< Pointer to the previous node. struct IntrusiveNode *next; ///< Pointer to the next node. } IntrusiveNode; /// Intrusive list structure definition. typedef union IntrusiveList { IntrusiveNode node; struct { IntrusiveNode *last; ///< Pointer to the last element. IntrusiveNode *first; ///< Pointer to the first element. }; } IntrusiveList; /** * @brief Initializes the intrusive linked list. * * @param ll The intrusive list to initialize. */ static inline void IntrusiveList_Init(IntrusiveList *ll) { ll->node.prev = &ll->node; ll->node.next = &ll->node; } /** * @brief Tests if a node is past the end of the list containing it (if any). * * @param nd The node to test. * @return bool true iff node is past the end of the list. */ static inline bool IntrusiveList_TestEnd(const IntrusiveList *ll, const IntrusiveNode *nd) { return nd == &ll->node; } /** * @brief Inserts a node after another one list. * * @param pos The node to insert the new node after. * @param nd The new node. */ static inline void IntrusiveList_InsertAfter(IntrusiveNode *pos, IntrusiveNode *nd) { // if pos is last & list is empty, ->next writes to first, etc. pos->next->prev = nd; nd->prev = pos; nd->next = pos->next; pos->next = nd; } /** * @brief Erases a node. * * @param nd The node to erase. */ static inline void IntrusiveList_Erase(const IntrusiveNode *nd) { nd->prev->next = nd->next; nd->next->prev = nd->prev; } /** * @brief Makes a list storage from a buffer, using each element's intrusive node field at offset 0. * * @param ll The intrusive list to create. * @param buf The buffer to use. * @param elem_size The size of each element. * @param total_size The total size of the buffer. * * @pre @ref ll has not been initialized yet. * @pre Each element must contain a @ref IntrusiveNode instance at offset 0, which is then used. */ static inline void IntrusiveList_CreateFromBuffer(IntrusiveList *ll, void *buf, size_t elemSize, size_t totalSize) { IntrusiveList_Init(ll); for (size_t pos = 0; pos < totalSize; pos += elemSize) { IntrusiveList_InsertAfter(ll->last, (IntrusiveNode *)((char *)buf + pos)); } }