dlinklist.h 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /*
  2. Unix SMB/CIFS implementation.
  3. some simple double linked list macros
  4. Copyright (C) Andrew Tridgell 1998-2010
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 3 of the License, or
  8. (at your option) any later version.
  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. You should have received a copy of the GNU General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. /* To use these macros you must have a structure containing a next and
  17. prev pointer */
  18. #ifndef _DLINKLIST_H
  19. #define _DLINKLIST_H
  20. /*
  21. February 2010 - changed list format to have a prev pointer from the
  22. list head. This makes DLIST_ADD_END() O(1) even though we only have
  23. one list pointer.
  24. The scheme is as follows:
  25. 1) with no entries in the list:
  26. list_head == NULL
  27. 2) with 1 entry in the list:
  28. list_head->next == NULL
  29. list_head->prev == list_head
  30. 3) with 2 entries in the list:
  31. list_head->next == element2
  32. list_head->prev == element2
  33. element2->prev == list_head
  34. element2->next == NULL
  35. 4) with N entries in the list:
  36. list_head->next == element2
  37. list_head->prev == elementN
  38. elementN->prev == element{N-1}
  39. elementN->next == NULL
  40. This allows us to find the tail of the list by using
  41. list_head->prev, which means we can add to the end of the list in
  42. O(1) time
  43. Note that the 'type' arguments below are no longer needed, but
  44. are kept for now to prevent an incompatible argument change
  45. */
  46. /*
  47. add an element at the front of a list
  48. */
  49. #define DLIST_ADD(list, p) \
  50. do { \
  51. if (!(list)) { \
  52. (p)->prev = (list) = (p); \
  53. (p)->next = NULL; \
  54. } else { \
  55. (p)->prev = (list)->prev; \
  56. (list)->prev = (p); \
  57. (p)->next = (list); \
  58. (list) = (p); \
  59. } \
  60. } while (0)
  61. /*
  62. remove an element from a list
  63. Note that the element doesn't have to be in the list. If it
  64. isn't then this is a no-op
  65. */
  66. #define DLIST_REMOVE(list, p) \
  67. do { \
  68. if ((p) == (list)) { \
  69. if ((p)->next) (p)->next->prev = (p)->prev; \
  70. (list) = (p)->next; \
  71. } else if ((list) && (p) == (list)->prev) { \
  72. (p)->prev->next = NULL; \
  73. (list)->prev = (p)->prev; \
  74. } else { \
  75. if ((p)->prev) (p)->prev->next = (p)->next; \
  76. if ((p)->next) (p)->next->prev = (p)->prev; \
  77. } \
  78. if ((p) != (list)) (p)->next = (p)->prev = NULL; \
  79. } while (0)
  80. /*
  81. find the head of the list given any element in it.
  82. Note that this costs O(N), so you should avoid this macro
  83. if at all possible!
  84. */
  85. #define DLIST_HEAD(p, result_head) \
  86. do { \
  87. (result_head) = (p); \
  88. while (DLIST_PREV(result_head)) (result_head) = (result_head)->prev; \
  89. } while(0)
  90. /* return the last element in the list */
  91. #define DLIST_TAIL(list) ((list)?(list)->prev:NULL)
  92. /* return the previous element in the list. */
  93. #define DLIST_PREV(p) (((p)->prev && (p)->prev->next != NULL)?(p)->prev:NULL)
  94. /* insert 'p' after the given element 'el' in a list. If el is NULL then
  95. this is the same as a DLIST_ADD() */
  96. #define DLIST_ADD_AFTER(list, p, el) \
  97. do { \
  98. if (!(list) || !(el)) { \
  99. DLIST_ADD(list, p); \
  100. } else { \
  101. (p)->prev = (el); \
  102. (p)->next = (el)->next; \
  103. (el)->next = (p); \
  104. if ((p)->next) (p)->next->prev = (p); \
  105. if ((list)->prev == (el)) (list)->prev = (p); \
  106. }\
  107. } while (0)
  108. /*
  109. add to the end of a list.
  110. Note that 'type' is ignored
  111. */
  112. #define DLIST_ADD_END(list, p, type) \
  113. do { \
  114. if (!(list)) { \
  115. DLIST_ADD(list, p); \
  116. } else { \
  117. DLIST_ADD_AFTER(list, p, (list)->prev); \
  118. } \
  119. } while (0)
  120. /* promote an element to the from of a list */
  121. #define DLIST_PROMOTE(list, p) \
  122. do { \
  123. DLIST_REMOVE(list, p); \
  124. DLIST_ADD(list, p); \
  125. } while (0)
  126. /*
  127. demote an element to the end of a list.
  128. Note that 'type' is ignored
  129. */
  130. #define DLIST_DEMOTE(list, p, type) \
  131. do { \
  132. DLIST_REMOVE(list, p); \
  133. DLIST_ADD_END(list, p, NULL); \
  134. } while (0)
  135. /*
  136. concatenate two lists - putting all elements of the 2nd list at the
  137. end of the first list.
  138. Note that 'type' is ignored
  139. */
  140. #define DLIST_CONCATENATE(list1, list2, type) \
  141. do { \
  142. if (!(list1)) { \
  143. (list1) = (list2); \
  144. } else { \
  145. (list1)->prev->next = (list2); \
  146. if (list2) { \
  147. void *_tmplist = (void *)(list1)->prev; \
  148. (list1)->prev = (list2)->prev; \
  149. (list2)->prev = _tmplist; \
  150. } \
  151. } \
  152. } while (0)
  153. #endif /* _DLINKLIST_H */