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