/*------------------------------------------------------------------------------ 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 <> 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 <> 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 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 <> 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; }