2012-10-30 03:52:39 +00:00
# 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 ;
}
2013-02-18 22:31:03 +00:00
const void * cmStackTop ( cmStackH_t h )
{
unsigned n = cmStackCount ( h ) ;
if ( n = = 0 )
return NULL ;
return cmStackGet ( h , n - 1 ) ;
}
2012-10-30 03:52:39 +00:00
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 ) ;
}