]> git.proxmox.com Git - mirror_edk2.git/blame - MdePkg/Library/BaseLib/LinkedList.c
1. Sync LinkedList.c with MWG
[mirror_edk2.git] / MdePkg / Library / BaseLib / LinkedList.c
CommitLineData
878ddf1f 1/** @file\r
2 Linked List Library Functions.\r
3\r
4 Copyright (c) 2006, Intel Corporation<BR>\r
5 All rights reserved. This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13 Module Name: LinkedList.c\r
14\r
15**/\r
16\r
17BOOLEAN\r
18EFIAPI\r
19IsNodeInList (\r
20 IN CONST LIST_ENTRY *List,\r
21 IN CONST LIST_ENTRY *Node\r
22 )\r
23{\r
24 UINTN Count;\r
25 CONST LIST_ENTRY *Ptr;\r
26 BOOLEAN Found;\r
27\r
28 //\r
29 // Test the validity of List and Node\r
30 //\r
31 ASSERT (List != NULL);\r
32 ASSERT (List->ForwardLink != NULL);\r
33 ASSERT (List->BackLink != NULL);\r
34 ASSERT (Node != NULL);\r
35\r
dc530c7b 36 Count = PcdGet32 (PcdMaximumLinkedListLength);\r
7d7c2b46 37\r
878ddf1f 38 Ptr = List;\r
39 do {\r
40 Ptr = Ptr->ForwardLink;\r
41 Count--;\r
42 } while ((Ptr != List) && (Ptr != Node) && (Count > 0));\r
43 Found = (BOOLEAN)(Ptr == Node);\r
44\r
dc530c7b 45 if (PcdGet32 (PcdMaximumLinkedListLength) > 0) {\r
878ddf1f 46 while ((Count > 0) && (Ptr != List)) {\r
47 Ptr = Ptr->ForwardLink;\r
7d7c2b46 48 Count--;\r
878ddf1f 49 }\r
50 ASSERT (Count > 0);\r
51 }\r
52\r
53 return Found;\r
54}\r
55\r
56/**\r
57 Initializes the head node of a doubly linked list, and returns the pointer to\r
58 the head node of the doubly linked list.\r
59\r
60 Initializes the forward and backward links of a new linked list. After\r
61 initializing a linked list with this function, the other linked list\r
62 functions may be used to add and remove nodes from the linked list. It is up\r
63 to the caller of this function to allocate the memory for ListHead.\r
64\r
65 If ListHead is NULL, then ASSERT().\r
66\r
67 @param ListHead A pointer to the head node of a new doubly linked list.\r
68\r
69 @return ListHead\r
70\r
71**/\r
72LIST_ENTRY *\r
73EFIAPI\r
74InitializeListHead (\r
75 IN OUT LIST_ENTRY *List\r
76 )\r
77\r
78{\r
79 ASSERT (List != NULL);\r
80\r
81 List->ForwardLink = List;\r
82 List->BackLink = List;\r
83 return List;\r
84}\r
85\r
86/**\r
87 Adds a node to the beginning of a doubly linked list, and returns the pointer\r
88 to the head node of the doubly linked list.\r
89\r
90 Adds the node Entry at the beginning of the doubly linked list denoted by\r
91 ListHead, and returns ListHead.\r
92\r
93 If ListHead is NULL, then ASSERT().\r
94 If Entry is NULL, then ASSERT().\r
95 If ListHead was not initialized with InitializeListHead(), then ASSERT().\r
30817eb4 96 If PcdMaximumLinkedListLenth is not zero, and prior to insertion the number\r
97 of nodes in ListHead, including the ListHead node, is greater than or \r
98 equal to PcdMaximumLinkedListLength, then ASSERT().\r
878ddf1f 99\r
100 @param ListHead A pointer to the head node of a doubly linked list.\r
101 @param Entry A pointer to a node that is to be inserted at the beginning\r
102 of a doubly linked list.\r
103\r
104 @return ListHead\r
105\r
106**/\r
107LIST_ENTRY *\r
108EFIAPI\r
109InsertHeadList (\r
110 IN OUT LIST_ENTRY *List,\r
111 IN OUT LIST_ENTRY *Entry\r
112 )\r
113{\r
114 //\r
115 // ASSERT List not too long and Entry is not one of the nodes of List\r
116 //\r
117 ASSERT (!IsNodeInList (List, Entry));\r
118\r
119 Entry->ForwardLink = List->ForwardLink;\r
120 Entry->BackLink = List;\r
121 Entry->ForwardLink->BackLink = Entry;\r
122 List->ForwardLink = Entry;\r
123 return List;\r
124}\r
125\r
126/**\r
127 Adds a node to the end of a doubly linked list, and returns the pointer to\r
128 the head node of the doubly linked list.\r
129\r
130 Adds the node Entry to the end of the doubly linked list denoted by ListHead,\r
131 and returns ListHead.\r
132\r
133 If ListHead is NULL, then ASSERT().\r
134 If Entry is NULL, then ASSERT().\r
135 If ListHead was not initialized with InitializeListHead(), then ASSERT().\r
30817eb4 136 If PcdMaximumLinkedListLenth is not zero, and prior to insertion the number\r
137 of nodes in ListHead, including the ListHead node, is greater than or \r
138 equal to PcdMaximumLinkedListLength, then ASSERT().\r
878ddf1f 139\r
140 @param ListHead A pointer to the head node of a doubly linked list.\r
141 @param Entry A pointer to a node that is to be added at the end of the\r
142 doubly linked list.\r
143\r
144 @return ListHead\r
145\r
146**/\r
147LIST_ENTRY *\r
148EFIAPI\r
149InsertTailList (\r
150 IN OUT LIST_ENTRY *List,\r
151 IN OUT LIST_ENTRY *Entry\r
152 )\r
153{\r
154 //\r
155 // ASSERT List not too long and Entry is not one of the nodes of List\r
156 //\r
157 ASSERT (!IsNodeInList (List, Entry));\r
158\r
159 Entry->ForwardLink = List;\r
160 Entry->BackLink = List->BackLink;\r
161 Entry->BackLink->ForwardLink = Entry;\r
162 List->BackLink = Entry;\r
163 return List;\r
164}\r
165\r
166/**\r
167 Retrieves the first node of a doubly linked list.\r
168\r
169 Returns the first node of a doubly linked list. List must have been\r
170 initialized with InitializeListHead(). If List is empty, then NULL is\r
171 returned.\r
172\r
173 If List is NULL, then ASSERT().\r
174 If List was not initialized with InitializeListHead(), then ASSERT().\r
30817eb4 175 If PcdMaximumLinkedListLenth is not zero, and the number of nodes \r
176 in List, including the List node, is greater than or equal to \r
177 PcdMaximumLinkedListLength, then ASSERT().\r
878ddf1f 178\r
179 @param List A pointer to the head node of a doubly linked list.\r
180\r
181 @return The first node of a doubly linked list.\r
182 @retval NULL The list is empty.\r
183\r
184**/\r
185LIST_ENTRY *\r
186EFIAPI\r
187GetFirstNode (\r
188 IN CONST LIST_ENTRY *List\r
189 )\r
190{\r
191 //\r
192 // ASSERT List not too long\r
193 //\r
194 ASSERT (IsNodeInList (List, List));\r
195\r
196 return List->ForwardLink;\r
197}\r
198\r
199/**\r
200 Retrieves the next node of a doubly linked list.\r
201\r
202 Returns the node of a doubly linked list that follows Node. List must have\r
203 been initialized with InitializeListHead(). If List is empty, then List is\r
204 returned.\r
205\r
206 If List is NULL, then ASSERT().\r
207 If Node is NULL, then ASSERT().\r
208 If List was not initialized with InitializeListHead(), then ASSERT().\r
209 If PcdMaximumLinkedListLenth is not zero, and List contains more than\r
210 PcdMaximumLinkedListLenth nodes, then ASSERT().\r
211 If Node is not a node in List, then ASSERT().\r
212\r
213 @param List A pointer to the head node of a doubly linked list.\r
214 @param Node A pointer to a node in the doubly linked list.\r
215\r
216 @return Pointer to the next node if one exists. Otherwise a null value which\r
217 is actually List is returned.\r
218\r
219**/\r
220LIST_ENTRY *\r
221EFIAPI\r
222GetNextNode (\r
223 IN CONST LIST_ENTRY *List,\r
224 IN CONST LIST_ENTRY *Node\r
225 )\r
226{\r
227 //\r
228 // ASSERT List not too long and Node is one of the nodes of List\r
229 //\r
230 ASSERT (IsNodeInList (List, Node));\r
231\r
232 return Node->ForwardLink;\r
233}\r
234\r
235/**\r
236 Checks to see if a doubly linked list is empty or not.\r
237\r
238 Checks to see if the doubly linked list is empty. If the linked list contains\r
239 zero nodes, this function returns TRUE. Otherwise, it returns FALSE.\r
240\r
241 If ListHead is NULL, then ASSERT().\r
242 If ListHead was not initialized with InitializeListHead(), then ASSERT().\r
30817eb4 243 If PcdMaximumLinkedListLenth is not zero, and the number of nodes \r
244 in List, including the List node, is greater than or equal to \r
245 PcdMaximumLinkedListLength, then ASSERT().\r
878ddf1f 246\r
247 @param ListHead A pointer to the head node of a doubly linked list.\r
248\r
249 @retval TRUE The linked list is empty.\r
250 @retval FALSE The linked list is not empty.\r
251\r
252**/\r
253BOOLEAN\r
254EFIAPI\r
255IsListEmpty (\r
256 IN CONST LIST_ENTRY *List\r
257 )\r
258{\r
259 //\r
260 // ASSERT List not too long\r
261 //\r
262 ASSERT (IsNodeInList (List, List));\r
263\r
264 return (BOOLEAN)(List->ForwardLink == List);\r
265}\r
266\r
267/**\r
268 Determines if a node in a doubly linked list is null.\r
269\r
270 Returns FALSE if Node is one of the nodes in the doubly linked list specified\r
271 by List. Otherwise, TRUE is returned. List must have been initialized with\r
272 InitializeListHead().\r
273\r
274 If List is NULL, then ASSERT().\r
275 If Node is NULL, then ASSERT().\r
276 If List was not initialized with InitializeListHead(), then ASSERT().\r
30817eb4 277 If PcdMaximumLinkedListLenth is not zero, and the number of nodes \r
278 in List, including the List node, is greater than or equal to \r
279 PcdMaximumLinkedListLength, then ASSERT().\r
878ddf1f 280 If Node is not a node in List and Node is not equal to List, then ASSERT().\r
281\r
282 @param List A pointer to the head node of a doubly linked list.\r
24e25d11 283 @param Node A pointer to a node in the doubly linked list.\r
878ddf1f 284\r
285 @retval TRUE Node is one of the nodes in the doubly linked list.\r
286 @retval FALSE Node is not one of the nodes in the doubly linked list.\r
287\r
288**/\r
289BOOLEAN\r
290EFIAPI\r
291IsNull (\r
292 IN CONST LIST_ENTRY *List,\r
293 IN CONST LIST_ENTRY *Node\r
294 )\r
295{\r
296 //\r
297 // ASSERT List not too long and Node is one of the nodes of List\r
298 //\r
299 ASSERT (IsNodeInList (List, Node));\r
300\r
301 return (BOOLEAN)(Node == List);\r
302}\r
303\r
304/**\r
305 Determines if a node the last node in a doubly linked list.\r
306\r
307 Returns TRUE if Node is the last node in the doubly linked list specified by\r
308 List. Otherwise, FALSE is returned. List must have been initialized with\r
309 InitializeListHead().\r
310\r
311 If List is NULL, then ASSERT().\r
312 If Node is NULL, then ASSERT().\r
313 If List was not initialized with InitializeListHead(), then ASSERT().\r
30817eb4 314 If PcdMaximumLinkedListLenth is not zero, and the number of nodes \r
315 in List, including the List node, is greater than or equal to \r
316 PcdMaximumLinkedListLength, then ASSERT().\r
878ddf1f 317 If Node is not a node in List, then ASSERT().\r
318\r
319 @param List A pointer to the head node of a doubly linked list.\r
24e25d11 320 @param Node A pointer to a node in the doubly linked list.\r
878ddf1f 321\r
322 @retval TRUE Node is the last node in the linked list.\r
323 @retval FALSE Node is not the last node in the linked list.\r
324\r
325**/\r
326BOOLEAN\r
327EFIAPI\r
328IsNodeAtEnd (\r
329 IN CONST LIST_ENTRY *List,\r
330 IN CONST LIST_ENTRY *Node\r
331 )\r
332{\r
333 //\r
334 // ASSERT List not too long and Node is one of the nodes of List\r
335 //\r
336 ASSERT (IsNodeInList (List, Node));\r
337\r
338 return (BOOLEAN)(!IsNull (List, Node) && List->BackLink == Node);\r
339}\r
340\r
341/**\r
342 Swaps the location of two nodes in a doubly linked list, and returns the\r
343 first node after the swap.\r
344\r
345 If FirstEntry is identical to SecondEntry, then SecondEntry is returned.\r
346 Otherwise, the location of the FirstEntry node is swapped with the location\r
347 of the SecondEntry node in a doubly linked list. SecondEntry must be in the\r
348 same double linked list as FirstEntry and that double linked list must have\r
349 been initialized with InitializeListHead(). SecondEntry is returned after the\r
350 nodes are swapped.\r
351\r
352 If FirstEntry is NULL, then ASSERT().\r
353 If SecondEntry is NULL, then ASSERT().\r
354 If SecondEntry and FirstEntry are not in the same linked list, then ASSERT().\r
30817eb4 355 If PcdMaximumLinkedListLength is not zero, and the number of nodes in the\r
356 linked list containing the FirstEntry and SecondEntry nodes, including\r
357 the FirstEntry and SecondEntry nodes, is greater than or equal to \r
358 PcdMaximumLinkedListLength, then ASSERT().\r
878ddf1f 359\r
360 @param FirstEntry A pointer to a node in a linked list.\r
361 @param SecondEntry A pointer to another node in the same linked list.\r
362\r
363**/\r
364LIST_ENTRY *\r
365EFIAPI\r
366SwapListEntries (\r
367 IN OUT LIST_ENTRY *FirstEntry,\r
368 IN OUT LIST_ENTRY *SecondEntry\r
369 )\r
370{\r
371 LIST_ENTRY *Ptr;\r
372\r
373 if (FirstEntry == SecondEntry) {\r
374 return SecondEntry;\r
375 }\r
376\r
377 //\r
378 // ASSERT Entry1 and Entry2 are in the same linked list\r
379 //\r
380 ASSERT (IsNodeInList (FirstEntry, SecondEntry));\r
381\r
382 //\r
383 // Ptr is the node pointed to by FirstEntry->ForwardLink\r
384 //\r
385 Ptr = RemoveEntryList (FirstEntry);\r
386\r
387 //\r
388 // If FirstEntry immediately follows SecondEntry, FirstEntry willl be placed\r
389 // immediately in front of SecondEntry\r
390 //\r
391 if (Ptr->BackLink == SecondEntry) {\r
392 return InsertTailList (SecondEntry, FirstEntry);\r
393 }\r
394\r
395 //\r
396 // Ptr == SecondEntry means SecondEntry immediately follows FirstEntry,\r
397 // then there are no further steps necessary\r
398 //\r
399 if (Ptr == InsertHeadList (SecondEntry, FirstEntry)) {\r
400 return Ptr;\r
401 }\r
402\r
403 //\r
404 // Move SecondEntry to the front of Ptr\r
405 //\r
406 RemoveEntryList (SecondEntry);\r
407 InsertTailList (Ptr, SecondEntry);\r
408 return SecondEntry;\r
409}\r
410\r
411/**\r
412 Removes a node from a doubly linked list, and returns the node that follows\r
413 the removed node.\r
414\r
415 Removes the node Entry from a doubly linked list. It is up to the caller of\r
416 this function to release the memory used by this node if that is required. On\r
417 exit, the node following Entry in the doubly linked list is returned. If\r
418 Entry is the only node in the linked list, then the head node of the linked\r
419 list is returned.\r
420\r
421 If Entry is NULL, then ASSERT().\r
422 If Entry is the head node of an empty list, then ASSERT().\r
30817eb4 423 If PcdMaximumLinkedListLength is not zero, and the number of nodes in the \r
424 linked list containing Entry, including the Entry node, is greater than \r
425 or equal to PcdMaximumLinkedListLength, then ASSERT().\r
878ddf1f 426\r
427 @param Entry A pointer to a node in a linked list\r
428\r
429 @return Entry\r
430\r
431**/\r
432LIST_ENTRY *\r
433EFIAPI\r
434RemoveEntryList (\r
435 IN CONST LIST_ENTRY *Entry\r
436 )\r
437{\r
438 ASSERT (!IsListEmpty (Entry));\r
439\r
440 Entry->ForwardLink->BackLink = Entry->BackLink;\r
441 Entry->BackLink->ForwardLink = Entry->ForwardLink;\r
442 return Entry->ForwardLink;\r
443}\r