charset/tests: add more str[n]casecmp_m() tests to demonstrate the bug
[Samba.git] / lib / util / dlinklist.h
blob8a1b84d44291f26d53340b86a342bc8d92414730
1 /*
2 Unix SMB/CIFS implementation.
3 some simple double linked list macros
5 Copyright (C) Andrew Tridgell 1998-2010
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 /* To use these macros you must have a structure containing a next and
22 prev pointer */
24 #ifndef _DLINKLIST_H
25 #define _DLINKLIST_H
28 February 2010 - changed list format to have a prev pointer from the
29 list head. This makes DLIST_ADD_END() O(1) even though we only have
30 one list pointer.
32 The scheme is as follows:
34 1) with no entries in the list:
35 list_head == NULL
37 2) with 1 entry in the list:
38 list_head->next == NULL
39 list_head->prev == list_head
41 3) with 2 entries in the list:
42 list_head->next == element2
43 list_head->prev == element2
44 element2->prev == list_head
45 element2->next == NULL
47 4) with N entries in the list:
48 list_head->next == element2
49 list_head->prev == elementN
50 elementN->prev == element{N-1}
51 elementN->next == NULL
53 This allows us to find the tail of the list by using
54 list_head->prev, which means we can add to the end of the list in
55 O(1) time
60 add an element at the front of a list
62 #define DLIST_ADD(list, p) \
63 do { \
64 if (!(list)) { \
65 (p)->prev = (list) = (p); \
66 (p)->next = NULL; \
67 } else { \
68 (p)->prev = (list)->prev; \
69 (list)->prev = (p); \
70 (p)->next = (list); \
71 (list) = (p); \
72 } \
73 } while (0)
76 remove an element from a list
77 Note that the element doesn't have to be in the list. If it
78 isn't then this is a no-op
80 #define DLIST_REMOVE(list, p) \
81 do { \
82 if ((p) == (list)) { \
83 if ((p)->next) (p)->next->prev = (p)->prev; \
84 (list) = (p)->next; \
85 } else if ((list) && (p) == (list)->prev) { \
86 (p)->prev->next = NULL; \
87 (list)->prev = (p)->prev; \
88 } else { \
89 if ((p)->prev) (p)->prev->next = (p)->next; \
90 if ((p)->next) (p)->next->prev = (p)->prev; \
91 } \
92 if ((p) != (list)) (p)->next = (p)->prev = NULL; \
93 } while (0)
96 find the head of the list given any element in it.
97 Note that this costs O(N), so you should avoid this macro
98 if at all possible!
100 #define DLIST_HEAD(p, result_head) \
101 do { \
102 (result_head) = (p); \
103 while (DLIST_PREV(result_head)) (result_head) = (result_head)->prev; \
104 } while(0)
106 /* return the last element in the list */
107 #define DLIST_TAIL(list) ((list)?(list)->prev:NULL)
109 /* return the previous element in the list. */
110 #define DLIST_PREV(p) (((p)->prev && (p)->prev->next != NULL)?(p)->prev:NULL)
112 /* insert 'p' after the given element 'el' in a list. If el is NULL then
113 this is the same as a DLIST_ADD() */
114 #define DLIST_ADD_AFTER(list, p, el) \
115 do { \
116 if (!(list) || !(el)) { \
117 DLIST_ADD(list, p); \
118 } else { \
119 (p)->prev = (el); \
120 (p)->next = (el)->next; \
121 (el)->next = (p); \
122 if ((p)->next) (p)->next->prev = (p); \
123 if ((list)->prev == (el)) (list)->prev = (p); \
125 } while (0)
129 add to the end of a list.
131 #define DLIST_ADD_END(list, p) \
132 do { \
133 if (!(list)) { \
134 DLIST_ADD(list, p); \
135 } else { \
136 DLIST_ADD_AFTER(list, p, (list)->prev); \
138 } while (0)
140 /* promote an element to the front of a list */
141 #define DLIST_PROMOTE(list, p) \
142 do { \
143 DLIST_REMOVE(list, p); \
144 DLIST_ADD(list, p); \
145 } while (0)
148 demote an element to the end of a list.
150 #define DLIST_DEMOTE(list, p) \
151 do { \
152 DLIST_REMOVE(list, p); \
153 DLIST_ADD_END(list, p); \
154 } while (0)
157 concatenate two lists - putting all elements of the 2nd list at the
158 end of the first list.
160 #define DLIST_CONCATENATE(list1, list2) \
161 do { \
162 if (!(list1)) { \
163 (list1) = (list2); \
164 } else { \
165 (list1)->prev->next = (list2); \
166 if (list2) { \
167 void *_tmplist = (void *)(list1)->prev; \
168 (list1)->prev = (list2)->prev; \
169 (list2)->prev = _tmplist; \
172 } while (0)
174 #endif /* _DLINKLIST_H */