|
C Container Collection (CCC)
|
The Doubly Linked List Interface. More...


Go to the source code of this file.
The Doubly Linked List Interface.
A doubly linked list offers efficient push, pop, extract, and erase operations for elements stored in the list. For single elements, the list can offer O(1) push front/back, pop front/back, and removal of elements in arbitrary positions in the list. The cost of this efficiency is higher memory footprint. The linked list does not track internal state other than the head and tail of the list and type information about the user type stored in the list. Therefore, be aware that obtaining the count of nodes is an O(N) operation. Determining if the list is empty, however, is O(1).
This container offers pointer stability. Also, if the container function requesting an allocator is not provided one, all insertion code assumes that the user has allocated memory appropriately for the element to be inserted; it will not allocate or free in this case. If an allocator is passed to a function requesting one, the container will manage the memory as expected on insert or erase operations as defined by the interface; memory is allocated for insertions and freed for removals.
To shorten names in the interface, define the following preprocessor directive at the top of your file.
All types and functions can then be written without the CCC_ prefix.
Initialization Interface | |
Initialize the container with memory, callbacks, and permissions. | |
| #define | CCC_doubly_linked_list_default(type_name, type_intruder_field) CCC_private_doubly_linked_list_for(type_name, type_intruder_field) |
| Initialize an intrusive doubly linked list for a type with a user specified intruder field. | |
| #define | CCC_doubly_linked_list_for(type_name, type_intruder_field) CCC_private_doubly_linked_list_for(type_name, type_intruder_field) |
| Initialize an intrusive doubly linked list for a type with a user specified intruder field. | |
| #define | CCC_doubly_linked_list_from( type_intruder_field, allocator, destructor, compound_literal_array...) |
| Initialize a doubly linked list at runtime from a compound literal array. | |
Insert and Remove Interface | |
Add or remove elements from the doubly linked list. | |
| #define | CCC_doubly_linked_list_emplace_back( list_pointer, allocator_pointer, type_compound_literal...) |
| writes contents of type initializer directly to allocated memory at the back of the list. O(1). | |
| #define | CCC_doubly_linked_list_emplace_front( list_pointer, allocator_pointer, type_compound_literal...) |
| writes contents of type initializer directly to allocated memory at the front of the list. O(1). | |
| void * | CCC_doubly_linked_list_push_front (CCC_Doubly_linked_list *list, CCC_Doubly_linked_list_node *type_intruder, CCC_Allocator const *allocator) |
| Push user type wrapping type_intruder to the front of the list. O(1). | |
| void * | CCC_doubly_linked_list_push_back (CCC_Doubly_linked_list *list, CCC_Doubly_linked_list_node *type_intruder, CCC_Allocator const *allocator) |
| Push user type wrapping type_intruder to the back of the list. O(1). | |
| void * | CCC_doubly_linked_list_insert (CCC_Doubly_linked_list *list, CCC_Doubly_linked_list_node *position_node, CCC_Doubly_linked_list_node *type_intruder, CCC_Allocator const *allocator) |
| Insert user type wrapping type_intruder before position_node. O(1). | |
| CCC_Result | CCC_doubly_linked_list_pop_front (CCC_Doubly_linked_list *list, CCC_Allocator const *allocator) |
| Pop the user type at the front of the list. O(1). | |
| CCC_Result | CCC_doubly_linked_list_pop_back (CCC_Doubly_linked_list *list, CCC_Allocator const *allocator) |
| Pop the user type at the back of the list. O(1). | |
| void * | CCC_doubly_linked_list_extract (CCC_Doubly_linked_list *list, CCC_Doubly_linked_list_node *type_intruder) |
| Returns the element following an extracted element from the list without deallocating regardless of allocation permission provided to the container. O(1). | |
| void * | CCC_doubly_linked_list_erase (CCC_Doubly_linked_list *list, CCC_Doubly_linked_list_node *type_intruder, CCC_Allocator const *allocator) |
| Returns the element following an erased element from the list. O(1). | |
| void * | CCC_doubly_linked_list_erase_range (CCC_Doubly_linked_list *list, CCC_Doubly_linked_list_node *type_intruder_begin, CCC_Doubly_linked_list_node *type_intruder_end, CCC_Allocator const *allocator) |
| Returns the element following an extracted range of elements from the list. O(N). | |
| void * | CCC_doubly_linked_list_extract_range (CCC_Doubly_linked_list *list, CCC_Doubly_linked_list_node *type_intruder_begin, CCC_Doubly_linked_list_node *type_intruder_end) |
| Returns the element following an extracted range of elements from the list without deallocating regardless of allocation permission provided to the container. O(N). | |
| CCC_Result | CCC_doubly_linked_list_splice (CCC_Doubly_linked_list *position_doubly_linked_list, CCC_Doubly_linked_list_node *type_intruder_position, CCC_Doubly_linked_list *to_cut_doubly_linked_list, CCC_Doubly_linked_list_node *type_intruder_to_cut) |
| Repositions to_cut before pos. Only list pointers are modified. O(1). | |
| CCC_Result | CCC_doubly_linked_list_splice_range (CCC_Doubly_linked_list *position_doubly_linked_list, CCC_Doubly_linked_list_node *type_intruder_position, CCC_Doubly_linked_list *to_cut_doubly_linked_list, CCC_Doubly_linked_list_node *type_intruder_to_cut_begin, CCC_Doubly_linked_list_node *type_intruder_to_cut_exclusive_end) |
| Splices the list to cut before the specified position. The range being cut is exclusive from [start, end), meaning the final element provided is not move. This is an O(N) operation. | |
Container Types | |
Types available in the container interface. | |
| typedef struct CCC_Doubly_linked_list | CCC_Doubly_linked_list |
| A container offering bidirectional, insert, removal, and iteration. | |
| typedef struct CCC_Doubly_linked_list_node | CCC_Doubly_linked_list_node |
| A doubly linked list intrusive element to embedded in a user type. | |
Sorting Interface | |
Sort the container. | |
| void * | CCC_doubly_linked_list_insert_sorted (CCC_Doubly_linked_list *doubly_linked_list, CCC_Doubly_linked_list_node *type_intruder, CCC_Order order, CCC_Comparator const *comparator, CCC_Allocator const *allocator) |
Inserts type_intruder in sorted position according to the non-decreasing order of the list determined by the user provided comparison function. O(1). | |
| CCC_Tribool | CCC_doubly_linked_list_is_sorted (CCC_Doubly_linked_list const *doubly_linked_list, CCC_Order order, CCC_Comparator const *comparator) |
| Returns true if the list is sorted in non-decreasing order according to the user provided comparison function. | |
Deallocation Interface | |
Deallocate the container. | |
| CCC_Result | CCC_doubly_linked_list_clear (CCC_Doubly_linked_list *list, CCC_Destructor const *destructor, CCC_Allocator const *allocator) |
| Clear the contents of the list freeing elements, if given allocation permission. O(N). | |
Iteration Interface | |
Iterate through the doubly linked list. | |
| void * | CCC_doubly_linked_list_begin (CCC_Doubly_linked_list const *list) |
| Return the user type at the start of the list or NULL if empty. O(1). | |
| void * | CCC_doubly_linked_list_reverse_begin (CCC_Doubly_linked_list const *list) |
| Return the user type at the end of the list or NULL if empty. O(1). | |
| void * | CCC_doubly_linked_list_next (CCC_Doubly_linked_list const *list, CCC_Doubly_linked_list_node const *type_intruder) |
| Return the user type following the element known to be in the list. O(1). | |
| void * | CCC_doubly_linked_list_reverse_next (CCC_Doubly_linked_list const *list, CCC_Doubly_linked_list_node const *type_intruder) |
| Return the user type following the element known to be in the list moving from back to front. O(1). | |
| void * | CCC_doubly_linked_list_end (CCC_Doubly_linked_list const *list) |
| Return the end sentinel with no accessible fields. O(1). | |
| void * | CCC_doubly_linked_list_reverse_end (CCC_Doubly_linked_list const *list) |
| Return the start sentinel with no accessible fields. O(1). | |
State Interface | |
Obtain state from the doubly linked list. | |
| void * | CCC_doubly_linked_list_front (CCC_Doubly_linked_list const *list) |
| Returns the user type at the front of the list. O(1). | |
| void * | CCC_doubly_linked_list_back (CCC_Doubly_linked_list const *list) |
| Returns the user type at the back of the list. O(1). | |
| CCC_Doubly_linked_list_node * | CCC_doubly_linked_list_node_begin (CCC_Doubly_linked_list const *list) |
| Return a handle to the list element at the front of the list which may be the sentinel. O(1). | |
| CCC_Count | CCC_doubly_linked_list_count (CCC_Doubly_linked_list const *list) |
| Return the count of elements in the list. O(N). | |
| CCC_Tribool | CCC_doubly_linked_list_is_empty (CCC_Doubly_linked_list const *list) |
| Return if the size of the list is equal to 0. O(1). | |
| CCC_Tribool | CCC_doubly_linked_list_validate (CCC_Doubly_linked_list const *list) |
| Validates internal state of the list. | |
| #define CCC_doubly_linked_list_default | ( | type_name, | |
| type_intruder_field | |||
| ) | CCC_private_doubly_linked_list_for(type_name, type_intruder_field) |
Initialize an intrusive doubly linked list for a type with a user specified intruder field.
| [in] | type_name | the type containing the intrusive doubly_linked_list element. |
| [in] | type_intruder_field | name of the Doubly_linked_list element in the containing type. |
| #define CCC_doubly_linked_list_emplace_back | ( | list_pointer, | |
| allocator_pointer, | |||
| type_compound_literal... | |||
| ) |
writes contents of type initializer directly to allocated memory at the back of the list. O(1).
| [in] | list_pointer | the address of the doubly linked list. |
| [in] | allocator_pointer | the required CCC_Allocator for allocation. |
| [in] | type_compound_literal | the r-value initializer of the type to be inserted in the list. This should match the type containing Doubly_linked_list elements as a struct member for this list. |
Note that it does not make sense to use this method if the list has been initialized without an allocation function. If the user does not allow allocation, the contents of new elements to be inserted has been determined by the user prior to any inserts into the list.
| #define CCC_doubly_linked_list_emplace_front | ( | list_pointer, | |
| allocator_pointer, | |||
| type_compound_literal... | |||
| ) |
writes contents of type initializer directly to allocated memory at the front of the list. O(1).
| [in] | list_pointer | the address of the doubly linked list. |
| [in] | allocator_pointer | the required CCC_Allocator for allocation. |
| [in] | type_compound_literal | the r-value initializer of the type to be inserted in the list. This should match the type containing Doubly_linked_list elements as a struct member for this list. |
Note that it does not make sense to use this method if the list has been initialized without an allocation function. If the user does not allow allocation, the contents of new elements to be inserted has been determined by the user prior to any inserts into the list.
| #define CCC_doubly_linked_list_for | ( | type_name, | |
| type_intruder_field | |||
| ) | CCC_private_doubly_linked_list_for(type_name, type_intruder_field) |
Initialize an intrusive doubly linked list for a type with a user specified intruder field.
| [in] | type_name | the type containing the intrusive doubly_linked_list element. |
| [in] | type_intruder_field | name of the Doubly_linked_list element in the containing type. |
| #define CCC_doubly_linked_list_from | ( | type_intruder_field, | |
| allocator, | |||
| destructor, | |||
| compound_literal_array... | |||
| ) |
Initialize a doubly linked list at runtime from a compound literal array.
| [in] | type_intruder_field | the name of the field intruding on user's type. |
| [in] | allocator | the required CCC_Allocator for allocation. |
| [in] | destructor | the optional destructor to run over all allocated elements if memory exhaustion occurs at any point during construction. |
| [in] | compound_literal_array | the array of user types to insert into the map (e.g. (struct My_type[]){ {.val = 1}, {.val = 2}}). |
| typedef struct CCC_Doubly_linked_list CCC_Doubly_linked_list |
A container offering bidirectional, insert, removal, and iteration.
A doubly linked list may be stored in the stack, heap, or data segment. Once initialized it is passed by reference to all functions. A doubly linked list can be initialized at compile time or runtime.
| typedef struct CCC_Doubly_linked_list_node CCC_Doubly_linked_list_node |
A doubly linked list intrusive element to embedded in a user type.
It can be used in an allocating or non allocating container. If allocation is prohibited the container assumes the element is wrapped in pre-allocated memory with the appropriate lifetime and scope for the user's needs; the container does not allocate or free in this case. If allocation is allowed the container will handle copying the data wrapping the element to allocations and deallocating when necessary.
| void * CCC_doubly_linked_list_back | ( | CCC_Doubly_linked_list const * | list | ) |
Returns the user type at the back of the list. O(1).
| [in] | list | a pointer to the doubly linked list. |
| void * CCC_doubly_linked_list_begin | ( | CCC_Doubly_linked_list const * | list | ) |
Return the user type at the start of the list or NULL if empty. O(1).
| [in] | list | a pointer to the doubly linked list. |
| CCC_Result CCC_doubly_linked_list_clear | ( | CCC_Doubly_linked_list * | list, |
| CCC_Destructor const * | destructor, | ||
| CCC_Allocator const * | allocator | ||
| ) |
Clear the contents of the list freeing elements, if given allocation permission. O(N).
| [in] | list | a pointer to the doubly linked list. |
| [in] | destructor | an optional CCC_Destructor to run on each element. |
| [in] | allocator | the CCC_Allocator for freeing a user type. |
Note that if an allocator is provided it will be called to free each element in the list. Be mindful that the destructor does not free as well, instead taking care of any destructor-like book keeping. If no destructor is needed provide the default destructor &(CCC_Destructor){}.
If the list is not provided with an allocator, &(CCC_Allocator){}, the user should free the list elements with the destructor if they wish to do so. The implementation ensures the function is called after the element is removed. Otherwise, the user must manage their elements at their discretion after the list is emptied in this function.
| CCC_Count CCC_doubly_linked_list_count | ( | CCC_Doubly_linked_list const * | list | ) |
Return the count of elements in the list. O(N).
| [in] | list | a pointer to the doubly linked list. |
| void * CCC_doubly_linked_list_end | ( | CCC_Doubly_linked_list const * | list | ) |
Return the end sentinel with no accessible fields. O(1).
| [in] | list | a pointer to the doubly linked list. |
| void * CCC_doubly_linked_list_erase | ( | CCC_Doubly_linked_list * | list, |
| CCC_Doubly_linked_list_node * | type_intruder, | ||
| CCC_Allocator const * | allocator | ||
| ) |
Returns the element following an erased element from the list. O(1).
| [in] | list | a pointer to the doubly linked list. |
| [in] | type_intruder | the handle of an element known to be in the list. |
| [in] | allocator | the CCC_Allocator for freeing a user type. |
| void * CCC_doubly_linked_list_erase_range | ( | CCC_Doubly_linked_list * | list, |
| CCC_Doubly_linked_list_node * | type_intruder_begin, | ||
| CCC_Doubly_linked_list_node * | type_intruder_end, | ||
| CCC_Allocator const * | allocator | ||
| ) |
Returns the element following an extracted range of elements from the list. O(N).
| [in] | list | a pointer to the doubly linked list. |
| [in] | type_intruder_begin | the handle of an element known to be in the list at the start of the range. |
| [in] | type_intruder_end | the handle of an element known to be in the list at the end of the range following type_intruder_begin. |
| [in] | allocator | the CCC_Allocator for freeing a user type. |
Note that if the user does not permit the container to allocate they may iterate through the extracted range in the same way one iterates through a normal list using the iterator function. If allocation is allowed, all elements from type_intruder_begin to type_intruder_end will be erased and references invalidated.
| void * CCC_doubly_linked_list_extract | ( | CCC_Doubly_linked_list * | list, |
| CCC_Doubly_linked_list_node * | type_intruder | ||
| ) |
Returns the element following an extracted element from the list without deallocating regardless of allocation permission provided to the container. O(1).
| [in] | list | a pointer to the doubly linked list. |
| [in] | type_intruder | the handle of an element known to be in the list. |
| void * CCC_doubly_linked_list_extract_range | ( | CCC_Doubly_linked_list * | list, |
| CCC_Doubly_linked_list_node * | type_intruder_begin, | ||
| CCC_Doubly_linked_list_node * | type_intruder_end | ||
| ) |
Returns the element following an extracted range of elements from the list without deallocating regardless of allocation permission provided to the container. O(N).
| [in] | list | a pointer to the doubly linked list. |
| [in] | type_intruder_begin | the handle of an element known to be in the list at the start of the range. |
| [in] | type_intruder_end | the handle of an element known to be in the list at the end of the range following type_intruder_begin. |
Note that the user may iterate through the extracted range in the same way one iterates through a normal list using the iterator function.
| void * CCC_doubly_linked_list_front | ( | CCC_Doubly_linked_list const * | list | ) |
Returns the user type at the front of the list. O(1).
| [in] | list | a pointer to the doubly linked list. |
| void * CCC_doubly_linked_list_insert | ( | CCC_Doubly_linked_list * | list, |
| CCC_Doubly_linked_list_node * | position_node, | ||
| CCC_Doubly_linked_list_node * | type_intruder, | ||
| CCC_Allocator const * | allocator | ||
| ) |
Insert user type wrapping type_intruder before position_node. O(1).
| [in] | list | a pointer to the doubly linked list. |
| [in] | position_node | a pointer to the list element before which type_intruder inserts. |
| [in] | type_intruder | a pointer to the list element. |
| [in] | allocator | the CCC_Allocator for allocating a user type. |
| void * CCC_doubly_linked_list_insert_sorted | ( | CCC_Doubly_linked_list * | doubly_linked_list, |
| CCC_Doubly_linked_list_node * | type_intruder, | ||
| CCC_Order | order, | ||
| CCC_Comparator const * | comparator, | ||
| CCC_Allocator const * | allocator | ||
| ) |
Inserts type_intruder in sorted position according to the non-decreasing order of the list determined by the user provided comparison function. O(1).
| [in] | doubly_linked_list | a pointer to the doubly linked list. |
| [in] | type_intruder | a pointer to the element to be inserted in order. |
| [in] | order | the order by which the list should be sorted. CCC_ORDER_LESSER means the list should be in non-increasing order from [0, count). CCC_ORDER_GREATER means the list should be in non-decreasing order from [0, count). |
| [in] | comparator | the CCC_Comparator for comparing list elements. |
| [in] | allocator | the CCC_Allocator for allocating a user type. |
If a non-increasing order is desired, return opposite results from the user comparison function. If an element is CCC_ORDER_LESSERERS return CCC_ORDER_GREATER and vice versa. If elements are equal, CCC_ORDER_EQUAL.
| CCC_Tribool CCC_doubly_linked_list_is_empty | ( | CCC_Doubly_linked_list const * | list | ) |
Return if the size of the list is equal to 0. O(1).
| [in] | list | a pointer to the doubly linked list. |
| CCC_Tribool CCC_doubly_linked_list_is_sorted | ( | CCC_Doubly_linked_list const * | doubly_linked_list, |
| CCC_Order | order, | ||
| CCC_Comparator const * | comparator | ||
| ) |
Returns true if the list is sorted in non-decreasing order according to the user provided comparison function.
| [in] | doubly_linked_list | a pointer to the singly linked list. |
| [in] | order | the assumed order checked against last sorted order of list. |
| [in] | comparator | the comparator context for comparing list elements. |
If a non-increasing order is desired, return opposite results from the user comparison function. If an element is CCC_ORDER_LESSER return CCC_ORDER_GREATER and vice versa. If elements are equal, return CCC_ORDER_EQUAL.
| void * CCC_doubly_linked_list_next | ( | CCC_Doubly_linked_list const * | list, |
| CCC_Doubly_linked_list_node const * | type_intruder | ||
| ) |
Return the user type following the element known to be in the list. O(1).
| [in] | list | a pointer to the doubly linked list. |
| [in] | type_intruder | a handle to the list element known to be in the list. |
| CCC_Doubly_linked_list_node * CCC_doubly_linked_list_node_begin | ( | CCC_Doubly_linked_list const * | list | ) |
Return a handle to the list element at the front of the list which may be the sentinel. O(1).
| [in] | list | a pointer to the doubly linked list. |
| CCC_Result CCC_doubly_linked_list_pop_back | ( | CCC_Doubly_linked_list * | list, |
| CCC_Allocator const * | allocator | ||
| ) |
Pop the user type at the back of the list. O(1).
| [in] | list | a pointer to the doubly linked list. |
| [in] | allocator | the CCC_Allocator for freeing a user type. |
| CCC_Result CCC_doubly_linked_list_pop_front | ( | CCC_Doubly_linked_list * | list, |
| CCC_Allocator const * | allocator | ||
| ) |
Pop the user type at the front of the list. O(1).
| [in] | list | a pointer to the doubly linked list. |
| [in] | allocator | the CCC_Allocator for freeing a user type. |
| void * CCC_doubly_linked_list_push_back | ( | CCC_Doubly_linked_list * | list, |
| CCC_Doubly_linked_list_node * | type_intruder, | ||
| CCC_Allocator const * | allocator | ||
| ) |
Push user type wrapping type_intruder to the back of the list. O(1).
| [in] | list | a pointer to the doubly linked list. |
| [in] | type_intruder | a pointer to the list element. |
| [in] | allocator | the CCC_Allocator for allocating a user type. |
| void * CCC_doubly_linked_list_push_front | ( | CCC_Doubly_linked_list * | list, |
| CCC_Doubly_linked_list_node * | type_intruder, | ||
| CCC_Allocator const * | allocator | ||
| ) |
Push user type wrapping type_intruder to the front of the list. O(1).
| [in] | list | a pointer to the doubly linked list. |
| [in] | type_intruder | a pointer to the list element. |
| [in] | allocator | the CCC_Allocator for allocating a user type. |
| void * CCC_doubly_linked_list_reverse_begin | ( | CCC_Doubly_linked_list const * | list | ) |
Return the user type at the end of the list or NULL if empty. O(1).
| [in] | list | a pointer to the doubly linked list. |
| void * CCC_doubly_linked_list_reverse_end | ( | CCC_Doubly_linked_list const * | list | ) |
Return the start sentinel with no accessible fields. O(1).
| [in] | list | a pointer to the doubly linked list. |
| void * CCC_doubly_linked_list_reverse_next | ( | CCC_Doubly_linked_list const * | list, |
| CCC_Doubly_linked_list_node const * | type_intruder | ||
| ) |
Return the user type following the element known to be in the list moving from back to front. O(1).
| [in] | list | a pointer to the doubly linked list. |
| [in] | type_intruder | a handle to the list element known to be in the list. |
| CCC_Result CCC_doubly_linked_list_splice | ( | CCC_Doubly_linked_list * | position_doubly_linked_list, |
| CCC_Doubly_linked_list_node * | type_intruder_position, | ||
| CCC_Doubly_linked_list * | to_cut_doubly_linked_list, | ||
| CCC_Doubly_linked_list_node * | type_intruder_to_cut | ||
| ) |
Repositions to_cut before pos. Only list pointers are modified. O(1).
| [in] | position_doubly_linked_list | the list to which position belongs. |
| [in] | type_intruder_position | the position before which to_cut will be moved. |
| [in] | to_cut_doubly_linked_list | the list to which to_cut belongs. |
| [in] | type_intruder_to_cut | the element to cut. |
| CCC_Result CCC_doubly_linked_list_splice_range | ( | CCC_Doubly_linked_list * | position_doubly_linked_list, |
| CCC_Doubly_linked_list_node * | type_intruder_position, | ||
| CCC_Doubly_linked_list * | to_cut_doubly_linked_list, | ||
| CCC_Doubly_linked_list_node * | type_intruder_to_cut_begin, | ||
| CCC_Doubly_linked_list_node * | type_intruder_to_cut_exclusive_end | ||
| ) |
Splices the list to cut before the specified position. The range being cut is exclusive from [start, end), meaning the final element provided is not move. This is an O(N) operation.
| [in] | position_doubly_linked_list | the list to which position belongs. |
| [in] | type_intruder_position | the position before which the list is moved. |
| [in] | to_cut_doubly_linked_list | the list to which the range belongs. |
| [in] | type_intruder_to_cut_begin | the start of the list to splice. |
| [in] | type_intruder_to_cut_exclusive_end | the exclusive end of the list to splice, not included in the splice operation. |
| CCC_Tribool CCC_doubly_linked_list_validate | ( | CCC_Doubly_linked_list const * | list | ) |
Validates internal state of the list.
| [in] | list | a pointer to the doubly linked list. |