mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 21:57:57 +03:00
377 lines
7.6 KiB
C
377 lines
7.6 KiB
C
/*
|
|
*
|
|
* File: darray.c
|
|
* ---------------
|
|
* David Wright
|
|
* 10/8/98
|
|
*
|
|
* See darray.h for function descriptions
|
|
*/
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "darray.h"
|
|
|
|
#ifdef _MFC_MEM_DEBUG
|
|
#define _CRTDBG_MAP_ALLOC 1
|
|
#include <crtdbg.h>
|
|
#endif
|
|
|
|
|
|
#define DEF_GROWBY 8
|
|
|
|
#ifdef _NO_NOPORT_H_
|
|
#define gsimalloc malloc
|
|
#define gsifree free
|
|
#define gsirealloc realloc
|
|
#include "common/gsAssert.h"
|
|
#else
|
|
#include "nonport.h" //for gsimalloc/realloc/free/GS_ASSERT
|
|
#endif
|
|
|
|
|
|
// STRUCTURES
|
|
struct DArrayImplementation
|
|
{
|
|
int count, capacity;
|
|
int elemsize;
|
|
int growby;
|
|
ArrayElementFreeFn elemfreefn;
|
|
void *list; //array of elements
|
|
};
|
|
|
|
// PROTOTYPES
|
|
static void *mylsearch(const void *key, void *base, int count, int size,
|
|
ArrayCompareFn comparator);
|
|
static void *mybsearch(const void *elem, void *base, int num, int elemsize,
|
|
ArrayCompareFn comparator, int *found);
|
|
// FUNCTIONS
|
|
|
|
/* FreeElement
|
|
* Frees the element at position N in the array
|
|
*/
|
|
static void FreeElement(DArray array, int n)
|
|
{
|
|
if (array->elemfreefn != NULL)
|
|
array->elemfreefn(ArrayNth(array,n));
|
|
}
|
|
|
|
/* ArrayGrow
|
|
* Reallocates the array to a new size, incresed by growby
|
|
*/
|
|
static void ArrayGrow(DArray array)
|
|
{
|
|
GS_ASSERT(array->elemsize) // sanity check -mj Oct 31st
|
|
array->capacity += array->growby;
|
|
array->list = gsirealloc(array->list, (size_t) array->capacity * array->elemsize);
|
|
GS_ASSERT(array->list);
|
|
}
|
|
|
|
/* SetElement
|
|
* Sets the element at pos to the contents of elem
|
|
*/
|
|
static void SetElement(DArray array, const void *elem, int pos)
|
|
{
|
|
GS_ASSERT(array) // safety check -mj Oct 31st
|
|
GS_ASSERT(elem)
|
|
GS_ASSERT(array->elemsize)
|
|
|
|
memcpy(ArrayNth(array,pos), elem, (size_t)array->elemsize);
|
|
}
|
|
|
|
DArray ArrayNew(int elemSize, int numElemsToAllocate,
|
|
ArrayElementFreeFn elemFreeFn)
|
|
{
|
|
DArray array;
|
|
|
|
array = (DArray) gsimalloc(sizeof(struct DArrayImplementation));
|
|
GS_ASSERT(array);
|
|
GS_ASSERT(elemSize);
|
|
if (numElemsToAllocate == 0)
|
|
numElemsToAllocate = DEF_GROWBY;
|
|
array->count = 0;
|
|
array->capacity = numElemsToAllocate;;
|
|
array->elemsize = elemSize;
|
|
array->growby = numElemsToAllocate;
|
|
array->elemfreefn = elemFreeFn;
|
|
if (array->capacity != 0)
|
|
{
|
|
array->list = gsimalloc((size_t)array->capacity * array->elemsize);
|
|
GS_ASSERT(array->list);
|
|
} else
|
|
array->list = NULL;
|
|
|
|
return array;
|
|
}
|
|
|
|
void ArrayFree(DArray array)
|
|
{
|
|
int i;
|
|
|
|
GS_ASSERT(array);
|
|
for (i = 0; i < array->count; i++)
|
|
{
|
|
FreeElement(array, i);
|
|
}
|
|
// mj to do: move these asserts into gsi_free. maybe, depends on whether user overloads them
|
|
GS_ASSERT(array->list)
|
|
GS_ASSERT(array)
|
|
gsifree(array->list);
|
|
gsifree(array);
|
|
}
|
|
|
|
void *ArrayGetDataPtr(DArray array)
|
|
{
|
|
GS_ASSERT(array);
|
|
return array->list;
|
|
}
|
|
|
|
void ArraySetDataPtr(DArray array, void *ptr, int count, int capacity)
|
|
{
|
|
int i;
|
|
|
|
GS_ASSERT(array);
|
|
if (array->list != NULL)
|
|
{
|
|
for (i = 0; i < array->count; i++)
|
|
{
|
|
FreeElement(array, i);
|
|
}
|
|
gsifree(array->list);
|
|
}
|
|
array->list = ptr;
|
|
array->count = count;
|
|
array->capacity = capacity;
|
|
|
|
}
|
|
|
|
|
|
int ArrayLength(const DArray array)
|
|
{
|
|
GS_ASSERT(array)
|
|
return array->count;
|
|
}
|
|
|
|
void *ArrayNth(DArray array, int n)
|
|
{
|
|
// 2004.Nov.16.JED - modified GS_ASSERT to include "if" to add robustness
|
|
GS_ASSERT( (n >= 0) && (n < array->count));
|
|
if( ! ((n >= 0) && (n < array->count)) )
|
|
return NULL;
|
|
|
|
return (char *)array->list + array->elemsize*n;
|
|
}
|
|
|
|
/* ArrayAppend
|
|
* Just do an Insert at the end of the array
|
|
*/
|
|
void ArrayAppend(DArray array, const void *newElem)
|
|
{
|
|
GS_ASSERT(array);
|
|
if(array)
|
|
ArrayInsertAt(array, newElem, array->count);
|
|
}
|
|
|
|
void ArrayInsertAt(DArray array, const void *newElem, int n)
|
|
{
|
|
GS_ASSERT (array)
|
|
GS_ASSERT ( (n >= 0) && (n <= array->count));
|
|
|
|
if (array->count == array->capacity)
|
|
ArrayGrow(array);
|
|
array->count++;
|
|
if (n < array->count - 1) //if we aren't appending
|
|
memmove(ArrayNth(array, n+1), ArrayNth(array,n),
|
|
(size_t)(array->count - 1 - n) * array->elemsize);
|
|
SetElement(array, newElem, n);
|
|
}
|
|
|
|
void ArrayInsertSorted(DArray array, const void *newElem, ArrayCompareFn comparator)
|
|
{
|
|
int n;
|
|
void *res;
|
|
int found;
|
|
|
|
GS_ASSERT (array)
|
|
GS_ASSERT (comparator);
|
|
|
|
res=mybsearch(newElem, array->list, array->count, array->elemsize, comparator, &found);
|
|
n = (((char *)res - (char *)array->list) / array->elemsize);
|
|
ArrayInsertAt(array, newElem, n);
|
|
}
|
|
|
|
|
|
void ArrayRemoveAt(DArray array, int n)
|
|
{
|
|
GS_ASSERT (array)
|
|
GS_ASSERT( (n >= 0) && (n < array->count));
|
|
|
|
if (n < array->count - 1) //if not last element
|
|
memmove(ArrayNth(array,n),ArrayNth(array,n+1),
|
|
(size_t)(array->count - 1 - n) * array->elemsize);
|
|
array->count--;
|
|
}
|
|
|
|
void ArrayDeleteAt(DArray array, int n)
|
|
{
|
|
GS_ASSERT (array)
|
|
GS_ASSERT ( (n >= 0) && (n < array->count));
|
|
|
|
FreeElement(array,n);
|
|
ArrayRemoveAt(array, n);
|
|
}
|
|
|
|
|
|
void ArrayReplaceAt(DArray array, const void *newElem, int n)
|
|
{
|
|
GS_ASSERT (array)
|
|
GS_ASSERT ( (n >= 0) && (n < array->count));
|
|
|
|
FreeElement(array, n);
|
|
SetElement(array, newElem,n);
|
|
}
|
|
|
|
|
|
void ArraySort(DArray array, ArrayCompareFn comparator)
|
|
{
|
|
GS_ASSERT (array)
|
|
qsort(array->list, (size_t)array->count, (size_t)array->elemsize, comparator);
|
|
}
|
|
|
|
//GS_ASSERT will be raised by ArrayNth if fromindex out of range
|
|
int ArraySearch(DArray array, const void *key, ArrayCompareFn comparator,
|
|
int fromIndex, int isSorted)
|
|
{
|
|
void *res;
|
|
int found = 1;
|
|
if (!array || array->count == 0)
|
|
return NOT_FOUND;
|
|
|
|
if (isSorted)
|
|
res=mybsearch(key, ArrayNth(array,fromIndex),
|
|
array->count - fromIndex, array->elemsize, comparator, &found);
|
|
else
|
|
res=mylsearch(key, ArrayNth(array, fromIndex),
|
|
array->count - fromIndex, array->elemsize, comparator);
|
|
if (res != NULL && found)
|
|
return (((char *)res - (char *)array->list) / array->elemsize);
|
|
else
|
|
return NOT_FOUND;
|
|
}
|
|
|
|
|
|
void ArrayMap(DArray array, ArrayMapFn fn, void *clientData)
|
|
{
|
|
int i;
|
|
|
|
GS_ASSERT (array)
|
|
GS_ASSERT(fn);
|
|
|
|
for (i = 0; i < array->count; i++)
|
|
fn(ArrayNth(array,i), clientData);
|
|
|
|
}
|
|
|
|
void ArrayMapBackwards(DArray array, ArrayMapFn fn, void *clientData)
|
|
{
|
|
int i;
|
|
|
|
GS_ASSERT(fn);
|
|
|
|
for (i = (array->count - 1) ; i >= 0 ; i--)
|
|
fn(ArrayNth(array,i), clientData);
|
|
|
|
}
|
|
|
|
void * ArrayMap2(DArray array, ArrayMapFn2 fn, void *clientData)
|
|
{
|
|
int i;
|
|
void * pcurr;
|
|
|
|
GS_ASSERT(fn);
|
|
GS_ASSERT(clientData);
|
|
|
|
for (i = 0; i < array->count; i++)
|
|
{
|
|
pcurr = ArrayNth(array,i);
|
|
if(!fn(pcurr, clientData))
|
|
return pcurr;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void * ArrayMapBackwards2(DArray array, ArrayMapFn2 fn, void *clientData)
|
|
{
|
|
int i;
|
|
void * pcurr;
|
|
|
|
GS_ASSERT(fn);
|
|
GS_ASSERT(clientData);
|
|
|
|
for (i = (array->count - 1) ; i >= 0 ; i--)
|
|
{
|
|
pcurr = ArrayNth(array,i);
|
|
if(!fn(pcurr, clientData))
|
|
return pcurr;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void ArrayClear(DArray array)
|
|
{
|
|
int i;
|
|
|
|
// This could be more optimal!
|
|
//////////////////////////////
|
|
for(i = (ArrayLength(array) - 1) ; i >= 0 ; i--)
|
|
ArrayDeleteAt(array, i);
|
|
}
|
|
|
|
/* mylsearch
|
|
* Implementation of a standard linear search on an array, since we
|
|
* couldn't use lfind
|
|
*/
|
|
static void *mylsearch(const void *key, void *base, int count, int size,
|
|
ArrayCompareFn comparator)
|
|
{
|
|
int i;
|
|
GS_ASSERT(key);
|
|
GS_ASSERT(base);
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
if (comparator(key, (char *)base + size*i) == 0)
|
|
return (char *)base + size*i;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/* mybsearch
|
|
* Implementation of a bsearch, since its not available on all platforms
|
|
*/
|
|
static void *mybsearch(const void *elem, void *base, int num, int elemsize, ArrayCompareFn comparator, int *found)
|
|
{
|
|
int L, H, I, C;
|
|
|
|
GS_ASSERT(elem);
|
|
GS_ASSERT(base);
|
|
GS_ASSERT(found);
|
|
|
|
L = 0;
|
|
H = num - 1;
|
|
*found = 0;
|
|
while (L <= H)
|
|
{
|
|
I = (L + H) >> 1;
|
|
C = comparator(((char *)base) + I * elemsize,elem);
|
|
if (C == 0)
|
|
*found = 1;
|
|
if (C < 0)
|
|
L = I + 1;
|
|
else
|
|
{
|
|
H = I - 1;
|
|
}
|
|
}
|
|
return ((char *)base) + L * elemsize;
|
|
}
|