]>
Commit | Line | Data |
---|---|---|
f0cc3e7b A |
1 | /* |
2 | * Copyright (c) 2003-2019 Apple Inc. All rights reserved. | |
8e92c31c | 3 | * |
67c8f8a1 A |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. | |
6 | * You may obtain a copy of the License at | |
83fb1e36 | 7 | * |
67c8f8a1 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
83fb1e36 | 9 | * |
67c8f8a1 A |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the License for the specific language governing permissions and | |
8e92c31c | 14 | * limitations under the License. |
263eeeab | 15 | */ |
8e92c31c A |
16 | |
17 | #include "GenLinkedList.h" | |
18 | ||
19 | ||
20 | // Return the link pointer contained within element e at offset o. | |
83fb1e36 | 21 | #define GETLINK( e, o) ( *(void**)((char*) (e) + (o)) ) |
8e92c31c A |
22 | |
23 | // Assign the link pointer l to element e at offset o. | |
83fb1e36 | 24 | #define ASSIGNLINK( e, l, o) ( *((void**)((char*) (e) + (o))) = (l)) |
8e92c31c A |
25 | |
26 | ||
27 | // GenLinkedList ///////////////////////////////////////////////////////////// | |
28 | ||
83fb1e36 | 29 | void InitLinkedList( GenLinkedList *pList, size_t linkOffset) |
8e92c31c A |
30 | /* Initialize the block of memory pointed to by pList as a linked list. */ |
31 | { | |
83fb1e36 A |
32 | pList->Head = NULL; |
33 | pList->Tail = NULL; | |
34 | pList->LinkOffset = linkOffset; | |
8e92c31c A |
35 | } |
36 | ||
37 | ||
83fb1e36 | 38 | void AddToTail( GenLinkedList *pList, void *elem) |
8e92c31c A |
39 | /* Add a linked list element to the tail of the list. */ |
40 | { | |
83fb1e36 A |
41 | if ( pList->Tail) { |
42 | ASSIGNLINK( pList->Tail, elem, pList->LinkOffset); | |
43 | } else | |
44 | pList->Head = elem; | |
45 | ASSIGNLINK( elem, NULL, pList->LinkOffset); | |
8e92c31c | 46 | |
83fb1e36 | 47 | pList->Tail = elem; |
8e92c31c A |
48 | } |
49 | ||
50 | ||
83fb1e36 | 51 | void AddToHead( GenLinkedList *pList, void *elem) |
8e92c31c A |
52 | /* Add a linked list element to the head of the list. */ |
53 | { | |
83fb1e36 A |
54 | ASSIGNLINK( elem, pList->Head, pList->LinkOffset); |
55 | if ( pList->Tail == NULL) | |
56 | pList->Tail = elem; | |
8e92c31c | 57 | |
83fb1e36 | 58 | pList->Head = elem; |
8e92c31c A |
59 | } |
60 | ||
61 | ||
83fb1e36 | 62 | int RemoveFromList( GenLinkedList *pList, void *elem) |
8e92c31c A |
63 | /* Remove a linked list element from the list. Return 0 if it was not found. */ |
64 | /* If the element is removed, its link will be set to NULL. */ | |
65 | { | |
83fb1e36 A |
66 | void *iElem, *lastElem; |
67 | ||
68 | for ( iElem = pList->Head, lastElem = NULL; iElem; iElem = GETLINK( iElem, pList->LinkOffset)) { | |
69 | if ( iElem == elem) { | |
70 | if ( lastElem) { // somewhere past the head | |
71 | ASSIGNLINK( lastElem, GETLINK( elem, pList->LinkOffset), pList->LinkOffset); | |
72 | } else { // at the head | |
73 | pList->Head = GETLINK( elem, pList->LinkOffset); | |
74 | } | |
75 | if ( pList->Tail == elem) | |
76 | pList->Tail = lastElem ? lastElem : NULL; | |
77 | ASSIGNLINK( elem, NULL, pList->LinkOffset); // maybe catch a stale reference bug. | |
78 | return 1; | |
79 | } | |
80 | lastElem = iElem; | |
81 | } | |
82 | ||
83 | return 0; | |
8e92c31c A |
84 | } |
85 | ||
86 | ||
83fb1e36 | 87 | int ReplaceElem( GenLinkedList *pList, void *elemInList, void *newElem) |
8e92c31c A |
88 | /* Replace an element in the list with a new element, in the same position. */ |
89 | { | |
83fb1e36 A |
90 | void *iElem, *lastElem; |
91 | ||
92 | if ( elemInList == NULL || newElem == NULL) | |
93 | return 0; | |
94 | ||
95 | for ( iElem = pList->Head, lastElem = NULL; iElem; iElem = GETLINK( iElem, pList->LinkOffset)) | |
96 | { | |
97 | if ( iElem == elemInList) | |
98 | { | |
99 | ASSIGNLINK( newElem, GETLINK( elemInList, pList->LinkOffset), pList->LinkOffset); | |
100 | if ( lastElem) // somewhere past the head | |
101 | { | |
102 | ASSIGNLINK( lastElem, newElem, pList->LinkOffset); | |
103 | } | |
104 | else // at the head | |
105 | { | |
106 | pList->Head = newElem; | |
107 | } | |
108 | if ( pList->Tail == elemInList) | |
109 | pList->Tail = newElem; | |
110 | return 1; | |
111 | } | |
112 | lastElem = iElem; | |
113 | } | |
114 | ||
115 | return 0; | |
8e92c31c A |
116 | } |
117 | ||
118 | ||
119 | // GenDoubleLinkedList ///////////////////////////////////////////////////////// | |
120 | ||
83fb1e36 A |
121 | void InitDoubleLinkedList( GenDoubleLinkedList *pList, size_t fwdLinkOffset, |
122 | size_t backLinkOffset) | |
8e92c31c A |
123 | /* Initialize the block of memory pointed to by pList as a double linked list. */ |
124 | { | |
83fb1e36 A |
125 | pList->Head = NULL; |
126 | pList->Tail = NULL; | |
127 | pList->FwdLinkOffset = fwdLinkOffset; | |
128 | pList->BackLinkOffset = backLinkOffset; | |
8e92c31c A |
129 | } |
130 | ||
131 | ||
83fb1e36 | 132 | void DLLAddToHead( GenDoubleLinkedList *pList, void *elem) |
8e92c31c A |
133 | /* Add a linked list element to the head of the list. */ |
134 | { | |
83fb1e36 | 135 | void *pNext; |
8e92c31c | 136 | |
83fb1e36 | 137 | pNext = pList->Head; |
8e92c31c | 138 | |
83fb1e36 A |
139 | // fix up the forward links |
140 | ASSIGNLINK( elem, pList->Head, pList->FwdLinkOffset); | |
141 | pList->Head = elem; | |
8e92c31c | 142 | |
83fb1e36 A |
143 | // fix up the backward links |
144 | if ( pNext) { | |
145 | ASSIGNLINK( pNext, elem, pList->BackLinkOffset); | |
146 | } else | |
147 | pList->Tail = elem; | |
148 | ASSIGNLINK( elem, NULL, pList->BackLinkOffset); | |
8e92c31c A |
149 | } |
150 | ||
151 | ||
83fb1e36 | 152 | void DLLRemoveFromList( GenDoubleLinkedList *pList, void *elem) |
8e92c31c A |
153 | /* Remove a linked list element from the list. */ |
154 | /* When the element is removed, its link will be set to NULL. */ | |
155 | { | |
83fb1e36 A |
156 | void *pNext, *pPrev; |
157 | ||
158 | pNext = GETLINK( elem, pList->FwdLinkOffset); | |
159 | pPrev = GETLINK( elem, pList->BackLinkOffset); | |
160 | ||
161 | // fix up the forward links | |
162 | if ( pPrev) | |
163 | ASSIGNLINK( pPrev, pNext, pList->FwdLinkOffset); | |
164 | else | |
165 | pList->Head = pNext; | |
166 | ||
167 | // fix up the backward links | |
168 | if ( pNext) | |
169 | ASSIGNLINK( pNext, pPrev, pList->BackLinkOffset); | |
170 | else | |
171 | pList->Tail = pPrev; | |
172 | ||
173 | ASSIGNLINK( elem, NULL, pList->FwdLinkOffset); | |
174 | ASSIGNLINK( elem, NULL, pList->BackLinkOffset); | |
8e92c31c A |
175 | } |
176 | ||
177 | ||
178 | // GenLinkedOffsetList ///////////////////////////////////////////////////// | |
179 | ||
180 | // Extract the Next offset from element | |
83fb1e36 | 181 | #define GETOFFSET( e, o) ( *(size_t*)((char*) (e) + (o)) ) |
8e92c31c | 182 | |
83fb1e36 | 183 | static void AssignOffsetLink( void *elem, void *link, size_t linkOffset); |
8e92c31c A |
184 | |
185 | ||
83fb1e36 | 186 | static void AssignOffsetLink( void *elem, void *link, size_t linkOffset) |
8e92c31c A |
187 | // Assign link to elem as an offset from elem. Assign 0 to elem if link is NULL. |
188 | { | |
83fb1e36 | 189 | GETOFFSET( elem, linkOffset) = link ? (size_t) link - (size_t) elem : 0; |
8e92c31c A |
190 | } |
191 | ||
192 | ||
83fb1e36 | 193 | void *GetHeadPtr( GenLinkedOffsetList *pList) |
8e92c31c A |
194 | /* Return a pointer to the head element of a list, or NULL if none. */ |
195 | { | |
83fb1e36 | 196 | return pList->Head ? ( (char*) (pList) + pList->Head) : NULL; |
8e92c31c A |
197 | } |
198 | ||
199 | ||
83fb1e36 | 200 | void *GetTailPtr( GenLinkedOffsetList *pList) |
8e92c31c A |
201 | /* Return a pointer to the tail element of a list, or NULL if none. */ |
202 | { | |
83fb1e36 | 203 | return pList->Tail ? ( (char*) (pList) + pList->Tail) : NULL; |
8e92c31c A |
204 | } |
205 | ||
206 | ||
83fb1e36 | 207 | void *GetOffsetLink( GenLinkedOffsetList *pList, void *elem) |
8e92c31c A |
208 | /* Return the link pointer contained within element e for pList, or NULL if it is 0. */ |
209 | { | |
83fb1e36 | 210 | size_t nextOffset; |
8e92c31c | 211 | |
83fb1e36 | 212 | nextOffset = GETOFFSET( elem, pList->LinkOffset); |
8e92c31c | 213 | |
83fb1e36 | 214 | return nextOffset ? (char*) elem + nextOffset : NULL; |
8e92c31c A |
215 | } |
216 | ||
217 | ||
83fb1e36 | 218 | void InitLinkedOffsetList( GenLinkedOffsetList *pList, size_t linkOffset) |
8e92c31c A |
219 | /* Initialize the block of memory pointed to by pList as a linked list. */ |
220 | { | |
83fb1e36 A |
221 | pList->Head = 0; |
222 | pList->Tail = 0; | |
223 | pList->LinkOffset = linkOffset; | |
8e92c31c A |
224 | } |
225 | ||
226 | ||
83fb1e36 | 227 | void OffsetAddToTail( GenLinkedOffsetList *pList, void *elem) |
8e92c31c A |
228 | /* Add a linked list element to the tail of the list. */ |
229 | { | |
83fb1e36 A |
230 | if ( pList->Tail) { |
231 | AssignOffsetLink( GetTailPtr( pList), elem, pList->LinkOffset); | |
232 | } else | |
233 | pList->Head = (size_t) elem - (size_t) pList; | |
234 | AssignOffsetLink( elem, NULL, pList->LinkOffset); | |
8e92c31c | 235 | |
83fb1e36 | 236 | pList->Tail = (size_t) elem - (size_t) pList; |
8e92c31c A |
237 | } |
238 | ||
239 | ||
83fb1e36 | 240 | void OffsetAddToHead( GenLinkedOffsetList *pList, void *elem) |
8e92c31c A |
241 | /* Add a linked list element to the head of the list. */ |
242 | { | |
83fb1e36 A |
243 | AssignOffsetLink( elem, GetHeadPtr( pList), pList->LinkOffset); |
244 | if ( pList->Tail == 0) | |
245 | pList->Tail = (size_t) elem - (size_t) pList; | |
8e92c31c | 246 | |
83fb1e36 | 247 | pList->Head = (size_t) elem - (size_t) pList; |
8e92c31c A |
248 | } |
249 | ||
250 | ||
83fb1e36 | 251 | int OffsetRemoveFromList( GenLinkedOffsetList *pList, void *elem) |
8e92c31c A |
252 | /* Remove a linked list element from the list. Return 0 if it was not found. */ |
253 | /* If the element is removed, its link will be set to NULL. */ | |
254 | { | |
83fb1e36 A |
255 | void *iElem, *lastElem; |
256 | ||
f0cc3e7b A |
257 | if (elem == NULL) { |
258 | return 0; | |
259 | } | |
83fb1e36 A |
260 | for ( iElem = GetHeadPtr( pList), lastElem = NULL; iElem; |
261 | iElem = GetOffsetLink( pList, iElem)) | |
262 | { | |
263 | if ( iElem == elem) { | |
264 | if ( lastElem) { // somewhere past the head | |
265 | AssignOffsetLink( lastElem, GetOffsetLink( pList, elem), pList->LinkOffset); | |
266 | } else { // at the head | |
267 | iElem = GetOffsetLink( pList, elem); | |
268 | pList->Head = iElem ? (size_t) iElem - (size_t) pList : 0; | |
269 | } | |
270 | if ( GetTailPtr( pList) == elem) | |
271 | pList->Tail = lastElem ? (size_t) lastElem - (size_t) pList : 0; | |
272 | AssignOffsetLink( elem, NULL, pList->LinkOffset); // maybe catch a stale reference bug. | |
273 | return 1; | |
274 | } | |
275 | lastElem = iElem; | |
276 | } | |
277 | ||
278 | return 0; | |
8e92c31c A |
279 | } |
280 | ||
281 | ||
83fb1e36 | 282 | int OffsetReplaceElem( GenLinkedOffsetList *pList, void *elemInList, void *newElem) |
8e92c31c A |
283 | /* Replace an element in the list with a new element, in the same position. */ |
284 | { | |
83fb1e36 A |
285 | void *iElem, *lastElem; |
286 | ||
287 | if ( elemInList == NULL || newElem == NULL) | |
288 | return 0; | |
289 | ||
290 | for ( iElem = GetHeadPtr( pList), lastElem = NULL; iElem; | |
291 | iElem = GetOffsetLink( pList, iElem)) | |
292 | { | |
293 | if ( iElem == elemInList) | |
294 | { | |
295 | AssignOffsetLink( newElem, GetOffsetLink( pList, elemInList), pList->LinkOffset); | |
296 | if ( lastElem) // somewhere past the head | |
297 | { | |
298 | AssignOffsetLink( lastElem, newElem, pList->LinkOffset); | |
299 | } | |
300 | else // at the head | |
301 | { | |
302 | pList->Head = (size_t) newElem - (size_t) pList; | |
303 | } | |
304 | if ( GetTailPtr( pList) == elemInList) | |
305 | pList->Tail = (size_t) newElem - (size_t) pList; | |
306 | return 1; | |
307 | } | |
308 | lastElem = iElem; | |
309 | } | |
310 | ||
311 | return 0; | |
8e92c31c A |
312 | } |
313 | ||
314 |