smbd: Fix crossing automounter mount points
[Samba.git] / lib / ldb / include / dlinklist.h
blob49a135a23bd91cb68e1c98882449c34ed4e98497
1 /*
2 Unix SMB/CIFS implementation.
3 some simple double linked list macros
5 Copyright (C) Andrew Tridgell 1998-2010
7 ** NOTE! The following LGPL license applies to this file (*dlinklist.h).
8 ** This does NOT imply that all of Samba is released under the LGPL
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 3 of the License, or (at your option) any later version.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, see <http://www.gnu.org/licenses/>.
24 /* To use these macros you must have a structure containing a next and
25 prev pointer */
27 #ifndef _DLINKLIST_H
28 #define _DLINKLIST_H
31 February 2010 - changed list format to have a prev pointer from the
32 list head. This makes DLIST_ADD_END() O(1) even though we only have
33 one list pointer.
35 The scheme is as follows:
37 1) with no entries in the list:
38 list_head == NULL
40 2) with 1 entry in the list:
41 list_head->next == NULL
42 list_head->prev == list_head
44 3) with 2 entries in the list:
45 list_head->next == element2
46 list_head->prev == element2
47 element2->prev == list_head
48 element2->next == NULL
50 4) with N entries in the list:
51 list_head->next == element2
52 list_head->prev == elementN
53 elementN->prev == element{N-1}
54 elementN->next == NULL
56 This allows us to find the tail of the list by using
57 list_head->prev, which means we can add to the end of the list in
58 O(1) time
63 add an element at the front of a list
65 #define DLIST_ADD(list, p) \
66 do { \
67 if (!(list)) { \
68 (p)->prev = (list) = (p); \
69 (p)->next = NULL; \
70 } else { \
71 (p)->prev = (list)->prev; \
72 (list)->prev = (p); \
73 (p)->next = (list); \
74 (list) = (p); \
75 } \
76 } while (0)
79 remove an element from a list
80 Note that the element doesn't have to be in the list. If it
81 isn't then this is a no-op
83 #define DLIST_REMOVE(list, p) \
84 do { \
85 if ((p) == (list)) { \
86 if ((p)->next) (p)->next->prev = (p)->prev; \
87 (list) = (p)->next; \
88 } else if ((p)->prev && (list) && (p) == (list)->prev) { \
89 (p)->prev->next = NULL; \
90 (list)->prev = (p)->prev; \
91 } else { \
92 if ((p)->prev) (p)->prev->next = (p)->next; \
93 if ((p)->next) (p)->next->prev = (p)->prev; \
94 } \
95 if ((p) != (list)) (p)->next = (p)->prev = NULL; \
96 } while (0)
99 find the head of the list given any element in it.
100 Note that this costs O(N), so you should avoid this macro
101 if at all possible!
103 #define DLIST_HEAD(p, result_head) \
104 do { \
105 (result_head) = (p); \
106 while (DLIST_PREV(result_head)) (result_head) = (result_head)->prev; \
107 } while(0)
109 /* return the last element in the list */
110 #define DLIST_TAIL(list) ((list)?(list)->prev:NULL)
112 /* return the previous element in the list. */
113 #define DLIST_PREV(p) (((p)->prev && (p)->prev->next != NULL)?(p)->prev:NULL)
115 /* insert 'p' after the given element 'el' in a list. If el is NULL then
116 this is the same as a DLIST_ADD() */
117 #define DLIST_ADD_AFTER(list, p, el) \
118 do { \
119 if (!(list) || !(el)) { \
120 DLIST_ADD(list, p); \
121 } else { \
122 (p)->prev = (el); \
123 (p)->next = (el)->next; \
124 (el)->next = (p); \
125 if ((p)->next) (p)->next->prev = (p); \
126 if ((list)->prev == (el)) (list)->prev = (p); \
128 } while (0)
132 add to the end of a list.
134 #define DLIST_ADD_END(list, p) \
135 do { \
136 if (!(list)) { \
137 DLIST_ADD(list, p); \
138 } else { \
139 DLIST_ADD_AFTER(list, p, (list)->prev); \
141 } while (0)
143 /* promote an element to the front of a list */
144 #define DLIST_PROMOTE(list, p) \
145 do { \
146 DLIST_REMOVE(list, p); \
147 DLIST_ADD(list, p); \
148 } while (0)
151 demote an element to the end of a list.
153 #define DLIST_DEMOTE(list, p) \
154 do { \
155 DLIST_REMOVE(list, p); \
156 DLIST_ADD_END(list, p); \
157 } while (0)
160 * like DLIST_DEMOTE(), but optimized
161 * for short lists with 0, 1 or 2 elements
163 #define DLIST_DEMOTE_SHORT(list, p) \
164 do { \
165 if ((list) == NULL) { \
166 /* no reason to demote, just add */ \
167 DLIST_ADD(list, p); \
168 } else if ((list)->prev == (p)) { \
169 /* optimize if p is last */ \
170 } else if ((list) == (p)) { \
171 /* optimize if p is first */ \
172 (list)->prev->next = (p); \
173 (list) = (p)->next; \
174 (p)->next = NULL; \
175 } else { \
176 DLIST_DEMOTE(list, p); \
178 } while (0)
181 concatenate two lists - putting all elements of the 2nd list at the
182 end of the first list.
184 #define DLIST_CONCATENATE(list1, list2) \
185 do { \
186 if (!(list1)) { \
187 (list1) = (list2); \
188 } else { \
189 (list1)->prev->next = (list2); \
190 if (list2) { \
191 void *_tmplist = (void *)(list1)->prev; \
192 (list1)->prev = (list2)->prev; \
193 (list2)->prev = _tmplist; \
196 } while (0)
198 #endif /* _DLINKLIST_H */