summaryrefslogtreecommitdiff
path: root/include/queue.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/queue.h')
-rw-r--r--include/queue.h127
1 files changed, 106 insertions, 21 deletions
diff --git a/include/queue.h b/include/queue.h
index 2c967ee4a8..9be0f31bdc 100644
--- a/include/queue.h
+++ b/include/queue.h
@@ -4,37 +4,122 @@
*
* Queue data structure.
*/
+#ifndef INCLUDE_QUEUE_H
+#define INCLUDE_QUEUE_H
#include "common.h"
-/* Generic queue container.
- *
- * head: next to dequeqe
- * tail: next to enqueue
- *
- * Empty:
- * head == tail
- * Full:
- * ((tail + 1) % buf_bytes) == head
+#include <stddef.h>
+#include <stdint.h>
+
+/* Generic queue container. */
+
+/*
+ * RAM state for a queue.
+ */
+struct queue_state {
+ /*
+ * The queue head and tail pointers are not wrapped until they are
+ * needed to access the queue buffer. This has a number of advantages,
+ * the queue doesn't have to waste an entry to disambiguate full and
+ * empty for one. It also provides a convenient total enqueue/dequeue
+ * log (one that does wrap at the limit of a size_t however).
+ *
+ * Empty:
+ * head == tail
+ *
+ * Full:
+ * head - tail == buffer_units
+ */
+ size_t head; /* head: next to dequeue */
+ size_t tail; /* tail: next to enqueue */
+};
+
+/*
+ * Queue configuration stored in flash.
*/
struct queue {
- int head, tail;
- int buf_bytes; /* size of buffer (in byte) */
- int unit_bytes; /* size of unit (in byte) */
- uint8_t *buf;
+ struct queue_state volatile *state;
+
+ size_t buffer_units; /* size of buffer (in units) */
+ size_t unit_bytes; /* size of unit (in byte) */
+ uint8_t *buffer;
};
-/* Reset the queue to empty state. */
-void queue_reset(struct queue *queue);
+/*
+ * Convenience macro for construction of a Queue along with its backing buffer
+ * and state structure.
+ */
+#define QUEUE_CONFIG(NAME, SIZE, TYPE) \
+ static TYPE CONCAT2(NAME, _buffer)[SIZE]; \
+ \
+ static struct queue_state CONCAT2(NAME, _state); \
+ struct queue const NAME = \
+ { \
+ .state = &CONCAT2(NAME, _state), \
+ .buffer_units = SIZE, \
+ .unit_bytes = sizeof(TYPE), \
+ .buffer = (uint8_t *) CONCAT2(NAME, _buffer), \
+ };
+
+/* Initialize the queue to empty state. */
+void queue_init(struct queue const *q);
/* Return TRUE if the queue is empty. */
-int queue_is_empty(const struct queue *q);
+int queue_is_empty(struct queue const *q);
+
+/* Return the number of units stored in the queue. */
+size_t queue_count(struct queue const *q);
+
+/* Return the number of units worth of free space the queue has. */
+size_t queue_space(struct queue const *q);
-/* Return TRUE if the queue has at least one unit space. */
-int queue_has_space(const struct queue *q, int unit_count);
+/* Add one unit to queue. */
+size_t queue_add_unit(struct queue const *q, void const *src);
-/* Add multiple units into queue. */
-void queue_add_units(struct queue *q, const void *src, int unit_count);
+/* Add multiple units to queue. */
+size_t queue_add_units(struct queue const *q, void const *src, size_t count);
/* Remove one unit from the begin of the queue. */
-int queue_remove_unit(struct queue *q, void *dest);
+size_t queue_remove_unit(struct queue const *q, void *dest);
+
+/* Remove multiple units from the begin of the queue. */
+size_t queue_remove_units(struct queue const *q, void *dest, size_t count);
+
+/* Peek (return but don't remove) the count elements starting with the i'th. */
+size_t queue_peek_units(struct queue const *q,
+ void *dest,
+ size_t i,
+ size_t count);
+
+/*
+ * These macros will statically select the queue functions based on the number
+ * of units that are to be added or removed if they can. The single unit add
+ * and remove functions are much faster than calling the equivalent generic
+ * version with a count of one.
+ */
+#define QUEUE_ADD_UNITS(q, src, count) \
+ ({ \
+ size_t result; \
+ \
+ if (count == 1) \
+ result = queue_add_unit(q, src); \
+ else \
+ result = queue_add_units(q, src, count); \
+ \
+ result; \
+ })
+
+#define QUEUE_REMOVE_UNITS(q, dest, count) \
+ ({ \
+ size_t result; \
+ \
+ if (count == 1) \
+ result = queue_remove_unit(q, dest); \
+ else \
+ result = queue_remove_units(q, dest, count); \
+ \
+ result; \
+ })
+
+#endif /* INCLUDE_QUEUE_H */