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.

cmSymTbl.c 9.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  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 "cmSymTbl.h"
  9. #include "cmLinkedHeap.h"
  10. cmSymTblH_t cmSymTblNullHandle = cmSTATIC_NULL_HANDLE;
  11. enum
  12. {
  13. kDynStFl = 0x01
  14. };
  15. typedef struct cmSymLabel_str
  16. {
  17. unsigned flags;
  18. const cmChar_t* label;
  19. } cmSymLabel_t;
  20. struct cmSym_str;
  21. typedef struct cmSymAvail_str
  22. {
  23. unsigned id;
  24. struct cmSym_str* linkPtr;
  25. } cmSymAvail_t;
  26. typedef struct cmSym_str
  27. {
  28. union
  29. {
  30. cmSymLabel_t label;
  31. cmSymAvail_t avail;
  32. } u;
  33. } cmSym_t;
  34. typedef struct cmSymBlock_t
  35. {
  36. cmSym_t* base; // block base - contains cmSymTbl_t.symPerBlock cmSym_t records
  37. unsigned cnt; // cout of symbols actually used in this block
  38. struct cmSymBlock_t* link; // next block
  39. } cmSymBlock_t;
  40. typedef struct
  41. {
  42. cmSymTblH_t parentH; // parent symbols table
  43. cmLHeapH_t heapH; // symbol label storage
  44. cmSymBlock_t* first; // pointer to head of symbol block chain
  45. cmSymBlock_t* last; // pointer to last symbol block in chain
  46. unsigned blkCnt; // count of blocks on chain
  47. unsigned symCnt; // total count of symbols controlled by this symbol (does not include parent symbols)
  48. unsigned baseSymId;
  49. unsigned symPerBlock;
  50. cmSym_t* availPtr;
  51. } cmSymTbl_t;
  52. cmSymTbl_t* _cmSymTblHandleToPtr( cmSymTblH_t h )
  53. {
  54. cmSymTbl_t* stp = (cmSymTbl_t*)h.h;
  55. assert( stp != NULL );
  56. return stp;
  57. }
  58. cmSymBlock_t* _cmSymTblAllocateBlock( cmSymTbl_t* stp )
  59. {
  60. // allocate the new block
  61. cmSymBlock_t* sbp = (cmSymBlock_t*)cmMemMallocZ( sizeof(cmSymBlock_t) + (stp->symPerBlock * sizeof(cmSym_t)));
  62. // initialize the new block control recd
  63. sbp->base = (cmSym_t*)(sbp+1);
  64. sbp->cnt = 0;
  65. sbp->link = NULL;
  66. // add the new block control recd to the end of the block chain
  67. if( stp->last == NULL )
  68. stp->first = sbp;
  69. else
  70. stp->last->link = sbp;
  71. // the new block control recd always becomes the last recd in the chain
  72. stp->last = sbp;
  73. ++stp->blkCnt;
  74. return sbp;
  75. }
  76. bool _cmSymTblIsSymbolRemoved( cmSymTbl_t* stp, unsigned symId )
  77. {
  78. const cmSym_t* sp = stp->availPtr;
  79. for(; sp != NULL; sp=sp->u.avail.linkPtr)
  80. if( sp->u.avail.id == symId )
  81. return true;
  82. return false;
  83. }
  84. unsigned _cmSymTblLabelToId( cmSymTbl_t* stp, const char* label )
  85. {
  86. cmSymBlock_t* sbp = stp->first;
  87. unsigned symId = stp->baseSymId;
  88. while( sbp != NULL )
  89. {
  90. cmSym_t* sp = sbp->base;
  91. cmSym_t* ep = sbp->base + sbp->cnt;
  92. for(; sp<ep; ++sp,++symId)
  93. {
  94. if( _cmSymTblIsSymbolRemoved(stp, symId ) == false )
  95. if( strcmp( sp->u.label.label, label ) == 0 )
  96. return symId;
  97. }
  98. sbp = sbp->link;
  99. }
  100. return cmInvalidId;
  101. }
  102. cmSym_t* _cmSymTblIdToSymPtr( cmSymTbl_t* stp, unsigned symId )
  103. {
  104. if( cmSymTblIsValid(stp->parentH) && cmSymTblIsValidId( stp->parentH, symId ) )
  105. return _cmSymTblIdToSymPtr( _cmSymTblHandleToPtr(stp->parentH), symId );
  106. symId -= stp->baseSymId;
  107. unsigned n = symId / stp->symPerBlock;
  108. unsigned i = symId % stp->symPerBlock;
  109. if( n >= stp->blkCnt )
  110. return NULL;
  111. cmSymBlock_t* sbp = stp->first;
  112. unsigned j;
  113. for(j=0; j<n; ++j)
  114. sbp = sbp->link;
  115. if( i >= sbp->cnt )
  116. return NULL;
  117. return sbp->base + i;
  118. }
  119. cmSymTblH_t cmSymTblCreate( cmSymTblH_t parentH, unsigned baseSymId, cmCtx_t* ctx )
  120. {
  121. cmSymTblH_t h;
  122. cmSymTbl_t* stp = cmMemAllocZ( cmSymTbl_t, 1 );
  123. stp->heapH = cmLHeapCreate( 2048, ctx );
  124. stp->symPerBlock = 3;
  125. stp->baseSymId = baseSymId;
  126. stp->parentH = parentH;
  127. _cmSymTblAllocateBlock( stp );
  128. h.h = stp;
  129. return h;
  130. }
  131. void cmSymTblDestroy( cmSymTblH_t* hp )
  132. {
  133. if( hp==NULL || hp->h == NULL )
  134. return;
  135. cmSymTbl_t* stp = _cmSymTblHandleToPtr(*hp);
  136. assert( stp != NULL );
  137. cmSymBlock_t* sbp = stp->first;
  138. while( sbp != NULL )
  139. {
  140. cmSymBlock_t* t = sbp;
  141. sbp = sbp->link;
  142. cmMemFree(t);
  143. }
  144. cmLHeapDestroy(&stp->heapH);
  145. cmMemFree(hp->h);
  146. hp->h = NULL;
  147. }
  148. unsigned cmSymTblRegister( cmSymTblH_t h, const char* label, bool staticFl )
  149. {
  150. cmSymTbl_t* stp = _cmSymTblHandleToPtr(h);
  151. unsigned symId;
  152. unsigned flags = 0;
  153. cmSym_t* sp = NULL;
  154. // check for the label in the local symbol table
  155. if((symId = _cmSymTblLabelToId( stp, label )) != cmInvalidId )
  156. return symId;
  157. // check for the label in the parent symbol table
  158. if( cmSymTblIsValid(stp->parentH) )
  159. if((symId = _cmSymTblLabelToId( _cmSymTblHandleToPtr(stp->parentH), label)) != cmInvalidId )
  160. return symId;
  161. // if the label is not static then create a copy of it on the local heap
  162. if( !staticFl )
  163. {
  164. char* cp = (char*)cmLHeapAlloc( stp->heapH, strlen(label) + 1 );
  165. strcpy(cp,label);
  166. label = cp;
  167. flags |= kDynStFl;
  168. }
  169. // if there are no previosly removed symbols available
  170. if( stp->availPtr == NULL )
  171. {
  172. cmSymBlock_t*sbp = stp->last;
  173. // if the last block is full
  174. if( sbp->cnt == stp->symPerBlock )
  175. sbp = _cmSymTblAllocateBlock(stp);
  176. // the last block must now have an empty slot
  177. assert( sbp->cnt < stp->symPerBlock );
  178. unsigned idx = sbp->cnt++;
  179. sp = sbp->base + idx;
  180. //sbp->base[ idx ].u.label.label = label;
  181. //sbp->base[ idx ].u.label.flags = flags;
  182. // calculate the symbol id
  183. symId = stp->baseSymId + ((stp->blkCnt-1) * stp->symPerBlock) + sbp->cnt - 1;
  184. }
  185. else // there are previously removed symbols available
  186. {
  187. sp = stp->availPtr; // get the next avail symbol
  188. stp->availPtr = sp->u.avail.linkPtr; // take it off the avail list
  189. symId = sp->u.avail.id; // store the new symbol's id
  190. }
  191. // setup the symbol record
  192. sp->u.label.label = label;
  193. sp->u.label.flags = flags;
  194. // verify that the new symId does not already belong to the parent
  195. assert( cmSymTblIsValid(stp->parentH)==false ? 1 : cmSymTblLabel( stp->parentH, symId)==NULL );
  196. ++stp->symCnt;
  197. return symId;
  198. }
  199. unsigned cmSymTblRegisterSymbol( cmSymTblH_t h, const char* label )
  200. { return cmSymTblRegister( h, label, false ); }
  201. unsigned cmSymTblRegisterStaticSymbol( cmSymTblH_t h, const char* label )
  202. { return cmSymTblRegister( h, label, true ); }
  203. unsigned cmSymTblRegisterVFmt( cmSymTblH_t h, const cmChar_t* fmt, va_list vl )
  204. {
  205. unsigned n = vsnprintf(NULL,0,fmt,vl);
  206. cmChar_t b[n+1];
  207. vsnprintf(b,n,fmt,vl);
  208. return cmSymTblRegister(h,fmt,vl);
  209. }
  210. unsigned cmSymTblRegisterFmt( cmSymTblH_t h, const cmChar_t* fmt, ... )
  211. {
  212. va_list vl;
  213. va_start(vl,fmt);
  214. unsigned id = cmSymTblRegisterVFmt(h,fmt,vl);
  215. va_end(vl);
  216. return id;
  217. }
  218. bool cmSymTblRemove( cmSymTblH_t h, unsigned symId )
  219. {
  220. cmSymTbl_t* stp = _cmSymTblHandleToPtr(h);
  221. cmSym_t* sp;
  222. if((sp = _cmSymTblIdToSymPtr(stp,symId)) == NULL )
  223. return false;
  224. if( cmIsFlag(sp->u.label.flags,kDynStFl))
  225. cmLHeapFree(stp->heapH,(void*)sp->u.label.label);
  226. sp->u.avail.id = symId;
  227. sp->u.avail.linkPtr = stp->availPtr;
  228. stp->availPtr = sp;
  229. return true;
  230. }
  231. const char* cmSymTblLabel( cmSymTblH_t h, unsigned symId )
  232. {
  233. cmSymTbl_t* stp = _cmSymTblHandleToPtr(h);
  234. cmSym_t* sp;
  235. if((sp = _cmSymTblIdToSymPtr(stp,symId)) == NULL )
  236. return NULL;
  237. return sp->u.label.label;
  238. }
  239. unsigned cmSymTblId( cmSymTblH_t h, const char* label )
  240. {
  241. cmSymTbl_t* stp = _cmSymTblHandleToPtr(h);
  242. unsigned id;
  243. if((id=_cmSymTblLabelToId(stp,label)) == cmInvalidId )
  244. if( cmSymTblIsValid(stp->parentH))
  245. return _cmSymTblLabelToId( _cmSymTblHandleToPtr(stp->parentH), label );
  246. return id;
  247. }
  248. bool cmSymTblIsValid( cmSymTblH_t h )
  249. { return h.h != NULL; }
  250. bool cmSymTblIsValidId( cmSymTblH_t h, unsigned symId )
  251. {
  252. cmSymTbl_t* stp = _cmSymTblHandleToPtr(h);
  253. return stp->baseSymId <= symId && symId < (stp->baseSymId + stp->symCnt);
  254. }
  255. void cmSymTblReport( cmSymTblH_t h )
  256. {
  257. cmSymTbl_t* stp = _cmSymTblHandleToPtr(h);
  258. cmSymBlock_t* sbp = stp->first;
  259. unsigned i=0, j=0, symId = stp->baseSymId;
  260. printf("blks:%i syms:%i\n", stp->blkCnt, stp->symCnt );
  261. for(; sbp != NULL; sbp=sbp->link,++i)
  262. for(j=0; j<sbp->cnt; ++j,++symId)
  263. {
  264. bool remFl = _cmSymTblIsSymbolRemoved(stp, symId );
  265. printf("blk:%i sym:%i id:%i label:%s\n",i,j,symId,remFl ? "<removed>" : sbp->base[j].u.label.label);
  266. }
  267. }
  268. //{ { label:cmSymTblEx }
  269. //(
  270. // cmSymTblTest() gives a usage example for the symbol table component.
  271. //)
  272. //[
  273. void cmSymTblTest( cmCtx_t* ctx )
  274. {
  275. unsigned baseSymId = 100;
  276. unsigned i;
  277. unsigned n = 10;
  278. unsigned idArray[n];
  279. // create a symbol table
  280. cmSymTblH_t h = cmSymTblCreate( cmSymTblNullHandle, baseSymId, ctx );
  281. if( cmSymTblIsValid(h) == false )
  282. {
  283. cmRptPrintf(&ctx->rpt,"Symbol table creation failed.");
  284. return;
  285. }
  286. // generate and register some symbols
  287. for(i=0; i<n; ++i)
  288. {
  289. bool staticFl = false;
  290. char str[10];
  291. snprintf(str,9,"sym%i",i);
  292. idArray[i] = cmSymTblRegister( h, str, staticFl );
  293. }
  294. // remove the fourth symbol generated
  295. cmSymTblRemove( h, baseSymId+3 );
  296. // print the symbol table
  297. cmSymTblReport(h);
  298. // iterate through the symbol table
  299. for(i=0; i<n; ++i)
  300. {
  301. const cmChar_t* lbl = cmSymTblLabel(h,idArray[i]);
  302. if( lbl == NULL )
  303. cmRptPrintf(&ctx->rpt,"%i <removed>\n",i);
  304. else
  305. cmRptPrintf(&ctx->rpt,"%i %i==%i %s \n",i,idArray[i],cmSymTblId(h,lbl),lbl);
  306. }
  307. // release the symbol table
  308. cmSymTblDestroy(&h);
  309. return;
  310. }
  311. //]
  312. //}