aboutsummaryrefslogtreecommitdiff
path: root/src/queue.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/queue.c')
-rwxr-xr-xsrc/queue.c209
1 files changed, 209 insertions, 0 deletions
diff --git a/src/queue.c b/src/queue.c
new file mode 100755
index 0000000..3ce8a57
--- /dev/null
+++ b/src/queue.c
@@ -0,0 +1,209 @@
+#include <bh/queue.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+struct bh_queue_s
+{
+ void **data;
+ size_t size;
+ size_t head;
+ size_t tail;
+ size_t capacity;
+};
+
+
+static void bh_queue_init(bh_queue_t *queue)
+{
+ memset(queue, 0, sizeof(*queue));
+}
+
+
+static void bh_queue_destroy(bh_queue_t *queue)
+{
+ if (queue->capacity)
+ free(queue->data);
+}
+
+
+static void queue_copy(bh_queue_t *dest,
+ bh_queue_t *src)
+{
+ void *iter;
+
+ /* Iterate over old queue and insert data into new queue */
+ iter = bh_queue_iter_next(src, NULL);
+ while (iter)
+ {
+ bh_queue_insert(dest, bh_queue_iter_value(iter));
+ iter = bh_queue_iter_next(src, iter);
+ }
+}
+
+
+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_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;
+
+ /* Catch malloc overflow */
+ if (size >= ((size_t)-1) / sizeof(void *))
+ return BH_OOM;
+
+ /* Prevent same size memory reallocation */
+ if (size == queue->capacity)
+ return BH_OK;
+
+ /* Prepare new empty queue */
+ bh_queue_init(&other);
+ if (size)
+ {
+ /* Allocate new capacity for the queue */
+ other.data = malloc(size * sizeof(void *));
+ other.capacity = size;
+ if (!other.data)
+ return BH_OOM;
+
+ /* Iterate over old queue and insert data into new queue */
+ queue_copy(&other, queue);
+ }
+
+ /* If old queue had allocated data - free it */
+ if (queue->capacity)
+ free(queue->data);
+
+ /* Copy queue information */
+ *queue = other;
+ return BH_OK;
+}
+
+
+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 for capacity overflow and reserve capacity */
+ capacity = (queue->capacity) ? (queue->capacity * 2) : (16);
+ if (capacity < queue->capacity || bh_queue_reserve(queue, capacity))
+ return BH_OOM;
+ }
+
+ /* Increase queue size and advance tail index */
+ queue->data[queue->tail] = value;
+ queue->size++;
+ if (++queue->tail >= queue->capacity)
+ queue->tail = 0;
+
+ return BH_OK;
+}
+
+
+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;
+}
+
+
+int bh_queue_front(bh_queue_t *queue, void **value)
+{
+ /* Do nothing if queue is empty */
+ if (!queue->size)
+ return BH_ERROR;
+
+ /* Return front element */
+ *value = queue->data[queue->head];
+ return BH_OK;
+}
+
+
+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;
+}