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/ravicomp/src/ptrlist.c

987 lines
22 KiB

/*
* ptrlist.c
*
* Pointer ptrlist_t manipulation
*
* (C) Copyright Linus Torvalds 2003-2005
*/
/*
* This version is part of the dmr_c project.
* Copyright (C) 2017-2021 Dibyendu Majumdar
*/
#define PARANOIA 1
#include <ptrlist.h>
#include <stdio.h>
#include <stdlib.h>
/* The ptr list */
/* For testing we change this */
static int N_ = LIST_NODE_NR;
void raviX_ptrlist_split_node(PtrList *head)
{
int old = head->nr_, nr = old / 2;
Allocator *alloc = head->allocator_;
assert(alloc);
PtrList *newlist = (PtrList *)raviX_allocator_allocate(alloc, 0);
PtrList *next = head->next_;
newlist->allocator_ = alloc;
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 *));
}
PtrListIterator raviX_ptrlist_forward_iterator(PtrList *head)
{
PtrListIterator iter;
iter.__head = iter.__list = head;
iter.__nr = -1;
return iter;
}
// Reverse iterator has to start from previous node not previous entry
// in the given head
PtrListIterator raviX_ptrlist_reverse_iterator(PtrList *head)
{
PtrListIterator iter;
iter.__head = iter.__list = head ? head->prev_ : NULL;
iter.__nr = iter.__head ? iter.__head->nr_ : 0;
return iter;
}
void *raviX_ptrlist_iter_next(PtrListIterator *self)
{
if (self->__head == NULL)
return NULL;
self->__nr++;
Lretry:
if (self->__nr < self->__list->nr_) {
void *ptr = self->__list->list_[self->__nr];
if (self->__list->rm_ && !ptr) {
self->__nr++;
goto Lretry;
}
return ptr;
} else if (self->__list->next_ != self->__head) {
self->__list = self->__list->next_;
self->__nr = 0;
goto Lretry;
}
return NULL;
}
void *raviX_ptrlist_nth_entry(PtrList *list, unsigned int idx)
{
PtrList *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;
}
void *raviX_ptrlist_iter_prev(PtrListIterator *self)
{
if (self->__head == NULL)
return NULL;
self->__nr--;
Lretry:
if (self->__nr >= 0 && self->__nr < self->__list->nr_) {
void *ptr = self->__list->list_[self->__nr];
if (self->__list->rm_ && !ptr) {
self->__nr--;
goto Lretry;
}
return ptr;
} else if (self->__list->prev_ != self->__head) {
self->__list = self->__list->prev_;
self->__nr = self->__list->nr_ - 1;
goto Lretry;
}
return NULL;
}
void raviX_ptrlist_iter_split_current(PtrListIterator *self)
{
if (self->__list->nr_ == N_) {
/* full so split */
raviX_ptrlist_split_node(self->__list);
if (self->__nr >= self->__list->nr_) {
self->__nr -= self->__list->nr_;
self->__list = self->__list->next_;
}
}
}
void raviX_ptrlist_iter_insert(PtrListIterator *self, void *newitem)
{
assert(self->__nr >= 0);
raviX_ptrlist_iter_split_current(self);
void **__this = self->__list->list_ + self->__nr;
void **__last = self->__list->list_ + self->__list->nr_ - 1;
while (__last >= __this) {
__last[1] = __last[0];
__last--;
}
*__this = newitem;
self->__list->nr_++;
}
void raviX_ptrlist_iter_remove(PtrListIterator *self)
{
assert(self->__nr >= 0);
void **__this = self->__list->list_ + self->__nr;
void **__last = self->__list->list_ + self->__list->nr_ - 1;
while (__this < __last) {
__this[0] = __this[1];
__this++;
}
*__this = (void *)((uintptr_t)0xf0f0f0f0);
self->__list->nr_--;
self->__nr--;
}
void raviX_ptrlist_iter_set(PtrListIterator *self, void *ptr)
{
assert(self->__list && self->__nr >= 0 && self->__nr < self->__list->nr_);
self->__list->list_[self->__nr] = ptr;
}
void raviX_ptrlist_iter_mark_deleted(PtrListIterator *self)
{
raviX_ptrlist_iter_set(self, NULL);
self->__list->rm_++;
}
int raviX_ptrlist_size(const PtrList *self)
{
int nr = 0;
if (self) {
const PtrList *list = self;
do {
nr += list->nr_ - list->rm_;
} while ((list = list->next_) != self);
}
return nr;
}
void **raviX_ptrlist_add(PtrList **self, void *ptr, Allocator *ptr_list_allocator)
{
PtrList *list = *self;
PtrList *last = NULL;
void **ret;
int nr;
if (!list || (nr = (last = list->prev_)->nr_) >= N_) {
PtrList *newlist = (PtrList *)raviX_allocator_allocate(ptr_list_allocator, 0);
newlist->allocator_ = ptr_list_allocator;
if (!list) {
newlist->next_ = newlist;
newlist->prev_ = newlist;
*self = 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 *raviX_ptrlist_first(PtrList *list)
{
if (!list)
return NULL;
return list->list_[0];
}
void *raviX_ptrlist_last(PtrList *list)
{
if (!list)
return NULL;
list = list->prev_;
return list->list_[list->nr_ - 1];
}
/*
* Linearize the entries of a list up to a total of 'max',
* and return the nr of entries linearized.
*
* The array to linearize into (second argument) should really
* be "void *x[]", but we want to let people fill in any kind
* of pointer array, so let's just call it "void **".
*/
int raviX_ptrlist_linearize(PtrList *head, void **arr, int max)
{
int nr = 0;
if (head && max > 0) {
PtrList *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;
}
/*
* When we've walked the list and deleted entries,
* we may need to re-pack it so that we don't have
* any empty blocks left (empty blocks upset the
* walking code
*/
void raviX_ptrlist_pack(PtrList **self)
{
PtrList *head = *self;
if (head) {
PtrList *entry = head;
do {
PtrList *next;
restart:
next = entry->next_;
if (!entry->nr_) {
PtrList *prev;
if (next == entry) {
raviX_allocator_free(entry->allocator_, entry);
*self = NULL;
return;
}
prev = entry->prev_;
prev->next_ = next;
next->prev_ = prev;
raviX_allocator_free(entry->allocator_, entry);
if (entry == head) {
*self = next;
head = next;
entry = next;
goto restart;
}
}
entry = next;
} while (entry != head);
}
}
void raviX_ptrlist_remove_all(PtrList **self)
{
PtrList *tmp, *list = *self;
if (!list)
return;
list->prev_->next_ = NULL;
while (list) {
tmp = list;
list = list->next_;
raviX_allocator_free(tmp->allocator_, tmp);
}
*self = NULL;
}
int raviX_ptrlist_remove(PtrList **self, void *entry, int count)
{
PtrListIterator iter = raviX_ptrlist_forward_iterator(*self);
for (void *ptr = raviX_ptrlist_iter_next(&iter); ptr != NULL; ptr = raviX_ptrlist_iter_next(&iter)) {
if (ptr == entry) {
raviX_ptrlist_iter_remove(&iter);
if (!--count)
goto out;
}
}
assert(count <= 0);
out:
raviX_ptrlist_pack(self);
return count;
}
int raviX_ptrlist_replace(PtrList **self, void *old_ptr, void *new_ptr, int count)
{
PtrListIterator iter = raviX_ptrlist_forward_iterator(*self);
for (void *ptr = raviX_ptrlist_iter_next(&iter); ptr != NULL; ptr = raviX_ptrlist_iter_next(&iter)) {
if (ptr == old_ptr) {
raviX_ptrlist_iter_set(&iter, new_ptr);
if (!--count)
goto out;
}
}
assert(count <= 0);
out:
return count;
}
/* This removes the last entry, but doesn't pack the ptr list */
void *raviX_ptrlist_undo_last(PtrList **self)
{
PtrList *last, *first = *self;
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 *)((intptr_t)0xf1f1f1f1);
return ptr;
}
} while (last != first);
return NULL;
}
void *raviX_ptrlist_delete_last(PtrList **self)
{
void *ptr = NULL;
PtrList *last, *first = *self;
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)
*self = NULL;
raviX_allocator_free(last->allocator_, last);
}
return ptr;
}
void raviX_ptrlist_concat(PtrList *a, PtrList **self)
{
Allocator *alloc = NULL;
PtrListIterator iter = raviX_ptrlist_forward_iterator(a);
if (a)
alloc = a->allocator_;
else if (*self)
alloc = (*self)->allocator_;
else
return;
for (void *ptr = raviX_ptrlist_iter_next(&iter); ptr != NULL; ptr = raviX_ptrlist_iter_next(&iter)) {
raviX_ptrlist_add(self, ptr, alloc);
}
}
/*
* sort_list: a stable sort for lists.
*
* Time complexity: O(n*log n)
* [assuming limited zero-element fragments]
*
* Space complexity: O(1).
*
* Stable: yes.
*/
static void array_sort(void **ptr, int nr, void *userdata, int (*cmp)(void *, const void *, const void *))
{
int i;
for (i = 1; i < nr; i++) {
void *p = ptr[i];
if (cmp(userdata, ptr[i - 1], p) > 0) {
int j = i;
do {
ptr[j] = ptr[j - 1];
if (!--j)
break;
} while (cmp(userdata, ptr[j - 1], p) > 0);
ptr[j] = p;
}
}
}
static void verify_sorted(PtrList *l, int n, void *userdata, int (*cmp)(void *, const void *, const void *))
{
int i = 0;
const void *a;
PtrList *head = l;
while (l->nr_ == 0) {
l = l->next_;
if (--n == 0)
return;
assert(l != head);
}
a = l->list_[0];
while (n > 0) {
const void *b;
if (++i >= l->nr_) {
i = 0;
l = l->next_;
n--;
assert(l != head || n == 0);
continue;
}
b = l->list_[i];
assert(cmp(userdata, a, b) <= 0);
a = b;
}
}
static void flush_to(PtrList *b, void **buffer, int *nbuf)
{
int nr = b->nr_;
assert(*nbuf >= nr);
memcpy(b->list_, buffer, nr * sizeof(void *));
*nbuf = *nbuf - nr;
memmove(buffer, buffer + nr, *nbuf * sizeof(void *));
}
static void dump_to(PtrList *b, void **buffer, int nbuf)
{
assert(nbuf <= b->nr_);
memcpy(b->list_, buffer, nbuf * sizeof(void *));
}
// Merge two already-sorted sequences of blocks:
// (b1_1, ..., b1_n) and (b2_1, ..., b2_m)
// Since we may be moving blocks around, we return the new head
// of the merged list.
static PtrList *merge_block_seqs(PtrList *b1, int n, PtrList *b2, int m, void *userdata,
int (*cmp)(void *, const void *, const void *))
{
int i1 = 0, i2 = 0;
void *buffer[2 * LIST_NODE_NR];
int nbuf = 0;
PtrList *newhead = b1;
// printf ("Merging %d blocks at %p with %d blocks at %p\n", n, b1, m, b2);
// Skip empty blocks in b2.
while (b2->nr_ == 0) {
// BEEN_THERE('F');
b2 = b2->next_;
if (--m == 0) {
// BEEN_THERE('G');
return newhead;
}
}
// Do a quick skip in case entire blocks from b1 are
// already less than smallest element in b2.
while (b1->nr_ == 0 || cmp(userdata, PTR_ENTRY(b1, b1->nr_ - 1), PTR_ENTRY(b2, 0)) < 0) {
// printf ("Skipping whole block.\n");
// BEEN_THERE('H');
b1 = b1->next_;
if (--n == 0) {
// BEEN_THERE('I');
return newhead;
}
}
while (1) {
void *d1 = PTR_ENTRY(b1, i1);
void *d2 = PTR_ENTRY(b2, i2);
assert(i1 >= 0 && i1 < b1->nr_);
assert(i2 >= 0 && i2 < b2->nr_);
assert(b1 != b2);
assert(n > 0);
assert(m > 0);
if (cmp(userdata, d1, d2) <= 0) {
// BEEN_THERE('J');
buffer[nbuf++] = d1;
// Element from b1 is smaller
if (++i1 >= b1->nr_) {
// BEEN_THERE('L');
flush_to(b1, buffer, &nbuf);
do {
b1 = b1->next_;
if (--n == 0) {
// BEEN_THERE('O');
while (b1 != b2) {
// BEEN_THERE('P');
flush_to(b1, buffer, &nbuf);
b1 = b1->next_;
}
assert(nbuf == i2);
dump_to(b2, buffer, nbuf);
return newhead;
}
} while (b1->nr_ == 0);
i1 = 0;
}
} else {
// BEEN_THERE('K');
// Element from b2 is smaller
buffer[nbuf++] = d2;
if (++i2 >= b2->nr_) {
PtrList *l = b2;
// BEEN_THERE('M');
// OK, we finished with b2. Pull it out
// and plug it in before b1.
b2 = b2->next_;
b2->prev_ = l->prev_;
b2->prev_->next_ = b2;
l->next_ = b1;
l->prev_ = b1->prev_;
l->next_->prev_ = l;
l->prev_->next_ = l;
if (b1 == newhead) {
// BEEN_THERE('N');
newhead = l;
}
flush_to(l, buffer, &nbuf);
b2 = b2->prev_;
do {
b2 = b2->next_;
if (--m == 0) {
// BEEN_THERE('Q');
assert(nbuf == i1);
dump_to(b1, buffer, nbuf);
return newhead;
}
} while (b2->nr_ == 0);
i2 = 0;
}
}
}
}
void raviX_ptrlist_sort(PtrList **plist, void *userdata, int (*cmp)(void *, const void *, const void *))
{
PtrList *head = *plist, *list = head;
int blocks = 1;
assert(N_ == LIST_NODE_NR);
if (!head)
return;
// Sort all the sub-lists
do {
array_sort(list->list_, list->nr_, userdata, cmp);
#ifdef PARANOIA
verify_sorted(list, 1, userdata, cmp);
#endif
list = list->next_;
} while (list != head);
// Merge the damn things together
while (1) {
PtrList *block1 = head;
do {
PtrList *block2 = block1;
PtrList *next, *newhead;
int i;
for (i = 0; i < blocks; i++) {
block2 = block2->next_;
if (block2 == head) {
if (block1 == head) {
// BEEN_THERE('A');
*plist = head;
return;
}
// BEEN_THERE('B');
goto next_pass;
}
}
next = block2;
for (i = 0; i < blocks;) {
next = next->next_;
i++;
if (next == head) {
// BEEN_THERE('C');
break;
}
// BEEN_THERE('D');
}
newhead = merge_block_seqs(block1, blocks, block2, i, userdata, cmp);
#ifdef PARANOIA
verify_sorted(newhead, blocks + i, userdata, cmp);
#endif
if (block1 == head) {
// BEEN_THERE('E');
head = newhead;
}
block1 = next;
} while (block1 != head);
next_pass:
blocks <<= 1;
}
}
#if 0
static int int_cmp(void *ud, const void *_a, const void *_b)
{
(void)ud;
const int *a = (const int *)_a;
const int *b = (const int *)_b;
return *a - *b;
}
#define MIN(_x, _y) ((_x) < (_y) ? (_x) : (_y))
static int test_sort()
{
int i, *e;
const int N = 10000;
srand(N);
for (i = 0; i < 1000; i++)
(void)rand();
Allocator ptrlist_allocator;
raviX_allocator_init(&ptrlist_allocator, "ptrlist_nodes", sizeof(PtrList), __alignof__(PtrList),
CHUNK);
Allocator int_allocator;
raviX_allocator_init(&int_allocator, "ints", sizeof(int), __alignof__(int), CHUNK);
PtrList *int_list = NULL;
for (i = 0; i < N; i++) {
e = (int *)raviX_allocator_allocate(&int_allocator, 0);
*e = rand();
raviX_ptrlist_add(&int_list, e, &ptrlist_allocator);
}
if (raviX_ptrlist_size(int_list) != N)
return 1;
raviX_ptrlist_sort(&int_list, NULL, int_cmp);
// Sort already sorted stuff.
raviX_ptrlist_sort(&int_list, NULL, int_cmp);
int *p = NULL;
PtrListIterator iter = raviX_ptrlist_forward_iterator(int_list);
int count = 0;
for (int *k = (int *)raviX_ptrlist_iter_next(&iter); k != NULL; k = (int *)raviX_ptrlist_iter_next(&iter)) {
if (p != NULL) {
if (*k < *p)
return 1;
}
p = k;
count++;
}
if (count != N)
return 1;
PtrList *l = int_list, *l2;
l2 = l;
int expected_count = 0;
do {
l2->nr_ = MIN(l2->nr_, rand() % 3);
for (i = 0; i < l2->nr_; i++) {
*((int *)(l2->list_[i])) = rand();
expected_count++;
}
l2 = l2->next_;
} while (l2 != l);
raviX_ptrlist_sort(&int_list, NULL, int_cmp);
p = NULL;
iter = raviX_ptrlist_forward_iterator(int_list);
count = 0;
for (int *k = (int *)raviX_ptrlist_iter_next(&iter); k != NULL; k = (int *)raviX_ptrlist_iter_next(&iter)) {
if (p != NULL) {
if (*k < *p)
return 1;
}
p = k;
count++;
}
if (count != expected_count)
return 1;
raviX_ptrlist_remove_all(&int_list);
raviX_allocator_destroy(&int_allocator);
raviX_allocator_destroy(&ptrlist_allocator);
return 0;
}
struct mystruct {
int i;
};
struct mytoken {
const char *a;
};
static int test_ptrlist_basics()
{
Allocator ptrlist_allocator;
raviX_allocator_init(&ptrlist_allocator, "ptrlist_nodes", sizeof(PtrList), __alignof__(PtrList),
CHUNK);
Allocator token_allocator;
raviX_allocator_init(&token_allocator, "ptr_list_tokens", sizeof(struct mytoken), __alignof__(struct mytoken),
CHUNK);
PtrList *token_list = NULL;
if (raviX_ptrlist_size(token_list) != 0)
return 1;
struct mytoken *tok1 = (struct mytoken *)raviX_allocator_allocate(&token_allocator, 0);
struct mytoken **tok1p = (struct mytoken **)raviX_ptrlist_add(&token_list, tok1, &ptrlist_allocator);
if (raviX_ptrlist_size(token_list) != 1)
return 1;
if (tok1 != *tok1p)
return 1;
if (raviX_ptrlist_first(token_list) != tok1)
return 1;
if (raviX_ptrlist_last(token_list) != tok1)
return 1;
struct mytoken *tok2 = (struct mytoken *)raviX_allocator_allocate(&token_allocator, 0);
struct mytoken **tok2p = (struct mytoken **)raviX_ptrlist_add(&token_list, tok2, &ptrlist_allocator);
if (raviX_ptrlist_size(token_list) != 2)
return 1;
struct mytoken *tok3 = (struct mytoken *)raviX_allocator_allocate(&token_allocator, 0);
raviX_ptrlist_add(&token_list, tok3, &ptrlist_allocator);
if (raviX_ptrlist_size(token_list) != 3)
return 1;
struct mytoken *tok4 = (struct mytoken *)raviX_allocator_allocate(&token_allocator, 0);
raviX_ptrlist_add(&token_list, tok4, &ptrlist_allocator);
if (raviX_ptrlist_size(token_list) != 4)
return 1;
struct mytoken *tok5 = (struct mytoken *)raviX_allocator_allocate(&token_allocator, 0);
struct mytoken **tok5p = (struct mytoken **)raviX_ptrlist_add(&token_list, tok5, &ptrlist_allocator);
if (raviX_ptrlist_size(token_list) != 5)
return 1;
if (tok2 != *tok2p)
return 1;
if (tok5 != *tok5p)
return 1;
if (raviX_ptrlist_first(token_list) != tok1)
return 1;
if (raviX_ptrlist_last(token_list) != tok5)
return 1;
struct mytoken *toks[5];
int lin1 = raviX_ptrlist_linearize(token_list, (void **)toks, 5);
if (lin1 != 5)
return 1;
if (toks[0] != tok1)
return 1;
if (toks[1] != tok2)
return 1;
if (toks[2] != tok3)
return 1;
if (toks[3] != tok4)
return 1;
if (toks[4] != tok5)
return 1;
if (raviX_ptrlist_size(token_list) != 5)
return 1;
raviX_ptrlist_pack(&token_list);
if (raviX_ptrlist_size(token_list) != 5)
return 1;
if (raviX_ptrlist_first(token_list) != tok1)
return 1;
if (raviX_ptrlist_last(token_list) != tok5)
return 1;
const int X = 5 + 1;
const int Y = X - 1;
const int Z = Y - 1;
PtrListIterator iter1 = raviX_ptrlist_forward_iterator(token_list);
for (int i = 0; i < X; i++) {
struct mytoken *tk = (struct mytoken *)raviX_ptrlist_iter_next(&iter1);
if (tk == NULL) {
if (i == Y)
break;
return 1;
}
if (tk != toks[i])
return 1;
}
PtrListIterator iter2 = raviX_ptrlist_reverse_iterator(token_list);
for (int i = 0; i < X; i++) {
struct mytoken *tk = (struct mytoken *)raviX_ptrlist_iter_prev(&iter2);
if (tk == NULL) {
if (i == Y)
break;
return 1;
}
if (tk != toks[Z - i])
return 1;
}
struct mytoken *tok0 = (struct mytoken *)raviX_allocator_allocate(&token_allocator, 0);
PtrListIterator iter3 = raviX_ptrlist_forward_iterator(token_list);
if (!raviX_ptrlist_iter_next(&iter3))
return 1;
raviX_ptrlist_iter_insert(&iter3, tok0);
if (raviX_ptrlist_size(token_list) != 6)
return 1;
if (raviX_ptrlist_first(token_list) != tok0)
return 1;
if (raviX_ptrlist_last(token_list) != tok5)
return 1;
Allocator mystruct_allocator;
raviX_allocator_init(&mystruct_allocator, "mystructs", sizeof(struct mystruct), __alignof__(struct mystruct),
CHUNK);
PtrList *mystruct_list = NULL;
struct mystruct *s1 = (struct mystruct *)raviX_allocator_allocate(&mystruct_allocator, 0);
s1->i = 1;
struct mystruct *s2 = (struct mystruct *)raviX_allocator_allocate(&mystruct_allocator, 0);
s2->i = 2;
struct mystruct *s3 = (struct mystruct *)raviX_allocator_allocate(&mystruct_allocator, 0);
s3->i = 3;
struct mystruct *s4 = (struct mystruct *)raviX_allocator_allocate(&mystruct_allocator, 0);
s4->i = 4;
struct mystruct *s5 = (struct mystruct *)raviX_allocator_allocate(&mystruct_allocator, 0);
s5->i = 5;
struct mystruct *s6 = (struct mystruct *)raviX_allocator_allocate(&mystruct_allocator, 0);
s6->i = 6;
raviX_ptrlist_add(&mystruct_list, s1, &ptrlist_allocator);
raviX_ptrlist_add(&mystruct_list, s2, &ptrlist_allocator);
raviX_ptrlist_add(&mystruct_list, s3, &ptrlist_allocator);
raviX_ptrlist_add(&mystruct_list, s4, &ptrlist_allocator);
raviX_ptrlist_add(&mystruct_list, s5, &ptrlist_allocator);
raviX_ptrlist_add(&mystruct_list, s6, &ptrlist_allocator);
struct mystruct *serial1_expected[6] = {s1, s2, s3, s4, s5, s6};
struct mystruct *serial1_got[6];
raviX_ptrlist_linearize(mystruct_list, (void **)serial1_got, 6);
for (int i = 0; i < 6; i++) {
if (serial1_expected[i] != serial1_got[i])
return 1;
}
if (raviX_ptrlist_remove(&mystruct_list, s3, 1) != 0)
return 1;
PtrListIterator iter4 = raviX_ptrlist_forward_iterator(mystruct_list);
for (struct mystruct *p = (struct mystruct *)raviX_ptrlist_iter_next(&iter4); p != NULL;
p = (struct mystruct *)raviX_ptrlist_iter_next(&iter4)) {
if (p->i == 4)
raviX_ptrlist_iter_remove(&iter4);
}
if (raviX_ptrlist_size(mystruct_list) != 4)
return 1;
struct mystruct *serial3_expected[4] = {s1, s2, s5, s6};
struct mystruct *serial3_got[4];
int reverse_expected[2] = {2, 1};
int i = 0;
struct mystruct *p;
FOR_EACH_PTR(mystruct_list, p)
{
if (i == 4)
return 1;
serial3_got[i++] = p;
if (i == 3) {
struct mystruct *p2;
int j = 0;
RECURSE_PTR_REVERSE(p, p2)
{
if (j >= 2 || reverse_expected[j] != p2->i)
return 1;
j++;
}
END_FOR_EACH_PTR_REVERSE(p2);
}
}
END_FOR_EACH_PTR(p);
if (i != 4)
return 1;
for (i = 0; i < 4; i++) {
if (serial3_expected[i] != serial3_got[i])
return 1;
}
i = 0;
PREPARE_PTR_LIST(mystruct_list, p);
while (p != NULL) {
if (i == 4)
return 1;
serial3_got[i++] = p;
NEXT_PTR_LIST(p);
}
FINISH_PTR_LIST(p);
if (i != 4)
return 1;
for (i = 0; i < 4; i++) {
if (serial3_expected[i] != serial3_got[i])
return 1;
}
i = 0;
FOR_EACH_PTR_REVERSE(mystruct_list, p)
{
if (i == 4)
return 1;
serial3_got[i++] = p;
if (i == 2) {
struct mystruct *p3;
int j = 0;
RECURSE_PTR_REVERSE(p, p3)
{
if (j >= 2 || reverse_expected[j] != p3->i)
return 1;
j++;
}
END_FOR_EACH_PTR_REVERSE(p3);
}
}
END_FOR_EACH_PTR_REVERSE(p);
if (i != 4)
return 1;
for (int i = 0; i < 4; i++) {
if (serial3_expected[3 - i] != serial3_got[i])
return 1;
}
raviX_ptrlist_remove_all(&token_list);
raviX_ptrlist_remove_all(&mystruct_list);
raviX_allocator_destroy(&token_allocator);
raviX_allocator_destroy(&mystruct_allocator);
raviX_allocator_destroy(&ptrlist_allocator);
return 0;
}
int test_ptrlist()
{
if (test_sort() != 0)
return 1;
/* For testing we set N_ temporarily */
N_ = 2;
int failure_count = test_ptrlist_basics();
N_ = LIST_NODE_NR;
if (failure_count == 0)
printf("ptrlist test okay\n");
return failure_count;
}
#endif