libcm is a C development framework with an emphasis on audio signal processing applications.
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

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. }