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.

cmDList.c 14KB

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