]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdePkg/Library/BaseLib/LinkedList.c
MdePkg: Apply uncrustify changes
[mirror_edk2.git] / MdePkg / Library / BaseLib / LinkedList.c
... / ...
CommitLineData
1/** @file\r
2 Linked List Library Functions.\r
3\r
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
6\r
7**/\r
8\r
9#include "BaseLibInternals.h"\r
10\r
11/**\r
12 If PcdVerifyNodeInList is TRUE, ASSERTs when SecondEntry is or is not part of\r
13 the same doubly-linked list as FirstEntry depending on the value of InList.\r
14 Independent of PcdVerifyNodeInList, ASSERTs when FirstEntry is not part of a\r
15 valid list.\r
16\r
17 If FirstEntry is NULL, then ASSERT().\r
18 If FirstEntry->ForwardLink is NULL, then ASSERT().\r
19 If FirstEntry->BackLink is NULL, then ASSERT().\r
20 If PcdMaximumLinkedListLength is not zero, and List contains more than\r
21 PcdMaximumLinkedListLength nodes, then ASSERT().\r
22 If PcdVerifyNodeInList is TRUE and SecondEntry is NULL, then ASSERT().\r
23\r
24 @param FirstEntry A pointer to a node in a linked list.\r
25 @param SecondEntry A pointer to the node to locate.\r
26 @param InList Defines whether to check if SecondEntry is or is not part\r
27 of the same doubly-linked list as FirstEntry.\r
28\r
29**/\r
30#if !defined (MDEPKG_NDEBUG)\r
31#define ASSERT_VERIFY_NODE_IN_VALID_LIST(FirstEntry, SecondEntry, InList) \\r
32 do { \\r
33 if (FeaturePcdGet (PcdVerifyNodeInList)) { \\r
34 ASSERT (InList == IsNodeInList ((FirstEntry), (SecondEntry))); \\r
35 } else { \\r
36 ASSERT (InternalBaseLibIsListValid (FirstEntry)); \\r
37 } \\r
38 } while (FALSE)\r
39#else\r
40#define ASSERT_VERIFY_NODE_IN_VALID_LIST(FirstEntry, SecondEntry, InList)\r
41#endif\r
42\r
43/**\r
44 Worker function that verifies the validity of this list.\r
45\r
46 If List is NULL, then ASSERT().\r
47 If List->ForwardLink is NULL, then ASSERT().\r
48 If List->BackLink is NULL, then ASSERT().\r
49 If PcdMaximumLinkedListLength is not zero, and List contains more than\r
50 PcdMaximumLinkedListLength nodes, then ASSERT().\r
51\r
52 @param List A pointer to a node in a linked list.\r
53\r
54 @retval TRUE if PcdVerifyNodeInList is FALSE\r
55 @retval TRUE if DoMembershipCheck is FALSE\r
56 @retval TRUE if PcdVerifyNodeInList is TRUE and DoMembershipCheck is TRUE\r
57 and Node is a member of List.\r
58 @retval FALSE if PcdVerifyNodeInList is TRUE and DoMembershipCheck is TRUE\r
59 and Node is in not a member of List.\r
60\r
61**/\r
62BOOLEAN\r
63EFIAPI\r
64InternalBaseLibIsListValid (\r
65 IN CONST LIST_ENTRY *List\r
66 )\r
67{\r
68 UINTN Count;\r
69 CONST LIST_ENTRY *Ptr;\r
70\r
71 //\r
72 // Test the validity of List and Node\r
73 //\r
74 ASSERT (List != NULL);\r
75 ASSERT (List->ForwardLink != NULL);\r
76 ASSERT (List->BackLink != NULL);\r
77\r
78 if (PcdGet32 (PcdMaximumLinkedListLength) > 0) {\r
79 Count = 0;\r
80 Ptr = List;\r
81\r
82 //\r
83 // Count the total number of nodes in List.\r
84 // Exit early if the number of nodes in List >= PcdMaximumLinkedListLength\r
85 //\r
86 do {\r
87 Ptr = Ptr->ForwardLink;\r
88 Count++;\r
89 } while ((Ptr != List) && (Count < PcdGet32 (PcdMaximumLinkedListLength)));\r
90\r
91 //\r
92 // return whether linked list is too long\r
93 //\r
94 return (BOOLEAN)(Count < PcdGet32 (PcdMaximumLinkedListLength));\r
95 }\r
96\r
97 return TRUE;\r
98}\r
99\r
100/**\r
101 Checks whether FirstEntry and SecondEntry are part of the same doubly-linked\r
102 list.\r
103\r
104 If FirstEntry is NULL, then ASSERT().\r
105 If FirstEntry->ForwardLink is NULL, then ASSERT().\r
106 If FirstEntry->BackLink is NULL, then ASSERT().\r
107 If SecondEntry is NULL, then ASSERT();\r
108 If PcdMaximumLinkedListLength is not zero, and List contains more than\r
109 PcdMaximumLinkedListLength nodes, then ASSERT().\r
110\r
111 @param FirstEntry A pointer to a node in a linked list.\r
112 @param SecondEntry A pointer to the node to locate.\r
113\r
114 @retval TRUE SecondEntry is in the same doubly-linked list as FirstEntry.\r
115 @retval FALSE SecondEntry isn't in the same doubly-linked list as FirstEntry,\r
116 or FirstEntry is invalid.\r
117\r
118**/\r
119BOOLEAN\r
120EFIAPI\r
121IsNodeInList (\r
122 IN CONST LIST_ENTRY *FirstEntry,\r
123 IN CONST LIST_ENTRY *SecondEntry\r
124 )\r
125{\r
126 UINTN Count;\r
127 CONST LIST_ENTRY *Ptr;\r
128\r
129 //\r
130 // ASSERT List not too long\r
131 //\r
132 ASSERT (InternalBaseLibIsListValid (FirstEntry));\r
133\r
134 ASSERT (SecondEntry != NULL);\r
135\r
136 Count = 0;\r
137 Ptr = FirstEntry;\r
138\r
139 //\r
140 // Check to see if SecondEntry is a member of FirstEntry.\r
141 // Exit early if the number of nodes in List >= PcdMaximumLinkedListLength\r
142 //\r
143 do {\r
144 Ptr = Ptr->ForwardLink;\r
145 if (PcdGet32 (PcdMaximumLinkedListLength) > 0) {\r
146 Count++;\r
147\r
148 //\r
149 // Return if the linked list is too long\r
150 //\r
151 if (Count == PcdGet32 (PcdMaximumLinkedListLength)) {\r
152 return (BOOLEAN)(Ptr == SecondEntry);\r
153 }\r
154 }\r
155\r
156 if (Ptr == SecondEntry) {\r
157 return TRUE;\r
158 }\r
159 } while (Ptr != FirstEntry);\r
160\r
161 return FALSE;\r
162}\r
163\r
164/**\r
165 Initializes the head node of a doubly-linked list, and returns the pointer to\r
166 the head node of the doubly-linked list.\r
167\r
168 Initializes the forward and backward links of a new linked list. After\r
169 initializing a linked list with this function, the other linked list\r
170 functions may be used to add and remove nodes from the linked list. It is up\r
171 to the caller of this function to allocate the memory for ListHead.\r
172\r
173 If ListHead is NULL, then ASSERT().\r
174\r
175 @param ListHead A pointer to the head node of a new doubly-linked list.\r
176\r
177 @return ListHead\r
178\r
179**/\r
180LIST_ENTRY *\r
181EFIAPI\r
182InitializeListHead (\r
183 IN OUT LIST_ENTRY *ListHead\r
184 )\r
185\r
186{\r
187 ASSERT (ListHead != NULL);\r
188\r
189 ListHead->ForwardLink = ListHead;\r
190 ListHead->BackLink = ListHead;\r
191 return ListHead;\r
192}\r
193\r
194/**\r
195 Adds a node to the beginning of a doubly-linked list, and returns the pointer\r
196 to the head node of the doubly-linked list.\r
197\r
198 Adds the node Entry at the beginning of the doubly-linked list denoted by\r
199 ListHead, and returns ListHead.\r
200\r
201 If ListHead is NULL, then ASSERT().\r
202 If Entry is NULL, then ASSERT().\r
203 If ListHead was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or\r
204 InitializeListHead(), then ASSERT().\r
205 If PcdMaximumLinkedListLength is not zero, and prior to insertion the number\r
206 of nodes in ListHead, including the ListHead node, is greater than or\r
207 equal to PcdMaximumLinkedListLength, then ASSERT().\r
208\r
209 @param ListHead A pointer to the head node of a doubly-linked list.\r
210 @param Entry A pointer to a node that is to be inserted at the beginning\r
211 of a doubly-linked list.\r
212\r
213 @return ListHead\r
214\r
215**/\r
216LIST_ENTRY *\r
217EFIAPI\r
218InsertHeadList (\r
219 IN OUT LIST_ENTRY *ListHead,\r
220 IN OUT LIST_ENTRY *Entry\r
221 )\r
222{\r
223 //\r
224 // ASSERT List not too long and Entry is not one of the nodes of List\r
225 //\r
226 ASSERT_VERIFY_NODE_IN_VALID_LIST (ListHead, Entry, FALSE);\r
227\r
228 Entry->ForwardLink = ListHead->ForwardLink;\r
229 Entry->BackLink = ListHead;\r
230 Entry->ForwardLink->BackLink = Entry;\r
231 ListHead->ForwardLink = Entry;\r
232 return ListHead;\r
233}\r
234\r
235/**\r
236 Adds a node to the end of a doubly-linked list, and returns the pointer to\r
237 the head node of the doubly-linked list.\r
238\r
239 Adds the node Entry to the end of the doubly-linked list denoted by ListHead,\r
240 and returns ListHead.\r
241\r
242 If ListHead is NULL, then ASSERT().\r
243 If Entry is NULL, then ASSERT().\r
244 If ListHead was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or\r
245 InitializeListHead(), then ASSERT().\r
246 If PcdMaximumLinkedListLength is not zero, and prior to insertion the number\r
247 of nodes in ListHead, including the ListHead node, is greater than or\r
248 equal to PcdMaximumLinkedListLength, then ASSERT().\r
249\r
250 @param ListHead A pointer to the head node of a doubly-linked list.\r
251 @param Entry A pointer to a node that is to be added at the end of the\r
252 doubly-linked list.\r
253\r
254 @return ListHead\r
255\r
256**/\r
257LIST_ENTRY *\r
258EFIAPI\r
259InsertTailList (\r
260 IN OUT LIST_ENTRY *ListHead,\r
261 IN OUT LIST_ENTRY *Entry\r
262 )\r
263{\r
264 //\r
265 // ASSERT List not too long and Entry is not one of the nodes of List\r
266 //\r
267 ASSERT_VERIFY_NODE_IN_VALID_LIST (ListHead, Entry, FALSE);\r
268\r
269 Entry->ForwardLink = ListHead;\r
270 Entry->BackLink = ListHead->BackLink;\r
271 Entry->BackLink->ForwardLink = Entry;\r
272 ListHead->BackLink = Entry;\r
273 return ListHead;\r
274}\r
275\r
276/**\r
277 Retrieves the first node of a doubly-linked list.\r
278\r
279 Returns the first node of a doubly-linked list. List must have been\r
280 initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead().\r
281 If List is empty, then List is returned.\r
282\r
283 If List is NULL, then ASSERT().\r
284 If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or\r
285 InitializeListHead(), then ASSERT().\r
286 If PcdMaximumLinkedListLength is not zero, and the number of nodes\r
287 in List, including the List node, is greater than or equal to\r
288 PcdMaximumLinkedListLength, then ASSERT().\r
289\r
290 @param List A pointer to the head node of a doubly-linked list.\r
291\r
292 @return The first node of a doubly-linked list.\r
293 @retval List The list is empty.\r
294\r
295**/\r
296LIST_ENTRY *\r
297EFIAPI\r
298GetFirstNode (\r
299 IN CONST LIST_ENTRY *List\r
300 )\r
301{\r
302 //\r
303 // ASSERT List not too long\r
304 //\r
305 ASSERT (InternalBaseLibIsListValid (List));\r
306\r
307 return List->ForwardLink;\r
308}\r
309\r
310/**\r
311 Retrieves the next node of a doubly-linked list.\r
312\r
313 Returns the node of a doubly-linked list that follows Node.\r
314 List must have been initialized with INTIALIZE_LIST_HEAD_VARIABLE()\r
315 or InitializeListHead(). If List is empty, then List is returned.\r
316\r
317 If List is NULL, then ASSERT().\r
318 If Node is NULL, then ASSERT().\r
319 If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or\r
320 InitializeListHead(), then ASSERT().\r
321 If PcdMaximumLinkedListLength is not zero, and List contains more than\r
322 PcdMaximumLinkedListLength nodes, then ASSERT().\r
323 If PcdVerifyNodeInList is TRUE and Node is not a node in List, then ASSERT().\r
324\r
325 @param List A pointer to the head node of a doubly-linked list.\r
326 @param Node A pointer to a node in the doubly-linked list.\r
327\r
328 @return A pointer to the next node if one exists. Otherwise List is returned.\r
329\r
330**/\r
331LIST_ENTRY *\r
332EFIAPI\r
333GetNextNode (\r
334 IN CONST LIST_ENTRY *List,\r
335 IN CONST LIST_ENTRY *Node\r
336 )\r
337{\r
338 //\r
339 // ASSERT List not too long and Node is one of the nodes of List\r
340 //\r
341 ASSERT_VERIFY_NODE_IN_VALID_LIST (List, Node, TRUE);\r
342\r
343 return Node->ForwardLink;\r
344}\r
345\r
346/**\r
347 Retrieves the previous node of a doubly-linked list.\r
348\r
349 Returns the node of a doubly-linked list that precedes Node.\r
350 List must have been initialized with INTIALIZE_LIST_HEAD_VARIABLE()\r
351 or InitializeListHead(). If List is empty, then List is returned.\r
352\r
353 If List is NULL, then ASSERT().\r
354 If Node is NULL, then ASSERT().\r
355 If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or\r
356 InitializeListHead(), then ASSERT().\r
357 If PcdMaximumLinkedListLength is not zero, and List contains more than\r
358 PcdMaximumLinkedListLength nodes, then ASSERT().\r
359 If PcdVerifyNodeInList is TRUE and Node is not a node in List, then ASSERT().\r
360\r
361 @param List A pointer to the head node of a doubly-linked list.\r
362 @param Node A pointer to a node in the doubly-linked list.\r
363\r
364 @return A pointer to the previous node if one exists. Otherwise List is returned.\r
365\r
366**/\r
367LIST_ENTRY *\r
368EFIAPI\r
369GetPreviousNode (\r
370 IN CONST LIST_ENTRY *List,\r
371 IN CONST LIST_ENTRY *Node\r
372 )\r
373{\r
374 //\r
375 // ASSERT List not too long and Node is one of the nodes of List\r
376 //\r
377 ASSERT_VERIFY_NODE_IN_VALID_LIST (List, Node, TRUE);\r
378\r
379 return Node->BackLink;\r
380}\r
381\r
382/**\r
383 Checks to see if a doubly-linked list is empty or not.\r
384\r
385 Checks to see if the doubly-linked list is empty. If the linked list contains\r
386 zero nodes, this function returns TRUE. Otherwise, it returns FALSE.\r
387\r
388 If ListHead is NULL, then ASSERT().\r
389 If ListHead was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or\r
390 InitializeListHead(), then ASSERT().\r
391 If PcdMaximumLinkedListLength is not zero, and the number of nodes\r
392 in List, including the List node, is greater than or equal to\r
393 PcdMaximumLinkedListLength, then ASSERT().\r
394\r
395 @param ListHead A pointer to the head node of a doubly-linked list.\r
396\r
397 @retval TRUE The linked list is empty.\r
398 @retval FALSE The linked list is not empty.\r
399\r
400**/\r
401BOOLEAN\r
402EFIAPI\r
403IsListEmpty (\r
404 IN CONST LIST_ENTRY *ListHead\r
405 )\r
406{\r
407 //\r
408 // ASSERT List not too long\r
409 //\r
410 ASSERT (InternalBaseLibIsListValid (ListHead));\r
411\r
412 return (BOOLEAN)(ListHead->ForwardLink == ListHead);\r
413}\r
414\r
415/**\r
416 Determines if a node in a doubly-linked list is the head node of a the same\r
417 doubly-linked list. This function is typically used to terminate a loop that\r
418 traverses all the nodes in a doubly-linked list starting with the head node.\r
419\r
420 Returns TRUE if Node is equal to List. Returns FALSE if Node is one of the\r
421 nodes in the doubly-linked list specified by List. List must have been\r
422 initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead().\r
423\r
424 If List is NULL, then ASSERT().\r
425 If Node is NULL, then ASSERT().\r
426 If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead(),\r
427 then ASSERT().\r
428 If PcdMaximumLinkedListLength is not zero, and the number of nodes\r
429 in List, including the List node, is greater than or equal to\r
430 PcdMaximumLinkedListLength, then ASSERT().\r
431 If PcdVerifyNodeInList is TRUE and Node is not a node in List and Node is not\r
432 equal to List, then ASSERT().\r
433\r
434 @param List A pointer to the head node of a doubly-linked list.\r
435 @param Node A pointer to a node in the doubly-linked list.\r
436\r
437 @retval TRUE Node is the head of the doubly-linked list pointed by List.\r
438 @retval FALSE Node is not the head of the doubly-linked list pointed by List.\r
439\r
440**/\r
441BOOLEAN\r
442EFIAPI\r
443IsNull (\r
444 IN CONST LIST_ENTRY *List,\r
445 IN CONST LIST_ENTRY *Node\r
446 )\r
447{\r
448 //\r
449 // ASSERT List not too long and Node is one of the nodes of List\r
450 //\r
451 ASSERT_VERIFY_NODE_IN_VALID_LIST (List, Node, TRUE);\r
452\r
453 return (BOOLEAN)(Node == List);\r
454}\r
455\r
456/**\r
457 Determines if a node the last node in a doubly-linked list.\r
458\r
459 Returns TRUE if Node is the last node in the doubly-linked list specified by\r
460 List. Otherwise, FALSE is returned. List must have been initialized with\r
461 INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead().\r
462\r
463 If List is NULL, then ASSERT().\r
464 If Node is NULL, then ASSERT().\r
465 If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or\r
466 InitializeListHead(), then ASSERT().\r
467 If PcdMaximumLinkedListLength is not zero, and the number of nodes\r
468 in List, including the List node, is greater than or equal to\r
469 PcdMaximumLinkedListLength, then ASSERT().\r
470 If PcdVerifyNodeInList is TRUE and Node is not a node in List, then ASSERT().\r
471\r
472 @param List A pointer to the head node of a doubly-linked list.\r
473 @param Node A pointer to a node in the doubly-linked list.\r
474\r
475 @retval TRUE Node is the last node in the linked list.\r
476 @retval FALSE Node is not the last node in the linked list.\r
477\r
478**/\r
479BOOLEAN\r
480EFIAPI\r
481IsNodeAtEnd (\r
482 IN CONST LIST_ENTRY *List,\r
483 IN CONST LIST_ENTRY *Node\r
484 )\r
485{\r
486 //\r
487 // ASSERT List not too long and Node is one of the nodes of List\r
488 //\r
489 ASSERT_VERIFY_NODE_IN_VALID_LIST (List, Node, TRUE);\r
490\r
491 return (BOOLEAN)(!IsNull (List, Node) && List->BackLink == Node);\r
492}\r
493\r
494/**\r
495 Swaps the location of two nodes in a doubly-linked list, and returns the\r
496 first node after the swap.\r
497\r
498 If FirstEntry is identical to SecondEntry, then SecondEntry is returned.\r
499 Otherwise, the location of the FirstEntry node is swapped with the location\r
500 of the SecondEntry node in a doubly-linked list. SecondEntry must be in the\r
501 same double linked list as FirstEntry and that double linked list must have\r
502 been initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead().\r
503 SecondEntry is returned after the nodes are swapped.\r
504\r
505 If FirstEntry is NULL, then ASSERT().\r
506 If SecondEntry is NULL, then ASSERT().\r
507 If PcdVerifyNodeInList is TRUE and SecondEntry and FirstEntry are not in the\r
508 same linked list, then ASSERT().\r
509 If PcdMaximumLinkedListLength is not zero, and the number of nodes in the\r
510 linked list containing the FirstEntry and SecondEntry nodes, including\r
511 the FirstEntry and SecondEntry nodes, is greater than or equal to\r
512 PcdMaximumLinkedListLength, then ASSERT().\r
513\r
514 @param FirstEntry A pointer to a node in a linked list.\r
515 @param SecondEntry A pointer to another node in the same linked list.\r
516\r
517 @return SecondEntry.\r
518\r
519**/\r
520LIST_ENTRY *\r
521EFIAPI\r
522SwapListEntries (\r
523 IN OUT LIST_ENTRY *FirstEntry,\r
524 IN OUT LIST_ENTRY *SecondEntry\r
525 )\r
526{\r
527 LIST_ENTRY *Ptr;\r
528\r
529 if (FirstEntry == SecondEntry) {\r
530 return SecondEntry;\r
531 }\r
532\r
533 //\r
534 // ASSERT Entry1 and Entry2 are in the same linked list\r
535 //\r
536 ASSERT_VERIFY_NODE_IN_VALID_LIST (FirstEntry, SecondEntry, TRUE);\r
537\r
538 //\r
539 // Ptr is the node pointed to by FirstEntry->ForwardLink\r
540 //\r
541 Ptr = RemoveEntryList (FirstEntry);\r
542\r
543 //\r
544 // If FirstEntry immediately follows SecondEntry, FirstEntry will be placed\r
545 // immediately in front of SecondEntry\r
546 //\r
547 if (Ptr->BackLink == SecondEntry) {\r
548 return InsertTailList (SecondEntry, FirstEntry);\r
549 }\r
550\r
551 //\r
552 // Ptr == SecondEntry means SecondEntry immediately follows FirstEntry,\r
553 // then there are no further steps necessary\r
554 //\r
555 if (Ptr == InsertHeadList (SecondEntry, FirstEntry)) {\r
556 return Ptr;\r
557 }\r
558\r
559 //\r
560 // Move SecondEntry to the front of Ptr\r
561 //\r
562 RemoveEntryList (SecondEntry);\r
563 InsertTailList (Ptr, SecondEntry);\r
564 return SecondEntry;\r
565}\r
566\r
567/**\r
568 Removes a node from a doubly-linked list, and returns the node that follows\r
569 the removed node.\r
570\r
571 Removes the node Entry from a doubly-linked list. It is up to the caller of\r
572 this function to release the memory used by this node if that is required. On\r
573 exit, the node following Entry in the doubly-linked list is returned. If\r
574 Entry is the only node in the linked list, then the head node of the linked\r
575 list is returned.\r
576\r
577 If Entry is NULL, then ASSERT().\r
578 If Entry is the head node of an empty list, then ASSERT().\r
579 If PcdMaximumLinkedListLength is not zero, and the number of nodes in the\r
580 linked list containing Entry, including the Entry node, is greater than\r
581 or equal to PcdMaximumLinkedListLength, then ASSERT().\r
582\r
583 @param Entry A pointer to a node in a linked list.\r
584\r
585 @return Entry.\r
586\r
587**/\r
588LIST_ENTRY *\r
589EFIAPI\r
590RemoveEntryList (\r
591 IN CONST LIST_ENTRY *Entry\r
592 )\r
593{\r
594 ASSERT (!IsListEmpty (Entry));\r
595\r
596 Entry->ForwardLink->BackLink = Entry->BackLink;\r
597 Entry->BackLink->ForwardLink = Entry->ForwardLink;\r
598 return Entry->ForwardLink;\r
599}\r