diff options
Diffstat (limited to 'src/queue.c')
| -rw-r--r-- | src/queue.c | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/src/queue.c b/src/queue.c new file mode 100644 index 0000000..8d48401 --- /dev/null +++ b/src/queue.c @@ -0,0 +1,176 @@ +#include <bh/internal/queue.h> +#include <stdlib.h> +#include <string.h> + +bh_queue_t *bh_queue_new(void) +{ + bh_queue_t *result; + + result = malloc(sizeof(*result)); + if (result) + bh_queue_init(result); + + return result; +} + +void bh_queue_free(bh_queue_t *queue) +{ + bh_queue_destroy(queue); + free(queue); +} + +void bh_queue_init(bh_queue_t *queue) +{ + memset(queue, 0, sizeof(*queue)); +} + +void bh_queue_destroy(bh_queue_t *queue) +{ + if (queue->capacity) + free(queue->data); +} + +void bh_queue_clear(bh_queue_t *queue) +{ + queue->head = 0; + queue->tail = 0; + queue->size = 0; +} + +int bh_queue_reserve(bh_queue_t *queue, + size_t size) +{ + bh_queue_t other; + + /* New capacity should be great or equal to current size */ + if (size < queue->size) + size = queue->size; + + /* New capacity should not exceed maximum capacity */ + if (size > ((size_t)-1) / sizeof(void *)) + return -1; + + /* Prevent same size memory reallocation */ + if (size == queue->capacity) + return 0; + + /* Prepare new empty queue */ + bh_queue_init(&other); + if (size) + { + void *iter; + + /* Allocate new capacity for the queue */ + other.data = malloc(size * sizeof(void *)); + other.capacity = size; + if (!other.data) + return -1; + + /* Iterate over old queue and insert data into new queue */ + iter = bh_queue_iter_next(queue, NULL); + while (iter) + { + bh_queue_insert(&other, bh_queue_iter_value(iter)); + iter = bh_queue_iter_next(queue, iter); + } + } + + /* If old queue had allocated data - free it */ + if (queue->capacity) + free(queue->data); + + /* Copy queue information */ + *queue = other; + return 0; +} + +int bh_queue_insert(bh_queue_t *queue, + void *value) +{ + /* Check if queue can contain new element */ + if (queue->size + 1 > queue->capacity) + { + size_t capacity; + + /* Check potential size overflow and reserve capacity */ + capacity = (queue->capacity) ? (queue->capacity * 2) : (16); + if (capacity < queue->capacity || bh_queue_reserve(queue, capacity)) + return -1; + } + + /* Increase queue size and advance tail index */ + queue->data[queue->tail] = value; + queue->size++; + if (++queue->tail >= queue->capacity) + queue->tail = 0; + + return 0; +} + +void bh_queue_remove(bh_queue_t *queue) +{ + /* Do nothing if queue is empty */ + if (!queue->size) + return; + + /* Decrease queue size and advance head index */ + queue->size--; + if (++queue->head >= queue->capacity) + queue->head = 0; +} + +void *bh_queue_front(bh_queue_t *queue) +{ + /* Do nothing if queue is empty */ + if (!queue->size) + return NULL; + + /* Return front element */ + return queue->data[queue->head]; +} + +int bh_queue_empty(bh_queue_t *queue) +{ + return !queue->size; +} + +size_t bh_queue_size(bh_queue_t *queue) +{ + return queue->size; +} + +size_t bh_queue_capacity(bh_queue_t *queue) +{ + return queue->capacity; +} + +void *bh_queue_iter_next(bh_queue_t *queue, + void *iter) +{ + void **element = (void **)iter; + + /* Do nothing if queue is empty */ + if (!queue->size) + return NULL; + + /* Advance or set iterator */ + if (element) + { + element++; + if (element == queue->data + queue->capacity) + element = queue->data; + + /* Check if we reached the end */ + if (element == queue->data + queue->tail) + return NULL; + } + else + element = queue->data + queue->head; + + return element; +} + +void *bh_queue_iter_value(void *iter) +{ + return *(void **)iter; +} |
