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