C Container Collection (CCC)
|
The Flat Priority Queue Interface. More...
Go to the source code of this file.
The Flat Priority Queue Interface.
A flat priority queue is a contiguous container storing storing elements in heap order. This offers tightly packed data for efficient push, pop, min/max operations in O(lg N). Also, this container requires no intrusive elements.
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_fpq_init(mem_ptr, cmp_order, cmp_fn, alloc_fn, aux_data, capacity) ccc_impl_fpq_init(mem_ptr, cmp_order, cmp_fn, alloc_fn, aux_data, capacity) |
Initialize a fpq as a min or max heap. | |
#define | ccc_fpq_heapify_init(mem_ptr, cmp_order, cmp_fn, alloc_fn, aux_data, capacity, size) |
Order an existing array of elements as a min or max heap. O(N). | |
ccc_result | ccc_fpq_copy (ccc_flat_priority_queue *dst, ccc_flat_priority_queue const *src, ccc_any_alloc_fn *fn) |
Copy the fpq from src to newly initialized dst. | |
ccc_result | ccc_fpq_reserve (ccc_flat_priority_queue *fpq, size_t to_add, ccc_any_alloc_fn *fn) |
Reserves space for at least to_add more elements. | |
Insert and Remove Interface | |
Insert or remove elements from the flat priority queue. | |
#define | ccc_fpq_emplace(fpq, val_initializer...) ccc_impl_fpq_emplace(fpq, val_initializer) |
Write a type directly to a priority queue slot. O(lgN). | |
#define | ccc_fpq_update_w(fpq_ptr, any_type_ptr, update_closure_over_T...) ccc_impl_fpq_update_w(fpq_ptr, any_type_ptr, update_closure_over_T) |
Update the user type stored in the priority queue directly. O(lgN). | |
#define | ccc_fpq_increase_w(fpq_ptr, any_type_ptr, increase_closure_over_T...) ccc_impl_fpq_increase_w(fpq_ptr, any_type_ptr, increase_closure_over_T) |
Increase the user type stored in the priority queue directly. O(lgN). | |
#define | ccc_fpq_decrease_w(fpq_ptr, any_type_ptr, decrease_closure_over_T...) ccc_impl_fpq_decrease_w(fpq_ptr, any_type_ptr, decrease_closure_over_T) |
Increase the user type stored in the priority queue directly. O(lgN). | |
ccc_result | ccc_fpq_heapify (ccc_flat_priority_queue *fpq, void *input_array, size_t input_n, size_t input_sizeof_type) |
Copy input array into the fpq, organizing into heap. O(N). | |
ccc_result | ccc_fpq_heapify_inplace (ccc_flat_priority_queue *fpq, size_t n) |
Order n elements of the underlying fpq buffer as an fpq. | |
ccc_result | ccc_fpq_alloc (ccc_flat_priority_queue *fpq, size_t new_capacity, ccc_any_alloc_fn *fn) |
Many allocate memory for the fpq. | |
void * | ccc_fpq_push (ccc_flat_priority_queue *fpq, void const *e) |
Pushes element pointed to at e into fpq. O(lgN). | |
ccc_result | ccc_fpq_pop (ccc_flat_priority_queue *fpq) |
Pop the front element (min or max) element in the fpq. O(lgN). | |
ccc_result | ccc_fpq_erase (ccc_flat_priority_queue *fpq, void *e) |
Erase element e that is a handle to the stored fpq element. | |
void * | ccc_fpq_update (ccc_flat_priority_queue *fpq, void *e, ccc_any_type_update_fn *fn, void *aux) |
Update e that is a handle to the stored fpq element. O(lgN). | |
void * | ccc_fpq_increase (ccc_flat_priority_queue *fpq, void *e, ccc_any_type_update_fn *fn, void *aux) |
Increase e that is a handle to the stored fpq element. O(lgN). | |
void * | ccc_fpq_decrease (ccc_flat_priority_queue *fpq, void *e, ccc_any_type_update_fn *fn, void *aux) |
Decrease e that is a handle to the stored fpq element. O(lgN). | |
Container Types | |
Types available in the container interface. | |
typedef struct ccc_fpq | ccc_flat_priority_queue |
A container offering direct storage and sorting of user data by heap order. | |
Deallocation Interface | |
Deallocate the container. | |
ccc_result | ccc_fpq_clear (ccc_flat_priority_queue *fpq, ccc_any_type_destructor_fn *fn) |
Clears the fpq calling fn on every element if provided. O(1)-O(N). | |
ccc_result | ccc_fpq_clear_and_free (ccc_flat_priority_queue *fpq, ccc_any_type_destructor_fn *fn) |
Clears the fpq calling fn on every element if provided and frees the underlying buffer. O(1)-O(N). | |
ccc_result | ccc_fpq_clear_and_free_reserve (ccc_flat_priority_queue *fpq, ccc_any_type_destructor_fn *destructor, ccc_any_alloc_fn *alloc) |
Frees all slots in the fpq and frees the underlying buffer that was previously dynamically reserved with the reserve function. | |
State Interface | |
Obtain state from the container. | |
void * | ccc_fpq_front (ccc_flat_priority_queue const *fpq) |
Return a pointer to the front (min or max) element in the fpq. O(1). | |
ccc_tribool | ccc_fpq_is_empty (ccc_flat_priority_queue const *fpq) |
Returns true if the fpq is empty false if not. O(1). | |
ccc_ucount | ccc_fpq_size (ccc_flat_priority_queue const *fpq) |
Returns the size of the fpq representing active slots. | |
ccc_ucount | ccc_fpq_capacity (ccc_flat_priority_queue const *fpq) |
Returns the capacity of the fpq representing total possible slots. | |
void * | ccc_fpq_data (ccc_flat_priority_queue const *fpq) |
Return a pointer to the base of the backing array. O(1). | |
ccc_tribool | ccc_fpq_validate (ccc_flat_priority_queue const *fpq) |
Verifies the internal invariants of the fpq hold. | |
ccc_threeway_cmp | ccc_fpq_order (ccc_flat_priority_queue const *fpq) |
Return the order used to initialize the fpq. | |
#define ccc_fpq_decrease_w | ( | fpq_ptr, | |
any_type_ptr, | |||
decrease_closure_over_T... | |||
) | ccc_impl_fpq_decrease_w(fpq_ptr, any_type_ptr, decrease_closure_over_T) |
Increase the user type stored in the priority queue directly. O(lgN).
[in] | fpq_ptr | a pointer to the flat priority queue. |
[in] | any_type_ptr | a pointer to the user type being updated. |
[in] | decrease_closure_over_T | the semicolon separated statements to execute on the user type at T (optionally wrapping {code here} in braces may help with formatting). This closure may safely modify the key used to track the user element's priority in the priority queue. |
Note that if this priority queue is min or max, the runtime is the same.
#define ccc_fpq_emplace | ( | fpq, | |
val_initializer... | |||
) | ccc_impl_fpq_emplace(fpq, val_initializer) |
Write a type directly to a priority queue slot. O(lgN).
[in] | fpq | a pointer to the priority queue. |
[in] | val_initializer | the compound literal or direct scalar type. |
#define ccc_fpq_heapify_init | ( | mem_ptr, | |
cmp_order, | |||
cmp_fn, | |||
alloc_fn, | |||
aux_data, | |||
capacity, | |||
size | |||
) |
Order an existing array of elements as a min or max heap. O(N).
[in] | mem_ptr | a pointer to an array of user types or ((T *)NULL). |
[in] | cmp_order | CCC_LES or CCC_GRT for min or max heap, respectively. |
[in] | cmp_fn | the user defined comparison function for user types. |
[in] | alloc_fn | the allocation function or NULL if no allocation. |
[in] | aux_data | any auxiliary data needed for destruction of elements. |
[in] | capacity | the capacity of contiguous elements at mem_ptr. |
[in] | size | the size <= capacity. |
Note that to avoid temporary or unpredictable allocation the fpq requires one slot for swapping. Therefore if the user wants a fixed size fpq of size N, N + 1 capacity is required.
#define ccc_fpq_increase_w | ( | fpq_ptr, | |
any_type_ptr, | |||
increase_closure_over_T... | |||
) | ccc_impl_fpq_increase_w(fpq_ptr, any_type_ptr, increase_closure_over_T) |
Increase the user type stored in the priority queue directly. O(lgN).
[in] | fpq_ptr | a pointer to the flat priority queue. |
[in] | any_type_ptr | a pointer to the user type being updated. |
[in] | increase_closure_over_T | the semicolon separated statements to execute on the user type at T (optionally wrapping {code here} in braces may help with formatting). This closure may safely modify the key used to track the user element's priority in the priority queue. |
Note that if this priority queue is min or max, the runtime is the same.
#define ccc_fpq_init | ( | mem_ptr, | |
cmp_order, | |||
cmp_fn, | |||
alloc_fn, | |||
aux_data, | |||
capacity | |||
) | ccc_impl_fpq_init(mem_ptr, cmp_order, cmp_fn, alloc_fn, aux_data, capacity) |
Initialize a fpq as a min or max heap.
[in] | mem_ptr | a pointer to an array of user types or ((T *)NULL). |
[in] | cmp_order | CCC_LES or CCC_GRT for min or max heap, respectively. |
[in] | cmp_fn | the user defined comarison function for user types. |
[in] | alloc_fn | the allocation function or NULL if no allocation. |
[in] | aux_data | any auxiliary data needed for destruction of elements. |
[in] | capacity | the capacity of contiguous elements at mem_ptr. |
Note that to avoid temporary or unpredictable allocation the fpq requires one slot for swapping. Therefore if the user wants a fixed size fpq of size N, N + 1 capacity is required.
#define ccc_fpq_update_w | ( | fpq_ptr, | |
any_type_ptr, | |||
update_closure_over_T... | |||
) | ccc_impl_fpq_update_w(fpq_ptr, any_type_ptr, update_closure_over_T) |
Update the user type stored in the priority queue directly. O(lgN).
[in] | fpq_ptr | a pointer to the flat priority queue. |
[in] | any_type_ptr | a pointer to the user type being updated. |
[in] | update_closure_over_T | the semicolon separated statements to execute on the user type at T (optionally wrapping {code here} in braces may help with formatting). This closure may safely modify the key used to track the user element's priority in the priority queue. |
Note that whether the key increases or decreases does not affect runtime.
typedef struct ccc_fpq ccc_flat_priority_queue |
A container offering direct storage and sorting of user data by heap order.
A flat priority queue can be initialized on the stack, heap, or data segment at runtime or compile time.
ccc_result ccc_fpq_alloc | ( | ccc_flat_priority_queue * | fpq, |
size_t | new_capacity, | ||
ccc_any_alloc_fn * | fn | ||
) |
Many allocate memory for the fpq.
[in] | fpq | a pointer to the priority queue. |
[in] | new_capacity | the desired capacity for the fpq. |
[in] | fn | the allocation function. May be the same as used on init. |
ccc_ucount ccc_fpq_capacity | ( | ccc_flat_priority_queue const * | fpq | ) |
Returns the capacity of the fpq representing total possible slots.
[in] | fpq | a pointer to the flat priority queue. |
ccc_result ccc_fpq_clear | ( | ccc_flat_priority_queue * | fpq, |
ccc_any_type_destructor_fn * | fn | ||
) |
Clears the fpq calling fn on every element if provided. O(1)-O(N).
[in] | fpq | a pointer to the flat priority queue. |
[in] | fn | the destructor function or NULL if not needed. |
Note that because the priority queue is flat there is no need to free elements stored in the fpq. However, the destructor is free to manage cleanup in other parts of user code as needed upon destruction of each element.
If the destructor is NULL, the function is O(1) and no attempt is made to free capacity of the fpq.
ccc_result ccc_fpq_clear_and_free | ( | ccc_flat_priority_queue * | fpq, |
ccc_any_type_destructor_fn * | fn | ||
) |
Clears the fpq calling fn on every element if provided and frees the underlying buffer. O(1)-O(N).
[in] | fpq | a pointer to the flat priority queue. |
[in] | fn | the destructor function or NULL if not needed. |
Note that because the priority queue is flat there is no need to free elements stored in the fpq. However, the destructor is free to manage cleanup in other parts of user code as needed upon destruction of each element.
If the destructor is NULL, the function is O(1) and only relies on the runtime of the provided allocation function free operation.
ccc_result ccc_fpq_clear_and_free_reserve | ( | ccc_flat_priority_queue * | fpq, |
ccc_any_type_destructor_fn * | destructor, | ||
ccc_any_alloc_fn * | alloc | ||
) |
Frees all slots in the fpq and frees the underlying buffer that was previously dynamically reserved with the reserve function.
[in] | fpq | the fpq to be cleared. |
[in] | destructor | the destructor for each element. NULL can be passed if no maintenance is required on the elements in the fpq before their slots are dropped. |
[in] | alloc | the required allocation function to provide to a dynamically reserved fpq. Any auxiliary data provided upon initialization will be passed to the allocation function when called. |
This function covers the edge case of reserving a dynamic capacity for a fpq at runtime but denying the fpq allocation permission to resize. This can help prevent a fpq from growing unbounded. The user in this case knows the fpq does not have allocation permission and therefore no further memory will be dedicated to the fpq.
However, to free the fpq in such a case this function must be used because the fpq has no ability to free itself. Just as the allocation function is required to reserve memory so to is it required to free memory.
This function will work normally if called on a fpq with allocation permission however the normal ccc_fpq_clear_and_free is sufficient for that use case.
ccc_result ccc_fpq_copy | ( | ccc_flat_priority_queue * | dst, |
ccc_flat_priority_queue const * | src, | ||
ccc_any_alloc_fn * | fn | ||
) |
Copy the fpq from src to newly initialized dst.
[in] | dst | the destination that will copy the source fpq. |
[in] | src | the source of the fpq. |
[in] | fn | the allocation function in case resizing of dst is needed. |
Note that there are two ways to copy data from source to destination: provide sufficient memory and pass NULL as fn, or allow the copy function to take care of allocation for the copy.
Manual memory management with no allocation function provided.
The above requires dst capacity be greater than or equal to src capacity. Here is memory management handed over to the copy function.
The above allows dst to have a capacity less than that of the src as long as copy has been provided an allocation function to resize dst. Note that this would still work if copying to a destination that the user wants as a fixed size fpq.
The above sets up dst with fixed size while src is a dynamic fpq. Because an allocation function is provided, the dst is resized once for the copy and retains its fixed size after the copy is complete. This would require the user to manually free the underlying buffer at dst eventually if this method is used. Usually it is better to allocate the memory explicitly before the copy if copying between ring buffers.
These options allow users to stay consistent across containers with their memory management strategies.
void * ccc_fpq_data | ( | ccc_flat_priority_queue const * | fpq | ) |
Return a pointer to the base of the backing array. O(1).
[in] | fpq | a pointer to the priority queue. |
void * ccc_fpq_decrease | ( | ccc_flat_priority_queue * | fpq, |
void * | e, | ||
ccc_any_type_update_fn * | fn, | ||
void * | aux | ||
) |
Decrease e that is a handle to the stored fpq element. O(lgN).
[in] | fpq | a pointer to the flat priority queue. |
[in] | e | a handle to the stored fpq element. Must be in the fpq. |
[in] | fn | the update function to act on e. |
[in] | aux | any auxiliary data needed for the update function. |
ccc_result ccc_fpq_erase | ( | ccc_flat_priority_queue * | fpq, |
void * | e | ||
) |
Erase element e that is a handle to the stored fpq element.
[in] | fpq | a pointer to the priority queue. |
[in] | e | a handle to the stored fpq element. Must be in the fpq. |
Note that the reference to e is invalidated after this call.
void * ccc_fpq_front | ( | ccc_flat_priority_queue const * | fpq | ) |
Return a pointer to the front (min or max) element in the fpq. O(1).
[in] | fpq | a pointer to the priority queue. |
ccc_result ccc_fpq_heapify | ( | ccc_flat_priority_queue * | fpq, |
void * | input_array, | ||
size_t | input_n, | ||
size_t | input_sizeof_type | ||
) |
Copy input array into the fpq, organizing into heap. O(N).
[in] | fpq | a pointer to the priority queue. |
[in] | input_array | an array of elements of the same size as the type used to initialize fpq. |
[in] | input_n | the number of contiguous elements at input_array. |
[in] | input_sizeof_type | size of each element in input_array matching element size of fpq. |
Note that this version of heapify copies elements from the input array. If an in place heapify is required use the initializer version of this method.
ccc_result ccc_fpq_heapify_inplace | ( | ccc_flat_priority_queue * | fpq, |
size_t | n | ||
) |
Order n elements of the underlying fpq buffer as an fpq.
[in] | fpq | a pointer to the flat priority queue. |
[in] | n | the number n of elements where 0 < (n + 1) <= capacity. |
This is another method to order a heap that already has all the elements one needs sorted. The underlying buffer will be interpreted to have n valid elements starting at index 0 to index n - 1.
void * ccc_fpq_increase | ( | ccc_flat_priority_queue * | fpq, |
void * | e, | ||
ccc_any_type_update_fn * | fn, | ||
void * | aux | ||
) |
Increase e that is a handle to the stored fpq element. O(lgN).
[in] | fpq | a pointer to the flat priority queue. |
[in] | e | a handle to the stored fpq element. Must be in the fpq. |
[in] | fn | the update function to act on e. |
[in] | aux | any auxiliary data needed for the update function. |
ccc_tribool ccc_fpq_is_empty | ( | ccc_flat_priority_queue const * | fpq | ) |
Returns true if the fpq is empty false if not. O(1).
[in] | fpq | a pointer to the flat priority queue. |
ccc_threeway_cmp ccc_fpq_order | ( | ccc_flat_priority_queue const * | fpq | ) |
Return the order used to initialize the fpq.
[in] | fpq | a pointer to the flat priority queue. |
ccc_result ccc_fpq_pop | ( | ccc_flat_priority_queue * | fpq | ) |
Pop the front element (min or max) element in the fpq. O(lgN).
[in] | fpq | a pointer to the priority queue. |
void * ccc_fpq_push | ( | ccc_flat_priority_queue * | fpq, |
void const * | e | ||
) |
Pushes element pointed to at e into fpq. O(lgN).
[in] | fpq | a pointer to the priority queue. |
[in] | e | a pointer to the user element of same type as in fpq. |
ccc_result ccc_fpq_reserve | ( | ccc_flat_priority_queue * | fpq, |
size_t | to_add, | ||
ccc_any_alloc_fn * | fn | ||
) |
Reserves space for at least to_add more elements.
[in] | fpq | a pointer to the flat priority queue. |
[in] | to_add | the number of elements to add to the current size. |
[in] | fn | the allocation function to use to reserve memory. |
This function can be used for a dynamic fpq with or without allocation permission. If the fpq has allocation permission, it will reserve the required space and later resize if more space is needed.
If the fpq has been initialized with no allocation permission and no memory this function can serve as a one-time reservation. This is helpful when a fixed size is needed but that size is only known dynamically at runtime. To free the fpq in such a case see the ccc_fpq_clear_and_free_reserve function.
ccc_ucount ccc_fpq_size | ( | ccc_flat_priority_queue const * | fpq | ) |
Returns the size of the fpq representing active slots.
[in] | fpq | a pointer to the flat priority queue. |
void * ccc_fpq_update | ( | ccc_flat_priority_queue * | fpq, |
void * | e, | ||
ccc_any_type_update_fn * | fn, | ||
void * | aux | ||
) |
Update e that is a handle to the stored fpq element. O(lgN).
[in] | fpq | a pointer to the flat priority queue. |
[in] | e | a handle to the stored fpq element. Must be in the fpq. |
[in] | fn | the update function to act on e. |
[in] | aux | any auxiliary data needed for the update function. |
ccc_tribool ccc_fpq_validate | ( | ccc_flat_priority_queue const * | fpq | ) |
Verifies the internal invariants of the fpq hold.
[in] | fpq | a pointer to the flat priority queue. |