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