1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
|
#ifndef AWS_COMMON_PRIORITY_QUEUE_H
#define AWS_COMMON_PRIORITY_QUEUE_H
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <aws/common/array_list.h>
#include <aws/common/common.h>
AWS_PUSH_SANE_WARNING_LEVEL
/* The comparator should return a positive value if the second argument has a
* higher priority than the first; Otherwise, it should return a negative value
* or zero. NOTE: priority_queue pops its highest priority element first. For
* example: int cmp(const void *a, const void *b) { return a < b; } would result
* in a max heap, while: int cmp(const void *a, const void *b) { return a > b; }
* would result in a min heap.
*/
typedef int(aws_priority_queue_compare_fn)(const void *a, const void *b);
struct aws_priority_queue {
/**
* predicate that determines the priority of the elements in the queue.
*/
aws_priority_queue_compare_fn *pred;
/**
* The underlying container storing the queue elements.
*/
struct aws_array_list container;
/**
* An array of pointers to backpointer elements. This array is initialized when
* the first call to aws_priority_queue_push_bp is made, and is subsequently maintained
* through any heap node manipulations.
*
* Each element is a struct aws_priority_queue_node *, pointing to a backpointer field
* owned by the calling code, or a NULL. The backpointer field is continually updated
* with information needed to locate and remove a specific node later on.
*/
struct aws_array_list backpointers;
};
struct aws_priority_queue_node {
/** The current index of the node in question, or SIZE_MAX if the node has been removed. */
size_t current_index;
};
AWS_EXTERN_C_BEGIN
/**
* Initializes a priority queue struct for use. This mode will grow memory automatically (exponential model)
* Default size is the inital size of the queue
* item_size is the size of each element in bytes. Mixing items types is not supported by this API.
* pred is the function that will be used to determine priority.
*/
AWS_COMMON_API
int aws_priority_queue_init_dynamic(
struct aws_priority_queue *queue,
struct aws_allocator *alloc,
size_t default_size,
size_t item_size,
aws_priority_queue_compare_fn *pred);
/**
* Initializes a priority queue struct for use. This mode will not allocate any additional memory. When the heap fills
* new enqueue operations will fail with AWS_ERROR_PRIORITY_QUEUE_FULL.
*
* Heaps initialized using this call do not support the aws_priority_queue_push_ref call with a non-NULL backpointer
* parameter.
*
* heap is the raw memory allocated for this priority_queue
* item_count is the maximum number of elements the raw heap can contain
* item_size is the size of each element in bytes. Mixing items types is not supported by this API.
* pred is the function that will be used to determine priority.
*/
AWS_COMMON_API
void aws_priority_queue_init_static(
struct aws_priority_queue *queue,
void *heap,
size_t item_count,
size_t item_size,
aws_priority_queue_compare_fn *pred);
/**
* Checks that the backpointer at a specific index of the queue is
* NULL or points to a correctly allocated aws_priority_queue_node.
*/
bool aws_priority_queue_backpointer_index_valid(const struct aws_priority_queue *const queue, size_t index);
/**
* Checks that the backpointers of the priority queue are either NULL
* or correctly allocated to point at aws_priority_queue_nodes. This
* check is O(n), as it accesses every backpointer in a loop, and thus
* shouldn't be used carelessly.
*/
bool aws_priority_queue_backpointers_valid_deep(const struct aws_priority_queue *const queue);
/**
* Checks that the backpointers of the priority queue satisfy validity
* constraints.
*/
bool aws_priority_queue_backpointers_valid(const struct aws_priority_queue *const queue);
/**
* Set of properties of a valid aws_priority_queue.
*/
AWS_COMMON_API
bool aws_priority_queue_is_valid(const struct aws_priority_queue *const queue);
/**
* Cleans up any internally allocated memory and resets the struct for reuse or deletion.
*/
AWS_COMMON_API
void aws_priority_queue_clean_up(struct aws_priority_queue *queue);
/**
* Copies item into the queue and places it in the proper priority order. Complexity: O(log(n)).
*/
AWS_COMMON_API
int aws_priority_queue_push(struct aws_priority_queue *queue, void *item);
/**
* Copies item into the queue and places it in the proper priority order. Complexity: O(log(n)).
*
* If the backpointer parameter is non-null, the heap will continually update the pointed-to field
* with information needed to remove the node later on. *backpointer must remain valid until the node
* is removed from the heap, and may be updated on any mutating operation on the priority queue.
*
* If the node is removed, the backpointer will be set to a sentinel value that indicates that the
* node has already been removed. It is safe (and a no-op) to call aws_priority_queue_remove with
* such a sentinel value.
*/
AWS_COMMON_API
int aws_priority_queue_push_ref(
struct aws_priority_queue *queue,
void *item,
struct aws_priority_queue_node *backpointer);
/**
* Copies the element of the highest priority, and removes it from the queue.. Complexity: O(log(n)).
* If queue is empty, AWS_ERROR_PRIORITY_QUEUE_EMPTY will be raised.
*/
AWS_COMMON_API
int aws_priority_queue_pop(struct aws_priority_queue *queue, void *item);
/**
* Removes a specific node from the priority queue. Complexity: O(log(n))
* After removing a node (using either _remove or _pop), the backpointer set at push_ref time is set
* to a sentinel value. If this sentinel value is passed to aws_priority_queue_remove,
* AWS_ERROR_PRIORITY_QUEUE_BAD_NODE will be raised. Note, however, that passing uninitialized
* aws_priority_queue_nodes, or ones from different priority queues, results in undefined behavior.
*/
AWS_COMMON_API
int aws_priority_queue_remove(struct aws_priority_queue *queue, void *item, const struct aws_priority_queue_node *node);
/**
* Obtains a pointer to the element of the highest priority. Complexity: constant time.
* If queue is empty, AWS_ERROR_PRIORITY_QUEUE_EMPTY will be raised.
*/
AWS_COMMON_API
int aws_priority_queue_top(const struct aws_priority_queue *queue, void **item);
/**
* Removes all elements from the queue, but does not free internal memory.
*/
AWS_COMMON_API
void aws_priority_queue_clear(struct aws_priority_queue *queue);
/**
* Current number of elements in the queue
*/
AWS_COMMON_API
size_t aws_priority_queue_size(const struct aws_priority_queue *queue);
/**
* Current allocated capacity for the queue, in dynamic mode this grows over time, in static mode, this will never
* change.
*/
AWS_COMMON_API
size_t aws_priority_queue_capacity(const struct aws_priority_queue *queue);
/**
* Initializes a queue node to a default value that indicates the node is not in the queue.
*
* @param node priority queue node to initialize with a default value
*/
AWS_COMMON_API
void aws_priority_queue_node_init(struct aws_priority_queue_node *node);
/**
* Checks if a priority queue node is currently in a priority queue.
*
* @param node priority queue node to check usage for
*
* @return true if the node is in a queue, false otherwise
*/
AWS_COMMON_API
bool aws_priority_queue_node_is_in_queue(const struct aws_priority_queue_node *node);
AWS_EXTERN_C_END
AWS_POP_SANE_WARNING_LEVEL
#endif /* AWS_COMMON_PRIORITY_QUEUE_H */
|