389 lines
8.9 KiB
C
389 lines
8.9 KiB
C
/************************************************************//**
|
|
*
|
|
* @file: lists.h
|
|
* @author: Martin Fouilleul
|
|
* @date: 22/11/2017
|
|
* @brief: Implements generic intrusive linked list and dynamic array
|
|
*
|
|
****************************************************************/
|
|
#ifndef __CONTAINERS_H_
|
|
#define __CONTAINERS_H_
|
|
|
|
#include"util/macro_helpers.h"
|
|
#include"platform/platform_assert.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#define OFFSET_OF_CONTAINER(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
|
|
|
#ifdef __cplusplus
|
|
#define CONTAINER_OF(ptr, type, member) ({ \
|
|
const decltype( ((type *)0)->member ) *__mptr = (ptr); \
|
|
(type *)( (char *)__mptr - OFFSET_OF_CONTAINER(type,member) );})
|
|
#else
|
|
#define CONTAINER_OF(ptr, type, member) (type *)((char*)(ptr) - OFFSET_OF_CONTAINER(type,member))
|
|
#endif
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Intrusive linked lists
|
|
//-------------------------------------------------------------------------
|
|
|
|
#define list_entry(ptr, type, member) \
|
|
CONTAINER_OF(ptr, type, member)
|
|
|
|
#define list_next(elt) (elt)->next
|
|
#define list_prev(elt) (elt)->prev
|
|
|
|
#define list_next_entry(list, elt, type, member) \
|
|
((elt->member.next != list_end(list)) ? list_entry(elt->member.next, type, member) : 0)
|
|
|
|
#define list_prev_entry(list, elt, type, member) \
|
|
((elt->member.prev != list_end(list)) ? list_entry(elt->member.prev, type, member) : 0)
|
|
|
|
#define list_checked_entry(list, type, member) \
|
|
(((list) != 0) ? list_entry(list, type, member) : 0)
|
|
|
|
#define list_first_entry(list, type, member) \
|
|
(list_checked_entry(list_begin(list), type, member))
|
|
|
|
#define list_last_entry(list, type, member) \
|
|
(list_checked_entry(list_last(list), type, member))
|
|
|
|
#define for_list(list, elt, type, member) \
|
|
for(type* elt = list_checked_entry(list_begin(list), type, member); \
|
|
elt != 0; \
|
|
elt = list_checked_entry(elt->member.next, type, member)) \
|
|
|
|
#define for_list_reverse(list, elt, type, member) \
|
|
for(type* elt = list_checked_entry(list_last(list), type, member); \
|
|
elt != 0; \
|
|
elt = list_checked_entry(elt->member.prev, type, member)) \
|
|
|
|
#define for_list_safe(list, elt, type, member) \
|
|
for(type* elt = list_checked_entry(list_begin(list), type, member), \
|
|
*__tmp = elt ? list_checked_entry(elt->member.next, type, member) : 0 ; \
|
|
elt != 0; \
|
|
elt = __tmp, \
|
|
__tmp = elt ? list_checked_entry(elt->member.next, type, member) : 0) \
|
|
|
|
#define list_pop_entry(list, type, member) (list_empty(list) ? 0 : list_entry(list_pop(list), type, member))
|
|
|
|
typedef struct list_elt list_elt;
|
|
struct list_elt
|
|
{
|
|
list_elt* next;
|
|
list_elt* prev;
|
|
};
|
|
|
|
typedef struct list_info
|
|
{
|
|
list_elt* first;
|
|
list_elt* last;
|
|
} list_info;
|
|
|
|
static inline void list_init(list_info* list)
|
|
{
|
|
list->first = list->last = 0;
|
|
}
|
|
|
|
static inline list_elt* list_begin(list_info* list)
|
|
{
|
|
return(list->first);
|
|
}
|
|
static inline list_elt* list_end(list_info* list)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
static inline list_elt* list_last(list_info* list)
|
|
{
|
|
return(list->last);
|
|
}
|
|
|
|
static inline void list_insert(list_info* list, list_elt* afterElt, list_elt* elt)
|
|
{
|
|
elt->prev = afterElt;
|
|
elt->next = afterElt->next;
|
|
if(afterElt->next)
|
|
{
|
|
afterElt->next->prev = elt;
|
|
}
|
|
else
|
|
{
|
|
list->last = elt;
|
|
}
|
|
afterElt->next = elt;
|
|
|
|
DEBUG_ASSERT(elt->next != elt, "list_insert(): can't insert an element into itself");
|
|
}
|
|
|
|
static inline void list_insert_before(list_info* list, list_elt* beforeElt, list_elt* elt)
|
|
{
|
|
elt->next = beforeElt;
|
|
elt->prev = beforeElt->prev;
|
|
|
|
if(beforeElt->prev)
|
|
{
|
|
beforeElt->prev->next = elt;
|
|
}
|
|
else
|
|
{
|
|
list->first = elt;
|
|
}
|
|
beforeElt->prev = elt;
|
|
|
|
DEBUG_ASSERT(elt->next != elt, "list_insert_before(): can't insert an element into itself");
|
|
}
|
|
|
|
static inline void list_remove(list_info* list, list_elt* elt)
|
|
{
|
|
if(elt->prev)
|
|
{
|
|
elt->prev->next = elt->next;
|
|
}
|
|
else
|
|
{
|
|
DEBUG_ASSERT(list->first == elt);
|
|
list->first = elt->next;
|
|
}
|
|
if(elt->next)
|
|
{
|
|
elt->next->prev = elt->prev;
|
|
}
|
|
else
|
|
{
|
|
DEBUG_ASSERT(list->last == elt);
|
|
list->last = elt->prev;
|
|
}
|
|
elt->prev = elt->next = 0;
|
|
}
|
|
|
|
static inline void list_push(list_info* list, list_elt* elt)
|
|
{
|
|
elt->next = list->first;
|
|
elt->prev = 0;
|
|
if(list->first)
|
|
{
|
|
list->first->prev = elt;
|
|
}
|
|
else
|
|
{
|
|
list->last = elt;
|
|
}
|
|
list->first = elt;
|
|
}
|
|
|
|
static inline list_elt* list_pop(list_info* list)
|
|
{
|
|
list_elt* elt = list_begin(list);
|
|
if(elt != list_end(list))
|
|
{
|
|
list_remove(list, elt);
|
|
return(elt);
|
|
}
|
|
else
|
|
{
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
static inline void list_push_back(list_info* list, list_elt* elt)
|
|
{
|
|
elt->prev = list->last;
|
|
elt->next = 0;
|
|
if(list->last)
|
|
{
|
|
list->last->next = elt;
|
|
}
|
|
else
|
|
{
|
|
list->first = elt;
|
|
}
|
|
list->last = elt;
|
|
}
|
|
#define list_append(a, b) list_push_back(a, b)
|
|
|
|
|
|
static inline list_elt* list_pop_back(list_info* list)
|
|
{
|
|
list_elt* elt = list_last(list);
|
|
if(elt != list_end(list))
|
|
{
|
|
list_remove(list, elt);
|
|
return(elt);
|
|
}
|
|
else
|
|
{
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
static inline bool list_empty(list_info* list)
|
|
{
|
|
return(list->first == 0 || list->last == 0);
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Circular Intrusive linked lists
|
|
//-------------------------------------------------------------------------
|
|
|
|
#define clist_entry(ptr, type, member) list_entry(ptr, type, member)
|
|
#define clist_next(elt) list_next(elt)
|
|
#define clist_prev(elt) list_prev(elt)
|
|
|
|
#define clist_next_entry(head, elt, type, member) \
|
|
((elt->member.next != clist_end(head)) ? clist_entry(elt->member.next, type, member) : 0)
|
|
|
|
#define clist_prev_entry(head, elt, type, member) \
|
|
((elt->member.prev != clist_end(head)) ? clist_entry(elt->member.prev, type, member) : 0)
|
|
|
|
#define clist_checked_entry(head, info, type, member) \
|
|
((info != clist_end(head)) ? clist_entry(info, type, member) : 0)
|
|
|
|
#define clist_first_entry(head, type, member) \
|
|
(clist_checked_entry(head, clist_begin(head), type, member))
|
|
|
|
#define clist_last_entry(head, type, member) \
|
|
(clist_checked_entry(head, clist_last(head), type, member))
|
|
|
|
#define for_clist(list, elt, type, member) \
|
|
for(type* elt = clist_entry(clist_begin(list), type, member); \
|
|
&elt->member != clist_end(list); \
|
|
elt = clist_entry(elt->member.next, type, member)) \
|
|
|
|
|
|
#define for_clist_reverse(list, elt, type, member) \
|
|
for(type* elt = clist_entry(clist_last(list), type, member); \
|
|
&elt->member != clist_end(list); \
|
|
elt = clist_entry(elt->member.prev, type, member)) \
|
|
|
|
|
|
#define for_clist_safe(list, elt, type, member) \
|
|
for(type* elt = clist_entry(clist_begin(list), type, member), \
|
|
*__tmp = clist_entry(elt->member.next, type, member); \
|
|
&elt->member != clist_end(list); \
|
|
elt = clist_entry(&__tmp->member, type, member), \
|
|
__tmp = clist_entry(elt->member.next, type, member)) \
|
|
|
|
|
|
#define clist_push(a, b) clist_insert(a, b)
|
|
#define clist_insert_before(a, b) clist_append(a, b)
|
|
|
|
#define clist_pop_entry(list, type, member) (clist_empty(list) ? 0 : clist_entry(clist_pop(list), type, member))
|
|
|
|
static inline void clist_init(list_elt* info)
|
|
{
|
|
info->next = info->prev = info;
|
|
}
|
|
|
|
static inline list_elt* clist_begin(list_elt* head)
|
|
{
|
|
return(head->next ? head->next : head );
|
|
}
|
|
static inline list_elt* clist_end(list_elt* head)
|
|
{
|
|
return(head);
|
|
}
|
|
|
|
static inline list_elt* clist_last(list_elt* head)
|
|
{
|
|
return(head->prev ? head->prev : head);
|
|
}
|
|
|
|
static inline void clist_insert(list_elt* head, list_elt* elt)
|
|
{
|
|
elt->prev = head;
|
|
elt->next = head->next;
|
|
if(head->next)
|
|
{
|
|
head->next->prev = elt;
|
|
}
|
|
else
|
|
{
|
|
head->prev = elt;
|
|
}
|
|
head->next = elt;
|
|
|
|
ASSERT(elt->next != elt, "clist_insert(): can't insert an element into itself");
|
|
}
|
|
|
|
static inline void clist_append(list_elt* head, list_elt* elt)
|
|
{
|
|
clist_insert(head->prev, elt);
|
|
}
|
|
|
|
static inline void clist_cat(list_elt* head, list_elt* list)
|
|
{
|
|
if(head->prev)
|
|
{
|
|
head->prev->next = list->next;
|
|
}
|
|
if(head->prev && head->prev->next)
|
|
{
|
|
head->prev->next->prev = head->prev;
|
|
}
|
|
head->prev = list->prev;
|
|
if(head->prev)
|
|
{
|
|
head->prev->next = head;
|
|
}
|
|
clist_init(list);
|
|
}
|
|
|
|
static inline void clist_remove(list_elt* elt)
|
|
{
|
|
if(elt->prev)
|
|
{
|
|
elt->prev->next = elt->next;
|
|
}
|
|
if(elt->next)
|
|
{
|
|
elt->next->prev = elt->prev;
|
|
}
|
|
elt->prev = elt->next = 0;
|
|
}
|
|
|
|
static inline list_elt* clist_pop(list_elt* head)
|
|
{
|
|
list_elt* it = clist_begin(head);
|
|
if(it != clist_end(head))
|
|
{
|
|
clist_remove(it);
|
|
return(it);
|
|
}
|
|
else
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
}
|
|
|
|
static inline list_elt* clist_pop_back(list_elt* head)
|
|
{
|
|
list_elt* it = clist_last(head);
|
|
if(it != clist_end(head))
|
|
{
|
|
clist_remove(it);
|
|
return(it);
|
|
}
|
|
else
|
|
{
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
static inline bool clist_empty(list_elt* head)
|
|
{
|
|
return(head->next == 0 || head->next == head);
|
|
}
|
|
|
|
|
|
#ifdef __cplusplus
|
|
} // extern "C"
|
|
#endif
|
|
|
|
#endif //__CONTAINERS_H_
|