You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ravi/dmr_c/src/ptrlist.h

334 lines
11 KiB

#ifndef DMR_C_PTRLIST_H
#define DMR_C_PTRLIST_H
/*
* Generic pointer list manipulation code.
*
* (C) Copyright Linus Torvalds 2003-2005
*/
/*
* This version is part of the dmr_c project.
* Copyright (C) 2017 Dibyendu Majumdar
*/
#include <allocate.h>
#include <assert.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* The ptr list data structure is like a train - with cars linked to each other.
* Just as in a train each car has many seats, so in ptr list each "node" has
* several entries. Unlike a train however, the ptr list is arranged as a ring,
* i.e. the the front and back nodes are linked to each other. Hence there is no
* such thing as a 'head' of the list - i.e. any node can be the head!
*/
#ifndef LIST_NODE_NR
#define LIST_NODE_NR (29)
#endif
#define DECLARE_PTR_LIST(listname, type) \
struct listname { \
int nr_ : 8; \
int rm_ : 8; \
struct listname *prev_; \
struct listname *next_; \
struct allocator *allocator_; \
type *list_[LIST_NODE_NR]; \
}
/* Each node in the list */
DECLARE_PTR_LIST(ptr_list, void);
struct ptr_list_iter {
struct ptr_list *__head;
struct ptr_list *__list;
int __nr;
};
/* The ptr list */
extern int ptrlist_size(const struct ptr_list *self);
extern void **ptrlist_add(struct ptr_list **self, void *ptr, struct allocator *ptr_list_allocator);
extern void *ptrlist_nth_entry(struct ptr_list *list, unsigned int idx);
extern void *ptrlist_first(struct ptr_list *list);
extern void *ptrlist_last(struct ptr_list *list);
extern int ptrlist_linearize(struct ptr_list *head, void **arr, int max);
extern void ptrlist_split_node(struct ptr_list *head);
extern void ptrlist_pack(struct ptr_list **self);
extern void ptrlist_remove_all(struct ptr_list **self);
extern int ptrlist_remove(struct ptr_list **self, void *entry, int count);
extern int ptrlist_replace(struct ptr_list **self, void *old_ptr, void *new_ptr,
int count);
extern void *ptrlist_undo_last(struct ptr_list **self);
extern void *ptrlist_delete_last(struct ptr_list **self);
extern void ptrlist_concat(struct ptr_list *a, struct ptr_list **self);
extern void ptrlist_sort(struct ptr_list **self, void *,
int (*cmp)(void *, const void *, const void *));
/* iterator functions */
extern struct ptr_list_iter ptrlist_forward_iterator(struct ptr_list *self);
extern struct ptr_list_iter ptrlist_reverse_iterator(struct ptr_list *self);
extern void *ptrlist_iter_next(struct ptr_list_iter *self);
extern void *ptrlist_iter_prev(struct ptr_list_iter *self);
extern void ptrlist_iter_split_current(struct ptr_list_iter *self);
extern void ptrlist_iter_insert(struct ptr_list_iter *self, void *newitem);
extern void ptrlist_iter_remove(struct ptr_list_iter *self);
extern void ptrlist_iter_set(struct ptr_list_iter *self, void *ptr);
extern void ptrlist_iter_mark_deleted(struct ptr_list_iter *self);
static inline void **ptrlist_iter_this_address(struct ptr_list_iter *self) {
return &self->__list->list_[self->__nr];
}
#define ptr_list_empty(x) ((x) == NULL)
#define PTR_ENTRY_NOTAG(h,i) ((h)->list_[i])
#define PTR_ENTRY(h,i) (void *)(PTR_ENTRY_NOTAG(h,i))
#if 1
#define FOR_EACH_PTR(list, var) \
{ struct ptr_list_iter var##iter__ = ptrlist_forward_iterator((struct ptr_list *)list); \
for (var = ptrlist_iter_next(&var##iter__); var != NULL; var = ptrlist_iter_next(&var##iter__))
#define END_FOR_EACH_PTR(var) }
#define FOR_EACH_PTR_REVERSE(list, var) \
{ struct ptr_list_iter var##iter__ = ptrlist_reverse_iterator((struct ptr_list *)list); \
for (var = ptrlist_iter_prev(&var##iter__); var != NULL; var = ptrlist_iter_prev(&var##iter__))
#define END_FOR_EACH_PTR_REVERSE(var) }
#define RECURSE_PTR_REVERSE(list, var) \
{ struct ptr_list_iter var##iter__ = list##iter__; \
for (var = ptrlist_iter_prev(&var##iter__); var != NULL; var = ptrlist_iter_prev(&var##iter__))
#define PREPARE_PTR_LIST(list, var) \
struct ptr_list_iter var##iter__ = ptrlist_forward_iterator((struct ptr_list *)list); \
var = ptrlist_iter_next(&var##iter__)
#define NEXT_PTR_LIST(var) \
var = ptrlist_iter_next(&var##iter__)
#define FINISH_PTR_LIST(var)
#define THIS_ADDRESS(type, var) \
(type *)ptrlist_iter_this_address(&var##iter__)
#define DELETE_CURRENT_PTR(var) \
ptrlist_iter_remove(&var##iter__)
#define REPLACE_CURRENT_PTR(type, var, replacement) \
ptrlist_iter_set(&var##iter__, replacement)
#define INSERT_CURRENT(newval, var) \
ptrlist_iter_insert(&var##iter__, newval)
#define MARK_CURRENT_DELETED(PTR_TYPE, var) \
ptrlist_iter_mark_deleted(&var##iter__)
#else
#define DO_PREPARE(head, ptr, __head, __list, __nr, PTR_ENTRY) \
do { \
struct ptr_list *__head = (struct ptr_list *) (head); \
struct ptr_list *__list = __head; \
int __nr = 0; \
if (__head) ptr = PTR_ENTRY(__head, 0); \
else ptr = NULL
#define DO_NEXT(ptr, __head, __list, __nr, PTR_ENTRY) \
if (ptr) { \
if (++__nr < __list->nr_) { \
ptr = PTR_ENTRY(__list,__nr); \
} else { \
__list = __list->next_; \
ptr = NULL; \
while (__list->nr_ == 0 && __list != __head) \
__list = __list->next_; \
if (__list != __head) { \
__nr = 0; \
ptr = PTR_ENTRY(__list,0); \
} \
} \
}
#define DO_RESET(ptr, __head, __list, __nr, PTR_ENTRY) \
do { \
__nr = 0; \
__list = __head; \
if (__head) ptr = PTR_ENTRY(__head, 0); \
} while (0)
#define DO_FINISH(ptr, __head, __list, __nr) \
(void)(__nr); /* Sanity-check nesting */ \
} while (0)
#define PREPARE_PTR_LIST(head, ptr) \
DO_PREPARE(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY)
#define NEXT_PTR_LIST(ptr) \
DO_NEXT(ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY)
#define RESET_PTR_LIST(ptr) \
DO_RESET(ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY)
#define FINISH_PTR_LIST(ptr) \
DO_FINISH(ptr, __head##ptr, __list##ptr, __nr##ptr)
#define DO_FOR_EACH(head, ptr, __head, __list, __nr, PTR_ENTRY) do { \
struct ptr_list *__head = (struct ptr_list *) (head); \
struct ptr_list *__list = __head; \
if (__head) { \
do { int __nr; \
for (__nr = 0; __nr < __list->nr_; __nr++) { \
do { \
ptr = PTR_ENTRY(__list,__nr); \
if (__list->rm_ && !ptr) \
continue; \
do {
#define DO_END_FOR_EACH(ptr, __head, __list, __nr) \
} while (0); \
} while (0); \
} \
} while ((__list = __list->next_) != __head); \
} \
} while (0)
#define DO_FOR_EACH_REVERSE(head, ptr, __head, __list, __nr, PTR_ENTRY) do { \
struct ptr_list *__head = (struct ptr_list *) (head); \
struct ptr_list *__list = __head; \
if (__head) { \
do { int __nr; \
__list = __list->prev_; \
__nr = __list->nr_; \
while (--__nr >= 0) { \
do { \
ptr = PTR_ENTRY(__list,__nr); \
if (__list->rm_ && !ptr) \
continue; \
do {
#define DO_END_FOR_EACH_REVERSE(ptr, __head, __list, __nr) \
} while (0); \
} while (0); \
} \
} while (__list != __head); \
} \
} while (0)
#define DO_REVERSE(ptr, __head, __list, __nr, new, __newhead, \
__newlist, __newnr, PTR_ENTRY) do { \
struct ptr_list *__newhead = __head; \
struct ptr_list *__newlist = __list; \
int __newnr = __nr; \
new = ptr; \
goto __inside##new; \
if (1) { \
do { \
__newlist = __newlist->prev_; \
__newnr = __newlist->nr_; \
__inside##new: \
while (--__newnr >= 0) { \
do { \
new = PTR_ENTRY(__newlist,__newnr); \
do {
#define RECURSE_PTR_REVERSE(ptr, new) \
DO_REVERSE(ptr, __head##ptr, __list##ptr, __nr##ptr, \
new, __head##new, __list##new, __nr##new, PTR_ENTRY)
#define DO_THIS_ADDRESS(PTR_TYPE, ptr, __head, __list, __nr) \
((PTR_TYPE*) (__list->list_ + __nr))
#define FOR_EACH_PTR(head, ptr) \
DO_FOR_EACH(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY)
#define END_FOR_EACH_PTR(ptr) \
DO_END_FOR_EACH(ptr, __head##ptr, __list##ptr, __nr##ptr)
#define FOR_EACH_PTR_NOTAG(head, ptr) \
DO_FOR_EACH(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY_NOTAG)
#define END_FOR_EACH_PTR_NOTAG(ptr) END_FOR_EACH_PTR(ptr)
#define FOR_EACH_PTR_REVERSE(head, ptr) \
DO_FOR_EACH_REVERSE(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY)
#define END_FOR_EACH_PTR_REVERSE(ptr) \
DO_END_FOR_EACH_REVERSE(ptr, __head##ptr, __list##ptr, __nr##ptr)
#define FOR_EACH_PTR_REVERSE_NOTAG(head, ptr) \
DO_FOR_EACH_REVERSE(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY_NOTAG)
#define END_FOR_EACH_PTR_REVERSE_NOTAG(ptr) END_FOR_EACH_PTR_REVERSE(ptr)
#define THIS_ADDRESS(PTR_TYPE, ptr) \
DO_THIS_ADDRESS(PTR_TYPE, ptr, __head##ptr, __list##ptr, __nr##ptr)
#define DO_SPLIT(ptr, __head, __list, __nr) do { \
ptrlist_split_node(__list); \
if (__nr >= __list->nr_) { \
__nr -= __list->nr_; \
__list = __list->next_; \
}; \
} while (0)
#define DO_INSERT_CURRENT(new, ptr, __head, __list, __nr) do { \
void **__this, **__last; \
if (__list->nr_ == LIST_NODE_NR) \
DO_SPLIT(ptr, __head, __list, __nr); \
__this = __list->list_ + __nr; \
__last = __list->list_ + __list->nr_ - 1; \
while (__last >= __this) { \
__last[1] = __last[0]; \
__last--; \
} \
*__this = (new); \
__list->nr_++; \
} while (0)
#define INSERT_CURRENT(new, ptr) \
DO_INSERT_CURRENT(new, ptr, __head##ptr, __list##ptr, __nr##ptr)
#define DO_DELETE_CURRENT(ptr, __head, __list, __nr) do { \
void **__this = __list->list_ + __nr; \
void **__last = __list->list_ + __list->nr_ - 1; \
while (__this < __last) { \
__this[0] = __this[1]; \
__this++; \
} \
*__this = (void *)((uintptr_t)0xf0f0f0f0); \
__list->nr_--; __nr--; \
} while (0)
#define DELETE_CURRENT_PTR(ptr) \
DO_DELETE_CURRENT(ptr, __head##ptr, __list##ptr, __nr##ptr)
#define REPLACE_CURRENT_PTR(PTR_TYPE, ptr, new_ptr) \
do { *THIS_ADDRESS(PTR_TYPE, ptr) = (new_ptr); } while (0)
#define DO_MARK_CURRENT_DELETED(PTR_TYPE, ptr, __list) do { \
REPLACE_CURRENT_PTR(PTR_TYPE, ptr, NULL); \
__list->rm++; \
} while (0)
#define MARK_CURRENT_DELETED(PTR_TYPE, ptr) \
DO_MARK_CURRENT_DELETED(PTR_TYPE, ptr, __list##ptr)
#endif
extern int test_ptrlist();
#ifdef __cplusplus
}
#endif
#endif