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. If the nodes and/or list
165  * object is shared by multiple threads, explicit steps must be taken to maintain mutual
166  * exclusion of access.
167  *
168  * <HR>
169  *
170  * Copyright (C) Sierra Wireless Inc. Use of this work is subject to license.
171  */
172 
173 
174  /** @file le_doublyLinkedList.h
175  *
176  * Legato @ref c_doublyLinkedList include file.
177  *
178  * Copyright (C) Sierra Wireless Inc. Use of this work is subject to license.
179  */
180 
181 #ifndef LEGATO_DOUBLY_LINKED_LIST_INCLUDE_GUARD
182 #define LEGATO_DOUBLY_LINKED_LIST_INCLUDE_GUARD
183 
184 
185 //--------------------------------------------------------------------------------------------------
186 /**
187  * This link object must be included in each user node. The node's link object is used to add the
188  * node to a list. A node may have multiple link objects which would allow the node to be part of
189  * multiple lists simultaneously. This link object must be initialized by assigning
190  * LE_DLS_LINK_INIT to it.
191  *
192  * @warning The structure's content MUST NOT be accessed directly.
193  */
194 //--------------------------------------------------------------------------------------------------
195 typedef struct le_dls_Link
196 {
197  struct le_dls_Link* nextPtr; ///< Next link pointer.
198  struct le_dls_Link* prevPtr; ///< Previous link pointer.
199 }
201 
202 
203 //--------------------------------------------------------------------------------------------------
204 /**
205  * This is the list object. User must create this list object and initialize it by assigning
206  * LE_DLS_LIST_INIT to it.
207  *
208  * @warning User MUST NOT access the contents of this structure directly.
209  */
210 //--------------------------------------------------------------------------------------------------
211 typedef struct
212 {
213  le_dls_Link_t* headLinkPtr; ///< Link to list head.
214 }
216 
217 
218 //--------------------------------------------------------------------------------------------------
219 /**
220  * When a list is created it must be initialized by assigning this macro to the list before the list
221  * can be used.
222  */
223 //--------------------------------------------------------------------------------------------------
224 #define LE_DLS_LIST_INIT (le_dls_List_t){NULL}
225 
226 
227 //--------------------------------------------------------------------------------------------------
228 /**
229  * When a link is created it must be initialized by assigning this macro to the link before it can
230  * be used.
231  */
232 //--------------------------------------------------------------------------------------------------
233 #define LE_DLS_LINK_INIT (le_dls_Link_t){NULL, NULL}
234 
235 
236 //--------------------------------------------------------------------------------------------------
237 /**
238  * Adds a link at the head of the list.
239  */
240 //--------------------------------------------------------------------------------------------------
241 void le_dls_Stack
242 (
243  le_dls_List_t* listPtr, ///< [IN] List to add to.
244  le_dls_Link_t* newLinkPtr ///< [IN] New link to add.
245 );
246 
247 
248 //--------------------------------------------------------------------------------------------------
249 /**
250  * Adds a link to the tail of the list.
251  */
252 //--------------------------------------------------------------------------------------------------
253 void le_dls_Queue
254 (
255  le_dls_List_t* listPtr, ///< [IN] List to add to.
256  le_dls_Link_t* newLinkPtr ///< [IN] New link to add.
257 );
258 
259 
260 //--------------------------------------------------------------------------------------------------
261 /**
262  * Adds a link after currentLinkPtr. User must ensure that currentLinkPtr is in the list
263  * otherwise the behaviour of this function is undefined.
264  */
265 //--------------------------------------------------------------------------------------------------
266 void le_dls_AddAfter
267 (
268  le_dls_List_t* listPtr, ///< [IN] List to add to.
269  le_dls_Link_t* currentLinkPtr, ///< [IN] New link will be inserted after this link.
270  le_dls_Link_t* newLinkPtr ///< [IN] New link to add.
271 );
272 
273 
274 //--------------------------------------------------------------------------------------------------
275 /**
276  * Adds a link after currentLinkPtr. User must ensure that currentLinkPtr is in the list
277  * otherwise the behaviour of this function is undefined.
278  */
279 //--------------------------------------------------------------------------------------------------
280 void le_dls_AddBefore
281 (
282  le_dls_List_t* listPtr, ///< [IN] List to add to.
283  le_dls_Link_t* currentLinkPtr, ///< [IN] New link will be inserted before this link.
284  le_dls_Link_t* newLinkPtr ///< [IN] New link to add.
285 );
286 
287 
288 //--------------------------------------------------------------------------------------------------
289 /**
290  * Removes and returns the link at the head of the list.
291  *
292  * @return
293  * Removed link.
294  * NULL if the link is not available because the list is empty.
295  */
296 //--------------------------------------------------------------------------------------------------
298 (
299  le_dls_List_t* listPtr ///< [IN] List to remove from.
300 );
301 
302 
303 //--------------------------------------------------------------------------------------------------
304 /**
305  * Removes and returns the link at the tail of the list.
306  *
307  * @return
308  * The removed link.
309  * NULL if the link is not available because the list is empty.
310  */
311 //--------------------------------------------------------------------------------------------------
313 (
314  le_dls_List_t* listPtr ///< [IN] List to remove from.
315 );
316 
317 
318 //--------------------------------------------------------------------------------------------------
319 /**
320  * Removes the specified link from the list. Ensure the link is in the list
321  * otherwise the behaviour of this function is undefined.
322  */
323 //--------------------------------------------------------------------------------------------------
324 void le_dls_Remove
325 (
326  le_dls_List_t* listPtr, ///< [IN] List to remove from.
327  le_dls_Link_t* linkToRemovePtr ///< [IN] Link to remove.
328 );
329 
330 
331 //--------------------------------------------------------------------------------------------------
332 /**
333  * Returns the link at the head of the list without removing it from the list.
334  *
335  * @return
336  * Pointer to the head link if successful.
337  * NULL if the list is empty.
338  */
339 //--------------------------------------------------------------------------------------------------
341 (
342  const le_dls_List_t* listPtr ///< [IN] The list.
343 );
344 
345 
346 //--------------------------------------------------------------------------------------------------
347 /**
348  * Returns the link at the tail of the list without removing it from the list.
349  *
350  * @return
351  * A pointer to the tail link if successful.
352  * NULL if the list is empty.
353  */
354 //--------------------------------------------------------------------------------------------------
356 (
357  const le_dls_List_t* listPtr ///< [IN] The list.
358 );
359 
360 
361 //--------------------------------------------------------------------------------------------------
362 /**
363  * Checks if a list is empty.
364  *
365  * @return
366  * true if empty, false if not empty.
367  */
368 //--------------------------------------------------------------------------------------------------
369 static inline bool le_dls_IsEmpty
370 (
371  const le_dls_List_t* listPtr ///< [IN] The list.
372 )
373 //--------------------------------------------------------------------------------------------------
374 {
375  return (le_dls_Peek(listPtr) == NULL);
376 }
377 
378 
379 //--------------------------------------------------------------------------------------------------
380 /**
381  * Returns the link next to currentLinkPtr (i.e., the link beside currentLinkPtr that is closer to the
382  * tail) without removing it from the list. User must ensure that currentLinkPtr is in the list
383  * otherwise the behaviour of this function is undefined.
384  *
385  * @return
386  * Pointer to the next link if successful.
387  * NULL if there is no link next to the currentLinkPtr (currentLinkPtr is at the tail of the
388  * list).
389  */
390 //--------------------------------------------------------------------------------------------------
392 (
393  const le_dls_List_t* listPtr, ///< [IN] List containing currentLinkPtr.
394  const le_dls_Link_t* currentLinkPtr ///< [IN] Get the link that is relative to this link.
395 );
396 
397 
398 //--------------------------------------------------------------------------------------------------
399 /**
400  * Returns the link previous to currentLinkPtr without removing it from the list. User must
401  * ensure that currentLinkPtr is in the list otherwise the behaviour of this function is undefined.
402  *
403  * @return
404  * Pointer to the previous link if successful.
405  * NULL if there is no link previous to the currentLinkPtr (currentLinkPtr is at the head of
406  * the list).
407  */
408 //--------------------------------------------------------------------------------------------------
410 (
411  const le_dls_List_t* listPtr, ///< [IN] List containing currentLinkPtr.
412  const le_dls_Link_t* currentLinkPtr ///< [IN] Get the link that is relative to this link.
413 );
414 
415 
416 //--------------------------------------------------------------------------------------------------
417 /**
418  * Swaps the position of two links in the list. User must ensure that both links are in the
419  * list otherwise the behaviour of this function is undefined.
420  */
421 //--------------------------------------------------------------------------------------------------
422 void le_dls_Swap
423 (
424  le_dls_List_t* listPtr, ///< [IN] List containing the links to swap.
425  le_dls_Link_t* linkPtr, ///< [IN] One of the two link pointers to swap.
426  le_dls_Link_t* otherLinkPtr ///< [IN] Other link pointer to swap.
427 );
428 
429 
430 //--------------------------------------------------------------------------------------------------
431 /**
432  * Checks if a link is in the list.
433  *
434  * @return
435  * true if the link is in the list.
436  * false if the link is not in the list.
437  */
438 //--------------------------------------------------------------------------------------------------
439 bool le_dls_IsInList
440 (
441  const le_dls_List_t* listPtr, ///< [IN] List to check.
442  const le_dls_Link_t* linkPtr ///< [IN] Check if this link is in the list.
443 );
444 
445 
446 //--------------------------------------------------------------------------------------------------
447 /**
448  * Checks if a link is at the head of the list (next to be popped).
449  *
450  * @return
451  * - true if the link is at the head of the list.
452  * - false if not.
453  */
454 //--------------------------------------------------------------------------------------------------
455 static inline bool le_dls_IsHead
456 (
457  const le_dls_List_t* listPtr, ///< [IN] List to check.
458  const le_dls_Link_t* linkPtr ///< [IN] Check if this link is at the head of the list.
459 )
460 {
461  return (le_dls_Peek(listPtr) == linkPtr);
462 }
463 
464 
465 //--------------------------------------------------------------------------------------------------
466 /**
467  * Checks if a link is at the tail of the list (last to be popped).
468  *
469  * @return
470  * - true if the link is at the tail of the list.
471  * - false if not.
472  */
473 //--------------------------------------------------------------------------------------------------
474 static inline bool le_dls_IsTail
475 (
476  const le_dls_List_t* listPtr, ///< [IN] List to check.
477  const le_dls_Link_t* linkPtr ///< [IN] Check if this link is at the tail of the list.
478 )
479 {
480  return (le_dls_PeekTail(listPtr) == linkPtr);
481 }
482 
483 
484 //--------------------------------------------------------------------------------------------------
485 /**
486  * Returns the number of links in a list.
487  *
488  * @return
489  * Number of links.
490  */
491 //--------------------------------------------------------------------------------------------------
492 size_t le_dls_NumLinks
493 (
494  const le_dls_List_t* listPtr ///< [IN] List to count.
495 );
496 
497 
498 //--------------------------------------------------------------------------------------------------
499 /**
500  * Checks if the list is corrupted.
501  *
502  * @return
503  * true if the list is corrupted.
504  * false if the list is not corrupted.
505  */
506 //--------------------------------------------------------------------------------------------------
508 (
509  const le_dls_List_t* listPtr ///< [IN] List to check.
510 );
511 
512 #endif // LEGATO_DOUBLY_LINKED_LIST_INCLUDE_GUARD
513 
void le_dls_AddAfter(le_dls_List_t *listPtr, le_dls_Link_t *currentLinkPtr, le_dls_Link_t *newLinkPtr)
le_dls_Link_t * le_dls_PeekTail(const le_dls_List_t *listPtr)
static bool le_dls_IsHead(const le_dls_List_t *listPtr, const le_dls_Link_t *linkPtr)
Definition: le_doublyLinkedList.h:456
le_dls_Link_t * le_dls_PeekPrev(const le_dls_List_t *listPtr, const le_dls_Link_t *currentLinkPtr)
bool le_dls_IsListCorrupted(const le_dls_List_t *listPtr)
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)
le_dls_Link_t * le_dls_PopTail(le_dls_List_t *listPtr)
Definition: le_doublyLinkedList.h:211
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)
le_dls_Link_t * headLinkPtr
Link to list head.
Definition: le_doublyLinkedList.h:213
bool le_dls_IsInList(const le_dls_List_t *listPtr, const le_dls_Link_t *linkPtr)
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_Peek(const le_dls_List_t *listPtr)
static bool le_dls_IsEmpty(const le_dls_List_t *listPtr)
Definition: le_doublyLinkedList.h:370
le_dls_Link_t * le_dls_PeekNext(const le_dls_List_t *listPtr, const le_dls_Link_t *currentLinkPtr)
static bool le_dls_IsTail(const le_dls_List_t *listPtr, const le_dls_Link_t *linkPtr)
Definition: le_doublyLinkedList.h:475
void le_dls_Remove(le_dls_List_t *listPtr, le_dls_Link_t *linkToRemovePtr)