ptrlist.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. /*
  2. * ptrlist.c
  3. *
  4. * (C) Copyright Linus Torvalds 2003-2005
  5. */
  6. ///
  7. // Pointer list manipulation
  8. // -------------------------
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <assert.h>
  12. #include "ptrlist.h"
  13. #include "allocate.h"
  14. #include "compat.h"
  15. __DECLARE_ALLOCATOR(struct ptr_list, ptrlist);
  16. __ALLOCATOR(struct ptr_list, "ptr list", ptrlist);
  17. ///
  18. // get the size of a ptrlist
  19. // @head: the head of the list
  20. // @return: the size of the list given by @head.
  21. int ptr_list_size(struct ptr_list *head)
  22. {
  23. int nr = 0;
  24. if (head) {
  25. struct ptr_list *list = head;
  26. do {
  27. nr += list->nr - list->rm;
  28. } while ((list = list->next) != head);
  29. }
  30. return nr;
  31. }
  32. ///
  33. // test if a list is empty
  34. // @head: the head of the list
  35. // @return: ``true`` if the list is empty, ``false`` otherwise.
  36. bool ptr_list_empty(const struct ptr_list *head)
  37. {
  38. const struct ptr_list *list = head;
  39. if (!head)
  40. return true;
  41. do {
  42. if (list->nr - list->rm)
  43. return false;
  44. } while ((list = list->next) != head);
  45. return true;
  46. }
  47. ///
  48. // test is a list contains more than one element
  49. // @head: the head of the list
  50. // @return: ``true`` if the list has more than 1 element, ``false`` otherwise.
  51. bool ptr_list_multiple(const struct ptr_list *head)
  52. {
  53. const struct ptr_list *list = head;
  54. int nr = 0;
  55. if (!head)
  56. return false;
  57. do {
  58. nr += list->nr - list->rm;
  59. if (nr > 1)
  60. return true;
  61. } while ((list = list->next) != head);
  62. return false;
  63. }
  64. ///
  65. // get the first element of a ptrlist
  66. // @head: the head of the list
  67. // @return: the first element of the list or ``NULL`` if the list is empty
  68. void *first_ptr_list(struct ptr_list *head)
  69. {
  70. struct ptr_list *list = head;
  71. if (!head)
  72. return NULL;
  73. while (list->nr == 0) {
  74. list = list->next;
  75. if (list == head)
  76. return NULL;
  77. }
  78. return PTR_ENTRY_NOTAG(list, 0);
  79. }
  80. ///
  81. // get the last element of a ptrlist
  82. // @head: the head of the list
  83. // @return: the last element of the list or ``NULL`` if the list is empty
  84. void *last_ptr_list(struct ptr_list *head)
  85. {
  86. struct ptr_list *list;
  87. if (!head)
  88. return NULL;
  89. list = head->prev;
  90. while (list->nr == 0) {
  91. if (list == head)
  92. return NULL;
  93. list = list->prev;
  94. }
  95. return PTR_ENTRY_NOTAG(list, list->nr-1);
  96. }
  97. ///
  98. // get the nth element of a ptrlist
  99. // @head: the head of the list
  100. // @return: the nth element of the list or ``NULL`` if the list is too short.
  101. void *ptr_list_nth_entry(struct ptr_list *list, unsigned int idx)
  102. {
  103. struct ptr_list *head = list;
  104. if (!head)
  105. return NULL;
  106. do {
  107. unsigned int nr = list->nr;
  108. if (idx < nr)
  109. return list->list[idx];
  110. else
  111. idx -= nr;
  112. } while ((list = list->next) != head);
  113. return NULL;
  114. }
  115. ///
  116. // linearize the entries of a list
  117. //
  118. // @head: the list to be linearized
  119. // @arr: a ``void*`` array to fill with @head's entries
  120. // @max: the maximum number of entries to store into @arr
  121. // @return: the number of entries linearized.
  122. //
  123. // Linearize the entries of a list up to a total of @max,
  124. // and return the nr of entries linearized.
  125. //
  126. // The array to linearize into (@arr) should really
  127. // be ``void *x[]``, but we want to let people fill in any kind
  128. // of pointer array, so let's just call it ``void **``.
  129. int linearize_ptr_list(struct ptr_list *head, void **arr, int max)
  130. {
  131. int nr = 0;
  132. if (head && max > 0) {
  133. struct ptr_list *list = head;
  134. do {
  135. int i = list->nr;
  136. if (i > max)
  137. i = max;
  138. memcpy(arr, list->list, i*sizeof(void *));
  139. arr += i;
  140. nr += i;
  141. max -= i;
  142. if (!max)
  143. break;
  144. } while ((list = list->next) != head);
  145. }
  146. return nr;
  147. }
  148. ///
  149. // pack a ptrlist
  150. //
  151. // @listp: a pointer to the list to be packed.
  152. //
  153. // When we've walked the list and deleted entries,
  154. // we may need to re-pack it so that we don't have
  155. // any empty blocks left (empty blocks upset the
  156. // walking code).
  157. void pack_ptr_list(struct ptr_list **listp)
  158. {
  159. struct ptr_list *head = *listp;
  160. if (head) {
  161. struct ptr_list *entry = head;
  162. do {
  163. struct ptr_list *next;
  164. restart:
  165. next = entry->next;
  166. if (!entry->nr) {
  167. struct ptr_list *prev;
  168. if (next == entry) {
  169. __free_ptrlist(entry);
  170. *listp = NULL;
  171. return;
  172. }
  173. prev = entry->prev;
  174. prev->next = next;
  175. next->prev = prev;
  176. __free_ptrlist(entry);
  177. if (entry == head) {
  178. *listp = next;
  179. head = next;
  180. entry = next;
  181. goto restart;
  182. }
  183. }
  184. entry = next;
  185. } while (entry != head);
  186. }
  187. }
  188. ///
  189. // split a ptrlist block
  190. // @head: the ptrlist block to be split
  191. //
  192. // A new block is inserted just after @head and the entries
  193. // at the half end of @head are moved to this new block.
  194. // The goal being to create space inside @head for a new entry.
  195. void split_ptr_list_head(struct ptr_list *head)
  196. {
  197. int old = head->nr, nr = old / 2;
  198. struct ptr_list *newlist = __alloc_ptrlist(0);
  199. struct ptr_list *next = head->next;
  200. old -= nr;
  201. head->nr = old;
  202. newlist->next = next;
  203. next->prev = newlist;
  204. newlist->prev = head;
  205. head->next = newlist;
  206. newlist->nr = nr;
  207. memcpy(newlist->list, head->list + old, nr * sizeof(void *));
  208. memset(head->list + old, 0xf0, nr * sizeof(void *));
  209. }
  210. ///
  211. // add an entry to a ptrlist
  212. // @listp: a pointer to the list
  213. // @ptr: the entry to add to the list
  214. // @return: the address where the new entry is stored.
  215. //
  216. // :note: code must not use this function and should use
  217. // :func:`add_ptr_list` instead.
  218. void **__add_ptr_list(struct ptr_list **listp, void *ptr)
  219. {
  220. struct ptr_list *list = *listp;
  221. struct ptr_list *last = NULL; /* gcc complains needlessly */
  222. void **ret;
  223. int nr;
  224. if (!list || (nr = (last = list->prev)->nr) >= LIST_NODE_NR) {
  225. struct ptr_list *newlist = __alloc_ptrlist(0);
  226. if (!list) {
  227. newlist->next = newlist;
  228. newlist->prev = newlist;
  229. *listp = newlist;
  230. } else {
  231. newlist->prev = last;
  232. newlist->next = list;
  233. list->prev = newlist;
  234. last->next = newlist;
  235. }
  236. last = newlist;
  237. nr = 0;
  238. }
  239. ret = last->list + nr;
  240. *ret = ptr;
  241. nr++;
  242. last->nr = nr;
  243. return ret;
  244. }
  245. ///
  246. // add a tagged entry to a ptrlist
  247. // @listp: a pointer to the list
  248. // @ptr: the entry to add to the list
  249. // @tag: the tag to add to @ptr
  250. // @return: the address where the new entry is stored.
  251. //
  252. // :note: code must not use this function and should use
  253. // :func:`add_ptr_list_tag` instead.
  254. void **__add_ptr_list_tag(struct ptr_list **listp, void *ptr, unsigned long tag)
  255. {
  256. /* The low two bits are reserved for tags */
  257. assert((3 & (unsigned long)ptr) == 0);
  258. assert((~3 & tag) == 0);
  259. ptr = (void *)(tag | (unsigned long)ptr);
  260. return __add_ptr_list(listp, ptr);
  261. }
  262. ///
  263. // test if some entry is already present in a ptrlist
  264. // @list: the head of the list
  265. // @entry: the entry to test
  266. // @return: ``true`` if the entry is already present, ``false`` otherwise.
  267. bool lookup_ptr_list_entry(const struct ptr_list *head, const void *entry)
  268. {
  269. const struct ptr_list *list = head;
  270. if (!head)
  271. return false;
  272. do {
  273. int nr = list->nr;
  274. int i;
  275. for (i = 0; i < nr; i++)
  276. if (list->list[i] == entry)
  277. return true;
  278. } while ((list = list->next) != head);
  279. return false;
  280. }
  281. ///
  282. // delete an entry from a ptrlist
  283. // @list: a pointer to the list
  284. // @entry: the item to be deleted
  285. // @count: the minimum number of times @entry should be deleted or 0.
  286. int delete_ptr_list_entry(struct ptr_list **list, void *entry, int count)
  287. {
  288. void *ptr;
  289. FOR_EACH_PTR(*list, ptr) {
  290. if (ptr == entry) {
  291. DELETE_CURRENT_PTR(ptr);
  292. if (!--count)
  293. goto out;
  294. }
  295. } END_FOR_EACH_PTR(ptr);
  296. assert(count <= 0);
  297. out:
  298. pack_ptr_list(list);
  299. return count;
  300. }
  301. ///
  302. // replace an entry in a ptrlist
  303. // @list: a pointer to the list
  304. // @old_ptr: the entry to be replaced
  305. // @new_ptr: the new entry
  306. // @count: the minimum number of times @entry should be deleted or 0.
  307. int replace_ptr_list_entry(struct ptr_list **list, void *old_ptr,
  308. void *new_ptr, int count)
  309. {
  310. void *ptr;
  311. FOR_EACH_PTR(*list, ptr) {
  312. if (ptr==old_ptr) {
  313. REPLACE_CURRENT_PTR(ptr, new_ptr);
  314. if (!--count)
  315. goto out;
  316. }
  317. }END_FOR_EACH_PTR(ptr);
  318. assert(count <= 0);
  319. out:
  320. return count;
  321. }
  322. ///
  323. // remove the last entry of a ptrlist
  324. // @head: a pointer to the list
  325. // @return: the last element of the list or NULL if the list is empty.
  326. //
  327. // :note: this doesn't repack the list
  328. void * undo_ptr_list_last(struct ptr_list **head)
  329. {
  330. struct ptr_list *last, *first = *head;
  331. if (!first)
  332. return NULL;
  333. last = first;
  334. do {
  335. last = last->prev;
  336. if (last->nr) {
  337. void *ptr;
  338. int nr = --last->nr;
  339. ptr = last->list[nr];
  340. last->list[nr] = (void *)0xf1f1f1f1;
  341. return ptr;
  342. }
  343. } while (last != first);
  344. return NULL;
  345. }
  346. ///
  347. // remove the last entry and repack the list
  348. // @head: a pointer to the list
  349. // @return: the last element of the list or NULL if the list is empty.
  350. void * delete_ptr_list_last(struct ptr_list **head)
  351. {
  352. void *ptr = NULL;
  353. struct ptr_list *last, *first = *head;
  354. if (!first)
  355. return NULL;
  356. last = first->prev;
  357. if (last->nr)
  358. ptr = last->list[--last->nr];
  359. if (last->nr <=0) {
  360. first->prev = last->prev;
  361. last->prev->next = first;
  362. if (last == first)
  363. *head = NULL;
  364. __free_ptrlist(last);
  365. }
  366. return ptr;
  367. }
  368. ///
  369. // concat two ptrlists
  370. // @a: the source list
  371. // @b: a pointer to the destination list.
  372. // The element of @a are added at the end of @b.
  373. void concat_ptr_list(struct ptr_list *a, struct ptr_list **b)
  374. {
  375. void *entry;
  376. FOR_EACH_PTR(a, entry) {
  377. add_ptr_list(b, entry);
  378. } END_FOR_EACH_PTR(entry);
  379. }
  380. ///
  381. // copy the elements of a list at the end of another list.
  382. // @listp: a pointer to the destination list.
  383. // @src: the head of the source list.
  384. void copy_ptr_list(struct ptr_list **listp, struct ptr_list *src)
  385. {
  386. struct ptr_list *head, *tail;
  387. struct ptr_list *cur = src;
  388. int idx;
  389. if (!src)
  390. return;
  391. head = *listp;
  392. if (!head) {
  393. *listp = src;
  394. return;
  395. }
  396. tail = head->prev;
  397. idx = tail->nr;
  398. do {
  399. struct ptr_list *next;
  400. int nr = cur->nr;
  401. int i;
  402. for (i = 0; i < nr;) {
  403. void *ptr = cur->list[i++];
  404. if (!ptr)
  405. continue;
  406. if (idx >= LIST_NODE_NR) {
  407. struct ptr_list *prev = tail;
  408. tail = __alloc_ptrlist(0);
  409. prev->next = tail;
  410. tail->prev = prev;
  411. prev->nr = idx;
  412. idx = 0;
  413. }
  414. tail->list[idx++] = ptr;
  415. }
  416. next = cur->next;
  417. __free_ptrlist(cur);
  418. cur = next;
  419. } while (cur != src);
  420. tail->nr = idx;
  421. head->prev = tail;
  422. tail->next = head;
  423. }
  424. ///
  425. // free a ptrlist
  426. // @listp: a pointer to the list
  427. // Each blocks of the list are freed (but the entries
  428. // themselves are not freed).
  429. //
  430. // :note: code must not use this function and should use
  431. // the macro :func:`free_ptr_list` instead.
  432. void __free_ptr_list(struct ptr_list **listp)
  433. {
  434. struct ptr_list *tmp, *list = *listp;
  435. if (!list)
  436. return;
  437. list->prev->next = NULL;
  438. while (list) {
  439. tmp = list;
  440. list = list->next;
  441. __free_ptrlist(tmp);
  442. }
  443. *listp = NULL;
  444. }