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 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  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; // pointer to the owner cmDList
  36. cmDListIndex_t* x; // pointer to the index this iterator traverses
  37. cmDListIndexRecd_t* s; // current record
  38. struct cmDListIter_str* link; // p->iters list 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. // Given an indexId return the associated index.
  58. cmDListIndex_t* _cmDListIdToIndex( cmDList_t* p, unsigned indexId )
  59. {
  60. cmDListIndex_t* x = p->indexes;
  61. for(; x!=NULL; x=x->link)
  62. if( x->id == indexId )
  63. return x;
  64. return NULL;
  65. }
  66. // Allocate 'n' new index records for the index 'x'.
  67. void _cmDListIndexAllocRecds( cmDListIndex_t* x, unsigned n )
  68. {
  69. unsigned i;
  70. for(i=0; i<n; ++i)
  71. {
  72. cmDListIndexRecd_t* s = cmMemAllocZ(cmDListIndexRecd_t,1);
  73. s->prev = x->last;
  74. if( x->last != NULL )
  75. x->last->next = s;
  76. else
  77. {
  78. assert( x->first == NULL );
  79. x->first = s;
  80. }
  81. x->last = s;
  82. }
  83. x->recdN += n;
  84. }
  85. void _cmDListRecdFree( cmDList_t* p, cmDListRecd_t* r )
  86. {
  87. if( r->prev != NULL )
  88. r->prev->next = r->next;
  89. else
  90. p->first = r->next;
  91. if( r->next != NULL )
  92. r->next->prev = r->prev;
  93. else
  94. p->last = r->prev;
  95. cmMemFree(r);
  96. }
  97. // Unlink and free the index record s;
  98. void _cmDListIndexRecdFree( cmDListIndex_t* x, cmDListIndexRecd_t* s )
  99. {
  100. if( s->prev != NULL )
  101. s->prev->next = s->next;
  102. else
  103. x->first = s->next;
  104. if( s->next != NULL )
  105. s->next->prev = s->prev;
  106. else
  107. x->last = s->prev;
  108. cmMemFree(s);
  109. }
  110. // Unlink and release an index.
  111. void _cmDListIndexFree( cmDList_t* p, cmDListIndex_t* x )
  112. {
  113. if( x == NULL )
  114. return;
  115. cmDListIndex_t* x0 = NULL;
  116. cmDListIndex_t* x1 = p->indexes;
  117. // unlink 'x' from p->indexes
  118. while( x1 != NULL )
  119. {
  120. if( x1 == x )
  121. {
  122. // x is the first index
  123. if( x0 == NULL )
  124. {
  125. assert( x1 == p->indexes );
  126. p->indexes = x->link;
  127. }
  128. else
  129. {
  130. x0->link = x1->link;
  131. }
  132. break;
  133. }
  134. x0 = x1;
  135. x1 = x1->link;
  136. }
  137. // 'x' must have been found
  138. assert( x1 == x );
  139. // release each index record in 'x'
  140. cmDListIndexRecd_t* s = x->first;
  141. while( s != NULL )
  142. {
  143. cmDListIndexRecd_t* ns = s->next;
  144. cmMemFree(s);
  145. s = ns;
  146. }
  147. if( x->freeFunc != NULL )
  148. x->freeFunc(x->id,x->funcArg);
  149. cmMemFree(x);
  150. }
  151. // Unlink and release the iterator 'e'.
  152. cmDlRC_t _cmDListIterFree( cmDListIter_t* e )
  153. {
  154. cmDList_t* p = e->p;
  155. cmDListIter_t* e0 = NULL;
  156. cmDListIter_t* e1 = p->iters;
  157. while( e1 != NULL )
  158. {
  159. if( e1 == e )
  160. {
  161. if( e0 == NULL )
  162. p->iters = e1->link;
  163. else
  164. e0->link = e1->link;
  165. cmMemFree(e1);
  166. break;
  167. }
  168. e0 = e1;
  169. e1 = e1->link;
  170. }
  171. if( e1 == NULL )
  172. return cmErrMsg(&p->err,kIterNotFoundDlRC,"The delete target iterator could not be found.");
  173. return kOkDlRC;
  174. }
  175. cmDlRC_t _cmDListFree( cmDList_t* p )
  176. {
  177. cmDlRC_t rc = kOkDlRC;
  178. // release all indexes
  179. while( p->indexes != NULL )
  180. _cmDListIndexFree(p,p->indexes);
  181. while( p->iters != NULL )
  182. _cmDListIterFree(p->iters);
  183. // release all data records
  184. while( p->first != NULL )
  185. _cmDListRecdFree(p,p->first);
  186. cmMemFree(p);
  187. return rc;
  188. }
  189. void _cmDListIndexUpdate( cmDList_t* p, cmDListIndex_t* x )
  190. {
  191. cmDListIndexRecd_t* first = NULL;
  192. cmDListIndexRecd_t* last = NULL;
  193. assert( x->recdN >= p->recdN );
  194. // for each data recd
  195. cmDListRecd_t* r = p->first;
  196. for(; r!=NULL; r=r->next)
  197. {
  198. // get the next available index record
  199. cmDListIndexRecd_t* a = x->first;
  200. assert(a!=NULL);
  201. x->first = x->first->next;
  202. if( x->first != NULL )
  203. x->first->prev = NULL;
  204. // The count of index records and data records should always be the same.
  205. assert( a != NULL );
  206. a->r = r;
  207. cmDListIndexRecd_t* s = first;
  208. // for each index recd that has already been sorted
  209. for(; s!=NULL; s=s->next)
  210. if( x->cmpFunc( x->funcArg, r->dV, r->dN, s->r->dV, s->r->dN ) < 0 )
  211. {
  212. // r is less than s->r
  213. // insert 'a' prior to 's' in the index
  214. a->next = s;
  215. a->prev = s->prev;
  216. // if 's' is not first
  217. if( s->prev != NULL )
  218. s->prev->next = a;
  219. else
  220. { // 's' was first - now 'a' is first
  221. assert( s == first );
  222. first = a;
  223. }
  224. s->prev = a;
  225. break;
  226. }
  227. // No records are greater than r or the index is empty - 'a' is last in the index.
  228. if( s == NULL )
  229. {
  230. // insert 'a' after 'last'
  231. // if the index is empty
  232. if( last == NULL )
  233. {
  234. first = a;
  235. a->prev = NULL;
  236. }
  237. else // make 'a' last in the index
  238. {
  239. a->prev = last;
  240. a->next = NULL;
  241. assert( last->next == NULL );
  242. last->next = a;
  243. }
  244. a->next = NULL;
  245. last = a;
  246. }
  247. }
  248. // release any index records that are not in use
  249. while(x->first!=NULL)
  250. {
  251. _cmDListIndexRecdFree(x,x->first);
  252. x->recdN -= 1;
  253. }
  254. assert( x->recdN == p->recdN );
  255. // Invalidate all iterators which use index x.
  256. cmDListIter_t* e = p->iters;
  257. for(; e!=NULL; e=e->link)
  258. if( e->x == x )
  259. e->s = NULL;
  260. x->first = first;
  261. x->last = last;
  262. }
  263. cmDlRC_t _cmDListIndexAlloc( cmDList_t* p, unsigned indexId, cmDListCmpFunc_t func, void* funcArg )
  264. {
  265. cmDListIndex_t* x;
  266. if((x =_cmDListIdToIndex(p, indexId )) != NULL )
  267. return cmErrMsg(&p->err,kDuplicateIndexIdDlRC,"The indexId '%i' has already been used.",indexId);
  268. x = cmMemAllocZ(cmDListIndex_t,1);
  269. x->id = indexId;
  270. x->cmpFunc = func;
  271. x->funcArg = funcArg;
  272. x->link = p->indexes;
  273. p->indexes = x;
  274. _cmDListIndexAllocRecds(x,p->recdN);
  275. _cmDListIndexUpdate(p,x);
  276. return kOkDlRC;
  277. }
  278. cmDlRC_t cmDListAlloc( cmCtx_t* ctx, cmDListH_t* hp, cmDListCmpFunc_t func, void* funcArg )
  279. {
  280. cmDlRC_t rc = kOkDlRC;
  281. if((rc = cmDListFree(hp)) != kOkDlRC )
  282. return rc;
  283. cmDList_t* p = cmMemAllocZ(cmDList_t,1);
  284. cmErrSetup(&p->err,&ctx->rpt,"cmDList");
  285. if( func!=NULL )
  286. if((rc = _cmDListIndexAlloc(p,0,func,funcArg)) != kOkDlRC )
  287. goto errLabel;
  288. hp->h = p;
  289. errLabel:
  290. if( rc != kOkDlRC )
  291. _cmDListFree(p);
  292. return rc;
  293. }
  294. cmDlRC_t cmDListFree( cmDListH_t* hp )
  295. {
  296. cmDlRC_t rc;
  297. if( hp==NULL || cmDListIsValid(*hp)==false)
  298. return kOkDlRC;
  299. cmDList_t* p = _cmDListHandleToPtr(*hp);
  300. if((rc = _cmDListFree(p)) != kOkDlRC )
  301. return rc;
  302. hp->h = NULL;
  303. return rc;
  304. }
  305. bool cmDListIsValid( cmDListH_t h )
  306. { return h.h != NULL; }
  307. cmDlRC_t cmDListInsert( cmDListH_t h, const void* recd, unsigned recdByteN, bool resyncFl )
  308. {
  309. cmDList_t* p = _cmDListHandleToPtr(h);
  310. char* vp = cmMemAllocZ(char,sizeof(cmDListRecd_t) + recdByteN );
  311. cmDListRecd_t* r = (cmDListRecd_t*)vp;
  312. r->dV = r + 1;
  313. r->dN = recdByteN;
  314. memcpy( r->dV, recd, recdByteN );
  315. // Add records at the end of the data record list.
  316. // If the list is not empty
  317. if( p->last != NULL )
  318. p->last->next = r;
  319. else
  320. {
  321. // The list was empty
  322. assert( p->first == NULL );
  323. p->first = r;
  324. }
  325. r->prev = p->last;
  326. r->next = NULL;
  327. p->last = r;
  328. p->recdN += 1;
  329. // add a record to each index
  330. cmDListIndex_t* x = p->indexes;
  331. for(; x!=NULL; x=x->link)
  332. {
  333. if( x->recdN < p->recdN )
  334. _cmDListIndexAllocRecds(x,1);
  335. assert( x->recdN >= p->recdN );
  336. if( resyncFl )
  337. _cmDListIndexUpdate(p,x);
  338. }
  339. return kOkDlRC;
  340. }
  341. cmDlRC_t cmDListDelete( cmDListH_t h, const void* recd, bool resyncFl )
  342. {
  343. cmDList_t* p = _cmDListHandleToPtr(h);
  344. cmDListIndex_t* x = p->indexes;
  345. cmDListIndexRecd_t* s = NULL;
  346. cmDListRecd_t* r = NULL;
  347. if( resyncFl==false )
  348. {
  349. r = p->first;
  350. for(; r!=NULL; r=r->next)
  351. if( r->dV == recd )
  352. {
  353. _cmDListRecdFree(p,r);
  354. break;
  355. }
  356. }
  357. else
  358. {
  359. // for each index
  360. for(; x!=NULL; x=x->link)
  361. {
  362. // for each index recd
  363. for(s=x->first; s!=NULL; s=s->next)
  364. if( s->r->dV == recd ) // if this index recd points to the deletion target
  365. {
  366. // store a ptr to the data recd to be deleted
  367. if( r == NULL )
  368. r = s->r;
  369. else
  370. {
  371. // the same data record should be found for all indexes
  372. assert( s->r == r );
  373. }
  374. // free the index record
  375. _cmDListIndexRecdFree(x,s);
  376. break;
  377. }
  378. // if the deletion target was not found
  379. if( r == NULL )
  380. goto errLabel;
  381. }
  382. // advance any iterators that are pointing to the deleted record
  383. cmDListIter_t* e = p->iters;
  384. for(; e!=NULL; e=e->link)
  385. if( e->s != NULL && e->s->r != NULL && e->s->r == r )
  386. e->s = e->s->next;
  387. // release the data record
  388. _cmDListRecdFree(p,r);
  389. }
  390. errLabel:
  391. if( r == NULL )
  392. return cmErrMsg(&p->err,kDataRecdNotFoundDlRC,"The deletion target record could not be found.");
  393. assert( p->recdN > 0 );
  394. p->recdN -= 1;
  395. return kOkDlRC;
  396. }
  397. cmDlRC_t cmDListIndexAlloc( cmDListH_t h, unsigned indexId, cmDListCmpFunc_t func, void* funcArg )
  398. {
  399. cmDList_t* p = _cmDListHandleToPtr(h);
  400. return _cmDListIndexAlloc(p,indexId,func,funcArg);
  401. }
  402. cmDlRC_t cmDListIndexFree( cmDListH_t h, unsigned indexId )
  403. {
  404. cmDList_t* p = _cmDListHandleToPtr(h);
  405. cmDListIndex_t* x;
  406. if((x = _cmDListIdToIndex(p,indexId)) == NULL )
  407. return cmErrMsg(&p->err,kInvalidIndexDlRC,"The indexId '%i' could not be found.",indexId);
  408. _cmDListIndexFree(p,x);
  409. return kOkDlRC;
  410. }
  411. cmDlRC_t cmDListIndexSetFreeFunc(cmDListH_t h, unsigned indexId, cmDListIndexFreeFunc_t func )
  412. {
  413. cmDList_t* p = _cmDListHandleToPtr(h);
  414. cmDListIndex_t* x;
  415. if((x = _cmDListIdToIndex(p,indexId)) == NULL )
  416. return cmErrMsg(&p->err,kInvalidIndexDlRC,"The indexId '%i' could not be found.",indexId);
  417. x->freeFunc = func;
  418. return kOkDlRC;
  419. }
  420. cmDlRC_t cmDListIndexUpdateAll( cmDListH_t h )
  421. {
  422. cmDList_t* p = _cmDListHandleToPtr(h);
  423. cmDListIndex_t* x = p->indexes;
  424. for(; x!=NULL; x=x->link)
  425. _cmDListIndexUpdate(p,x);
  426. return kOkDlRC;
  427. }
  428. cmDListIter_t* _cmDListIterHandleToPtr( cmDListIterH_t h )
  429. {
  430. cmDListIter_t* e = (cmDListIter_t*)h.h;
  431. assert(e != NULL );
  432. return e;
  433. }
  434. cmDlRC_t cmDListIterAlloc( cmDListH_t h, cmDListIterH_t* iHp, unsigned indexId )
  435. {
  436. cmDlRC_t rc = kOkDlRC;
  437. cmDList_t* p = _cmDListHandleToPtr(h);
  438. cmDListIndex_t* x;
  439. if((rc = cmDListIterFree(iHp)) != kOkDlRC )
  440. return rc;
  441. if((x = _cmDListIdToIndex(p, indexId)) == NULL )
  442. return cmErrMsg(&p->err,kInvalidIndexDlRC,"The indexId '%i' could not be found.",indexId);
  443. cmDListIter_t* e = cmMemAllocZ(cmDListIter_t,1);
  444. e->p = p;
  445. e->x = x;
  446. e->s = x->first;
  447. e->link = p->iters;
  448. p->iters = e;
  449. iHp->h = e;
  450. return rc;
  451. }
  452. cmDlRC_t cmDListIterFree( cmDListIterH_t* iHp )
  453. {
  454. cmDlRC_t rc;
  455. if( iHp==NULL || cmDListIterIsValid(*iHp)==false )
  456. return kOkDlRC;
  457. cmDListIter_t* e = _cmDListIterHandleToPtr(*iHp);
  458. if(( rc = _cmDListIterFree( e )) != kOkDlRC )
  459. return rc;
  460. iHp->h = NULL;
  461. return rc;
  462. }
  463. bool cmDListIterIsValid( cmDListIterH_t iH )
  464. { return iH.h != NULL; }
  465. cmDlRC_t cmDListIterSeekBegin( cmDListIterH_t iH )
  466. {
  467. cmDListIter_t* e = _cmDListIterHandleToPtr(iH);
  468. e->s = e->x->first;
  469. return kOkDlRC;
  470. }
  471. cmDlRC_t cmDListIterSeekLast( cmDListIterH_t iH )
  472. {
  473. cmDListIter_t* e = _cmDListIterHandleToPtr(iH);
  474. e->s = e->x->last;
  475. return kOkDlRC;
  476. }
  477. const void* _cmDListIterGet( cmDListIter_t* e, unsigned* recdByteNRef )
  478. {
  479. if( e->s == NULL )
  480. {
  481. if( recdByteNRef != NULL )
  482. *recdByteNRef = 0;
  483. return NULL;
  484. }
  485. assert( e->s->r != NULL );
  486. if( recdByteNRef != NULL )
  487. *recdByteNRef = e->s->r->dN;
  488. return e->s->r->dN==0 ? NULL : e->s->r->dV;
  489. }
  490. const void* cmDListIterGet( cmDListIterH_t iH, unsigned* recdByteNRef )
  491. {
  492. cmDListIter_t* e = _cmDListIterHandleToPtr(iH);
  493. return _cmDListIterGet(e,recdByteNRef);
  494. }
  495. const void* cmDListIterPrev( cmDListIterH_t iH, unsigned* recdByteNRef )
  496. {
  497. cmDListIter_t* e = _cmDListIterHandleToPtr(iH);
  498. const void* rv = _cmDListIterGet(e,recdByteNRef);
  499. if( e->s != NULL )
  500. e->s = e->s->prev;
  501. return rv;
  502. }
  503. const void* cmDListIterNext( cmDListIterH_t iH, unsigned* recdByteNRef )
  504. {
  505. cmDListIter_t* e = _cmDListIterHandleToPtr(iH);
  506. const void* rv = _cmDListIterGet(e,recdByteNRef);
  507. if( e->s != NULL )
  508. e->s = e->s->next;
  509. return rv;
  510. }
  511. const void* cmDListIterFind( cmDListIterH_t iH, const void* key, unsigned keyN, unsigned* recdByteNRef)
  512. {
  513. cmDListIter_t* e = _cmDListIterHandleToPtr(iH);
  514. cmDListIndexRecd_t* s = e->s;
  515. for(; s!=NULL; s=s->next)
  516. if( e->x->cmpFunc( e->x->funcArg, s->r->dV, s->r->dN, key, keyN ) == 0 )
  517. {
  518. e->s = s;
  519. return _cmDListIterGet(e,recdByteNRef);
  520. }
  521. if( recdByteNRef != NULL )
  522. *recdByteNRef = 0;
  523. return NULL;
  524. }