375 lines
16 KiB
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;
|
|
}
|