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.6KB

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