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.

cmDList.c 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. #include "cmGlobal.h"
  2. #include "cmRpt.h"
  3. #include "cmErr.h"
  4. #include "cmCtx.h"
  5. #include "cmMem.h"
  6. #include "cmMallocDebug.h"
  7. #include "cmDList.h"
  8. typedef struct cmDListRecd_str
  9. {
  10. void* dV;
  11. unsigned dN;
  12. struct cmDListRecd_str* prev;
  13. struct cmDListRecd_str* next;
  14. } cmDListRecd_t;
  15. typedef struct cmDListIndexRecd_str
  16. {
  17. cmDListRecd_t* r;
  18. struct cmDListIndexRecd_str* prev;
  19. struct cmDListIndexRecd_str* next;
  20. } cmDListIndexRecd_t;
  21. typedef struct cmDListIndex_str
  22. {
  23. unsigned id;
  24. cmDListCmpFunc_t cmpFunc;
  25. void* funcArg;
  26. cmDListIndexFreeFunc_t freeFunc;
  27. cmDListIndexRecd_t* first;
  28. cmDListIndexRecd_t* last;
  29. unsigned recdN;
  30. struct cmDListIndex_str* link;
  31. } cmDListIndex_t;
  32. struct cmDList_str;
  33. typedef struct cmDListIter_str
  34. {
  35. struct cmDList_str* p;
  36. cmDListIndex_t* x;
  37. cmDListIndexRecd_t* s;
  38. struct cmDListIter_str* link;
  39. } cmDListIter_t;
  40. typedef struct cmDList_str
  41. {
  42. cmErr_t err;
  43. cmDListRecd_t* first;
  44. cmDListRecd_t* last;
  45. unsigned recdN;
  46. cmDListIndex_t* indexes;
  47. cmDListIter_t* iters;
  48. } cmDList_t;
  49. cmDListH_t cmDListNullHandle = cmSTATIC_NULL_HANDLE;
  50. cmDListIterH_t cmDListIterNullHandle = cmSTATIC_NULL_HANDLE;
  51. cmDList_t* _cmDListHandleToPtr( cmDListH_t h )
  52. {
  53. cmDList_t* p = (cmDList_t*)h.h;
  54. assert( p!=NULL );
  55. return p;
  56. }
  57. cmDListIndex_t* _cmDListIdToIndex( cmDList_t* p, unsigned indexId )
  58. {
  59. cmDListIndex_t* x = p->indexes;
  60. for(; x!=NULL; x=x->link)
  61. if( x->id == indexId )
  62. return x;
  63. return NULL;
  64. }
  65. void _cmDListIndexAllocRecds( cmDListIndex_t* x, unsigned n )
  66. {
  67. unsigned i;
  68. for(i=0; i<n; ++i)
  69. {
  70. cmDListIndexRecd_t* s = cmMemAllocZ(cmDListIndexRecd_t,1);
  71. s->prev = x->last;
  72. if( x->last != NULL )
  73. x->last->next = s;
  74. else
  75. {
  76. assert( x->first == NULL );
  77. x->first = s;
  78. }
  79. x->last = s;
  80. }
  81. x->recdN += n;
  82. }
  83. void _cmDListIndexUpdate( cmDList_t* p, cmDListIndex_t* x )
  84. {
  85. cmDListIndexRecd_t* first = NULL;
  86. cmDListIndexRecd_t* last = NULL;
  87. cmDListIndexRecd_t* avail = x->first;
  88. // for each data recd
  89. cmDListRecd_t* r = p->first;
  90. for(; r!=NULL; r=r->next)
  91. {
  92. // get the next available index record
  93. cmDListIndexRecd_t* a = avail;
  94. avail = avail->next;
  95. // The count of index records and data records should always be the same.
  96. assert( a != NULL );
  97. a->r = r;
  98. cmDListIndexRecd_t* s = first;
  99. // for each index recd that has already been sorted
  100. for(; s!=NULL; s=s->next)
  101. if( x->cmpFunc( x->funcArg, r->dV, r->dN, s->r->dV, s->r->dN ) < 0 )
  102. {
  103. // r is less than s->r
  104. // insert 'a' prior to 's' in the index
  105. a->next = s;
  106. a->prev = s->prev;
  107. // if 's' is not first
  108. if( s->prev != NULL )
  109. s->prev->next = a;
  110. else
  111. { // 's' was first - now 'a' is first
  112. assert( s == first );
  113. first = a;
  114. }
  115. s->prev = a;
  116. break;
  117. }
  118. // No records are greater than r or the index is empty - 'a' is last in the index.
  119. if( s == NULL )
  120. {
  121. // insert 'a' after 'last'
  122. // if the index is empty
  123. if( last == NULL )
  124. {
  125. first = a;
  126. a->prev = NULL;
  127. }
  128. else // make 'a' last in the index
  129. {
  130. a->prev = last;
  131. a->next = NULL;
  132. assert( last->next == NULL );
  133. last->next = a;
  134. }
  135. a->next = NULL;
  136. last = a;
  137. }
  138. }
  139. x->first = first;
  140. x->last = last;
  141. }
  142. void _cmDListRecdFree( cmDList_t* p, cmDListRecd_t* r )
  143. {
  144. if( r->prev != NULL )
  145. r->prev->next = r->next;
  146. else
  147. p->first = r->next;
  148. if( r->next != NULL )
  149. r->next->prev = r->prev;
  150. else
  151. p->last = r->prev;
  152. cmMemFree(r);
  153. }
  154. // Unlink and free the index record s;
  155. void _cmDListIndexRecdFree( cmDListIndex_t* x, cmDListIndexRecd_t* s )
  156. {
  157. if( s->prev != NULL )
  158. s->prev->next = s->next;
  159. else
  160. x->first = s->next;
  161. if( s->next != NULL )
  162. s->next->prev = s->prev;
  163. else
  164. x->last = s->prev;
  165. cmMemFree(s);
  166. }
  167. // Unlink and release an index.
  168. void _cmDListIndexFree( cmDList_t* p, cmDListIndex_t* x )
  169. {
  170. if( x == NULL )
  171. return;
  172. cmDListIndex_t* x0 = NULL;
  173. cmDListIndex_t* x1 = p->indexes;
  174. // unlink 'x' from p->indexes
  175. while( x1 != NULL )
  176. {
  177. if( x1 == x )
  178. {
  179. // x is the first index
  180. if( x0 == NULL )
  181. {
  182. assert( x1 = p->indexes );
  183. p->indexes = x->link;
  184. }
  185. else
  186. {
  187. x0->link = x1->link;
  188. }
  189. break;
  190. }
  191. x0 = x1;
  192. x1 = x1->link;
  193. }
  194. // 'x' must have been found
  195. assert( x1 == x );
  196. // release each index record in 'x'
  197. cmDListIndexRecd_t* s = x->first;
  198. while( s != NULL )
  199. {
  200. cmDListIndexRecd_t* ns = s->next;
  201. cmMemFree(s);
  202. s = ns;
  203. }
  204. if( x->freeFunc != NULL )
  205. x->freeFunc(x->id,x->funcArg);
  206. cmMemFree(x);
  207. }
  208. // Unlink and release the iterator 'e'.
  209. cmDlRC_t _cmDListIterFree( cmDListIter_t* e )
  210. {
  211. cmDList_t* p = e->p;
  212. cmDListIter_t* e0 = NULL;
  213. cmDListIter_t* e1 = p->iters;
  214. while( e1 != NULL )
  215. {
  216. if( e1 == e )
  217. {
  218. if( e0 == NULL )
  219. p->iters = e1->link;
  220. else
  221. e0->link = e1->link;
  222. cmMemFree(e0);
  223. break;
  224. }
  225. e0 = e1;
  226. e1 = e1->link;
  227. }
  228. if( e1 == NULL )
  229. return cmErrMsg(&p->err,kIterNotFoundDlRC,"The delete target iterator could not be found.");
  230. return kOkDlRC;
  231. }
  232. cmDlRC_t _cmDListFree( cmDList_t* p )
  233. {
  234. cmDlRC_t rc = kOkDlRC;
  235. // release all indexes
  236. while( p->indexes != NULL )
  237. _cmDListIndexFree(p,p->indexes);
  238. while( p->iters != NULL )
  239. _cmDListIterFree(p->iters);
  240. // release all data records
  241. while( p->first != NULL )
  242. _cmDListRecdFree(p,p->first);
  243. cmMemFree(p);
  244. return rc;
  245. }
  246. cmDlRC_t _cmDListIndexAlloc( cmDList_t* p, unsigned indexId, cmDListCmpFunc_t func, void* funcArg )
  247. {
  248. cmDListIndex_t* x;
  249. if((x =_cmDListIdToIndex(p, indexId )) != NULL )
  250. return cmErrMsg(&p->err,kDuplicateIndexIdDlRC,"The indexId '%i' has already been used.",indexId);
  251. x = cmMemAllocZ(cmDListIndex_t,1);
  252. x->id = indexId;
  253. x->cmpFunc = func;
  254. x->funcArg = funcArg;
  255. x->link = p->indexes;
  256. p->indexes = x;
  257. _cmDListIndexAllocRecds(x,p->recdN);
  258. _cmDListIndexUpdate(p,x);
  259. return kOkDlRC;
  260. }
  261. cmDlRC_t cmDListAlloc( cmCtx_t* ctx, cmDListH_t* hp, cmDListCmpFunc_t func, void* funcArg )
  262. {
  263. cmDlRC_t rc = kOkDlRC;
  264. if((rc = cmDListFree(hp)) != kOkDlRC )
  265. return rc;
  266. cmDList_t* p = cmMemAllocZ(cmDList_t,1);
  267. cmErrSetup(&p->err,&ctx->rpt,"cmDList");
  268. if( func!=NULL )
  269. if((rc = _cmDListIndexAlloc(p,0,func,funcArg)) != kOkDlRC )
  270. goto errLabel;
  271. hp->h = p;
  272. errLabel:
  273. if( rc != kOkDlRC )
  274. _cmDListFree(p);
  275. return rc;
  276. }
  277. cmDlRC_t cmDListFree( cmDListH_t* hp )
  278. {
  279. cmDlRC_t rc;
  280. if( hp==NULL || cmDListIsValid(*hp)==false)
  281. return kOkDlRC;
  282. cmDList_t* p = _cmDListHandleToPtr(*hp);
  283. if((rc = _cmDListFree(p)) != kOkDlRC )
  284. return rc;
  285. hp->h = NULL;
  286. return rc;
  287. }
  288. bool cmDListIsValid( cmDListH_t h )
  289. { return h.h != NULL; }
  290. cmDlRC_t cmDListInsert( cmDListH_t h, const void* recd, unsigned recdByteN )
  291. {
  292. cmDList_t* p = _cmDListHandleToPtr(h);
  293. char* vp = cmMemAllocZ(char,sizeof(cmDListRecd_t) + recdByteN );
  294. cmDListRecd_t* r = (cmDListRecd_t*)vp;
  295. r->dV = r + 1;
  296. r->dN = recdByteN;
  297. memcpy( r->dV, recd, recdByteN );
  298. // Add records at the end of the list.
  299. // If the list is not empty
  300. if( p->last != NULL )
  301. p->last->next = r;
  302. else
  303. {
  304. // The list was empty
  305. assert( p->first == NULL );
  306. p->first = r;
  307. }
  308. r->prev = p->last;
  309. r->next = NULL;
  310. p->last = r;
  311. p->recdN += 1;
  312. // update the indexes
  313. cmDListIndex_t* x = p->indexes;
  314. for(; x!=NULL; x=x->link)
  315. {
  316. _cmDListIndexAllocRecds(x,1);
  317. _cmDListIndexUpdate(p,x);
  318. }
  319. return kOkDlRC;
  320. }
  321. cmDlRC_t cmDListDelete( cmDListH_t h, const void* recd )
  322. {
  323. cmDList_t* p = _cmDListHandleToPtr(h);
  324. cmDListIndex_t* x = p->indexes;
  325. cmDListIndexRecd_t* s = NULL;
  326. cmDListRecd_t* r = NULL;
  327. for(; x!=NULL; x=x->link)
  328. {
  329. for(s=x->first; s!=NULL; s=s->next)
  330. if( s->r->dV == recd )
  331. {
  332. if( r == NULL )
  333. r = s->r;
  334. else
  335. {
  336. // the same data record should be found for all indexes
  337. assert( s->r == r );
  338. }
  339. _cmDListIndexRecdFree(x,s);
  340. break;
  341. }
  342. if( r == NULL )
  343. return cmErrMsg(&p->err,kDataRecdNotFoundDlRC,"The delete target data record could not be found.");
  344. // if the indexes are valid then the recd should always be found
  345. assert( s!=NULL );
  346. }
  347. // release the data record
  348. _cmDListRecdFree(p,r);
  349. return kOkDlRC;
  350. }
  351. cmDlRC_t cmDListIndexAlloc( cmDListH_t h, unsigned indexId, cmDListCmpFunc_t func, void* funcArg )
  352. {
  353. cmDList_t* p = _cmDListHandleToPtr(h);
  354. return _cmDListIndexAlloc(p,indexId,func,funcArg);
  355. }
  356. cmDlRC_t cmDListIndexFree( cmDListH_t h, unsigned indexId )
  357. {
  358. cmDList_t* p = _cmDListHandleToPtr(h);
  359. cmDListIndex_t* x;
  360. if((x = _cmDListIdToIndex(p,indexId)) == NULL )
  361. return cmErrMsg(&p->err,kInvalidIndexDlRC,"The indexId '%i' could not be found.",indexId);
  362. _cmDListIndexFree(p,x);
  363. return kOkDlRC;
  364. }
  365. cmDlRC_t cmDListIndexSetFreeFunc(cmDListH_t h, unsigned indexId, cmDListIndexFreeFunc_t func )
  366. {
  367. cmDList_t* p = _cmDListHandleToPtr(h);
  368. cmDListIndex_t* x;
  369. if((x = _cmDListIdToIndex(p,indexId)) == NULL )
  370. return cmErrMsg(&p->err,kInvalidIndexDlRC,"The indexId '%i' could not be found.",indexId);
  371. x->freeFunc = func;
  372. return kOkDlRC;
  373. }
  374. cmDListIter_t* _cmDListIterHandleToPtr( cmDListIterH_t h )
  375. {
  376. cmDListIter_t* e = (cmDListIter_t*)h.h;
  377. assert(e != NULL );
  378. return e;
  379. }
  380. cmDlRC_t cmDListIterAlloc( cmDListH_t h, cmDListIterH_t* iHp, unsigned indexId )
  381. {
  382. cmDlRC_t rc = kOkDlRC;
  383. cmDList_t* p = _cmDListHandleToPtr(h);
  384. cmDListIndex_t* x;
  385. if((rc = cmDListIterFree(iHp)) != kOkDlRC )
  386. return rc;
  387. if((x = _cmDListIdToIndex(p, indexId)) == NULL )
  388. return cmErrMsg(&p->err,kInvalidIndexDlRC,"The indexId '%i' could not be found.",indexId);
  389. cmDListIter_t* e = cmMemAllocZ(cmDListIter_t,1);
  390. e->p = p;
  391. e->x = x;
  392. e->s = x->first;
  393. e->link = p->iters;
  394. p->iters = e;
  395. iHp->h = e;
  396. return rc;
  397. }
  398. cmDlRC_t cmDListIterFree( cmDListIterH_t* iHp )
  399. {
  400. cmDlRC_t rc;
  401. if( iHp==NULL || cmDListIterIsValid(*iHp)==false )
  402. return kOkDlRC;
  403. cmDListIter_t* e = _cmDListIterHandleToPtr(*iHp);
  404. if(( rc = _cmDListIterFree( e )) != kOkDlRC )
  405. return rc;
  406. iHp->h = NULL;
  407. return rc;
  408. }
  409. bool cmDListIterIsValid( cmDListIterH_t iH )
  410. { return iH.h != NULL; }
  411. cmDlRC_t cmDListIterSeekBegin( cmDListIterH_t iH )
  412. {
  413. cmDListIter_t* e = _cmDListIterHandleToPtr(iH);
  414. e->s = e->x->first;
  415. return kOkDlRC;
  416. }
  417. cmDlRC_t cmDListIterSeekLast( cmDListIterH_t iH )
  418. {
  419. cmDListIter_t* e = _cmDListIterHandleToPtr(iH);
  420. e->s = e->x->last;
  421. return kOkDlRC;
  422. }
  423. const void* _cmDListIterGet( cmDListIter_t* e, unsigned* recdByteNRef )
  424. {
  425. if( e->s == NULL )
  426. {
  427. if( recdByteNRef != NULL )
  428. *recdByteNRef = 0;
  429. return NULL;
  430. }
  431. if( recdByteNRef != NULL )
  432. *recdByteNRef = e->s->r->dN;
  433. return e->s->r->dN==0 ? NULL : e->s->r->dV;
  434. }
  435. const void* cmDListIterGet( cmDListIterH_t iH, unsigned* recdByteNRef )
  436. {
  437. cmDListIter_t* e = _cmDListIterHandleToPtr(iH);
  438. return _cmDListIterGet(e,recdByteNRef);
  439. }
  440. const void* cmDListIterPrev( cmDListIterH_t iH, unsigned* recdByteNRef )
  441. {
  442. cmDListIter_t* e = _cmDListIterHandleToPtr(iH);
  443. const void* rv = _cmDListIterGet(e,recdByteNRef);
  444. if( e->s != NULL )
  445. e->s = e->s->prev;
  446. return rv;
  447. }
  448. const void* cmDListIterNext( cmDListIterH_t iH, unsigned* recdByteNRef )
  449. {
  450. cmDListIter_t* e = _cmDListIterHandleToPtr(iH);
  451. const void* rv = _cmDListIterGet(e,recdByteNRef);
  452. if( e->s != NULL )
  453. e->s = e->s->next;
  454. return rv;
  455. }
  456. const void* cmDListIterFind( cmDListIterH_t iH, const void* key, unsigned keyN, unsigned* recdByteNRef)
  457. {
  458. cmDListIter_t* e = _cmDListIterHandleToPtr(iH);
  459. cmDListIndexRecd_t* s = e->s;
  460. for(; s!=NULL; s=s->next)
  461. if( e->x->cmpFunc( e->x->funcArg, s->r->dV, s->r->dN, key, keyN ) == 0 )
  462. {
  463. e->s = s;
  464. return _cmDListIterGet(e,recdByteNRef);
  465. }
  466. if( recdByteNRef != NULL )
  467. *recdByteNRef = 0;
  468. return NULL;
  469. }