2 * Amazon FreeRTOS Common V1.0.0
\r
3 * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\r
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
\r
6 * this software and associated documentation files (the "Software"), to deal in
\r
7 * the Software without restriction, including without limitation the rights to
\r
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
\r
9 * the Software, and to permit persons to whom the Software is furnished to do so,
\r
10 * subject to the following conditions:
\r
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software.
\r
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
22 * http://aws.amazon.com/freertos
\r
23 * http://www.FreeRTOS.org
\r
27 * @file iot_linear_containers.h
\r
28 * @brief Declares and implements doubly-linked lists and queues.
\r
31 #ifndef IOT_LINEAR_CONTAINERS_H_
\r
32 #define IOT_LINEAR_CONTAINERS_H_
\r
34 /* The config header is always included first. */
\r
35 #include "iot_config.h"
\r
37 /* Standard includes. */
\r
38 #include <stdbool.h>
\r
43 * @defgroup linear_containers_datatypes_listqueue List and queue
\r
44 * @brief Structures that represent a list or queue.
\r
48 * @ingroup linear_containers_datatypes_listqueue
\r
49 * @brief Link member placed in structs of a list or queue.
\r
51 * All elements in a list or queue must contain one of these members. The macro
\r
52 * #IotLink_Container can be used to calculate the starting address of the
\r
55 typedef struct IotLink
\r
57 struct IotLink * pPrevious; /**< @brief Pointer to the previous element. */
\r
58 struct IotLink * pNext; /**< @brief Pointer to the next element. */
\r
62 * @ingroup linear_containers_datatypes_listqueue
\r
63 * @brief Represents a doubly-linked list.
\r
65 typedef IotLink_t IotListDouble_t;
\r
68 * @ingroup linear_containers_datatypes_listqueue
\r
69 * @brief Represents a queue.
\r
71 typedef IotLink_t IotDeQueue_t;
\r
74 * @constantspage{linear_containers,linear containers library}
\r
76 * @section linear_containers_constants_initializers Linear Containers Initializers
\r
77 * @brief Provides default values for initializing the linear containers data types.
\r
79 * @snippet this define_linear_containers_initializers
\r
81 * All user-facing data types of the linear containers library should be initialized
\r
82 * using one of the following.
\r
84 * @warning Failure to initialize a linear containers data type with the appropriate
\r
85 * initializer may result in a runtime error!
\r
86 * @note The initializers may change at any time in future versions, but their
\r
87 * names will remain the same.
\r
89 /* @[define_linear_containers_initializers] */
\r
90 #define IOT_LINK_INITIALIZER { 0 } /**< @brief Initializer for an #IotLink_t. */
\r
91 #define IOT_LIST_DOUBLE_INITIALIZER IOT_LINK_INITIALIZER /**< @brief Initializer for an #IotListDouble_t. */
\r
92 #define IOT_DEQUEUE_INITIALIZER IOT_LINK_INITIALIZER /**< @brief Initializer for an #IotDeQueue_t. */
\r
93 /* @[define_linear_containers_initializers] */
\r
96 * @def IotContainers_Assert( expression )
\r
97 * @brief Assertion macro for the linear containers library.
\r
99 * Set @ref IOT_CONTAINERS_ENABLE_ASSERTS to `1` to enable assertions in the linear
\r
100 * containers library.
\r
102 * @param[in] expression Expression to be evaluated.
\r
104 #if IOT_CONTAINERS_ENABLE_ASSERTS == 1
\r
105 #ifndef IotContainers_Assert
\r
106 #include <assert.h>
\r
107 #define IotContainers_Assert( expression ) assert( expression )
\r
110 #define IotContainers_Assert( expression )
\r
114 * @brief Calculates the starting address of a containing struct.
\r
116 * @param[in] type Type of the containing struct.
\r
117 * @param[in] pLink Pointer to a link member.
\r
118 * @param[in] linkName Name of the #IotLink_t in the containing struct.
\r
120 #define IotLink_Container( type, pLink, linkName ) \
\r
121 ( ( type * ) ( void * ) ( ( ( uint8_t * ) ( pLink ) ) - offsetof( type, linkName ) ) )
\r
124 * @brief Iterates through all elements of a linear container.
\r
126 * Container elements must not be freed or removed while iterating.
\r
128 * @param[in] pStart The first element to iterate from.
\r
129 * @param[out] pLink Pointer to a container element.
\r
131 #define IotContainers_ForEach( pStart, pLink ) \
\r
132 for( ( pLink ) = ( pStart )->pNext; \
\r
133 ( pLink ) != ( pStart ); \
\r
134 ( pLink ) = ( pLink )->pNext )
\r
137 * @functionspage{linear_containers,linear containers library}
\r
138 * - @functionname{linear_containers_function_link_islinked}
\r
139 * - @functionname{linear_containers_function_list_double_create}
\r
140 * - @functionname{linear_containers_function_list_double_count}
\r
141 * - @functionname{linear_containers_function_list_double_isempty}
\r
142 * - @functionname{linear_containers_function_list_double_peekhead}
\r
143 * - @functionname{linear_containers_function_list_double_peektail}
\r
144 * - @functionname{linear_containers_function_list_double_inserthead}
\r
145 * - @functionname{linear_containers_function_list_double_inserttail}
\r
146 * - @functionname{linear_containers_function_list_double_insertbefore}
\r
147 * - @functionname{linear_containers_function_list_double_insertafter}
\r
148 * - @functionname{linear_containers_function_list_double_insertsorted}
\r
149 * - @functionname{linear_containers_function_list_double_remove}
\r
150 * - @functionname{linear_containers_function_list_double_removehead}
\r
151 * - @functionname{linear_containers_function_list_double_removetail}
\r
152 * - @functionname{linear_containers_function_list_double_removeall}
\r
153 * - @functionname{linear_containers_function_list_double_findfirstmatch}
\r
154 * - @functionname{linear_containers_function_list_double_removefirstmatch}
\r
155 * - @functionname{linear_containers_function_list_double_removeallmatches}
\r
156 * - @functionname{linear_containers_function_queue_create}
\r
157 * - @functionname{linear_containers_function_queue_count}
\r
158 * - @functionname{linear_containers_function_queue_isempty}
\r
159 * - @functionname{linear_containers_function_queue_peekhead}
\r
160 * - @functionname{linear_containers_function_queue_peektail}
\r
161 * - @functionname{linear_containers_function_queue_enqueuehead}
\r
162 * - @functionname{linear_containers_function_queue_dequeuehead}
\r
163 * - @functionname{linear_containers_function_queue_enqueuetail}
\r
164 * - @functionname{linear_containers_function_queue_dequeuetail}
\r
165 * - @functionname{linear_containers_function_queue_remove}
\r
166 * - @functionname{linear_containers_function_queue_removeall}
\r
167 * - @functionname{linear_containers_function_queue_removeallmatches}
\r
171 * @functionpage{IotLink_IsLinked,linear_containers,link_islinked}
\r
172 * @functionpage{IotListDouble_Create,linear_containers,list_double_create}
\r
173 * @functionpage{IotListDouble_Count,linear_containers,list_double_count}
\r
174 * @functionpage{IotListDouble_IsEmpty,linear_containers,list_double_isempty}
\r
175 * @functionpage{IotListDouble_PeekHead,linear_containers,list_double_peekhead}
\r
176 * @functionpage{IotListDouble_PeekTail,linear_containers,list_double_peektail}
\r
177 * @functionpage{IotListDouble_InsertHead,linear_containers,list_double_inserthead}
\r
178 * @functionpage{IotListDouble_InsertTail,linear_containers,list_double_inserttail}
\r
179 * @functionpage{IotListDouble_InsertBefore,linear_containers,list_double_insertbefore}
\r
180 * @functionpage{IotListDouble_InsertAfter,linear_containers,list_double_insertafter}
\r
181 * @functionpage{IotListDouble_InsertSorted,linear_containers,list_double_insertsorted}
\r
182 * @functionpage{IotListDouble_Remove,linear_containers,list_double_remove}
\r
183 * @functionpage{IotListDouble_RemoveHead,linear_containers,list_double_removehead}
\r
184 * @functionpage{IotListDouble_RemoveTail,linear_containers,list_double_removetail}
\r
185 * @functionpage{IotListDouble_RemoveAll,linear_containers,list_double_removeall}
\r
186 * @functionpage{IotListDouble_FindFirstMatch,linear_containers,list_double_findfirstmatch}
\r
187 * @functionpage{IotListDouble_RemoveFirstMatch,linear_containers,list_double_removefirstmatch}
\r
188 * @functionpage{IotListDouble_RemoveAllMatches,linear_containers,list_double_removeallmatches}
\r
189 * @functionpage{IotDeQueue_Create,linear_containers,queue_create}
\r
190 * @functionpage{IotDeQueue_Count,linear_containers,queue_count}
\r
191 * @functionpage{IotDeQueue_IsEmpty,linear_containers,queue_isempty}
\r
192 * @functionpage{IotDeQueue_PeekHead,linear_containers,queue_peekhead}
\r
193 * @functionpage{IotDeQueue_PeekTail,linear_containers,queue_peektail}
\r
194 * @functionpage{IotDeQueue_EnqueueHead,linear_containers,queue_enqueuehead}
\r
195 * @functionpage{IotDeQueue_DequeueHead,linear_containers,queue_dequeuehead}
\r
196 * @functionpage{IotDeQueue_EnqueueTail,linear_containers,queue_enqueuetail}
\r
197 * @functionpage{IotDeQueue_DequeueTail,linear_containers,queue_dequeuetail}
\r
198 * @functionpage{IotDeQueue_Remove,linear_containers,queue_remove}
\r
199 * @functionpage{IotDeQueue_RemoveAll,linear_containers,queue_removeall}
\r
200 * @functionpage{IotDeQueue_RemoveAllMatches,linear_containers,queue_removeallmatches}
\r
204 * @brief Check if an #IotLink_t is linked in a list or queue.
\r
206 * @param[in] pLink The link to check.
\r
208 * @return `true` if `pCurrent` is linked in a list or queue; `false` otherwise.
\r
210 /* @[declare_linear_containers_link_islinked] */
\r
211 static inline bool IotLink_IsLinked( const IotLink_t * const pLink )
\r
212 /* @[declare_linear_containers_link_islinked] */
\r
214 bool isLinked = false;
\r
216 if( pLink != NULL )
\r
218 isLinked = ( pLink->pNext != NULL ) && ( pLink->pPrevious != NULL );
\r
225 * @brief Create a new doubly-linked list.
\r
227 * This function initializes a new doubly-linked list. It must be called on an
\r
228 * uninitialized #IotListDouble_t before calling any other doubly-linked list
\r
229 * function. This function must not be called on an already-initialized
\r
230 * #IotListDouble_t.
\r
232 * This function will not fail. The function @ref linear_containers_function_list_double_removeall
\r
233 * may be called to destroy a list.
\r
235 * @param[in] pList Pointer to the memory that will hold the new doubly-linked list.
\r
237 /* @[declare_linear_containers_list_double_create] */
\r
238 static inline void IotListDouble_Create( IotListDouble_t * const pList )
\r
239 /* @[declare_linear_containers_list_double_create] */
\r
241 /* This function must not be called with a NULL parameter. */
\r
242 IotContainers_Assert( pList != NULL );
\r
244 /* An empty list is a link pointing to itself. */
\r
245 pList->pPrevious = pList;
\r
246 pList->pNext = pList;
\r
250 * @brief Return the number of elements contained in an #IotListDouble_t.
\r
252 * @param[in] pList The doubly-linked list with the elements to count.
\r
254 * @return The number of elements in the doubly-linked list.
\r
256 /* @[declare_linear_containers_list_double_count] */
\r
257 static inline size_t IotListDouble_Count( const IotListDouble_t * const pList )
\r
258 /* @[declare_linear_containers_list_double_count] */
\r
262 if( pList != NULL )
\r
264 /* Get the list head. */
\r
265 const IotLink_t * pCurrent = pList->pNext;
\r
267 /* Iterate through the list to count the elements. */
\r
268 while( pCurrent != pList )
\r
271 pCurrent = pCurrent->pNext;
\r
279 * @brief Check if a doubly-linked list is empty.
\r
281 * @param[in] pList The doubly-linked list to check.
\r
283 * @return `true` if the list is empty; `false` otherwise.
\r
285 /* @[declare_linear_containers_list_double_isempty] */
\r
286 static inline bool IotListDouble_IsEmpty( const IotListDouble_t * const pList )
\r
287 /* @[declare_linear_containers_list_double_isempty] */
\r
289 /* An empty list is NULL link, or a link pointing to itself. */
\r
290 return( ( pList == NULL ) || ( pList->pNext == pList ) );
\r
294 * @brief Return an #IotLink_t representing the first element in a doubly-linked list
\r
295 * without removing it.
\r
297 * @param[in] pList The list to peek.
\r
299 * @return Pointer to an #IotLink_t representing the element at the head of the
\r
300 * list; `NULL` if the list is empty. The macro #IotLink_Container may be used to
\r
301 * determine the address of the link's container.
\r
303 /* @[declare_linear_containers_list_double_peekhead] */
\r
304 static inline IotLink_t * IotListDouble_PeekHead( const IotListDouble_t * const pList )
\r
305 /* @[declare_linear_containers_list_double_peekhead] */
\r
307 IotLink_t * pHead = NULL;
\r
309 if( pList != NULL )
\r
311 if( IotListDouble_IsEmpty( pList ) == false )
\r
313 pHead = pList->pNext;
\r
321 * @brief Return an #IotLink_t representing the last element in a doubly-linked
\r
322 * list without removing it.
\r
324 * @param[in] pList The list to peek.
\r
326 * @return Pointer to an #IotLink_t representing the element at the tail of the
\r
327 * list; `NULL` if the list is empty. The macro #IotLink_Container may be used to
\r
328 * determine the address of the link's container.
\r
330 /* @[declare_linear_containers_list_double_peektail] */
\r
331 static inline IotLink_t * IotListDouble_PeekTail( const IotListDouble_t * const pList )
\r
332 /* @[declare_linear_containers_list_double_peektail] */
\r
334 IotLink_t * pTail = NULL;
\r
336 if( pList != NULL )
\r
338 if( IotListDouble_IsEmpty( pList ) == false )
\r
340 pTail = pList->pPrevious;
\r
348 * @brief Insert an element at the head of a doubly-linked list.
\r
350 * @param[in] pList The doubly-linked list that will hold the new element.
\r
351 * @param[in] pLink Pointer to the new element's link member.
\r
353 /* @[declare_linear_containers_list_double_inserthead] */
\r
354 static inline void IotListDouble_InsertHead( IotListDouble_t * const pList,
\r
355 IotLink_t * const pLink )
\r
356 /* @[declare_linear_containers_list_double_inserthead] */
\r
358 /* This function must not be called with NULL parameters. */
\r
359 IotContainers_Assert( pList != NULL );
\r
360 IotContainers_Assert( pLink != NULL );
\r
362 /* Save current list head. */
\r
363 IotLink_t * pHead = pList->pNext;
\r
365 /* Place new element before list head. */
\r
366 pLink->pNext = pHead;
\r
367 pLink->pPrevious = pList;
\r
369 /* Assign new list head. */
\r
370 pHead->pPrevious = pLink;
\r
371 pList->pNext = pLink;
\r
375 * @brief Insert an element at the tail of a doubly-linked list.
\r
377 * @param[in] pList The double-linked list that will hold the new element.
\r
378 * @param[in] pLink Pointer to the new element's link member.
\r
380 /* @[declare_linear_containers_list_double_inserttail] */
\r
381 static inline void IotListDouble_InsertTail( IotListDouble_t * const pList,
\r
382 IotLink_t * const pLink )
\r
383 /* @[declare_linear_containers_list_double_inserttail] */
\r
385 /* This function must not be called with NULL parameters. */
\r
386 IotContainers_Assert( pList != NULL );
\r
387 IotContainers_Assert( pLink != NULL );
\r
389 /* Save current list tail. */
\r
390 IotLink_t * pTail = pList->pPrevious;
\r
392 pLink->pNext = pList;
\r
393 pLink->pPrevious = pTail;
\r
395 pList->pPrevious = pLink;
\r
396 pTail->pNext = pLink;
\r
400 * @brief Insert an element before another element in a doubly-linked list.
\r
402 * @param[in] pElement The new element will be placed before this element.
\r
403 * @param[in] pLink Pointer to the new element's link member.
\r
405 /* @[declare_linear_containers_list_double_insertbefore] */
\r
406 static inline void IotListDouble_InsertBefore( IotLink_t * const pElement,
\r
407 IotLink_t * const pLink )
\r
408 /* @[declare_linear_containers_list_double_insertbefore] */
\r
410 IotListDouble_InsertTail( pElement, pLink );
\r
414 * @brief Insert an element after another element in a doubly-linked list.
\r
416 * @param[in] pElement The new element will be placed after this element.
\r
417 * @param[in] pLink Pointer to the new element's link member.
\r
419 /* @[declare_linear_containers_list_double_insertafter] */
\r
420 static inline void IotListDouble_InsertAfter( IotLink_t * const pElement,
\r
421 IotLink_t * const pLink )
\r
422 /* @[declare_linear_containers_list_double_insertafter] */
\r
424 IotListDouble_InsertHead( pElement, pLink );
\r
428 * @brief Insert an element in a sorted doubly-linked list.
\r
430 * Places an element into a list by sorting it into order. The function
\r
431 * `compare` is used to determine where to place the new element.
\r
433 * @param[in] pList The list that will hold the new element.
\r
434 * @param[in] pLink Pointer to the new element's link member.
\r
435 * @param[in] compare Determines the order of the list. Returns a negative
\r
436 * value if its first argument is less than its second argument; returns
\r
437 * zero if its first argument is equal to its second argument; returns a
\r
438 * positive value if its first argument is greater than its second argument.
\r
439 * The parameters to this function are #IotLink_t, so the macro #IotLink_Container
\r
440 * may be used to determine the address of the link's container.
\r
442 /* @[declare_linear_containers_list_double_insertsorted] */
\r
443 static inline void IotListDouble_InsertSorted( IotListDouble_t * const pList,
\r
444 IotLink_t * const pLink,
\r
445 int32_t ( *compare )( const IotLink_t * const, const IotLink_t * const ) )
\r
446 /* @[declare_linear_containers_list_double_insertsorted] */
\r
448 /* This function must not be called with NULL parameters. */
\r
449 IotContainers_Assert( pList != NULL );
\r
450 IotContainers_Assert( pLink != NULL );
\r
451 IotContainers_Assert( compare != NULL );
\r
453 /* Insert at head for empty list. */
\r
454 if( IotListDouble_IsEmpty( pList ) == true )
\r
456 IotListDouble_InsertHead( pList, pLink );
\r
460 bool inserted = false;
\r
461 IotLink_t * pCurrent = pList->pNext;
\r
463 /* Iterate through the list to find the correct position. */
\r
464 while( pCurrent != pList )
\r
466 /* Comparing for '<' preserves the order of insertion. */
\r
467 if( compare( pLink, pCurrent ) < 0 )
\r
469 IotListDouble_InsertBefore( pCurrent, pLink );
\r
475 pCurrent = pCurrent->pNext;
\r
478 /* New element is greater than all elements in list. Insert at tail. */
\r
479 if( inserted == false )
\r
481 IotListDouble_InsertTail( pList, pLink );
\r
487 * @brief Remove a single element from a doubly-linked list.
\r
489 * @param[in] pLink The element to remove.
\r
491 /* @[declare_linear_containers_list_double_remove] */
\r
492 static inline void IotListDouble_Remove( IotLink_t * const pLink )
\r
493 /* @[declare_linear_containers_list_double_remove] */
\r
495 /* This function must not be called with a NULL parameter. */
\r
496 IotContainers_Assert( pLink != NULL );
\r
498 /* This function must be called on a linked element. */
\r
499 IotContainers_Assert( IotLink_IsLinked( pLink ) == true );
\r
501 pLink->pPrevious->pNext = pLink->pNext;
\r
502 pLink->pNext->pPrevious = pLink->pPrevious;
\r
503 pLink->pPrevious = NULL;
\r
504 pLink->pNext = NULL;
\r
508 * @brief Remove the element at the head of a doubly-linked list.
\r
510 * @param[in] pList The doubly-linked list that holds the element to remove.
\r
512 * @return Pointer to an #IotLink_t representing the removed list head; `NULL`
\r
513 * if the list is empty. The macro #IotLink_Container may be used to determine
\r
514 * the address of the link's container.
\r
516 /* @[declare_linear_containers_list_double_removehead] */
\r
517 static inline IotLink_t * IotListDouble_RemoveHead( IotListDouble_t * const pList )
\r
518 /* @[declare_linear_containers_list_double_removehead] */
\r
520 IotLink_t * pHead = NULL;
\r
522 if( IotListDouble_IsEmpty( pList ) == false )
\r
524 pHead = pList->pNext;
\r
525 IotListDouble_Remove( pHead );
\r
532 * @brief Remove the element at the tail of a doubly-linked list.
\r
534 * @param[in] pList The doubly-linked list that holds the element to remove.
\r
536 * @return Pointer to an #IotLink_t representing the removed list tail; `NULL`
\r
537 * if the list is empty. The macro #IotLink_Container may be used to determine
\r
538 * the address of the link's container.
\r
540 /* @[declare_linear_containers_list_double_removetail] */
\r
541 static inline IotLink_t * IotListDouble_RemoveTail( IotListDouble_t * const pList )
\r
542 /* @[declare_linear_containers_list_double_removetail] */
\r
544 IotLink_t * pTail = NULL;
\r
546 if( IotListDouble_IsEmpty( pList ) == false )
\r
548 pTail = pList->pPrevious;
\r
549 IotListDouble_Remove( pTail );
\r
556 * @brief Remove all elements in a doubly-linked list.
\r
558 * @param[in] pList The list to empty.
\r
559 * @param[in] freeElement A function to free memory used by each removed list
\r
560 * element. Optional; pass `NULL` to ignore.
\r
561 * @param[in] linkOffset Offset in bytes of a link member in its container, used
\r
562 * to calculate the pointer to pass to `freeElement`. This value should be calculated
\r
563 * with the C `offsetof` macro. This parameter is ignored if `freeElement` is `NULL`
\r
564 * or its value is `0`.
\r
566 /* @[declare_linear_containers_list_double_removeall] */
\r
567 static inline void IotListDouble_RemoveAll( IotListDouble_t * const pList,
\r
568 void ( *freeElement )( void * ),
\r
569 size_t linkOffset )
\r
570 /* @[declare_linear_containers_list_double_removeall] */
\r
572 /* This function must not be called with a NULL pList parameter. */
\r
573 IotContainers_Assert( pList != NULL );
\r
575 /* Get the list head. */
\r
576 IotLink_t * pCurrent = pList->pNext;
\r
578 /* Iterate through the list and remove all elements. */
\r
579 while( pCurrent != pList )
\r
581 /* Save a pointer to the next list element. */
\r
582 IotLink_t * pNext = pCurrent->pNext;
\r
584 /* Remove and free the current list element. */
\r
585 IotListDouble_Remove( pCurrent );
\r
587 if( freeElement != NULL )
\r
589 freeElement( ( ( uint8_t * ) pCurrent ) - linkOffset );
\r
592 /* Move the iterating pointer to the next list element. */
\r
598 * @brief Search a doubly-linked list for the first matching element.
\r
600 * If a match is found, the matching element is <b>not</b> removed from the list.
\r
601 * See @ref linear_containers_function_list_double_removefirstmatch for the function
\r
602 * that searches and removes.
\r
604 * @param[in] pList The doubly-linked list to search.
\r
605 * @param[in] pStartPoint An element in `pList`. Only elements between this one and
\r
606 * the list tail are checked. Pass `NULL` to search from the beginning of the list.
\r
607 * @param[in] isMatch Function to determine if an element matches. Pass `NULL` to
\r
608 * search using the address `pMatch`, i.e. `element == pMatch`.
\r
609 * @param[in] pMatch If `isMatch` is `NULL`, each element in the list is compared
\r
610 * to this address to find a match. Otherwise, it is passed as the second argument
\r
613 * @return Pointer to an #IotLink_t representing the first matched element; `NULL`
\r
614 * if no match is found. The macro #IotLink_Container may be used to determine the
\r
615 * address of the link's container.
\r
617 /* @[declare_linear_containers_list_double_findfirstmatch] */
\r
618 static inline IotLink_t * IotListDouble_FindFirstMatch( const IotListDouble_t * const pList,
\r
619 const IotLink_t * const pStartPoint,
\r
620 bool ( *isMatch )( const IotLink_t * const, void * ),
\r
622 /* @[declare_linear_containers_list_double_findfirstmatch] */
\r
624 /* The const must be cast away to match this function's return value. Nevertheless,
\r
625 * this function will respect the const-ness of pStartPoint. */
\r
626 IotLink_t * pCurrent = ( IotLink_t * ) pStartPoint;
\r
628 /* This function must not be called with a NULL pList parameter. */
\r
629 IotContainers_Assert( pList != NULL );
\r
631 /* Search starting from list head if no start point is given. */
\r
632 if( pStartPoint == NULL )
\r
634 pCurrent = pList->pNext;
\r
637 /* Iterate through the list to search for matches. */
\r
638 while( pCurrent != pList )
\r
640 /* Call isMatch if provided. Otherwise, compare pointers. */
\r
641 if( isMatch != NULL )
\r
643 if( isMatch( pCurrent, pMatch ) == true )
\r
650 if( pCurrent == pMatch )
\r
656 pCurrent = pCurrent->pNext;
\r
659 /* No match found, return NULL. */
\r
664 * @brief Search a doubly-linked list for the first matching element and remove
\r
667 * An #IotLink_t may be passed as `pList` to start searching after the head of a
\r
668 * doubly-linked list.
\r
670 * @param[in] pList The doubly-linked list to search.
\r
671 * @param[in] pStartPoint An element in `pList`. Only elements between this one and
\r
672 * the list tail are checked. Pass `NULL` to search from the beginning of the list.
\r
673 * @param[in] isMatch Function to determine if an element matches. Pass `NULL` to
\r
674 * search using the address `pMatch`, i.e. `element == pMatch`.
\r
675 * @param[in] pMatch If `isMatch` is `NULL`, each element in the list is compared
\r
676 * to this address to find a match. Otherwise, it is passed as the second argument
\r
679 * @return Pointer to an #IotLink_t representing the matched and removed element;
\r
680 * `NULL` if no match is found. The macro #IotLink_Container may be used to determine
\r
681 * the address of the link's container.
\r
683 /* @[declare_linear_containers_list_double_removefirstmatch] */
\r
684 static inline IotLink_t * IotListDouble_RemoveFirstMatch( IotListDouble_t * const pList,
\r
685 const IotLink_t * const pStartPoint,
\r
686 bool ( *isMatch )( const IotLink_t *, void * ),
\r
688 /* @[declare_linear_containers_list_double_removefirstmatch] */
\r
690 IotLink_t * pMatchedElement = IotListDouble_FindFirstMatch( pList,
\r
695 if( pMatchedElement != NULL )
\r
697 IotListDouble_Remove( pMatchedElement );
\r
700 return pMatchedElement;
\r
704 * @brief Remove all matching elements from a doubly-linked list.
\r
706 * @param[in] pList The doubly-linked list to search.
\r
707 * @param[in] isMatch Function to determine if an element matches. Pass `NULL` to
\r
708 * search using the address `pMatch`, i.e. `element == pMatch`.
\r
709 * @param[in] pMatch If `isMatch` is `NULL`, each element in the list is compared
\r
710 * to this address to find a match. Otherwise, it is passed as the second argument
\r
712 * @param[in] freeElement A function to free memory used by each removed list
\r
713 * element. Optional; pass `NULL` to ignore.
\r
714 * @param[in] linkOffset Offset in bytes of a link member in its container, used
\r
715 * to calculate the pointer to pass to `freeElement`. This value should be calculated
\r
716 * with the C `offsetof` macro. This parameter is ignored if `freeElement` is `NULL`
\r
717 * or its value is `0`.
\r
719 /* @[declare_linear_containers_list_double_removeallmatches] */
\r
720 static inline void IotListDouble_RemoveAllMatches( IotListDouble_t * const pList,
\r
721 bool ( *isMatch )( const IotLink_t *, void * ),
\r
723 void ( *freeElement )( void * ),
\r
724 size_t linkOffset )
\r
725 /* @[declare_linear_containers_list_double_removeallmatches] */
\r
727 IotLink_t * pMatchedElement = NULL, * pNextElement = NULL;
\r
729 /* Search the list for all matching elements. */
\r
732 pMatchedElement = IotListDouble_FindFirstMatch( pList,
\r
737 if( pMatchedElement != NULL )
\r
739 /* Save pointer to next element. */
\r
740 pNextElement = pMatchedElement->pNext;
\r
742 /* Match found; remove and free. */
\r
743 IotListDouble_Remove( pMatchedElement );
\r
745 if( freeElement != NULL )
\r
747 freeElement( ( ( uint8_t * ) pMatchedElement ) - linkOffset );
\r
750 /* Continue search from next element. */
\r
751 pMatchedElement = pNextElement;
\r
753 } while( pMatchedElement != NULL );
\r
757 * @brief Create a new queue.
\r
759 * This function initializes a new double-ended queue. It must be called on an uninitialized
\r
760 * #IotDeQueue_t before calling any other queue function. This function must not be
\r
761 * called on an already-initialized #IotDeQueue_t.
\r
763 * This function will not fail.
\r
765 * @param[in] pQueue Pointer to the memory that will hold the new queue.
\r
767 /* @[declare_linear_containers_queue_create] */
\r
768 static inline void IotDeQueue_Create( IotDeQueue_t * const pQueue )
\r
769 /* @[declare_linear_containers_queue_create] */
\r
771 IotListDouble_Create( pQueue );
\r
775 * @brief Return the number of elements contained in an #IotDeQueue_t.
\r
777 * @param[in] pQueue The queue with the elements to count.
\r
779 * @return The number of items elements in the queue.
\r
781 /* @[declare_linear_containers_queue_count] */
\r
782 static inline size_t IotDeQueue_Count( const IotDeQueue_t * const pQueue )
\r
783 /* @[declare_linear_containers_queue_count] */
\r
785 return IotListDouble_Count( pQueue );
\r
789 * @brief Check if a queue is empty.
\r
791 * @param[in] pQueue The queue to check.
\r
793 * @return `true` if the queue is empty; `false` otherwise.
\r
796 /* @[declare_linear_containers_queue_isempty] */
\r
797 static inline bool IotDeQueue_IsEmpty( const IotDeQueue_t * const pQueue )
\r
798 /* @[declare_linear_containers_queue_isempty] */
\r
800 return IotListDouble_IsEmpty( pQueue );
\r
804 * @brief Return an #IotLink_t representing the element at the front of the queue
\r
805 * without removing it.
\r
807 * @param[in] pQueue The queue to peek.
\r
809 * @return Pointer to an #IotLink_t representing the element at the head of the
\r
810 * queue; `NULL` if the queue is empty. The macro #IotLink_Container may be used
\r
811 * to determine the address of the link's container.
\r
813 /* @[declare_linear_containers_queue_peekhead] */
\r
814 static inline IotLink_t * IotDeQueue_PeekHead( const IotDeQueue_t * const pQueue )
\r
815 /* @[declare_linear_containers_queue_peekhead] */
\r
817 return IotListDouble_PeekHead( pQueue );
\r
821 * @brief Return an #IotLink_t representing the element at the back of the queue
\r
822 * without removing it.
\r
824 * @param[in] pQueue The queue to peek.
\r
826 * @return Pointer to an #IotLink_t representing the element at the head of the
\r
827 * queue; `NULL` if the queue is empty. The macro #IotLink_Container may be used
\r
828 * to determine the address of the link's container.
\r
830 /* @[declare_linear_containers_queue_peektail] */
\r
831 static inline IotLink_t * IotDeQueue_PeekTail( const IotDeQueue_t * const pQueue )
\r
832 /* @[declare_linear_containers_queue_peektail] */
\r
834 return IotListDouble_PeekTail( pQueue );
\r
838 * @brief Add an element at the head of the queue.
\r
840 * @param[in] pQueue The queue that will hold the new element.
\r
841 * @param[in] pLink Pointer to the new element's link member.
\r
843 /* @[declare_linear_containers_queue_enqueuehead] */
\r
844 static inline void IotDeQueue_EnqueueHead( IotDeQueue_t * const pQueue,
\r
845 IotLink_t * const pLink )
\r
846 /* @[declare_linear_containers_queue_enqueuehead] */
\r
848 IotListDouble_InsertHead( pQueue, pLink );
\r
852 * @brief Remove an element at the head of the queue.
\r
854 * @param[in] pQueue The queue that holds the element to remove.
\r
856 * @return Pointer to an #IotLink_t representing the removed queue element; `NULL`
\r
857 * if the queue is empty. The macro #IotLink_Container may be used to determine
\r
858 * the address of the link's container.
\r
860 /* @[declare_linear_containers_queue_dequeuehead] */
\r
861 static inline IotLink_t * IotDeQueue_DequeueHead( IotDeQueue_t * const pQueue )
\r
862 /* @[declare_linear_containers_queue_dequeuehead] */
\r
864 return IotListDouble_RemoveHead( pQueue );
\r
868 * @brief Add an element at the tail of the queue.
\r
870 * @param[in] pQueue The queue that will hold the new element.
\r
871 * @param[in] pLink Pointer to the new element's link member.
\r
873 /* @[declare_linear_containers_queue_enqueuetail] */
\r
874 static inline void IotDeQueue_EnqueueTail( IotDeQueue_t * const pQueue,
\r
875 IotLink_t * const pLink )
\r
876 /* @[declare_linear_containers_queue_enqueuetail] */
\r
878 IotListDouble_InsertTail( pQueue, pLink );
\r
882 * @brief Remove an element at the tail of the queue.
\r
884 * @param[in] pQueue The queue that holds the element to remove.
\r
886 * @return Pointer to an #IotLink_t representing the removed queue element; `NULL`
\r
887 * if the queue is empty. The macro #IotLink_Container may be used to determine
\r
888 * the address of the link's container.
\r
890 /* @[declare_linear_containers_queue_dequeuetail] */
\r
891 static inline IotLink_t * IotDeQueue_DequeueTail( IotDeQueue_t * const pQueue )
\r
892 /* @[declare_linear_containers_queue_dequeuetail] */
\r
894 return IotListDouble_RemoveTail( pQueue );
\r
898 * @brief Remove a single element from a queue.
\r
900 * @param[in] pLink The element to remove.
\r
902 /* @[declare_linear_containers_queue_remove] */
\r
903 static inline void IotDeQueue_Remove( IotLink_t * const pLink )
\r
904 /* @[declare_linear_containers_queue_remove] */
\r
906 IotListDouble_Remove( pLink );
\r
910 * @brief Remove all elements in a queue.
\r
912 * @param[in] pQueue The queue to empty.
\r
913 * @param[in] freeElement A function to free memory used by each removed queue
\r
914 * element. Optional; pass `NULL` to ignore.
\r
915 * @param[in] linkOffset Offset in bytes of a link member in its container, used
\r
916 * to calculate the pointer to pass to `freeElement`. This value should be calculated
\r
917 * with the C `offsetof` macro. This parameter is ignored if `freeElement` is `NULL`
\r
918 * or its value is `0`.
\r
920 /* @[declare_linear_containers_queue_removeall] */
\r
921 static inline void IotDeQueue_RemoveAll( IotDeQueue_t * const pQueue,
\r
922 void ( * freeElement )( void * ),
\r
923 size_t linkOffset )
\r
924 /* @[declare_linear_containers_queue_removeall] */
\r
926 IotListDouble_RemoveAll( pQueue, freeElement, linkOffset );
\r
930 * @brief Remove all matching elements from a queue.
\r
932 * @param[in] pQueue The queue to search.
\r
933 * @param[in] isMatch Function to determine if an element matches. Pass `NULL` to
\r
934 * search using the address `pMatch`, i.e. `element == pMatch`.
\r
935 * @param[in] pMatch If `isMatch` is `NULL`, each element in the queue is compared
\r
936 * to this address to find a match. Otherwise, it is passed as the second argument
\r
938 * @param[in] freeElement A function to free memory used by each removed queue
\r
939 * element. Optional; pass `NULL` to ignore.
\r
940 * @param[in] linkOffset Offset in bytes of a link member in its container, used
\r
941 * to calculate the pointer to pass to `freeElement`. This value should be calculated
\r
942 * with the C `offsetof` macro. This parameter is ignored if `freeElement` is `NULL`
\r
943 * or its value is `0`.
\r
945 /* @[declare_linear_containers_queue_removeallmatches] */
\r
946 static inline void IotDeQueue_RemoveAllMatches( IotDeQueue_t * const pQueue,
\r
947 bool ( * isMatch )( const IotLink_t *, void * ),
\r
949 void ( * freeElement )( void * ),
\r
950 size_t linkOffset )
\r
951 /* @[declare_linear_containers_queue_removeallmatches] */
\r
953 IotListDouble_RemoveAllMatches( pQueue, isMatch, pMatch, freeElement, linkOffset );
\r
956 #endif /* IOT_LINEAR_CONTAINERS_H_ */
\r