libcm is a C development framework with an emphasis on audio signal processing applications.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cmStack.c 9.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. #include "cmPrefix.h"
  2. #include "cmGlobal.h"
  3. #include "cmRpt.h"
  4. #include "cmErr.h"
  5. #include "cmCtx.h"
  6. #include "cmMem.h"
  7. #include "cmMallocDebug.h"
  8. #include "cmStack.h"
  9. typedef struct cmStkBlk_str
  10. {
  11. char* base;
  12. unsigned curEleCnt;
  13. unsigned maxEleCnt;
  14. struct cmStkBlk_str* link;
  15. } cmStkBlk_t;
  16. typedef struct
  17. {
  18. cmErr_t err;
  19. unsigned expandBlkEleCnt; // count of ele's in all blocks after the first block
  20. unsigned cnt; // cur total count of elements in all blocks
  21. cmStkBlk_t* baseBlkPtr; // first block
  22. cmStkBlk_t* curBlkPtr; // current block - all blocks are always full except for the current block
  23. unsigned eleByteCnt; // bytes per element
  24. } cmStack_t;
  25. cmStackH_t cmStackNullHandle = cmSTATIC_NULL_HANDLE;
  26. cmStack_t* _cmStHandleToPtr( cmStackH_t h )
  27. {
  28. cmStack_t* p = (cmStack_t*)h.h;
  29. assert( p != NULL );
  30. return p;
  31. }
  32. cmStkBlk_t* _cmStkAllocBlk( cmStack_t* p, unsigned blkEleCnt )
  33. {
  34. cmStkBlk_t* blkPtr;
  35. // if a next block has already been created (because an earlier stack was cleared (w/o release)
  36. if( p->curBlkPtr != NULL && p->curBlkPtr->link != NULL )
  37. blkPtr = p->curBlkPtr->link;
  38. else
  39. {
  40. // ... otherwise allocate a new next block
  41. char* cp = cmMemAllocZ(char,sizeof(cmStkBlk_t) + p->eleByteCnt * blkEleCnt );
  42. blkPtr = (cmStkBlk_t*)cp;
  43. blkPtr->base = cp + sizeof(cmStkBlk_t);
  44. blkPtr->curEleCnt = 0;
  45. blkPtr->maxEleCnt = blkEleCnt;
  46. if( p->curBlkPtr != NULL )
  47. p->curBlkPtr->link = blkPtr;
  48. }
  49. if( p->baseBlkPtr == NULL )
  50. p->baseBlkPtr = blkPtr;
  51. p->curBlkPtr = blkPtr;
  52. return blkPtr;
  53. }
  54. cmStkBlk_t* _cmStackClear( cmStack_t* p, bool releaseFl )
  55. {
  56. cmStkBlk_t* bp = p->baseBlkPtr;
  57. while( bp != NULL )
  58. {
  59. cmStkBlk_t* nbp = bp->link;
  60. bp->curEleCnt = 0;
  61. if( releaseFl )
  62. cmMemFree(bp);
  63. bp = nbp;
  64. }
  65. p->cnt = 0;
  66. if( releaseFl )
  67. {
  68. p->curBlkPtr = NULL;
  69. p->baseBlkPtr = NULL;
  70. }
  71. else
  72. {
  73. p->curBlkPtr = p->baseBlkPtr;
  74. }
  75. return bp;
  76. }
  77. cmStRC_t _cmStackFree( cmStack_t* p )
  78. {
  79. cmStRC_t rc = kOkStRC;
  80. _cmStackClear(p,true);
  81. cmMemFree(p);
  82. return rc;
  83. }
  84. cmStRC_t cmStackAlloc( cmCtx_t* ctx, cmStackH_t* hp, unsigned initCnt, unsigned expandCnt, unsigned eleByteCnt )
  85. {
  86. cmStRC_t rc = kOkStRC;
  87. if((rc = cmStackFree(hp)) != kOkStRC )
  88. return rc;
  89. cmStack_t* p = cmMemAllocZ(cmStack_t,1);
  90. cmErrSetup(&p->err,&ctx->rpt,"Stack");
  91. p->expandBlkEleCnt = expandCnt;
  92. p->eleByteCnt = eleByteCnt;
  93. _cmStkAllocBlk(p,initCnt); // allocate the initial block
  94. hp->h = p;
  95. return rc;
  96. }
  97. cmStRC_t cmStackFree( cmStackH_t* hp )
  98. {
  99. cmStRC_t rc = kOkStRC;
  100. if( hp==NULL || cmStackIsValid(*hp) == false )
  101. return kOkStRC;
  102. cmStack_t* p = _cmStHandleToPtr(*hp);
  103. if((rc = _cmStackFree(p)) != kOkStRC )
  104. goto errLabel;
  105. hp->h = NULL;
  106. errLabel:
  107. return rc;
  108. }
  109. cmStRC_t cmStackIsValid( cmStackH_t h )
  110. { return h.h != NULL; }
  111. unsigned cmStackCount( cmStackH_t h )
  112. {
  113. cmStack_t* p = _cmStHandleToPtr(h);
  114. return p->cnt;
  115. }
  116. void cmStackClear( cmStackH_t h, bool releaseFl )
  117. {
  118. if( cmStackIsValid(h) == false )
  119. return;
  120. cmStack_t* p = _cmStHandleToPtr(h);
  121. _cmStackClear(p,releaseFl);
  122. }
  123. cmStRC_t cmStackPush( cmStackH_t h, const void* data, unsigned dataEleCnt )
  124. {
  125. cmStRC_t rc = kOkStRC;
  126. cmStack_t* p = _cmStHandleToPtr(h);
  127. while( dataEleCnt )
  128. {
  129. if( p->curBlkPtr == NULL || p->curBlkPtr->curEleCnt >= p->curBlkPtr->maxEleCnt )
  130. _cmStkAllocBlk(p, p->expandBlkEleCnt );
  131. // calc the count of ele's to copy into this block
  132. unsigned en = cmMin(dataEleCnt, p->curBlkPtr->maxEleCnt - p->curBlkPtr->curEleCnt );
  133. // calc the count of source bytes to copy into this block
  134. unsigned bn = en * p->eleByteCnt;
  135. // copy the source bytes into the block
  136. memcpy( p->curBlkPtr->base + (p->curBlkPtr->curEleCnt * p->eleByteCnt), data, bn );
  137. p->curBlkPtr->curEleCnt += en; // incr block element count
  138. p->cnt += en; // incr the total element count
  139. data = ((char*)data) + bn; // incr the source pointer
  140. dataEleCnt -= en; // decr the source ele count
  141. }
  142. return rc;
  143. }
  144. // Return the block and local index of the element at index *idxPtr.
  145. cmStkBlk_t* _cmStBlockIndex( cmStack_t* p, unsigned* idxPtr )
  146. {
  147. cmStkBlk_t* blkPtr;
  148. assert( p->baseBlkPtr != NULL);
  149. if( *idxPtr < p->baseBlkPtr->maxEleCnt )
  150. return p->baseBlkPtr;
  151. *idxPtr -= p->baseBlkPtr->maxEleCnt;
  152. unsigned bi = *idxPtr / p->expandBlkEleCnt;
  153. unsigned i;
  154. blkPtr = p->baseBlkPtr->link;
  155. for(i=0; i<bi; ++i)
  156. blkPtr = blkPtr->link;
  157. *idxPtr = *idxPtr - bi * p->expandBlkEleCnt;
  158. return blkPtr;
  159. }
  160. cmStRC_t cmStackPop( cmStackH_t h, unsigned eleCnt )
  161. {
  162. cmStRC_t rc = kOkStRC;
  163. cmStack_t* p = _cmStHandleToPtr(h);
  164. if( p->cnt < eleCnt )
  165. return cmErrMsg(&p->err,kUnderflowStRC,"Stack underflow. Cannot pop %i elements off stack with %i elements.", eleCnt, p->cnt );
  166. unsigned idx = p->cnt - eleCnt; // index of the first element to remove
  167. cmStkBlk_t* blkPtr = _cmStBlockIndex(p, &idx ); // get blk and local index of new curBlkPtr
  168. blkPtr->curEleCnt = idx; // update the element cnt for the new curBlkPtr
  169. p->curBlkPtr = blkPtr; // set the new curBlkPtr
  170. blkPtr = blkPtr->link; // for each blk after the current block ...
  171. while( blkPtr != NULL )
  172. {
  173. blkPtr->curEleCnt = 0; // ... set the block empty
  174. blkPtr = blkPtr->link;
  175. }
  176. p->cnt -= eleCnt;
  177. return rc;
  178. }
  179. const void* cmStackTop( cmStackH_t h )
  180. {
  181. unsigned n = cmStackCount(h);
  182. if( n == 0 )
  183. return NULL;
  184. return cmStackGet(h,n-1);
  185. }
  186. cmStRC_t _cmStackSetGet( cmStack_t* p, unsigned index, char* data, unsigned dataEleCnt, bool setFl )
  187. {
  188. cmStRC_t rc = kOkStRC;
  189. if( index + dataEleCnt > p->cnt )
  190. 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);
  191. cmStkBlk_t* blkPtr = _cmStBlockIndex(p,&index);
  192. assert( blkPtr != NULL );
  193. while( dataEleCnt )
  194. {
  195. // calc the count of ele's to copy into this block
  196. unsigned en = cmMin(dataEleCnt, blkPtr->curEleCnt - index );
  197. // calc the count of bytes in en elements
  198. unsigned bn = en * p->eleByteCnt;
  199. char* bp = blkPtr->base + (index * p->eleByteCnt);
  200. // copy the source bytes into the block
  201. memcpy( setFl ? bp:data, setFl ? data:bp, bn );
  202. data = data + bn; // incr the source pointer
  203. dataEleCnt -= en; // decr the source ele count
  204. index = 0; // all blocks after the first use index=0
  205. blkPtr = blkPtr->link;
  206. }
  207. return rc;
  208. }
  209. cmStRC_t cmStackSet( cmStackH_t h, unsigned index, const void* data, unsigned dataEleCnt )
  210. { return _cmStackSetGet( _cmStHandleToPtr(h), index, (char*) data, dataEleCnt,true ); }
  211. cmStRC_t cmStackGetN( cmStackH_t h, unsigned index, void* data, unsigned dataEleCnt )
  212. { return _cmStackSetGet( _cmStHandleToPtr(h), index, (char*)data, dataEleCnt, false ); }
  213. const void* cmStackGet( cmStackH_t h, unsigned index )
  214. {
  215. cmStack_t* p = _cmStHandleToPtr(h);
  216. if( index >= p->cnt )
  217. {
  218. cmErrMsg(&p->err,kInvalidIdxStRC,"The index %i is outside the valid range 0:%i.",index,p->cnt-1);
  219. return NULL;
  220. }
  221. cmStkBlk_t* blkPtr = _cmStBlockIndex(p,&index);
  222. assert( blkPtr != NULL );
  223. return blkPtr->base + (index * p->eleByteCnt);
  224. }
  225. void* cmStackFlatten( cmStackH_t h )
  226. {
  227. cmStack_t* p = _cmStHandleToPtr(h);
  228. cmStkBlk_t* bbp = p->baseBlkPtr;
  229. cmStkBlk_t* cbp = p->curBlkPtr;
  230. unsigned cnt = p->cnt;
  231. // pretend the stack is unallocated
  232. p->baseBlkPtr = NULL;
  233. p->curBlkPtr = NULL;
  234. // allocate a new initial block large enough to hold all the data
  235. cmStkBlk_t* nbp = _cmStkAllocBlk(p,cnt);
  236. cmStkBlk_t* bp = bbp;
  237. unsigned n = 0;
  238. // copy the existing stack values into the new initial block
  239. while( bp != NULL && bp->curEleCnt > 0 )
  240. {
  241. unsigned bn = bp->curEleCnt * p->eleByteCnt;
  242. assert( n < cnt*p->eleByteCnt );
  243. memcpy( nbp->base + n, bp->base, bn );
  244. n += bn;
  245. bp = bp->link;
  246. }
  247. // restore the stack to it's original state, clear and release
  248. p->baseBlkPtr = bbp;
  249. p->curBlkPtr = cbp;
  250. _cmStackClear(p,true);
  251. // setup new stack with the new initial block
  252. // (the data is now linearly arranged in nbp->base)
  253. p->baseBlkPtr = nbp;
  254. p->curBlkPtr = nbp;
  255. p->cnt = cnt;
  256. return p->baseBlkPtr->base;
  257. }
  258. void cmStackTest( cmCtx_t* ctx )
  259. {
  260. cmStackH_t h = cmStackNullHandle;
  261. int i;
  262. int v[20];
  263. if( cmStackAlloc(ctx,&h,10,5,sizeof(int)) != kOkStRC )
  264. goto errLabel;
  265. for(i=0; i<9; ++i)
  266. v[i] = i;
  267. cmStackPush(h,v,i);
  268. cmRptPrintf(&ctx->rpt,"count:%i %i\n",cmStackCount(h),i);
  269. for(; i<18; ++i)
  270. v[i] = i;
  271. cmStackPush(h,v,i);
  272. cmRptPrintf(&ctx->rpt,"count:%i %i\n",cmStackCount(h),i);
  273. cmStackPop(h,10);
  274. cmRptPrintf(&ctx->rpt,"count:%i %i\n",cmStackCount(h),i);
  275. cmStackPop(h,10);
  276. cmRptPrintf(&ctx->rpt,"count:%i %i\n",cmStackCount(h),i);
  277. cmStackPush(h,v,10);
  278. cmRptPrintf(&ctx->rpt,"count:%i %i\n",cmStackCount(h),i);
  279. for(i=0; i<cmStackCount(h); ++i)
  280. cmRptPrintf(&ctx->rpt,"%i ",cmStackEle(h,int,i));
  281. cmRptPrintf(&ctx->rpt,"\n");
  282. int* ip = (int*)cmStackFlatten(h);
  283. for(i=0; i<cmStackCount(h); ++i)
  284. cmRptPrintf(&ctx->rpt,"%i ",ip[i]);
  285. cmRptPrintf(&ctx->rpt,"\n");
  286. errLabel:
  287. cmStackFree(&h);
  288. }