/source/blender/blenlib/intern/listbase.c

https://bitbucket.org/brita/blender-gl_debug · C · 587 lines · 344 code · 107 blank · 136 comment · 108 complexity · cccb817668749fa36fb1d3b382a60c52 MD5 · raw file

  1. /*
  2. * ***** BEGIN GPL LICENSE BLOCK *****
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version 2
  7. * of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software Foundation,
  16. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  17. *
  18. * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
  19. * All rights reserved.
  20. *
  21. * The Original Code is: all of this file.
  22. *
  23. * Contributor(s): none yet.
  24. *
  25. * ***** END GPL LICENSE BLOCK *****
  26. *
  27. */
  28. /** \file blender/blenlib/intern/listbase.c
  29. * \ingroup bli
  30. *
  31. * Manipulations on ListBase structs
  32. */
  33. #include <string.h>
  34. #include <stdlib.h>
  35. #include "MEM_guardedalloc.h"
  36. #include "DNA_listBase.h"
  37. #include "BLI_listbase.h"
  38. /* implementation */
  39. /**
  40. * moves the entire contents of \a src onto the end of \a dst.
  41. */
  42. void BLI_movelisttolist(ListBase *dst, ListBase *src)
  43. {
  44. if (src->first == NULL) return;
  45. if (dst->first == NULL) {
  46. dst->first = src->first;
  47. dst->last = src->last;
  48. }
  49. else {
  50. ((Link *)dst->last)->next = src->first;
  51. ((Link *)src->first)->prev = dst->last;
  52. dst->last = src->last;
  53. }
  54. src->first = src->last = NULL;
  55. }
  56. /**
  57. * Prepends \a vlink (assumed to begin with a Link) onto listbase.
  58. */
  59. void BLI_addhead(ListBase *listbase, void *vlink)
  60. {
  61. Link *link = vlink;
  62. if (link == NULL) return;
  63. link->next = listbase->first;
  64. link->prev = NULL;
  65. if (listbase->first) ((Link *)listbase->first)->prev = link;
  66. if (listbase->last == NULL) listbase->last = link;
  67. listbase->first = link;
  68. }
  69. /**
  70. * Appends \a vlink (assumed to begin with a Link) onto listbase.
  71. */
  72. void BLI_addtail(ListBase *listbase, void *vlink)
  73. {
  74. Link *link = vlink;
  75. if (link == NULL) return;
  76. link->next = NULL;
  77. link->prev = listbase->last;
  78. if (listbase->last) ((Link *)listbase->last)->next = link;
  79. if (listbase->first == NULL) listbase->first = link;
  80. listbase->last = link;
  81. }
  82. /**
  83. * Removes \a vlink from \a listbase. Assumes it is linked into there!
  84. */
  85. void BLI_remlink(ListBase *listbase, void *vlink)
  86. {
  87. Link *link = vlink;
  88. if (link == NULL) return;
  89. if (link->next) link->next->prev = link->prev;
  90. if (link->prev) link->prev->next = link->next;
  91. if (listbase->last == link) listbase->last = link->prev;
  92. if (listbase->first == link) listbase->first = link->next;
  93. }
  94. /**
  95. * Checks that \a vlink is linked into listbase, removing it from there if so.
  96. */
  97. bool BLI_remlink_safe(ListBase *listbase, void *vlink)
  98. {
  99. if (BLI_findindex(listbase, vlink) != -1) {
  100. BLI_remlink(listbase, vlink);
  101. return true;
  102. }
  103. else {
  104. return false;
  105. }
  106. }
  107. /**
  108. * Removes \a vlink from listbase and disposes of it. Assumes it is linked into there!
  109. */
  110. void BLI_freelinkN(ListBase *listbase, void *vlink)
  111. {
  112. Link *link = vlink;
  113. if (link == NULL) return;
  114. BLI_remlink(listbase, link);
  115. MEM_freeN(link);
  116. }
  117. /**
  118. * Sorts the elements of listbase into the order defined by cmp
  119. * (which should return 1 iff its first arg should come after its second arg).
  120. * This uses insertion sort, so NOT ok for large list.
  121. */
  122. void BLI_sortlist(ListBase *listbase, int (*cmp)(void *, void *))
  123. {
  124. Link *current = NULL;
  125. Link *previous = NULL;
  126. Link *next = NULL;
  127. if (cmp == NULL) return;
  128. if (listbase->first != listbase->last) {
  129. for (previous = listbase->first, current = previous->next; current; current = next) {
  130. next = current->next;
  131. previous = current->prev;
  132. BLI_remlink(listbase, current);
  133. while (previous && cmp(previous, current) == 1) {
  134. previous = previous->prev;
  135. }
  136. BLI_insertlinkafter(listbase, previous, current);
  137. }
  138. }
  139. }
  140. /**
  141. * Inserts \a vnewlink immediately following \a vprevlink in \a listbase.
  142. * Or, if \a vprevlink is NULL, puts \a vnewlink at the front of the list.
  143. */
  144. void BLI_insertlinkafter(ListBase *listbase, void *vprevlink, void *vnewlink)
  145. {
  146. Link *prevlink = vprevlink;
  147. Link *newlink = vnewlink;
  148. /* newlink before nextlink */
  149. if (newlink == NULL) return;
  150. /* empty list */
  151. if (listbase->first == NULL) {
  152. listbase->first = newlink;
  153. listbase->last = newlink;
  154. return;
  155. }
  156. /* insert at head of list */
  157. if (prevlink == NULL) {
  158. newlink->prev = NULL;
  159. newlink->next = listbase->first;
  160. newlink->next->prev = newlink;
  161. listbase->first = newlink;
  162. return;
  163. }
  164. /* at end of list */
  165. if (listbase->last == prevlink) {
  166. listbase->last = newlink;
  167. }
  168. newlink->next = prevlink->next;
  169. newlink->prev = prevlink;
  170. prevlink->next = newlink;
  171. if (newlink->next) {
  172. newlink->next->prev = newlink;
  173. }
  174. }
  175. /**
  176. * Inserts \a vnewlink immediately preceding \a vnextlink in listbase.
  177. * Or, if \a vnextlink is NULL, puts \a vnewlink at the end of the list.
  178. */
  179. void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink)
  180. {
  181. Link *nextlink = vnextlink;
  182. Link *newlink = vnewlink;
  183. /* newlink before nextlink */
  184. if (newlink == NULL) return;
  185. /* empty list */
  186. if (listbase->first == NULL) {
  187. listbase->first = newlink;
  188. listbase->last = newlink;
  189. return;
  190. }
  191. /* insert at end of list */
  192. if (nextlink == NULL) {
  193. newlink->prev = listbase->last;
  194. newlink->next = NULL;
  195. ((Link *)listbase->last)->next = newlink;
  196. listbase->last = newlink;
  197. return;
  198. }
  199. /* at beginning of list */
  200. if (listbase->first == nextlink) {
  201. listbase->first = newlink;
  202. }
  203. newlink->next = nextlink;
  204. newlink->prev = nextlink->prev;
  205. nextlink->prev = newlink;
  206. if (newlink->prev) {
  207. newlink->prev->next = newlink;
  208. }
  209. }
  210. /**
  211. * Removes and disposes of the entire contents of listbase using direct free(3).
  212. */
  213. void BLI_freelist(ListBase *listbase)
  214. {
  215. Link *link, *next;
  216. link = listbase->first;
  217. while (link) {
  218. next = link->next;
  219. free(link);
  220. link = next;
  221. }
  222. listbase->first = NULL;
  223. listbase->last = NULL;
  224. }
  225. /**
  226. * Removes and disposes of the entire contents of \a listbase using guardedalloc.
  227. */
  228. void BLI_freelistN(ListBase *listbase)
  229. {
  230. Link *link, *next;
  231. link = listbase->first;
  232. while (link) {
  233. next = link->next;
  234. MEM_freeN(link);
  235. link = next;
  236. }
  237. listbase->first = NULL;
  238. listbase->last = NULL;
  239. }
  240. /**
  241. * Returns the number of elements in \a listbase.
  242. */
  243. int BLI_countlist(const ListBase *listbase)
  244. {
  245. Link *link;
  246. int count = 0;
  247. if (listbase) {
  248. link = listbase->first;
  249. while (link) {
  250. count++;
  251. link = link->next;
  252. }
  253. }
  254. return count;
  255. }
  256. /**
  257. * Returns the nth element of \a listbase, numbering from 1.
  258. */
  259. void *BLI_findlink(const ListBase *listbase, int number)
  260. {
  261. Link *link = NULL;
  262. if (number >= 0) {
  263. link = listbase->first;
  264. while (link != NULL && number != 0) {
  265. number--;
  266. link = link->next;
  267. }
  268. }
  269. return link;
  270. }
  271. /**
  272. * Returns the nth-last element of \a listbase, numbering from 1.
  273. */
  274. void *BLI_rfindlink(const ListBase *listbase, int number)
  275. {
  276. Link *link = NULL;
  277. if (number >= 0) {
  278. link = listbase->last;
  279. while (link != NULL && number != 0) {
  280. number--;
  281. link = link->prev;
  282. }
  283. }
  284. return link;
  285. }
  286. /**
  287. * Returns the position of \a vlink within \a listbase, numbering from 1, or -1 if not found.
  288. */
  289. int BLI_findindex(const ListBase *listbase, const void *vlink)
  290. {
  291. Link *link = NULL;
  292. int number = 0;
  293. if (vlink == NULL) return -1;
  294. link = listbase->first;
  295. while (link) {
  296. if (link == vlink)
  297. return number;
  298. number++;
  299. link = link->next;
  300. }
  301. return -1;
  302. }
  303. /**
  304. * Finds the first element of \a listbase which contains the null-terminated
  305. * string \a id at the specified offset, returning NULL if not found.
  306. */
  307. void *BLI_findstring(const ListBase *listbase, const char *id, const int offset)
  308. {
  309. Link *link = NULL;
  310. const char *id_iter;
  311. for (link = listbase->first; link; link = link->next) {
  312. id_iter = ((const char *)link) + offset;
  313. if (id[0] == id_iter[0] && strcmp(id, id_iter) == 0) {
  314. return link;
  315. }
  316. }
  317. return NULL;
  318. }
  319. /* same as above but find reverse */
  320. /**
  321. * Finds the last element of \a listbase which contains the
  322. * null-terminated string \a id at the specified offset, returning NULL if not found.
  323. */
  324. void *BLI_rfindstring(const ListBase *listbase, const char *id, const int offset)
  325. {
  326. Link *link = NULL;
  327. const char *id_iter;
  328. for (link = listbase->last; link; link = link->prev) {
  329. id_iter = ((const char *)link) + offset;
  330. if (id[0] == id_iter[0] && strcmp(id, id_iter) == 0) {
  331. return link;
  332. }
  333. }
  334. return NULL;
  335. }
  336. /**
  337. * Finds the first element of \a listbase which contains a pointer to the
  338. * null-terminated string \a id at the specified offset, returning NULL if not found.
  339. */
  340. void *BLI_findstring_ptr(const ListBase *listbase, const char *id, const int offset)
  341. {
  342. Link *link = NULL;
  343. const char *id_iter;
  344. for (link = listbase->first; link; link = link->next) {
  345. /* exact copy of BLI_findstring(), except for this line */
  346. id_iter = *((const char **)(((const char *)link) + offset));
  347. if (id[0] == id_iter[0] && strcmp(id, id_iter) == 0) {
  348. return link;
  349. }
  350. }
  351. return NULL;
  352. }
  353. /* same as above but find reverse */
  354. /**
  355. * Finds the last element of \a listbase which contains a pointer to the
  356. * null-terminated string \a id at the specified offset, returning NULL if not found.
  357. */
  358. void *BLI_rfindstring_ptr(const ListBase *listbase, const char *id, const int offset)
  359. {
  360. Link *link = NULL;
  361. const char *id_iter;
  362. for (link = listbase->last; link; link = link->prev) {
  363. /* exact copy of BLI_rfindstring(), except for this line */
  364. id_iter = *((const char **)(((const char *)link) + offset));
  365. if (id[0] == id_iter[0] && strcmp(id, id_iter) == 0) {
  366. return link;
  367. }
  368. }
  369. return NULL;
  370. }
  371. /**
  372. * Finds the first element of listbase which contains the specified pointer value
  373. * at the specified offset, returning NULL if not found.
  374. */
  375. void *BLI_findptr(const ListBase *listbase, const void *ptr, const int offset)
  376. {
  377. Link *link = NULL;
  378. const void *ptr_iter;
  379. for (link = listbase->first; link; link = link->next) {
  380. /* exact copy of BLI_findstring(), except for this line */
  381. ptr_iter = *((const void **)(((const char *)link) + offset));
  382. if (ptr == ptr_iter) {
  383. return link;
  384. }
  385. }
  386. return NULL;
  387. }
  388. /* same as above but find reverse */
  389. /**
  390. * Finds the last element of listbase which contains the specified pointer value
  391. * at the specified offset, returning NULL if not found.
  392. */
  393. void *BLI_rfindptr(const ListBase *listbase, const void *ptr, const int offset)
  394. {
  395. Link *link = NULL;
  396. const void *ptr_iter;
  397. for (link = listbase->last; link; link = link->prev) {
  398. /* exact copy of BLI_rfindstring(), except for this line */
  399. ptr_iter = *((const void **)(((const char *)link) + offset));
  400. if (ptr == ptr_iter) {
  401. return link;
  402. }
  403. }
  404. return NULL;
  405. }
  406. /**
  407. * Returns the 1-based index of the first element of listbase which contains the specified
  408. * null-terminated string at the specified offset, or -1 if not found.
  409. */
  410. int BLI_findstringindex(const ListBase *listbase, const char *id, const int offset)
  411. {
  412. Link *link = NULL;
  413. const char *id_iter;
  414. int i = 0;
  415. link = listbase->first;
  416. while (link) {
  417. id_iter = ((const char *)link) + offset;
  418. if (id[0] == id_iter[0] && strcmp(id, id_iter) == 0)
  419. return i;
  420. i++;
  421. link = link->next;
  422. }
  423. return -1;
  424. }
  425. /**
  426. * Sets dst to a duplicate of the entire contents of src. dst may be the same as src.
  427. */
  428. void BLI_duplicatelist(ListBase *dst, const ListBase *src)
  429. {
  430. struct Link *dst_link, *src_link;
  431. /* in this order, to ensure it works if dst == src */
  432. src_link = src->first;
  433. dst->first = dst->last = NULL;
  434. while (src_link) {
  435. dst_link = MEM_dupallocN(src_link);
  436. BLI_addtail(dst, dst_link);
  437. src_link = src_link->next;
  438. }
  439. }
  440. void BLI_reverselist(ListBase *lb)
  441. {
  442. struct Link *curr = lb->first;
  443. struct Link *prev = NULL;
  444. struct Link *next = NULL;
  445. while (curr) {
  446. next = curr->next;
  447. curr->next = prev;
  448. curr->prev = next;
  449. prev = curr;
  450. curr = next;
  451. }
  452. /* swap first/last */
  453. curr = lb->first;
  454. lb->first = lb->last;
  455. lb->last = curr;
  456. }
  457. /**
  458. * \param vlink Link to make first.
  459. */
  460. void BLI_rotatelist(ListBase *lb, LinkData *vlink)
  461. {
  462. /* make circular */
  463. ((LinkData *)lb->first)->prev = lb->last;
  464. ((LinkData *)lb->last)->next = lb->first;
  465. lb->first = vlink;
  466. lb->last = vlink->prev;
  467. ((LinkData *)lb->first)->prev = NULL;
  468. ((LinkData *)lb->last)->next = NULL;
  469. }
  470. /* create a generic list node containing link to provided data */
  471. LinkData *BLI_genericNodeN(void *data)
  472. {
  473. LinkData *ld;
  474. if (data == NULL)
  475. return NULL;
  476. /* create new link, and make it hold the given data */
  477. ld = MEM_callocN(sizeof(LinkData), __func__);
  478. ld->data = data;
  479. return ld;
  480. }