le_doublyLinkedList.h

Go to the documentation of this file.
1 /**
2  * @page c_doublyLinkedList Doubly Linked List API
3  *
4  * @ref le_doublyLinkedList.h "API Reference"
5  *
6  * <HR>
7  *
8  * A doubly linked list is a data structure consisting of a group of nodes linked together linearly.
9  * Each node consists of data elements with links to the next node and previous nodes. The main
10  * advantage of linked lists (over simple arrays) is the nodes can be inserted and removed
11  * anywhere in the list without reallocating the entire array. Linked list nodes don't
12  * need to be stored contiguously in memory, but nodes then you can't access by
13  * index, you have to be access by traversing the list.
14  *
15  * @section dls_createList Creating and Initializing Lists
16  *
17  * To create and initialize a linked list the user must create a le_dls_List_t typed list and assign
18  * LE_DLS_LIST_INIT to it. The assignment of LE_DLS_LIST_INIT can be done either when the list is
19  * declared or after its declared. The list <b>must</b> be initialized before it can be
20  * used.
21  *
22  * @code
23  * // Create and initialized the list in the declaration.
24  * le_dls_List_t MyList = LE_DLS_LIST_INIT;
25  * @endcode
26  *
27  * Or
28  *
29  * @code
30  * // Create list.
31  * le_dls_List_t MyList;
32  *
33  * // Initialize the list.
34  * MyList = LE_DLS_LIST_INIT;
35  * @endcode
36  *
37  * <b> Elements of le_dls_List_t MUST NOT be accessed directly by the user. </b>
38  *
39  *
40  * @section dls_createNode Creating and Accessing Nodes
41  *
42  * Nodes can contain any data in any format and is defined and created by the user. The only
43  * requirement for nodes is that it must contain a @c le_dls_Link_t link member. The link member must
44  * be initialized by assigning LE_DLS_LINK_INIT to it before it can be used. Nodes can then be
45  * added to the list by passing their links to the add functions (le_dls_Stack(), le_dls_Queue(),
46  * etc.). For example:
47  *
48  * @code
49  * // The node may be defined like this.
50  * typedef struct
51  * {
52  * dataType someUserData;
53  * ...
54  * le_dls_Link_t myLink;
55  *
56  * }
57  * MyNodeClass_t;
58  *
59  * // Create and initialize the list.
60  * le_dls_List_t MyList = LE_DLS_LIST_INIT;
61  *
62  * void foo (void)
63  * {
64  * // Create the node. Get the memory from a memory pool previously created.
65  * MyNodeClass_t* myNodePtr = le_mem_ForceAlloc(MyNodePool);
66  *
67  * // Initialize the node's link.
68  * myNodePtr->myLink = LE_DLS_LINK_INIT;
69  *
70  * // Add the node to the head of the list by passing in the node's link.
71  * le_dls_Stack(&MyList, &(myNodePtr->myLink));
72  * }
73  * @endcode
74  *
75  * The links in the nodes are actually added to the list and not the nodes themselves. This
76  * allows a node to be included on multiple lists through links
77  * added to different lists. It also allows linking different type nodes in a list.
78  *
79  * To obtain the node itself, use the @c CONTAINER_OF macro defined in
80  * le_basics.h. Here's a code sample using CONTAINER_OF to obtain the node:
81  *
82  * @code
83  * // Assuming mylist has been created and initialized and is not empty.
84  * le_dls_Link_t* linkPtr = le_dls_Peek(&MyList);
85  *
86  * // Now we have the link but still need the node to access user data.
87  * // We use CONTAINER_OF to get a pointer to the node given the node's link.
88  * if (linkPtr != NULL)
89  * {
90  * MyNodeClass_t* myNodePtr = CONTAINER_OF(linkPtr, MyNodeClass_t, myLink);
91  * }
92  * @endcode
93  *
94  * The user is responsible for creating and freeing memory for all nodes; the linked list module
95  * only manages the links in the nodes. The node must be removed from all lists before its
96  * memory can be freed.
97  *
98  * <b>The elements of @c le_dls_Link_t MUST NOT be accessed directly by the user.</b>
99  *
100  *
101  * @section dls_add Adding Links to a List
102  *
103  * To add nodes to a list, pass the node's link to one of these functions:
104  *
105  * - @c le_dls_Stack() - Adds the link to the head of the list.
106  * - @c le_dls_Queue() - Adds the link to the tail of the list.
107  * - @c le_dls_AddAfter() - Adds the link to a list after another specified link.
108  * - @c le_dls_AddBefore() - Adds the link to a list before another specified link.
109  *
110  *
111  * @section dls_remove Removing Links from a List
112  *
113  * To remove nodes from a list, use one of these functions:
114  *
115  * - @c le_dls_Pop() - Removes and returns the link at the head of the list.
116  * - @c le_dls_PopTail() - Removes and returns the link at the tail of the list.
117  * - @c le_dls_Remove() - Remove a specified link from the list.
118  *
119  *
120  * @section dls_peek Accessing Links in a List
121  *
122  * To access a link in a list without removing the link, use one of these functions:
123  *
124  * - @c le_dls_Peek() - Returns the link at the head of the list without removing it.
125  * - @c le_dls_PeekTail() - Returns the link at the tail of the list without removing it.
126  * - @c le_dls_PeekNext() - Returns the link next to a specified link without removing it.
127  * - @c le_dls_PeekPrev() - Returns the link previous to a specified link without removing it.
128  *
129  *
130  * @section dls_swap Swapping Links
131  *
132  * To swap two links, use:
133  *
134  * - @c le_dls_Swap() - Swaps the position of two links in a list.
135  *
136  * The le_dls_Swap() function can be used to sort a list.
137  *
138  *
139  * @section dls_query Querying List Status
140  *
141  * These functions can be used to query a list's current status:
142  *
143  * - @c le_dls_IsEmpty() - Checks if a given list is empty.
144  * - @c le_dls_IsInList() - Checks if a specified link is in the list.
145  * - @c le_dls_IsHead() - Checks if a specified link is at the head of the list.
146  * - @c le_dls_IsTail() - Checks if a specified link is at the tail of the list.
147  * - @c le_dls_NumLinks() - Checks the number of links currently in the list.
148  * - @c le_dls_IsListCorrupted() - Checks if the list is corrupted.
149  *
150  *
151  * @section dls_fifo Queues and Stacks
152  *
153  * This implementation of linked lists can be used for either queues or stacks.
154  *
155  * To use the list as a queue, restrict additions to the list to @c le_dls_Queue() and removals
156  * from the list to @c le_dls_Pop().
157  *
158  * To use the list as a stack, restrict additions to the list to @c le_dls_Stack() and removals
159  * from the list to @c le_dls_Pop().
160  *
161  *
162  * @section dls_synch Thread Safety and Re-Entrancy
163  *
164  * All linked list function calls are re-entrant and thread safe themselves, but if the nodes and/or
165  * list object are shared by multiple threads, explicit steps must be taken to maintain mutual
166  * exclusion of access. If you're accessing the same list from multiple threads, you @e must use a
167  * @ref c_mutex "mutex" or some other form of thread synchronization to ensure only one thread
168  * accesses the list at a time.
169  *
170  * <HR>
171  *
172  * Copyright (C) Sierra Wireless Inc.
173  */
174 
175 
176  /** @file le_doublyLinkedList.h
177  *
178  * Legato @ref c_doublyLinkedList include file.
179  *
180  * Copyright (C) Sierra Wireless Inc.
181  */
182 
183 #ifndef LEGATO_DOUBLY_LINKED_LIST_INCLUDE_GUARD
184 #define LEGATO_DOUBLY_LINKED_LIST_INCLUDE_GUARD
185 
186 
187 //--------------------------------------------------------------------------------------------------
188 /**
189  * This link object must be included in each user node. The node's link object is used to add the
190  * node to a list. A node may have multiple link objects which would allow the node to be part of
191  * multiple lists simultaneously. This link object must be initialized by assigning
192  * LE_DLS_LINK_INIT to it.
193  *
194  * @warning The structure's content MUST NOT be accessed directly.
195  */
196 //--------------------------------------------------------------------------------------------------
197 typedef struct le_dls_Link
198 {
199  struct le_dls_Link* nextPtr; ///< Next link pointer.
200  struct le_dls_Link* prevPtr; ///< Previous link pointer.
201 }
203 
204 
205 //--------------------------------------------------------------------------------------------------
206 /**
207  * This is the list object. User must create this list object and initialize it by assigning
208  * LE_DLS_LIST_INIT to it.
209  *
210  * @warning User MUST NOT access the contents of this structure directly.
211  */
212 //--------------------------------------------------------------------------------------------------
213 typedef struct
214 {
215  le_dls_Link_t* headLinkPtr; ///< Link to list head.
216 }
218 
219 
220 //--------------------------------------------------------------------------------------------------
221 /**
222  * When a list is created it must be initialized by assigning this macro to the list before the list
223  * can be used.
224  */
225 //--------------------------------------------------------------------------------------------------
226 #define LE_DLS_LIST_INIT (le_dls_List_t){NULL}
227 
228 
229 //--------------------------------------------------------------------------------------------------
230 /**
231  * When a link is created it must be initialized by assigning this macro to the link before it can
232  * be used.
233  */
234 //--------------------------------------------------------------------------------------------------
235 #define LE_DLS_LINK_INIT (le_dls_Link_t){NULL, NULL}
236 
237 
238 //--------------------------------------------------------------------------------------------------
239 /**
240  * Adds a link at the head of the list.
241  */
242 //--------------------------------------------------------------------------------------------------
243 void le_dls_Stack
244 (
245  le_dls_List_t* listPtr, ///< [IN] List to add to.
246  le_dls_Link_t* newLinkPtr ///< [IN] New link to add.
247 );
248 
249 
250 //--------------------------------------------------------------------------------------------------
251 /**
252  * Adds a link to the tail of the list.
253  */
254 //--------------------------------------------------------------------------------------------------
255 void le_dls_Queue
256 (
257  le_dls_List_t* listPtr, ///< [IN] List to add to.
258  le_dls_Link_t* newLinkPtr ///< [IN] New link to add.
259 );
260 
261 
262 //--------------------------------------------------------------------------------------------------
263 /**
264  * Adds a link after currentLinkPtr. User must ensure that currentLinkPtr is in the list
265  * otherwise the behaviour of this function is undefined.
266  */
267 //--------------------------------------------------------------------------------------------------
268 void le_dls_AddAfter
269 (
270  le_dls_List_t* listPtr, ///< [IN] List to add to.
271  le_dls_Link_t* currentLinkPtr, ///< [IN] New link will be inserted after this link.
272  le_dls_Link_t* newLinkPtr ///< [IN] New link to add.
273 );
274 
275 
276 //--------------------------------------------------------------------------------------------------
277 /**
278  * Adds a link after currentLinkPtr. User must ensure that currentLinkPtr is in the list
279  * otherwise the behaviour of this function is undefined.
280  */
281 //--------------------------------------------------------------------------------------------------
282 void le_dls_AddBefore
283 (
284  le_dls_List_t* listPtr, ///< [IN] List to add to.
285  le_dls_Link_t* currentLinkPtr, ///< [IN] New link will be inserted before this link.
286  le_dls_Link_t* newLinkPtr ///< [IN] New link to add.
287 );
288 
289 
290 //--------------------------------------------------------------------------------------------------
291 /**
292  * Removes and returns the link at the head of the list.
293  *
294  * @return
295  * Removed link.
296  * NULL if the link is not available because the list is empty.
297  */
298 //--------------------------------------------------------------------------------------------------
300 (
301  le_dls_List_t* listPtr ///< [IN] List to remove from.
302 );
303 
304 
305 //--------------------------------------------------------------------------------------------------
306 /**
307  * Removes and returns the link at the tail of the list.
308  *
309  * @return
310  * The removed link.
311  * NULL if the link is not available because the list is empty.
312  */
313 //--------------------------------------------------------------------------------------------------
315 (
316  le_dls_List_t* listPtr ///< [IN] List to remove from.
317 );
318 
319 
320 //--------------------------------------------------------------------------------------------------
321 /**
322  * Removes the specified link from the list. Ensure the link is in the list
323  * otherwise the behaviour of this function is undefined.
324  */
325 //--------------------------------------------------------------------------------------------------
326 void le_dls_Remove
327 (
328  le_dls_List_t* listPtr, ///< [IN] List to remove from.
329  le_dls_Link_t* linkToRemovePtr ///< [IN] Link to remove.
330 );
331 
332 
333 //--------------------------------------------------------------------------------------------------
334 /**
335  * Returns the link at the head of the list without removing it from the list.
336  *
337  * @return
338  * Pointer to the head link if successful.
339  * NULL if the list is empty.
340  */
341 //--------------------------------------------------------------------------------------------------
343 (
344  const le_dls_List_t* listPtr ///< [IN] The list.
345 );
346 
347 
348 //--------------------------------------------------------------------------------------------------
349 /**
350  * Returns the link at the tail of the list without removing it from the list.
351  *
352  * @return
353  * A pointer to the tail link if successful.
354  * NULL if the list is empty.
355  */
356 //--------------------------------------------------------------------------------------------------
358 (
359  const le_dls_List_t* listPtr ///< [IN] The list.
360 );
361 
362 
363 //--------------------------------------------------------------------------------------------------
364 /**
365  * Checks if a list is empty.
366  *
367  * @return
368  * true if empty, false if not empty.
369  */
370 //--------------------------------------------------------------------------------------------------
371 static inline bool le_dls_IsEmpty
372 (
373  const le_dls_List_t* listPtr ///< [IN] The list.
374 )
375 //--------------------------------------------------------------------------------------------------
376 {
377  return (le_dls_Peek(listPtr) == NULL);
378 }
379 
380 
381 //--------------------------------------------------------------------------------------------------
382 /**
383  * Returns the link next to currentLinkPtr (i.e., the link beside currentLinkPtr that is closer to the
384  * tail) without removing it from the list. User must ensure that currentLinkPtr is in the list
385  * otherwise the behaviour of this function is undefined.
386  *
387  * @return
388  * Pointer to the next link if successful.
389  * NULL if there is no link next to the currentLinkPtr (currentLinkPtr is at the tail of the
390  * list).
391  */
392 //--------------------------------------------------------------------------------------------------
394 (
395  const le_dls_List_t* listPtr, ///< [IN] List containing currentLinkPtr.
396  const le_dls_Link_t* currentLinkPtr ///< [IN] Get the link that is relative to this link.
397 );
398 
399 
400 //--------------------------------------------------------------------------------------------------
401 /**
402  * Returns the link previous to currentLinkPtr without removing it from the list. User must
403  * ensure that currentLinkPtr is in the list otherwise the behaviour of this function is undefined.
404  *
405  * @return
406  * Pointer to the previous link if successful.
407  * NULL if there is no link previous to the currentLinkPtr (currentLinkPtr is at the head of
408  * the list).
409  */
410 //--------------------------------------------------------------------------------------------------
412 (
413  const le_dls_List_t* listPtr, ///< [IN] List containing currentLinkPtr.
414  const le_dls_Link_t* currentLinkPtr ///< [IN] Get the link that is relative to this link.
415 );
416 
417 
418 //--------------------------------------------------------------------------------------------------
419 /**
420  * Swaps the position of two links in the list. User must ensure that both links are in the
421  * list otherwise the behaviour of this function is undefined.
422  */
423 //--------------------------------------------------------------------------------------------------
424 void le_dls_Swap
425 (
426  le_dls_List_t* listPtr, ///< [IN] List containing the links to swap.
427  le_dls_Link_t* linkPtr, ///< [IN] One of the two link pointers to swap.
428  le_dls_Link_t* otherLinkPtr ///< [IN] Other link pointer to swap.
429 );
430 
431 
432 //--------------------------------------------------------------------------------------------------
433 /**
434  * Checks if a link is in the list.
435  *
436  * @return
437  * true if the link is in the list.
438  * false if the link is not in the list.
439  */
440 //--------------------------------------------------------------------------------------------------
441 bool le_dls_IsInList
442 (
443  const le_dls_List_t* listPtr, ///< [IN] List to check.
444  const le_dls_Link_t* linkPtr ///< [IN] Check if this link is in the list.
445 );
446 
447 
448 //--------------------------------------------------------------------------------------------------
449 /**
450  * Checks if a link is at the head of the list (next to be popped).
451  *
452  * @return
453  * - true if the link is at the head of the list.
454  * - false if not.
455  */
456 //--------------------------------------------------------------------------------------------------
457 static inline bool le_dls_IsHead
458 (
459  const le_dls_List_t* listPtr, ///< [IN] List to check.
460  const le_dls_Link_t* linkPtr ///< [IN] Check if this link is at the head of the list.
461 )
462 {
463  return (le_dls_Peek(listPtr) == linkPtr);
464 }
465 
466 
467 //--------------------------------------------------------------------------------------------------
468 /**
469  * Checks if a link is at the tail of the list (last to be popped).
470  *
471  * @return
472  * - true if the link is at the tail of the list.
473  * - false if not.
474  */
475 //--------------------------------------------------------------------------------------------------
476 static inline bool le_dls_IsTail
477 (
478  const le_dls_List_t* listPtr, ///< [IN] List to check.
479  const le_dls_Link_t* linkPtr ///< [IN] Check if this link is at the tail of the list.
480 )
481 {
482  return (le_dls_PeekTail(listPtr) == linkPtr);
483 }
484 
485 
486 //--------------------------------------------------------------------------------------------------
487 /**
488  * Returns the number of links in a list.
489  *
490  * @return
491  * Number of links.
492  */
493 //--------------------------------------------------------------------------------------------------
494 size_t le_dls_NumLinks
495 (
496  const le_dls_List_t* listPtr ///< [IN] List to count.
497 );
498 
499 
500 //--------------------------------------------------------------------------------------------------
501 /**
502  * Checks if the list is corrupted.
503  *
504  * @return
505  * true if the list is corrupted.
506  * false if the list is not corrupted.
507  */
508 //--------------------------------------------------------------------------------------------------
510 (
511  const le_dls_List_t* listPtr ///< [IN] List to check.
512 );
513 
514 //--------------------------------------------------------------------------------------------------
515 /**
516  * Simple iteration through a doubly linked list
517  */
518 //--------------------------------------------------------------------------------------------------
519 #define LE_DLS_FOREACH(listPtr, iteratorPtr, type, member) \
520  for ((iteratorPtr) = CONTAINER_OF(le_dls_Peek(listPtr), type, member); \
521  &((iteratorPtr)->member); \
522  (iteratorPtr) = CONTAINER_OF(le_dls_PeekNext((listPtr),&((iteratorPtr)->member)), \
523  type, member))
524 
525 
526 #endif // LEGATO_DOUBLY_LINKED_LIST_INCLUDE_GUARD
527 
static bool le_dls_IsTail(const le_dls_List_t *listPtr, const le_dls_Link_t *linkPtr)
Definition: le_doublyLinkedList.h:477
le_dls_Link_t * le_dls_PeekPrev(const le_dls_List_t *listPtr, const le_dls_Link_t *currentLinkPtr)
le_dls_Link_t * le_dls_PeekTail(const le_dls_List_t *listPtr)
static bool le_dls_IsEmpty(const le_dls_List_t *listPtr)
Definition: le_doublyLinkedList.h:372
void le_dls_AddBefore(le_dls_List_t *listPtr, le_dls_Link_t *currentLinkPtr, le_dls_Link_t *newLinkPtr)
void le_dls_Queue(le_dls_List_t *listPtr, le_dls_Link_t *newLinkPtr)
bool le_dls_IsListCorrupted(const le_dls_List_t *listPtr)
le_dls_Link_t * headLinkPtr
Link to list head.
Definition: le_doublyLinkedList.h:215
void le_dls_AddAfter(le_dls_List_t *listPtr, le_dls_Link_t *currentLinkPtr, le_dls_Link_t *newLinkPtr)
void le_dls_Remove(le_dls_List_t *listPtr, le_dls_Link_t *linkToRemovePtr)
le_dls_Link_t * le_dls_PeekNext(const le_dls_List_t *listPtr, const le_dls_Link_t *currentLinkPtr)
le_dls_Link_t * le_dls_Pop(le_dls_List_t *listPtr)
void le_dls_Stack(le_dls_List_t *listPtr, le_dls_Link_t *newLinkPtr)
static bool le_dls_IsHead(const le_dls_List_t *listPtr, const le_dls_Link_t *linkPtr)
Definition: le_doublyLinkedList.h:458
size_t le_dls_NumLinks(const le_dls_List_t *listPtr)
void le_dls_Swap(le_dls_List_t *listPtr, le_dls_Link_t *linkPtr, le_dls_Link_t *otherLinkPtr)
le_dls_Link_t * le_dls_PopTail(le_dls_List_t *listPtr)
Definition: le_doublyLinkedList.h:213
le_dls_Link_t * le_dls_Peek(const le_dls_List_t *listPtr)
bool le_dls_IsInList(const le_dls_List_t *listPtr, const le_dls_Link_t *linkPtr)