ban2fail/ptrvec.c

271 lines
6.3 KiB
C

/***************************************************************************
* Copyright (C) 2008 by John D. Robertson *
* john@rrci.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "ptrvec.h"
static int
grow (PTRVEC * self)
{
if (PTRVEC_resize (self, self->maxItems * 2))
{
if (PTRVEC_resize (self, self->maxItems + self->maxItems / 2))
{
if (PTRVEC_resize (self, self->maxItems + self->maxItems / 4))
return 1;
}
}
return 0;
}
int
PTRVEC_find (PTRVEC * self, unsigned int *ndxBuf, void *item)
{
unsigned int i;
void *ptr;
PTRVEC_loopFwd (self, i, ptr)
{
if (ptr == item)
{
if(ndxBuf) *ndxBuf = (self->head + i) % self->maxItems;
return 1;
}
}
return 0;
}
int
PTRVEC_sinit(PTRVEC *self, unsigned initMaxItems)
/***********************************************
* Static initialization call.
*/
{
int rtn= 1;
if(!(self->ptrArr)) {
if(!(PTRVEC_constructor(self, initMaxItems))) goto abort;
} else {
PTRVEC_reset(self);
}
rtn= 0;
abort:
return rtn;
}
PTRVEC *
PTRVEC_constructor (PTRVEC * self, unsigned int initMaxItems)
{
if (!self) return NULL;
memset (self, 0, sizeof (*self));
if (!(self->ptrArr = malloc (initMaxItems * sizeof (void*)))) return NULL;
self->maxItems = initMaxItems;
return self;
}
void *
PTRVEC_destructor (PTRVEC * self)
{
if (self->ptrArr) free (self->ptrArr);
if(self->sortBuf) free(self->sortBuf);
return self;
}
int
PTRVEC_sort (PTRVEC * self, int (*cmp) (const void *const*, const void *const*))
{
void *ptr;
unsigned int i, sz;
unsigned int numItems = self->numItems;;
/* Nothing to sort */
if(!numItems) return 0;
/* Compute how large the sort buffer needs to be */
sz= numItems * sizeof (void *);
/* If there is no sort buffer, or it isn't big enough, allocate more */
if(sz > self->sortBuf_sz) {
if(self->sortBuf) free(self->sortBuf);
self->sortBuf_sz= 0;
if(!(self->sortBuf= malloc(sz))) return 1;
self->sortBuf_sz= sz;
}
// if (!(block = malloc (numItems * sizeof (void *)))) return 1;
PTRVEC_loopFwd (self, i, ptr) self->sortBuf[i] = ptr;
PTRVEC_reset (self);
qsort(self->sortBuf, numItems, sizeof (void *), (int(*)(const void*, const void*))cmp);
for (i = 0; i < numItems; i++) {
PTRVEC_addTail (self, self->sortBuf[i]);
}
return 0;
}
int
PTRVEC_resize (PTRVEC * self, unsigned int maxItems)
{
unsigned int headSize;
void *tmp;
if (!maxItems)
return 0;
if (maxItems < self->numItems)
return 1;
if (!(tmp = realloc (self->ptrArr, maxItems * sizeof (void*))))
return 1;
self->ptrArr = tmp;
if (self->head > self->tail)
{
headSize = self->maxItems - self->head;
memmove (self->ptrArr + maxItems - headSize,
self->ptrArr + self->maxItems - headSize,
headSize * sizeof (*self->ptrArr));
self->head = maxItems - headSize;
}
self->maxItems = maxItems;
return 0;
}
void *
PTRVEC_addHead (PTRVEC * self, void *ptr)
{
if (self->numItems == self->maxItems && grow (self))
return NULL;
if (self->numItems)
self->head = (self->head + self->maxItems - 1) % self->maxItems;
self->ptrArr[self->head] = ptr;
self->numItems++;
return ptr;
}
void *
PTRVEC_remHead (PTRVEC * self)
{
void *tmp;
if (!self->numItems)
return NULL;
self->numItems--;
tmp = self->ptrArr[self->head];
if (self->numItems)
self->head = (self->head + 1) % self->maxItems;
return tmp;
}
void *
PTRVEC_addTail (PTRVEC * self, void *ptr)
{
if (self->numItems == self->maxItems && grow (self))
return NULL;
if (self->numItems)
self->tail = (self->tail + 1) % self->maxItems;
self->ptrArr[self->tail] = ptr;
self->numItems++;
return ptr;
}
void *
PTRVEC_remTail (PTRVEC * self)
{
void *tmp;
if (!self->numItems)
return NULL;
self->numItems--;
tmp = self->ptrArr[self->tail];
if (self->numItems)
self->tail = (self->tail + self->maxItems - 1) % self->maxItems;
return tmp;
}
void *
PTRVEC_remove (PTRVEC * self, void *item)
{
unsigned int blockLen;
unsigned int ndx;
if (!PTRVEC_find (self, &ndx, item))
return NULL;
if (self->numItems == 1)
{
self->head = self->tail = 0;
}
else if (ndx == self->head)
{
self->head = (self->head + 1) % self->maxItems;
}
else if (ndx == self->tail)
{
self->tail = (self->tail + self->maxItems - 1) % self->maxItems;
}
else if (ndx < self->tail) /* Non contiguous, top block */
{
blockLen = self->tail - ndx;
memmove (self->ptrArr + ndx,
self->ptrArr + ndx + 1, blockLen * sizeof (*self->ptrArr));
self->tail--;
}
else /* Contiguous or non contiguous bottom block */
{
blockLen = ndx - self->head;
memmove (self->ptrArr + self->head + 1,
self->ptrArr + self->head, blockLen * sizeof (*self->ptrArr));
self->head++;
}
self->numItems--;
return item;
}
#ifdef DEBUG
void
PTRVEC_assert_integrity(PTRVEC *self)
{
char *p, val;
unsigned i;
PTRVEC_loopFwd(self, i, p) {
val= *p;
}
}
#endif