#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "ptrlist.h"
#include "allocate.h"
#include "compat.h"
__DECLARE_ALLOCATOR(struct ptr_list, ptrlist);
__ALLOCATOR(struct ptr_list, "ptr list", ptrlist);
__ALLOCATOR(struct ptr_list, "rl ptr list", rl_ptrlist);
int ptr_list_size(struct ptr_list *head)
{
int nr = 0;
if (head) {
struct ptr_list *list = head;
do {
nr += list->nr - list->rm;
} while ((list = list->next) != head);
}
return nr;
}
bool ptr_list_empty(const struct ptr_list *head)
{
const struct ptr_list *list = head;
if (!head)
return true;
do {
if (list->nr - list->rm)
return false;
} while ((list = list->next) != head);
return true;
}
bool ptr_list_multiple(const struct ptr_list *head)
{
const struct ptr_list *list = head;
int nr = 0;
if (!head)
return false;
do {
nr += list->nr - list->rm;
if (nr > 1)
return true;
} while ((list = list->next) != head);
return false;
}
void *first_ptr_list(struct ptr_list *head)
{
struct ptr_list *list = head;
if (!head)
return NULL;
while (list->nr == 0) {
list = list->next;
if (list == head)
return NULL;
}
return PTR_ENTRY_NOTAG(list, 0);
}
void *last_ptr_list(struct ptr_list *head)
{
struct ptr_list *list;
if (!head)
return NULL;
list = head->prev;
while (list->nr == 0) {
if (list == head)
return NULL;
list = list->prev;
}
return PTR_ENTRY_NOTAG(list, list->nr-1);
}
void *ptr_list_nth_entry(struct ptr_list *list, unsigned int idx)
{
struct ptr_list *head = list;
if (!head)
return NULL;
do {
unsigned int nr = list->nr;
if (idx < nr)
return list->list[idx];
else
idx -= nr;
} while ((list = list->next) != head);
return NULL;
}
int linearize_ptr_list(struct ptr_list *head, void **arr, int max)
{
int nr = 0;
if (head && max > 0) {
struct ptr_list *list = head;
do {
int i = list->nr;
if (i > max)
i = max;
memcpy(arr, list->list, i*sizeof(void *));
arr += i;
nr += i;
max -= i;
if (!max)
break;
} while ((list = list->next) != head);
}
return nr;
}
void pack_ptr_list(struct ptr_list **listp)
{
struct ptr_list *head = *listp;
if (head) {
struct ptr_list *entry = head;
do {
struct ptr_list *next;
restart:
next = entry->next;
if (!entry->nr) {
struct ptr_list *prev;
if (next == entry) {
__free_ptrlist(entry);
*listp = NULL;
return;
}
prev = entry->prev;
prev->next = next;
next->prev = prev;
__free_ptrlist(entry);
if (entry == head) {
*listp = next;
head = next;
entry = next;
goto restart;
}
}
entry = next;
} while (entry != head);
}
}
void split_ptr_list_head(struct ptr_list *head)
{
int old = head->nr, nr = old / 2;
struct ptr_list *newlist = __alloc_ptrlist(0);
struct ptr_list *next = head->next;
old -= nr;
head->nr = old;
newlist->next = next;
next->prev = newlist;
newlist->prev = head;
head->next = newlist;
newlist->nr = nr;
memcpy(newlist->list, head->list + old, nr * sizeof(void *));
memset(head->list + old, 0xf0, nr * sizeof(void *));
}
int rl_ptrlist_hack;
void **__add_ptr_list(struct ptr_list **listp, void *ptr)
{
struct ptr_list *list = *listp;
struct ptr_list *last = NULL;
void **ret;
int nr;
if (!list || (nr = (last = list->prev)->nr) >= LIST_NODE_NR) {
struct ptr_list *newlist;
if (rl_ptrlist_hack)
newlist = __alloc_rl_ptrlist(0);
else
newlist = __alloc_ptrlist(0);
if (!list) {
newlist->next = newlist;
newlist->prev = newlist;
*listp = newlist;
} else {
newlist->prev = last;
newlist->next = list;
list->prev = newlist;
last->next = newlist;
}
last = newlist;
nr = 0;
}
ret = last->list + nr;
*ret = ptr;
nr++;
last->nr = nr;
return ret;
}
void **__add_ptr_list_tag(struct ptr_list **listp, void *ptr, unsigned long tag)
{
assert((3 & (unsigned long)ptr) == 0);
assert((~3 & tag) == 0);
ptr = (void *)(tag | (unsigned long)ptr);
return __add_ptr_list(listp, ptr);
}
bool lookup_ptr_list_entry(const struct ptr_list *head, const void *entry)
{
const struct ptr_list *list = head;
if (!head)
return false;
do {
int nr = list->nr;
int i;
for (i = 0; i < nr; i++)
if (list->list[i] == entry)
return true;
} while ((list = list->next) != head);
return false;
}
int delete_ptr_list_entry(struct ptr_list **list, void *entry, int count)
{
void *ptr;
FOR_EACH_PTR(*list, ptr) {
if (ptr == entry) {
DELETE_CURRENT_PTR(ptr);
if (!--count)
goto out;
}
} END_FOR_EACH_PTR(ptr);
assert(count <= 0);
out:
pack_ptr_list(list);
return count;
}
int replace_ptr_list_entry(struct ptr_list **list, void *old_ptr,
void *new_ptr, int count)
{
void *ptr;
FOR_EACH_PTR(*list, ptr) {
if (ptr==old_ptr) {
REPLACE_CURRENT_PTR(ptr, new_ptr);
if (!--count)
goto out;
}
}END_FOR_EACH_PTR(ptr);
assert(count <= 0);
out:
return count;
}
void * undo_ptr_list_last(struct ptr_list **head)
{
struct ptr_list *last, *first = *head;
if (!first)
return NULL;
last = first;
do {
last = last->prev;
if (last->nr) {
void *ptr;
int nr = --last->nr;
ptr = last->list[nr];
last->list[nr] = (void *)0xf1f1f1f1;
return ptr;
}
} while (last != first);
return NULL;
}
void * delete_ptr_list_last(struct ptr_list **head)
{
void *ptr = NULL;
struct ptr_list *last, *first = *head;
if (!first)
return NULL;
last = first->prev;
if (last->nr)
ptr = last->list[--last->nr];
if (last->nr <=0) {
first->prev = last->prev;
last->prev->next = first;
if (last == first)
*head = NULL;
__free_ptrlist(last);
}
return ptr;
}
void concat_ptr_list(struct ptr_list *a, struct ptr_list **b)
{
void *entry;
FOR_EACH_PTR(a, entry) {
add_ptr_list(b, entry);
} END_FOR_EACH_PTR(entry);
}
void copy_ptr_list(struct ptr_list **listp, struct ptr_list *src)
{
struct ptr_list *head, *tail;
struct ptr_list *cur = src;
int idx;
if (!src)
return;
head = *listp;
if (!head) {
*listp = src;
return;
}
tail = head->prev;
idx = tail->nr;
do {
struct ptr_list *next;
int nr = cur->nr;
int i;
for (i = 0; i < nr;) {
void *ptr = cur->list[i++];
if (!ptr)
continue;
if (idx >= LIST_NODE_NR) {
struct ptr_list *prev = tail;
tail = __alloc_ptrlist(0);
prev->next = tail;
tail->prev = prev;
prev->nr = idx;
idx = 0;
}
tail->list[idx++] = ptr;
}
next = cur->next;
__free_ptrlist(cur);
cur = next;
} while (cur != src);
tail->nr = idx;
head->prev = tail;
tail->next = head;
}
void __free_ptr_list(struct ptr_list **listp)
{
struct ptr_list *tmp, *list = *listp;
if (!list)
return;
list->prev->next = NULL;
while (list) {
tmp = list;
list = list->next;
__free_ptrlist(tmp);
}
*listp = NULL;
}