123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393 |
- #include "cmPrefix.h"
- #include "cmGlobal.h"
- #include "cmRpt.h"
- #include "cmErr.h"
- #include "cmCtx.h"
- #include "cmMem.h"
- #include "cmMallocDebug.h"
- #include "cmStack.h"
-
- typedef struct cmStkBlk_str
- {
- char* base;
- unsigned curEleCnt;
- unsigned maxEleCnt;
- struct cmStkBlk_str* link;
- } cmStkBlk_t;
-
- typedef struct
- {
- cmErr_t err;
- unsigned expandBlkEleCnt; // count of ele's in all blocks after the first block
- unsigned cnt; // cur total count of elements in all blocks
- cmStkBlk_t* baseBlkPtr; // first block
- cmStkBlk_t* curBlkPtr; // current block - all blocks are always full except for the current block
- unsigned eleByteCnt; // bytes per element
- } cmStack_t;
-
- cmStackH_t cmStackNullHandle = cmSTATIC_NULL_HANDLE;
-
- cmStack_t* _cmStHandleToPtr( cmStackH_t h )
- {
- cmStack_t* p = (cmStack_t*)h.h;
- assert( p != NULL );
- return p;
- }
-
-
- cmStkBlk_t* _cmStkAllocBlk( cmStack_t* p, unsigned blkEleCnt )
- {
- cmStkBlk_t* blkPtr;
-
- // if a next block has already been created (because an earlier stack was cleared (w/o release)
- if( p->curBlkPtr != NULL && p->curBlkPtr->link != NULL )
- blkPtr = p->curBlkPtr->link;
- else
- {
- // ... otherwise allocate a new next block
- char* cp = cmMemAllocZ(char,sizeof(cmStkBlk_t) + p->eleByteCnt * blkEleCnt );
-
- blkPtr = (cmStkBlk_t*)cp;
-
- blkPtr->base = cp + sizeof(cmStkBlk_t);
- blkPtr->curEleCnt = 0;
- blkPtr->maxEleCnt = blkEleCnt;
-
- if( p->curBlkPtr != NULL )
- p->curBlkPtr->link = blkPtr;
- }
-
- if( p->baseBlkPtr == NULL )
- p->baseBlkPtr = blkPtr;
-
- p->curBlkPtr = blkPtr;
-
- return blkPtr;
- }
-
- cmStkBlk_t* _cmStackClear( cmStack_t* p, bool releaseFl )
- {
- cmStkBlk_t* bp = p->baseBlkPtr;
- while( bp != NULL )
- {
- cmStkBlk_t* nbp = bp->link;
- bp->curEleCnt = 0;
-
- if( releaseFl )
- cmMemFree(bp);
-
- bp = nbp;
- }
-
-
- p->cnt = 0;
-
- if( releaseFl )
- {
- p->curBlkPtr = NULL;
- p->baseBlkPtr = NULL;
- }
- else
- {
- p->curBlkPtr = p->baseBlkPtr;
- }
-
- return bp;
- }
-
- cmStRC_t _cmStackFree( cmStack_t* p )
- {
- cmStRC_t rc = kOkStRC;
-
- _cmStackClear(p,true);
- cmMemFree(p);
- return rc;
- }
-
-
- cmStRC_t cmStackAlloc( cmCtx_t* ctx, cmStackH_t* hp, unsigned initCnt, unsigned expandCnt, unsigned eleByteCnt )
- {
- cmStRC_t rc = kOkStRC;
-
- if((rc = cmStackFree(hp)) != kOkStRC )
- return rc;
-
- cmStack_t* p = cmMemAllocZ(cmStack_t,1);
-
- cmErrSetup(&p->err,&ctx->rpt,"Stack");
-
- p->expandBlkEleCnt = expandCnt;
- p->eleByteCnt = eleByteCnt;
-
- _cmStkAllocBlk(p,initCnt); // allocate the initial block
-
- hp->h = p;
-
- return rc;
- }
-
- cmStRC_t cmStackFree( cmStackH_t* hp )
- {
- cmStRC_t rc = kOkStRC;
- if( hp==NULL || cmStackIsValid(*hp) == false )
- return kOkStRC;
-
- cmStack_t* p = _cmStHandleToPtr(*hp);
-
- if((rc = _cmStackFree(p)) != kOkStRC )
- goto errLabel;
-
- hp->h = NULL;
-
- errLabel:
- return rc;
- }
-
- cmStRC_t cmStackIsValid( cmStackH_t h )
- { return h.h != NULL; }
-
- unsigned cmStackCount( cmStackH_t h )
- {
- cmStack_t* p = _cmStHandleToPtr(h);
- return p->cnt;
- }
-
- void cmStackClear( cmStackH_t h, bool releaseFl )
- {
- if( cmStackIsValid(h) == false )
- return;
-
- cmStack_t* p = _cmStHandleToPtr(h);
- _cmStackClear(p,releaseFl);
- }
-
-
- cmStRC_t cmStackPush( cmStackH_t h, const void* data, unsigned dataEleCnt )
- {
- cmStRC_t rc = kOkStRC;
- cmStack_t* p = _cmStHandleToPtr(h);
-
- while( dataEleCnt )
- {
- if( p->curBlkPtr == NULL || p->curBlkPtr->curEleCnt >= p->curBlkPtr->maxEleCnt )
- _cmStkAllocBlk(p, p->expandBlkEleCnt );
-
- // calc the count of ele's to copy into this block
- unsigned en = cmMin(dataEleCnt, p->curBlkPtr->maxEleCnt - p->curBlkPtr->curEleCnt );
-
- // calc the count of source bytes to copy into this block
- unsigned bn = en * p->eleByteCnt;
-
- // copy the source bytes into the block
- memcpy( p->curBlkPtr->base + (p->curBlkPtr->curEleCnt * p->eleByteCnt), data, bn );
-
- p->curBlkPtr->curEleCnt += en; // incr block element count
- p->cnt += en; // incr the total element count
- data = ((char*)data) + bn; // incr the source pointer
- dataEleCnt -= en; // decr the source ele count
- }
-
- return rc;
- }
-
- // Return the block and local index of the element at index *idxPtr.
- cmStkBlk_t* _cmStBlockIndex( cmStack_t* p, unsigned* idxPtr )
- {
- cmStkBlk_t* blkPtr;
-
- assert( p->baseBlkPtr != NULL);
-
- if( *idxPtr < p->baseBlkPtr->maxEleCnt )
- return p->baseBlkPtr;
-
- *idxPtr -= p->baseBlkPtr->maxEleCnt;
-
- unsigned bi = *idxPtr / p->expandBlkEleCnt;
- unsigned i;
- blkPtr = p->baseBlkPtr->link;
- for(i=0; i<bi; ++i)
- blkPtr = blkPtr->link;
-
- *idxPtr = *idxPtr - bi * p->expandBlkEleCnt;
-
- return blkPtr;
- }
-
- cmStRC_t cmStackPop( cmStackH_t h, unsigned eleCnt )
- {
- cmStRC_t rc = kOkStRC;
- cmStack_t* p = _cmStHandleToPtr(h);
-
- if( p->cnt < eleCnt )
- return cmErrMsg(&p->err,kUnderflowStRC,"Stack underflow. Cannot pop %i elements off stack with %i elements.", eleCnt, p->cnt );
-
- unsigned idx = p->cnt - eleCnt; // index of the first element to remove
- cmStkBlk_t* blkPtr = _cmStBlockIndex(p, &idx ); // get blk and local index of new curBlkPtr
-
- blkPtr->curEleCnt = idx; // update the element cnt for the new curBlkPtr
- p->curBlkPtr = blkPtr; // set the new curBlkPtr
- blkPtr = blkPtr->link; // for each blk after the current block ...
- while( blkPtr != NULL )
- {
- blkPtr->curEleCnt = 0; // ... set the block empty
- blkPtr = blkPtr->link;
- }
-
- p->cnt -= eleCnt;
-
- return rc;
- }
-
- const void* cmStackTop( cmStackH_t h )
- {
- unsigned n = cmStackCount(h);
- if( n == 0 )
- return NULL;
- return cmStackGet(h,n-1);
- }
-
- cmStRC_t _cmStackSetGet( cmStack_t* p, unsigned index, char* data, unsigned dataEleCnt, bool setFl )
- {
- cmStRC_t rc = kOkStRC;
-
- if( index + dataEleCnt > p->cnt )
- return cmErrMsg(&p->err,kInvalidIdxStRC,"The element index range:%i to %i falls outside the current index range:%i to %i of the stack.",index,index+dataEleCnt-1,0,p->cnt-1);
-
- cmStkBlk_t* blkPtr = _cmStBlockIndex(p,&index);
- assert( blkPtr != NULL );
-
- while( dataEleCnt )
- {
- // calc the count of ele's to copy into this block
- unsigned en = cmMin(dataEleCnt, blkPtr->curEleCnt - index );
-
- // calc the count of bytes in en elements
- unsigned bn = en * p->eleByteCnt;
-
- char* bp = blkPtr->base + (index * p->eleByteCnt);
-
- // copy the source bytes into the block
- memcpy( setFl ? bp:data, setFl ? data:bp, bn );
-
- data = data + bn; // incr the source pointer
- dataEleCnt -= en; // decr the source ele count
- index = 0; // all blocks after the first use index=0
- blkPtr = blkPtr->link;
- }
-
- return rc;
- }
-
- cmStRC_t cmStackSet( cmStackH_t h, unsigned index, const void* data, unsigned dataEleCnt )
- { return _cmStackSetGet( _cmStHandleToPtr(h), index, (char*) data, dataEleCnt,true ); }
-
-
- cmStRC_t cmStackGetN( cmStackH_t h, unsigned index, void* data, unsigned dataEleCnt )
- { return _cmStackSetGet( _cmStHandleToPtr(h), index, (char*)data, dataEleCnt, false ); }
-
- const void* cmStackGet( cmStackH_t h, unsigned index )
- {
- cmStack_t* p = _cmStHandleToPtr(h);
-
- if( index >= p->cnt )
- {
- cmErrMsg(&p->err,kInvalidIdxStRC,"The index %i is outside the valid range 0:%i.",index,p->cnt-1);
- return NULL;
- }
-
- cmStkBlk_t* blkPtr = _cmStBlockIndex(p,&index);
- assert( blkPtr != NULL );
- return blkPtr->base + (index * p->eleByteCnt);
- }
-
- void* cmStackFlatten( cmStackH_t h )
- {
- cmStack_t* p = _cmStHandleToPtr(h);
- cmStkBlk_t* bbp = p->baseBlkPtr;
- cmStkBlk_t* cbp = p->curBlkPtr;
- unsigned cnt = p->cnt;
-
- // pretend the stack is unallocated
- p->baseBlkPtr = NULL;
- p->curBlkPtr = NULL;
-
- // allocate a new initial block large enough to hold all the data
- cmStkBlk_t* nbp = _cmStkAllocBlk(p,cnt);
- cmStkBlk_t* bp = bbp;
- unsigned n = 0;
-
- // copy the existing stack values into the new initial block
- while( bp != NULL && bp->curEleCnt > 0 )
- {
- unsigned bn = bp->curEleCnt * p->eleByteCnt;
-
- assert( n < cnt*p->eleByteCnt );
-
- memcpy( nbp->base + n, bp->base, bn );
- n += bn;
- bp = bp->link;
- }
-
- // restore the stack to it's original state, clear and release
- p->baseBlkPtr = bbp;
- p->curBlkPtr = cbp;
- _cmStackClear(p,true);
-
- // setup new stack with the new initial block
- // (the data is now linearly arranged in nbp->base)
- p->baseBlkPtr = nbp;
- p->curBlkPtr = nbp;
- p->cnt = cnt;
-
- return p->baseBlkPtr->base;
- }
-
- void cmStackTest( cmCtx_t* ctx )
- {
- cmStackH_t h = cmStackNullHandle;
- int i;
- int v[20];
-
- if( cmStackAlloc(ctx,&h,10,5,sizeof(int)) != kOkStRC )
- goto errLabel;
-
- for(i=0; i<9; ++i)
- v[i] = i;
-
- cmStackPush(h,v,i);
-
- cmRptPrintf(&ctx->rpt,"count:%i %i\n",cmStackCount(h),i);
-
- for(; i<18; ++i)
- v[i] = i;
-
- cmStackPush(h,v,i);
-
- cmRptPrintf(&ctx->rpt,"count:%i %i\n",cmStackCount(h),i);
-
- cmStackPop(h,10);
-
- cmRptPrintf(&ctx->rpt,"count:%i %i\n",cmStackCount(h),i);
-
- cmStackPop(h,10);
-
- cmRptPrintf(&ctx->rpt,"count:%i %i\n",cmStackCount(h),i);
-
- cmStackPush(h,v,10);
-
- cmRptPrintf(&ctx->rpt,"count:%i %i\n",cmStackCount(h),i);
-
- for(i=0; i<cmStackCount(h); ++i)
- cmRptPrintf(&ctx->rpt,"%i ",cmStackEle(h,int,i));
-
- cmRptPrintf(&ctx->rpt,"\n");
-
- int* ip = (int*)cmStackFlatten(h);
- for(i=0; i<cmStackCount(h); ++i)
- cmRptPrintf(&ctx->rpt,"%i ",ip[i]);
-
- cmRptPrintf(&ctx->rpt,"\n");
-
- errLabel:
- cmStackFree(&h);
- }
|