libcm is a C development framework with an emphasis on audio signal processing applications.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

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. }