|
|
@@ -0,0 +1,252 @@
|
|
|
+#ifndef _DEQUE_H
|
|
|
+#define _DEQUE_H
|
|
|
+
|
|
|
+#include <assert.h>
|
|
|
+
|
|
|
+/**
|
|
|
+ * struct deq - deque metadata
|
|
|
+ * @v: char pointer to malloced memory
|
|
|
+ * @head: index of first item in deque
|
|
|
+ * @tail: index after last item in deque
|
|
|
+ * @len: length of deque
|
|
|
+ * @cap: total capacity of deque
|
|
|
+ * @min: initial capacity of deque
|
|
|
+ * @esz: element size
|
|
|
+ * @shrink: flag specifying shrink behavior
|
|
|
+ *
|
|
|
+ * len is distance between head and tail. cap changes with resizing.
|
|
|
+ * shrink must be one of DEQ_NO_SHRINK, DEQ_SHRINK_IF_EMPTY, or DEQ_SHRINK_AT_20PCT.
|
|
|
+ * When shrinking, min is the smallest size.
|
|
|
+ */
|
|
|
+
|
|
|
+enum deq_flag { DEQ_NO_SHRINK, DEQ_SHRINK_IF_EMPTY, DEQ_SHRINK_AT_20PCT };
|
|
|
+
|
|
|
+struct deq {
|
|
|
+ char *v;
|
|
|
+ unsigned head, tail, len, cap, min, esz, shrink;
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * DEQ_WRAP - declare a wrapper type for struct deq and base type
|
|
|
+ * @basetype: the base type to wrap
|
|
|
+ *
|
|
|
+ * Example:
|
|
|
+ * // init inline, defer malloc to first push/unshift
|
|
|
+ * struct point { int x, y; } a;
|
|
|
+ * DEQ_WRAP(struct point) pointq = DEQ_INIT(sizeof(struct point), 64, DEQ_NO_SHRINK);
|
|
|
+ *
|
|
|
+ * // or init and malloc by function call
|
|
|
+ * struct vector3 { double x, y, z; };
|
|
|
+ * typedef DEQ_WRAP(struct vector3) vector3q_t;
|
|
|
+ * vector3q_t v;
|
|
|
+ *
|
|
|
+ * if (deq_init(&v, 16, DEQ_SHRINK_IF_EMPTY) == -1)
|
|
|
+ * err(1, "deq_init");
|
|
|
+ *
|
|
|
+ * a.x = 1; a.y = 1;
|
|
|
+ * // first malloc for pointq
|
|
|
+ * if (deq_push(&pointq, a) == -1)
|
|
|
+ * err(1, "deq_push");
|
|
|
+ */
|
|
|
+#define DEQ_WRAP(basetype) \
|
|
|
+ union { \
|
|
|
+ struct deq deq; \
|
|
|
+ basetype *v; \
|
|
|
+ }
|
|
|
+
|
|
|
+#define DEQ_INIT_DEQ(esz, min, shrink) \
|
|
|
+ (struct deq) { 0, 0, 0, 0, 0, (min), (esz), (shrink) }
|
|
|
+
|
|
|
+#define DEQ_INIT(esz, min, shrink) { .deq = DEQ_INIT_DEQ(esz, min, shrink) }
|
|
|
+
|
|
|
+/**
|
|
|
+ * deq_init - initialize struct deq and malloc
|
|
|
+ * @w: pointer to wrapper
|
|
|
+ * @min: initial capacity of deque
|
|
|
+ * @shrink: flag specifying shrink behavior
|
|
|
+ *
|
|
|
+ * Returns: 0 on success, -1 on error
|
|
|
+ */
|
|
|
+int deq_resize_(struct deq *q, unsigned n);
|
|
|
+#define deq_init(w, min, shrink) ({ \
|
|
|
+ (w)->deq = DEQ_INIT_DEQ(sizeof(*(w)->v), min, shrink); \
|
|
|
+ deq_resize_(&(w)->deq, (min)); \
|
|
|
+})
|
|
|
+
|
|
|
+/**
|
|
|
+ * deq_new - malloc wrapper and run deq_init
|
|
|
+ * @w: pointer to wrapper
|
|
|
+ * @min: initial capacity of deque
|
|
|
+ * @shrink: flag specifying shrink behavior
|
|
|
+ *
|
|
|
+ * Example:
|
|
|
+ * vector3q_t *z;
|
|
|
+ *
|
|
|
+ * if (deq_new(z, 16, DEQ_SHRINK_AT_20PCT) == -1)
|
|
|
+ * err(1, "deq_new");
|
|
|
+ * //later
|
|
|
+ * deq_free(z);
|
|
|
+ *
|
|
|
+ * Returns: pointer on success, NULL on error
|
|
|
+ */
|
|
|
+#define deq_new(w, min, shrink) ({ \
|
|
|
+ w = malloc(sizeof(*w)); \
|
|
|
+ if (w && deq_init(w, min, shrink) == -1) { \
|
|
|
+ free(w); \
|
|
|
+ w = 0; \
|
|
|
+ } \
|
|
|
+ w ? 0 : -1; \
|
|
|
+})
|
|
|
+
|
|
|
+enum deq_op { DEQ_PUSH, DEQ_POP, DEQ_SHIFT, DEQ_UNSHIFT };
|
|
|
+int deq_op_(struct deq *q, enum deq_op op, unsigned *i);
|
|
|
+
|
|
|
+/**
|
|
|
+ * deq_push - add element to end of deque
|
|
|
+ * @w: pointer to wrapper
|
|
|
+ * @e: element to add
|
|
|
+ *
|
|
|
+ * Returns: 1 on success, -1 on error
|
|
|
+ */
|
|
|
+#define deq_push(w, e) ({ \
|
|
|
+ unsigned __i; \
|
|
|
+ int __ret = deq_op_(&(w)->deq, DEQ_PUSH, &__i); \
|
|
|
+ if (__ret == 1) \
|
|
|
+ (w)->v[__i] = (e); \
|
|
|
+ __ret; \
|
|
|
+})
|
|
|
+
|
|
|
+/**
|
|
|
+ * deq_unshift - add element to beginning of deque
|
|
|
+ * @w: pointer to wrapper
|
|
|
+ * @e: element to add
|
|
|
+ *
|
|
|
+ * Returns: 1 on success, -1 on error
|
|
|
+ */
|
|
|
+#define deq_unshift(w, e) ({ \
|
|
|
+ unsigned __i; \
|
|
|
+ int __ret = deq_op_(&(w)->deq, DEQ_UNSHIFT, &__i); \
|
|
|
+ if (__ret == 1) \
|
|
|
+ (w)->v[__i] = (e); \
|
|
|
+ __ret; \
|
|
|
+})
|
|
|
+
|
|
|
+/**
|
|
|
+ * deq_pop - dequeue element from end of deque
|
|
|
+ * @w: pointer to wrapper
|
|
|
+ * @e: pointer to receive dequeued element
|
|
|
+ *
|
|
|
+ * Returns: 1 on success, 0 if deque is empty, -1 on error
|
|
|
+ *
|
|
|
+ * Example:
|
|
|
+ * DEQ_WRAP(int) w = DEQ_INIT(sizeof(int), 8, DEQ_NO_SHRINK);
|
|
|
+ * int ret, i;
|
|
|
+ * // ... after enqueuing some ints
|
|
|
+ * while ((ret = deq_pop(&w, &i)) == 1)
|
|
|
+ * printf("%d\n", i);
|
|
|
+ * if (ret == -1)
|
|
|
+ * err(1, "deq_pop");
|
|
|
+ */
|
|
|
+#define deq_pop(w, e) ({ \
|
|
|
+ unsigned __i; \
|
|
|
+ int __ret = deq_op_(&(w)->deq, DEQ_POP, &__i); \
|
|
|
+ if (__ret == 1) \
|
|
|
+ *(e) = (w)->v[__i]; \
|
|
|
+ __ret; \
|
|
|
+})
|
|
|
+
|
|
|
+/**
|
|
|
+ * deq_shift - dequeue element from beginning of deque
|
|
|
+ * @w: pointer to wrapper
|
|
|
+ * @e: pointer to receive dequeued element
|
|
|
+ *
|
|
|
+ * Returns: 1 on success, 0 if deque is empty, -1 on error
|
|
|
+ */
|
|
|
+#define deq_shift(w, e) ({ \
|
|
|
+ unsigned __i; \
|
|
|
+ int __ret = deq_op_(&(w)->deq, DEQ_SHIFT, &__i); \
|
|
|
+ if (__ret == 1) \
|
|
|
+ *(e) = (w)->v[__i]; \
|
|
|
+ __ret; \
|
|
|
+})
|
|
|
+
|
|
|
+/**
|
|
|
+ * deq_first - get element from beginning of deque, deque is unchanged
|
|
|
+ * @w: pointer to wrapper
|
|
|
+ * @e: pointer to receive element
|
|
|
+ *
|
|
|
+ * Returns: 1 on success, 0 if deque is empty
|
|
|
+ */
|
|
|
+#define deq_first(w, e) ({ \
|
|
|
+ int __ret = 0; \
|
|
|
+ assert(w); \
|
|
|
+ assert(e); \
|
|
|
+ if ((w)->deq.len > 0) { \
|
|
|
+ *(e) = (w)->v[(w)->deq.head]; \
|
|
|
+ __ret = 1; \
|
|
|
+ } \
|
|
|
+ __ret; \
|
|
|
+})
|
|
|
+
|
|
|
+/**
|
|
|
+ * deq_last - get element from end of deque, deque is unchanged
|
|
|
+ * @w: pointer to wrapper
|
|
|
+ * @e: pointer to receive element
|
|
|
+ *
|
|
|
+ * Returns: 1 on success, 0 if deque is empty
|
|
|
+ */
|
|
|
+#define deq_last(w, e) ({ \
|
|
|
+ int __ret = 0; \
|
|
|
+ assert(w); \
|
|
|
+ assert(e); \
|
|
|
+ if ((w)->deq.len > 0) { \
|
|
|
+ unsigned __i = (w)->deq.tail == 0 ? \
|
|
|
+ (w)->deq.cap : (w)->deq.tail; \
|
|
|
+ *(e) = (w)->v[__i - 1]; \
|
|
|
+ __ret = 1; \
|
|
|
+ } \
|
|
|
+ __ret; \
|
|
|
+})
|
|
|
+
|
|
|
+/**
|
|
|
+ * deq_reset - set struct deq indexes and counters to zero, and free malloced buffer
|
|
|
+ * @w: pointer to wrapper
|
|
|
+ *
|
|
|
+ * Returns: void
|
|
|
+ */
|
|
|
+void deq_reset_(struct deq *q);
|
|
|
+#define deq_reset(w) do { \
|
|
|
+ assert(w); \
|
|
|
+ deq_reset_(&(w)->deq); \
|
|
|
+ (w)->v = 0; \
|
|
|
+} while (0)
|
|
|
+
|
|
|
+/**
|
|
|
+ * deq_free - run deq_reset and free malloced wrapper
|
|
|
+ * @w: pointer to wrapper
|
|
|
+ *
|
|
|
+ * Returns: void
|
|
|
+ */
|
|
|
+#define deq_free(w) do { \
|
|
|
+ deq_reset(w); \
|
|
|
+ free(w); \
|
|
|
+ w = 0; \
|
|
|
+} while (0)
|
|
|
+
|
|
|
+/**
|
|
|
+ * deq_len - return deque length
|
|
|
+ * @w: pointer to wrapper
|
|
|
+ *
|
|
|
+ * Returns: int
|
|
|
+ */
|
|
|
+#define deq_len(w) ({ assert(w); (w)->deq.len; })
|
|
|
+
|
|
|
+/**
|
|
|
+ * deq_cap - return deque capacity
|
|
|
+ * @w: pointer to wrapper
|
|
|
+ *
|
|
|
+ * Returns: int
|
|
|
+ */
|
|
|
+#define deq_cap(w) ({ assert(w); (w)->deq.cap; })
|
|
|
+
|
|
|
+#endif
|