libcm is a C development framework with an emphasis on audio signal processing applications.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

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