reman3/Rayman_X/cpa/tempgrp/ldt/Src/DynArray.c

375 lines
16 KiB
C

/*------------------------------------------------------------------------------
FILE : DynArray.c
CREATED : 97/12/02
AUTHOR : Catalin Cocos
CONTENTS: dynamic pointer array with sorting capabilities
------------------------------------------------------------------------------*/
#include "StdInc.h"
#include "DynArray.h"
/*------------------------------------------------------------------------------
DESC. : Creaton of a default array (allocation + default initialization)
CREATED : 97/12/02
AUTHOR : Catalin Cocos
------------------------------------------------------------------------------*/
LDT_tdst_DSArray* LDT_DSAr_new()
{
LDT_tdst_DSArray* pst_NewArray = malloc( sizeof(LDT_tdst_DSArray) ); /* allocate */
LDT_DSAr_Init( pst_NewArray );
return pst_NewArray;
}
/*------------------------------------------------------------------------------
DESC. : default initialization of an array - returns 1 if successful,
0 on error;
WARNING : This function should be called only once and prior to the use of
any other array functions.
CREATED : 97/12/02
AUTHOR : Catalin Cocos
------------------------------------------------------------------------------*/
int LDT_DSAr_Init( LDT_tdst_DSArray* pst_Ar)
{
if( !pst_Ar ) return 0; /* NULL argument */
memset( pst_Ar, 0, sizeof( LDT_tdst_DSArray ) );
return 1; /* success */
}
/*------------------------------------------------------------------------------
DESC. : deletes an existing array
WARNING : this should only be called for dinamically allocated arrays.
CREATED : 97/12/02
AUTHOR : Catalin Cocos
------------------------------------------------------------------------------*/
void LDT_DSAr_delete( LDT_tdst_DSArray* pst_Ar )
{
if( !pst_Ar ) return;
LDT_DSAr_RemoveAll( pst_Ar );
free( pst_Ar );
}
/*------------------------------------------------------------------------------
DESC. : sets the array's size. - returns 1 if successful, 0 on error;
CREATED : 97/12/02
AUTHOR : Catalin Cocos
------------------------------------------------------------------------------*/
int LDT_DSAr_SetSize( LDT_tdst_DSArray* pst_Ar, int nNewSize )
{
void** pNewData;
if(nNewSize < 0) return 0; /* wrong size input */
if (nNewSize == 0)
{
/* shrink to nothing */
if(pst_Ar->pData)
{
free( pst_Ar->pData );
pst_Ar->pData = NULL;
}
pst_Ar->nSize = pst_Ar->nMaxSize = 0;
}
else if (pst_Ar->pData == NULL)
{
int nNewMax = nNewSize;
if( nNewSize < pst_Ar->nGrowBy ) nNewMax = pst_Ar->nGrowBy;
/* create one with exact size */
pst_Ar->pData = malloc( nNewMax * sizeof(void*) );
if(!pst_Ar->pData ) return 0; /* allocation failed */
memset( pst_Ar->pData, 0, nNewMax * sizeof(void*) ); /* zero fill */
pst_Ar->nSize = nNewSize;
pst_Ar->nMaxSize = nNewMax;
}
else if (nNewSize <= pst_Ar->nMaxSize)
{
/* it fits */
if (nNewSize > pst_Ar->nSize)
/* initialize the new elements */
memset( &pst_Ar->pData[pst_Ar->nSize], 0,
(nNewSize-pst_Ar->nSize) * sizeof(void*));
pst_Ar->nSize = nNewSize;
}
else
{
/* Otherwise grow array */
int nNewMax;
if (nNewSize < pst_Ar->nMaxSize + pst_Ar->nGrowBy)
nNewMax = pst_Ar->nMaxSize + pst_Ar->nGrowBy; /* granularity */
else
nNewMax = nNewSize; /* no slush */
pNewData = realloc( pst_Ar->pData, nNewMax * sizeof(void*) );
if( !pNewData ) return 0; /* reallocation failed */
/* construct remaining elements */
memset( &pNewData[pst_Ar->nSize], 0,
(nNewSize-pst_Ar->nSize) * sizeof(void*));
pst_Ar->pData = pNewData;
pst_Ar->nSize = nNewSize;
pst_Ar->nMaxSize = nNewMax;
}
return 1; /* success */
}
/*------------------------------------------------------------------------------
DESC. : frees unused memory
CREATED : 97/12/02
AUTHOR : Catalin Cocos
------------------------------------------------------------------------------*/
void LDT_DSAr_FreeExtra( LDT_tdst_DSArray* pst_Ar)
{
void** pNewData;
if (pst_Ar->nSize != pst_Ar->nMaxSize)
{
/* shrink to desired size */
if( pst_Ar->nSize )
{
pNewData = realloc( pst_Ar->pData, pst_Ar->nSize * sizeof(void*) );
if( pNewData )
{
pst_Ar->pData = pNewData;
pst_Ar->nMaxSize = pst_Ar->nSize;
}
}
else
LDT_DSAr_SetSize( pst_Ar, 0 ); /* clean-up */
}
}
/*------------------------------------------------------------------------------
DESC. : Appends an array element. returns the index of the appended
element, or -1 on error
CREATED : 97/12/02
AUTHOR : Catalin Cocos
------------------------------------------------------------------------------*/
int LDT_DSAr_Add( LDT_tdst_DSArray* pst_Ar, void* newElement)
{
if(!LDT_DSAr_SetSize( pst_Ar, pst_Ar->nSize+1 )) return -1;
pst_Ar->pData[pst_Ar->nSize-1] = newElement;
return pst_Ar->nSize-1;
}
/*------------------------------------------------------------------------------
DESC. : Inserts a new array element. Returns 1 on success, 0 on failure
CREATED : 97/12/02
AUTHOR : Catalin Cocos
------------------------------------------------------------------------------*/
int LDT_DSAr_InsertAt(LDT_tdst_DSArray* pst_Ar, int nIndex, void* newElement )
{
if(nIndex < 0) return 0;
if (nIndex >= pst_Ar->nSize)
{
/* adding after the end of the array */
/* grow so nIndex is valid */
if(!LDT_DSAr_SetSize( pst_Ar, nIndex + 1)) return 0;
}
else
{
/* inserting in the middle of the array */
/* grow the array to new size */
if(!LDT_DSAr_SetSize( pst_Ar, pst_Ar->nSize + 1)) return 0;
/* shift old data up to fill gap */
memmove(pst_Ar->pData+nIndex+1, pst_Ar->pData+nIndex,
( pst_Ar->nSize - nIndex - 1 ) * sizeof(void*));
}
/* insert new value in the gap */
pst_Ar->pData[nIndex] = newElement;
return 1;
}
/*------------------------------------------------------------------------------
DESC. : removes an array element. Returns the element on success, NULL on failure
CREATED : 97/12/02
AUTHOR : Catalin Cocos
------------------------------------------------------------------------------*/
void* LDT_DSAr_RemoveAt(LDT_tdst_DSArray* pst_Ar, int nIndex )
{
int nMoveCount;
void * pRemoved;
if(nIndex < 0 || nIndex >= pst_Ar->nSize ) return NULL;
pRemoved = pst_Ar->pData[nIndex]; /* the removed element */
nMoveCount = pst_Ar->nSize - nIndex - 1;
memcpy(pst_Ar->pData+nIndex, pst_Ar->pData+nIndex+1, nMoveCount*sizeof(void*));
pst_Ar->nSize--;
return pRemoved;
}
/*------------------------------------------------------------------------------
DESC. : Inserts the elements of another array. Returns 1 on success,
0 on failure.
CREATED : 97/12/02
AUTHOR : Catalin Cocos
------------------------------------------------------------------------------*/
int LDT_DSAr_InsertArrayAt(LDT_tdst_DSArray* pst_Ar, int nIndex, LDT_tdst_DSArray* pNewArray)
{
int nCount, nOldSize;
if(pNewArray == NULL || nIndex < 0) return 0;
nCount = pNewArray->nSize;
if (nCount > 0)
{
if (nIndex >= pst_Ar->nSize)
{
/* adding after the end of the array */
/* grow so nIndex is valid */
if(!LDT_DSAr_SetSize(pst_Ar, nIndex + nCount)) return 0;
}
else
{
/* inserting in the middle of the array */
nOldSize = pst_Ar->nSize;
/* grow it to new size */
if(!LDT_DSAr_SetSize( pst_Ar, nOldSize + nCount)) return 0;
/* shift old data up to fill gap */
memmove(pst_Ar->pData+nIndex+nCount, pst_Ar->pData+nIndex,
(nOldSize-nIndex) * sizeof(void*));
}
memcpy( pst_Ar->pData + nIndex, pNewArray->pData, nCount * sizeof(void*));
}
return 1;
}
/*------------------------------------------------------------------------------
DESC. : Sorts the array, using the comparison function
CREATED : 97/12/03
AUTHOR : Catalin Cocos
------------------------------------------------------------------------------*/
void LDT_DSAr_QSort( LDT_tdst_DSArray* pst_Ar )
{
if( pst_Ar->pfnCompare)
qsort( &pst_Ar->pData[0], pst_Ar->nSize, sizeof(void*),
(int (*)(const void *,const void *)) pst_Ar->pfnCompare );
}
/*------------------------------------------------------------------------------
DESC. : Adds an element in the array, in sorted position.
Returns the index of the added element, -1 on failure
On failure,if the <<position>> parameter is not NULL, it will
contain the index at which the element(or an equivalent) was found.
CREATED : 97/12/03
AUTHOR : Catalin Cocos
------------------------------------------------------------------------------*/
int LDT_DSAr_SAdd( LDT_tdst_DSArray* pst_Ar, void* newElement, int AdmitDuplicates, int* position )
{
int iidx, idx = LDT_DSAr_Index( pst_Ar, newElement, &iidx );
if(position) *position = idx;
if(idx>=0 && ( !AdmitDuplicates || (newElement == pst_Ar->pData[idx]) ))
return -1;
else return ( LDT_DSAr_InsertAt(pst_Ar, iidx, newElement )? iidx: -1 );
}
/*------------------------------------------------------------------------------
DESC. : gets the index of a certain element. -1 if the element
(or an equivalent) is not found
CREATED : 97/12/03
AUTHOR : Catalin Cocos
------------------------------------------------------------------------------*/
int LDT_DSAr_Index( LDT_tdst_DSArray* pst_Ar, void* newElement, int *p_iidx )
{
int hidx = pst_Ar->nSize-1, lidx = 0, cidx; /* , i, plus, minus; */
assert(pst_Ar->pfnCompare); /* the comparison function must exist*/
if(p_iidx) *p_iidx = 0;
if(!newElement) return -1;
if(hidx<0) return hidx;
while(hidx > lidx)
switch(pst_Ar->pfnCompare(&newElement,pst_Ar->pData+(cidx = (hidx+lidx)/2)))
{
case 0: hidx = lidx = cidx; break;
case -1: hidx = cidx; break;
default: lidx = cidx+1; break;
}
if(p_iidx) *p_iidx = lidx+1;
switch(pst_Ar->pfnCompare( &newElement, pst_Ar->pData+lidx ))
{
case 0:
/* for( i = 0, plus = pst_Ar->nSize-1-lidx, minus = lidx; plus>=0 || minus>=0; i++ )
{
if( plus>=i &&
(plus = pst_Ar->pfnCompare(&newElement,pst_Ar->pData+lidx+1)?-1:plus)>=0 &&
newElement == pst_Ar->pData[lidx+i])
{
lidx += i;
break;
}
if( minus>=i &&
(minus = pst_Ar->pfnCompare(&newElement,pst_Ar->pData+lidx-1 )?-1:minus)>=0 &&
newElement == pst_Ar->pData[lidx+i])
{
lidx -= i;
break;
}
} */
if(p_iidx) *p_iidx = lidx+1;
return lidx;
case -1:
if(p_iidx) (*p_iidx)--;
default:
return -1;
}
}
/*------------------------------------------------------------------------------
DESC. : gets the starting of an equivalence interval that includes the
<<idx>> index
CREATED : 97/12/03
AUTHOR : Catalin Cocos
------------------------------------------------------------------------------*/
int LDT_DSAr_UpperBound( LDT_tdst_DSArray* pst_Ar, int idx)
{
void** pCrt;
int Midx = pst_Ar->nSize-1, lidx, hidx, cidx; /* the upper limit */
if(idx<0 || idx>=Midx ) return Midx; /* the item is out of bounds or the last in the array */
pCrt = pst_Ar->pData + (lidx = hidx = idx); /* this is the target */
/* if the last element of the array is <=> with the target, return its index (no use for further search)*/
if( !pst_Ar->pfnCompare( pCrt, pst_Ar->pData + Midx ) ) return Midx;
/* find the interval bound */
for(hidx ++; !pst_Ar->pfnCompare( pCrt,pst_Ar->pData + hidx );
lidx = hidx, cidx = idx+(hidx-idx)*2, hidx = ( cidx<Midx? cidx: Midx ));
hidx--;
while(hidx > lidx)
switch(pst_Ar->pfnCompare( pCrt, pst_Ar->pData +( cidx = (hidx+lidx+1)/2) ))
{
case -1: hidx = cidx-1; break;
default: lidx = cidx; break;
}
return lidx;
}
/*------------------------------------------------------------------------------
DESC. : gets the beginning of an equivalence interval that includes the
<<idx>> index
CREATED : 97/12/03
AUTHOR : Catalin Cocos
------------------------------------------------------------------------------*/
int LDT_DSAr_LowerBound( LDT_tdst_DSArray* pst_Ar, int idx)
{
int lidx, hidx, cidx;
void** pCrt;
if(idx<=0 || idx>pst_Ar->nSize-1 ) return 0; /* the item is out of bounds or the last in the array */
pCrt = pst_Ar->pData + (lidx = hidx = idx); /* this is the target */
/* if the first element of the array is <=> with the target, return its index (no use for further search) */
if(!pst_Ar->pfnCompare( pCrt, pst_Ar->pData )) return 0;
/* find the interval bound */
for(lidx--; !pst_Ar->pfnCompare( pCrt, pst_Ar->pData + lidx );
hidx = lidx, cidx = idx-(idx-lidx)*2, lidx = (cidx>lidx? cidx: lidx) );
lidx++;
while(hidx > lidx)
switch(pst_Ar->pfnCompare( pCrt, pst_Ar->pData + (cidx = (hidx+lidx)/2) ) )
{
case 0: case -1: hidx = cidx; break;
default: lidx = cidx+1; break;
}
return lidx;
}