VirtualBox

source: vbox/trunk/include/iprt/list.h@ 77807

Last change on this file since 77807 was 76585, checked in by vboxsync, 6 years ago

*: scm --fix-header-guard-endif

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.1 KB
Line 
1/** @file
2 * IPRT - Generic Doubly Linked List.
3 */
4
5/*
6 * Copyright (C) 2010-2019 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 *
16 * The contents of this file may alternatively be used under the terms
17 * of the Common Development and Distribution License Version 1.0
18 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
19 * VirtualBox OSE distribution, in which case the provisions of the
20 * CDDL are applicable instead of those of the GPL.
21 *
22 * You may elect to license modified versions of this file under the
23 * terms and conditions of either the GPL or the CDDL or both.
24 */
25
26#ifndef IPRT_INCLUDED_list_h
27#define IPRT_INCLUDED_list_h
28#ifndef RT_WITHOUT_PRAGMA_ONCE
29# pragma once
30#endif
31
32#include <iprt/types.h>
33
34/** @defgroup grp_rt_list RTList - Generic Doubly Linked List
35 * @ingroup grp_rt
36 *
37 * The list implementation is circular without any type wise distintion between
38 * the list and its nodes. This can be confusing since the list head usually
39 * resides in a different structure than the nodes, so care must be taken when
40 * walking the list.
41 *
42 * @{
43 */
44
45RT_C_DECLS_BEGIN
46
47/**
48 * A list node of a doubly linked list.
49 */
50typedef struct RTLISTNODE
51{
52 /** Pointer to the next list node. */
53 struct RTLISTNODE *pNext;
54 /** Pointer to the previous list node. */
55 struct RTLISTNODE *pPrev;
56} RTLISTNODE;
57/** Pointer to a list node. */
58typedef RTLISTNODE *PRTLISTNODE;
59/** Pointer to a const list node. */
60typedef RTLISTNODE const *PCRTLISTNODE;
61/** Pointer to a list node pointer. */
62typedef PRTLISTNODE *PPRTLISTNODE;
63
64/** The anchor (head/tail) of a doubly linked list.
65 *
66 * @remarks Please use this instead of RTLISTNODE to indicate a list
67 * head/tail. It makes the code so much easier to read. Also,
68 * always mention the actual list node type(s) in the comment. */
69typedef RTLISTNODE RTLISTANCHOR;
70/** Pointer to a doubly linked list anchor. */
71typedef RTLISTANCHOR *PRTLISTANCHOR;
72/** Pointer to a const doubly linked list anchor. */
73typedef RTLISTANCHOR const *PCRTLISTANCHOR;
74
75/** Version of RTLISTNODE for holding a ring-3 only list in data which gets
76 * shared between multiple contexts */
77#if defined(IN_RING3)
78typedef RTLISTNODE RTLISTNODER3;
79#else
80typedef struct { RTR3PTR aOffLimits[2]; } RTLISTNODER3;
81#endif
82/** Version of RTLISTANCHOR for holding a ring-3 only list in data which gets
83 * shared between multiple contexts */
84typedef RTLISTNODER3 RTLISTANCHORR3;
85
86
87/**
88 * Initialize a list.
89 *
90 * @param pList Pointer to an unitialised list.
91 */
92DECLINLINE(void) RTListInit(PRTLISTNODE pList)
93{
94 pList->pNext = pList;
95 pList->pPrev = pList;
96}
97
98/**
99 * Append a node to the end of the list.
100 *
101 * @param pList The list to append the node to.
102 * @param pNode The node to append.
103 */
104DECLINLINE(void) RTListAppend(PRTLISTNODE pList, PRTLISTNODE pNode)
105{
106 pList->pPrev->pNext = pNode;
107 pNode->pPrev = pList->pPrev;
108 pNode->pNext = pList;
109 pList->pPrev = pNode;
110}
111
112/**
113 * Add a node as the first element of the list.
114 *
115 * @param pList The list to prepend the node to.
116 * @param pNode The node to prepend.
117 */
118DECLINLINE(void) RTListPrepend(PRTLISTNODE pList, PRTLISTNODE pNode)
119{
120 pList->pNext->pPrev = pNode;
121 pNode->pNext = pList->pNext;
122 pNode->pPrev = pList;
123 pList->pNext = pNode;
124}
125
126/**
127 * Inserts a node after the specified one.
128 *
129 * @param pCurNode The current node.
130 * @param pNewNode The node to insert.
131 */
132DECLINLINE(void) RTListNodeInsertAfter(PRTLISTNODE pCurNode, PRTLISTNODE pNewNode)
133{
134 RTListPrepend(pCurNode, pNewNode);
135}
136
137/**
138 * Inserts a node before the specified one.
139 *
140 * @param pCurNode The current node.
141 * @param pNewNode The node to insert.
142 */
143DECLINLINE(void) RTListNodeInsertBefore(PRTLISTNODE pCurNode, PRTLISTNODE pNewNode)
144{
145 RTListAppend(pCurNode, pNewNode);
146}
147
148/**
149 * Remove a node from a list.
150 *
151 * @param pNode The node to remove.
152 */
153DECLINLINE(void) RTListNodeRemove(PRTLISTNODE pNode)
154{
155 PRTLISTNODE pPrev = pNode->pPrev;
156 PRTLISTNODE pNext = pNode->pNext;
157
158 pPrev->pNext = pNext;
159 pNext->pPrev = pPrev;
160
161 /* poison */
162 pNode->pNext = NULL;
163 pNode->pPrev = NULL;
164}
165
166
167/**
168 * Remove a node from a list, returns value.
169 *
170 * @returns pNode
171 * @param pNode The node to remove.
172 */
173DECLINLINE(PRTLISTNODE) RTListNodeRemoveRet(PRTLISTNODE pNode)
174{
175 PRTLISTNODE pPrev = pNode->pPrev;
176 PRTLISTNODE pNext = pNode->pNext;
177
178 pPrev->pNext = pNext;
179 pNext->pPrev = pPrev;
180
181 /* poison */
182 pNode->pNext = NULL;
183 pNode->pPrev = NULL;
184
185 return pNode;
186}
187
188/**
189 * Checks if a node is the last element in the list.
190 *
191 * @retval true if the node is the last element in the list.
192 * @retval false otherwise
193 *
194 * @param pList The list.
195 * @param pNode The node to check.
196 */
197#define RTListNodeIsLast(pList, pNode) ((pNode)->pNext == (pList))
198
199/**
200 * Checks if a node is the first element in the list.
201 *
202 * @retval true if the node is the first element in the list.
203 * @retval false otherwise.
204 *
205 * @param pList The list.
206 * @param pNode The node to check.
207 */
208#define RTListNodeIsFirst(pList, pNode) ((pNode)->pPrev == (pList))
209
210/**
211 * Checks if a type converted node is actually the dummy element (@a pList).
212 *
213 * @retval true if the node is the dummy element in the list.
214 * @retval false otherwise.
215 *
216 * @param pList The list.
217 * @param pNode The node structure to check. Typically
218 * something obtained from RTListNodeGetNext() or
219 * RTListNodeGetPrev(). This is NOT a PRTLISTNODE
220 * but something that contains a RTLISTNODE member!
221 * @param Type Structure the list node is a member of.
222 * @param Member The list node member.
223 */
224#define RTListNodeIsDummy(pList, pNode, Type, Member) \
225 ( (pNode) == RT_FROM_MEMBER((pList), Type, Member) )
226/** @copydoc RTListNodeIsDummy */
227#define RTListNodeIsDummyCpp(pList, pNode, Type, Member) \
228 ( (pNode) == RT_FROM_CPP_MEMBER((pList), Type, Member) )
229
230/**
231 * Checks if a list is empty.
232 *
233 * @retval true if the list is empty.
234 * @retval false otherwise.
235 *
236 * @param pList The list to check.
237 */
238#define RTListIsEmpty(pList) ((pList)->pPrev == (pList))
239
240/**
241 * Returns the next node in the list.
242 *
243 * @returns The next node.
244 *
245 * @param pCurNode The current node.
246 * @param Type Structure the list node is a member of.
247 * @param Member The list node member.
248 */
249#define RTListNodeGetNext(pCurNode, Type, Member) \
250 RT_FROM_MEMBER((pCurNode)->pNext, Type, Member)
251/** @copydoc RTListNodeGetNext */
252#define RTListNodeGetNextCpp(pCurNode, Type, Member) \
253 RT_FROM_CPP_MEMBER((pCurNode)->pNext, Type, Member)
254
255/**
256 * Returns the previous node in the list.
257 *
258 * @returns The previous node.
259 *
260 * @param pCurNode The current node.
261 * @param Type Structure the list node is a member of.
262 * @param Member The list node member.
263 */
264#define RTListNodeGetPrev(pCurNode, Type, Member) \
265 RT_FROM_MEMBER((pCurNode)->pPrev, Type, Member)
266/** @copydoc RTListNodeGetPrev */
267#define RTListNodeGetPrevCpp(pCurNode, Type, Member) \
268 RT_FROM_CPP_MEMBER((pCurNode)->pPrev, Type, Member)
269
270/**
271 * Returns the first element in the list (checks for empty list).
272 *
273 * @returns Pointer to the first list element, or NULL if empty list.
274 *
275 * @param pList List to get the first element from.
276 * @param Type Structure the list node is a member of.
277 * @param Member The list node member.
278 */
279#define RTListGetFirst(pList, Type, Member) \
280 (!RTListIsEmpty(pList) ? RTListNodeGetNext(pList, Type, Member) : NULL)
281/** @copydoc RTListGetFirst */
282#define RTListGetFirstCpp(pList, Type, Member) \
283 (!RTListIsEmpty(pList) ? RTListNodeGetNextCpp(pList, Type, Member) : NULL)
284
285/**
286 * Returns the last element in the list (checks for empty list).
287 *
288 * @returns Pointer to the last list element, or NULL if empty list.
289 *
290 * @param pList List to get the last element from.
291 * @param Type Structure the list node is a member of.
292 * @param Member The list node member.
293 */
294#define RTListGetLast(pList, Type, Member) \
295 (!RTListIsEmpty(pList) ? RTListNodeGetPrev(pList, Type, Member) : NULL)
296/** @copydoc RTListGetLast */
297#define RTListGetLastCpp(pList, Type, Member) \
298 (!RTListIsEmpty(pList) ? RTListNodeGetPrevCpp(pList, Type, Member) : NULL)
299
300/**
301 * Returns the next node in the list or NULL if the end has been reached.
302 *
303 * @returns The next node, or NULL if end of list.
304 *
305 * @param pList The list @a pCurNode is linked on.
306 * @param pCurNode The current node, of type @a Type.
307 * @param Type Structure the list node is a member of.
308 * @param Member The list node member.
309 */
310#define RTListGetNext(pList, pCurNode, Type, Member) \
311 ( (pCurNode)->Member.pNext != (pList) ? RT_FROM_MEMBER((pCurNode)->Member.pNext, Type, Member) : NULL )
312/** @copydoc RTListGetNext */
313#define RTListGetNextCpp(pList, pCurNode, Type, Member) \
314 ( (pCurNode)->Member.pNext != (pList) ? RT_FROM_CPP_MEMBER((pCurNode)->Member.pNext, Type, Member) : NULL )
315
316/**
317 * Returns the previous node in the list or NULL if the start has been reached.
318 *
319 * @returns The previous node, or NULL if end of list.
320 *
321 * @param pList The list @a pCurNode is linked on.
322 * @param pCurNode The current node, of type @a Type.
323 * @param Type Structure the list node is a member of.
324 * @param Member The list node member.
325 */
326#define RTListGetPrev(pList, pCurNode, Type, Member) \
327 ( (pCurNode)->Member.pPrev != (pList) ? RT_FROM_MEMBER((pCurNode)->Member.pPrev, Type, Member) : NULL )
328/** @copydoc RTListGetPrev */
329#define RTListGetPrevCpp(pList, pCurNode, Type, Member) \
330 ( (pCurNode)->Member.pPrev != (pList) ? RT_FROM_CPP_MEMBER((pCurNode)->Member.pPrev, Type, Member) : NULL )
331
332
333/**
334 * Removes and returns the first element in the list (checks for empty list).
335 *
336 * @returns Pointer to the first list element, or NULL if empty list.
337 *
338 * @param pList List to get the first element from.
339 * @param Type Structure the list node is a member of.
340 * @param Member The list node member.
341 */
342#define RTListRemoveFirst(pList, Type, Member) \
343 (!RTListIsEmpty(pList) ? RT_FROM_MEMBER(RTListNodeRemoveRet((pList)->pNext), Type, Member) : NULL)
344/** @copydoc RTListRemoveFirst */
345#define RTListRemoveFirstCpp(pList, Type, Member) \
346 (!RTListIsEmpty(pList) ? RT_FROM_CPP_MEMBER(RTListNodeRemoveRet((pList)->pNext), Type, Member) : NULL)
347
348/**
349 * Removes and returns the last element in the list (checks for empty list).
350 *
351 * @returns Pointer to the last list element, or NULL if empty list.
352 *
353 * @param pList List to get the last element from.
354 * @param Type Structure the list node is a member of.
355 * @param Member The list node member.
356 */
357#define RTListRemoveLast(pList, Type, Member) \
358 (!RTListIsEmpty(pList) ? RT_FROM_MEMBER(RTListNodeRemoveRet((pList)->pPrev), Type, Member) : NULL)
359/** @copydoc RTListRemoveLast */
360#define RTListRemoveLastCpp(pList, Type, Member) \
361 (!RTListIsEmpty(pList) ? RT_FROM_CPP_MEMBER(RTListNodeRemoveRet((pList)->pPrev), Type, Member) : NULL)
362
363/**
364 * Removes and returns the next node in the list or NULL if the end has been
365 * reached.
366 *
367 * @returns The next node, or NULL if end of list.
368 *
369 * @param pList The list @a pCurNode is linked on.
370 * @param pCurNode The current node, of type @a Type.
371 * @param Type Structure the list node is a member of.
372 * @param Member The list node member.
373 */
374#define RTListRemoveNext(pList, pCurNode, Type, Member) \
375 ( (pCurNode)->Member.pNext != (pList) ? RT_FROM_MEMBER(RTListNodeRemoveRet((pCurNode)->Member.pNext), Type, Member) : NULL )
376/** @copydoc RTListRemoveNext */
377#define RTListRemoveNextCpp(pList, pCurNode, Type, Member) \
378 ( (pCurNode)->Member.pNext != (pList) ? RT_FROM_CPP_MEMBER(RTListNodeRemoveRet((pCurNode)->Member.pNext), Type, Member) : NULL )
379
380/**
381 * Removes and returns the previous node in the list or NULL if the start has
382 * been reached.
383 *
384 * @returns The previous node, or NULL if end of list.
385 *
386 * @param pList The list @a pCurNode is linked on.
387 * @param pCurNode The current node, of type @a Type.
388 * @param Type Structure the list node is a member of.
389 * @param Member The list node member.
390 */
391#define RTListRemovePrev(pList, pCurNode, Type, Member) \
392 ( (pCurNode)->Member.pNext != (pList) ? RT_FROM_MEMBER(RTListNodeRemoveRet((pCurNode)->Member.pPrev), Type, Member) : NULL )
393/** @copydoc RTListRemovePrev */
394#define RTListRemovePrevCpp(pList, pCurNode, Type, Member) \
395 ( (pCurNode)->Member.pNext != (pList) ? RT_FROM_CPP_MEMBER(RTListNodeRemoveRet((pCurNode)->Member.pPrev), Type, Member) : NULL )
396
397
398/**
399 * Enumerate the list in head to tail order.
400 *
401 * @param pList List to enumerate.
402 * @param pIterator The iterator variable name.
403 * @param Type Structure the list node is a member of.
404 * @param Member The list node member name.
405 */
406#define RTListForEach(pList, pIterator, Type, Member) \
407 for (pIterator = RTListNodeGetNext(pList, Type, Member); \
408 !RTListNodeIsDummy(pList, pIterator, Type, Member); \
409 pIterator = RT_FROM_MEMBER((pIterator)->Member.pNext, Type, Member) )
410/** @copydoc RTListForEach */
411#define RTListForEachCpp(pList, pIterator, Type, Member) \
412 for (pIterator = RTListNodeGetNextCpp(pList, Type, Member); \
413 !RTListNodeIsDummyCpp(pList, pIterator, Type, Member); \
414 pIterator = RT_FROM_CPP_MEMBER((pIterator)->Member.pNext, Type, Member) )
415
416
417/**
418 * Enumerate the list in head to tail order, safe against removal of the
419 * current node.
420 *
421 * @param pList List to enumerate.
422 * @param pIterator The iterator variable name.
423 * @param pIterNext The name of the variable saving the pointer to
424 * the next element.
425 * @param Type Structure the list node is a member of.
426 * @param Member The list node member name.
427 */
428#define RTListForEachSafe(pList, pIterator, pIterNext, Type, Member) \
429 for (pIterator = RTListNodeGetNext(pList, Type, Member), \
430 pIterNext = RT_FROM_MEMBER((pIterator)->Member.pNext, Type, Member); \
431 !RTListNodeIsDummy(pList, pIterator, Type, Member); \
432 pIterator = pIterNext, \
433 pIterNext = RT_FROM_MEMBER((pIterator)->Member.pNext, Type, Member) )
434/** @copydoc RTListForEachSafe */
435#define RTListForEachSafeCpp(pList, pIterator, pIterNext, Type, Member) \
436 for (pIterator = RTListNodeGetNextCpp(pList, Type, Member), \
437 pIterNext = RT_FROM_CPP_MEMBER((pIterator)->Member.pNext, Type, Member); \
438 !RTListNodeIsDummyCpp(pList, pIterator, Type, Member); \
439 pIterator = pIterNext, \
440 pIterNext = RT_FROM_CPP_MEMBER((pIterator)->Member.pNext, Type, Member) )
441
442
443/**
444 * Enumerate the list in reverse order (tail to head).
445 *
446 * @param pList List to enumerate.
447 * @param pIterator The iterator variable name.
448 * @param Type Structure the list node is a member of.
449 * @param Member The list node member name.
450 */
451#define RTListForEachReverse(pList, pIterator, Type, Member) \
452 for (pIterator = RTListNodeGetPrev(pList, Type, Member); \
453 !RTListNodeIsDummy(pList, pIterator, Type, Member); \
454 pIterator = RT_FROM_MEMBER((pIterator)->Member.pPrev, Type, Member) )
455/** @copydoc RTListForEachReverse */
456#define RTListForEachReverseCpp(pList, pIterator, Type, Member) \
457 for (pIterator = RTListNodeGetPrevCpp(pList, Type, Member); \
458 !RTListNodeIsDummyCpp(pList, pIterator, Type, Member); \
459 pIterator = RT_FROM_CPP_MEMBER((pIterator)->Member.pPrev, Type, Member) )
460
461
462/**
463 * Enumerate the list in reverse order (tail to head).
464 *
465 * @param pList List to enumerate.
466 * @param pIterator The iterator variable name.
467 * @param pIterPrev The name of the variable saving the pointer to
468 * the previous element.
469 * @param Type Structure the list node is a member of.
470 * @param Member The list node member name.
471 */
472#define RTListForEachReverseSafe(pList, pIterator, pIterPrev, Type, Member) \
473 for (pIterator = RTListNodeGetPrev(pList, Type, Member), \
474 pIterPrev = RT_FROM_MEMBER((pIterator)->Member.pPrev, Type, Member); \
475 !RTListNodeIsDummy(pList, pIterator, Type, Member); \
476 pIterator = pIterPrev, \
477 pIterPrev = RT_FROM_MEMBER((pIterator)->Member.pPrev, Type, Member) )
478/** @copydoc RTListForEachReverseSafe */
479#define RTListForEachReverseSafeCpp(pList, pIterator, pIterPrev, Type, Member) \
480 for (pIterator = RTListNodeGetPrevCpp(pList, Type, Member), \
481 pIterPrev = RT_FROM_CPP_MEMBER((pIterator)->Member.pPrev, Type, Member); \
482 !RTListNodeIsDummyCpp(pList, pIterator, Type, Member); \
483 pIterator = pIterPrev, \
484 pIterPrev = RT_FROM_CPP_MEMBER((pIterator)->Member.pPrev, Type, Member) )
485
486
487/**
488 * Move the given list to a new list header.
489 *
490 * @param pListDst The new list.
491 * @param pListSrc The list to move.
492 */
493DECLINLINE(void) RTListMove(PRTLISTNODE pListDst, PRTLISTNODE pListSrc)
494{
495 if (!RTListIsEmpty(pListSrc))
496 {
497 pListDst->pNext = pListSrc->pNext;
498 pListDst->pPrev = pListSrc->pPrev;
499
500 /* Adjust the first and last element links */
501 pListDst->pNext->pPrev = pListDst;
502 pListDst->pPrev->pNext = pListDst;
503
504 /* Finally remove the elements from the source list */
505 RTListInit(pListSrc);
506 }
507 else
508 RTListInit(pListDst);
509}
510
511/**
512 * List concatenation.
513 *
514 * @returns nothing.
515 * @param pListDst The destination list.
516 * @param pListSrc The source list to concatenate.
517 */
518DECLINLINE(void) RTListConcatenate(PRTLISTANCHOR pListDst, PRTLISTANCHOR pListSrc)
519{
520 if (!RTListIsEmpty(pListSrc))
521 {
522 PRTLISTNODE pFirst = pListSrc->pNext;
523 PRTLISTNODE pLast = pListSrc->pPrev;
524
525 pListDst->pPrev->pNext = pFirst;
526 pFirst->pPrev = pListDst->pPrev;
527 pLast->pNext = pListDst;
528 pListDst->pPrev = pLast;
529
530 /* Finally remove the elements from the source list */
531 RTListInit(pListSrc);
532 }
533}
534
535RT_C_DECLS_END
536
537/** @} */
538
539#endif /* !IPRT_INCLUDED_list_h */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette