7 * struct deq - deque metadata
8 * @v: char pointer to malloced memory
9 * @head: index of first item in deque
10 * @tail: index after last item in deque
11 * @len: length of deque
12 * @cap: total capacity of deque
13 * @min: initial capacity of deque
15 * @shrink: flag specifying shrink behavior
17 * len is distance between head and tail. cap changes with resizing.
18 * shrink must be one of DEQ_NO_SHRINK, DEQ_SHRINK_IF_EMPTY, or DEQ_SHRINK_AT_20PCT.
19 * When shrinking, min is the smallest size.
22 enum deq_flag { DEQ_NO_SHRINK, DEQ_SHRINK_IF_EMPTY, DEQ_SHRINK_AT_20PCT };
26 unsigned head, tail, len, cap, min, esz, shrink;
30 * DEQ_WRAP - declare a wrapper type for struct deq and base type
31 * @basetype: the base type to wrap
34 * // init inline, defer malloc to first push/unshift
35 * struct point { int x, y; } a;
36 * DEQ_WRAP(struct point) pointq = DEQ_INIT(sizeof(struct point), 64, DEQ_NO_SHRINK);
38 * // or init and malloc by function call
39 * struct vector3 { double x, y, z; };
40 * typedef DEQ_WRAP(struct vector3) vector3q_t;
43 * if (deq_init(&v, 16, DEQ_SHRINK_IF_EMPTY) == -1)
47 * // first malloc for pointq
48 * if (deq_push(&pointq, a) == -1)
51 #define DEQ_WRAP(basetype) \
57 #define DEQ_INIT_DEQ(esz, min, shrink) \
58 (struct deq) { 0, 0, 0, 0, 0, (min), (esz), (shrink) }
60 #define DEQ_INIT(esz, min, shrink) { .deq = DEQ_INIT_DEQ(esz, min, shrink) }
63 * deq_init - initialize struct deq and malloc
64 * @w: pointer to wrapper
65 * @min: initial capacity of deque
66 * @shrink: flag specifying shrink behavior
68 * Returns: 0 on success, -1 on error
70 int deq_resize_(struct deq *q, unsigned n);
71 #define deq_init(w, min, shrink) ({ \
72 (w)->deq = DEQ_INIT_DEQ(sizeof(*(w)->v), min, shrink); \
73 deq_resize_(&(w)->deq, (min)); \
77 * deq_new - malloc wrapper and run deq_init
78 * @w: pointer to wrapper
79 * @min: initial capacity of deque
80 * @shrink: flag specifying shrink behavior
85 * if (deq_new(z, 16, DEQ_SHRINK_AT_20PCT) == -1)
90 * Returns: pointer on success, NULL on error
92 #define deq_new(w, min, shrink) ({ \
93 w = malloc(sizeof(*w)); \
94 if (w && deq_init(w, min, shrink) == -1) { \
101 enum deq_op { DEQ_PUSH, DEQ_POP, DEQ_SHIFT, DEQ_UNSHIFT };
102 int deq_op_(struct deq *q, enum deq_op op, unsigned *i);
105 * deq_push - add element to end of deque
106 * @w: pointer to wrapper
109 * Returns: 1 on success, -1 on error
111 #define deq_push(w, e) ({ \
113 int __ret = deq_op_(&(w)->deq, DEQ_PUSH, &__i); \
120 * deq_unshift - add element to beginning of deque
121 * @w: pointer to wrapper
124 * Returns: 1 on success, -1 on error
126 #define deq_unshift(w, e) ({ \
128 int __ret = deq_op_(&(w)->deq, DEQ_UNSHIFT, &__i); \
135 * deq_pop - dequeue element from end of deque
136 * @w: pointer to wrapper
137 * @e: pointer to receive dequeued element
139 * Returns: 1 on success, 0 if deque is empty, -1 on error
142 * DEQ_WRAP(int) w = DEQ_INIT(sizeof(int), 8, DEQ_NO_SHRINK);
144 * // ... after enqueuing some ints
145 * while ((ret = deq_pop(&w, &i)) == 1)
150 #define deq_pop(w, e) ({ \
152 int __ret = deq_op_(&(w)->deq, DEQ_POP, &__i); \
154 *(e) = (w)->v[__i]; \
159 * deq_shift - dequeue element from beginning of deque
160 * @w: pointer to wrapper
161 * @e: pointer to receive dequeued element
163 * Returns: 1 on success, 0 if deque is empty, -1 on error
165 #define deq_shift(w, e) ({ \
167 int __ret = deq_op_(&(w)->deq, DEQ_SHIFT, &__i); \
169 *(e) = (w)->v[__i]; \
174 * deq_first - get element from beginning of deque, deque is unchanged
175 * @w: pointer to wrapper
176 * @e: pointer to receive element
178 * Returns: 1 on success, 0 if deque is empty
180 #define deq_first(w, e) ({ \
184 if ((w)->deq.len > 0) { \
185 *(e) = (w)->v[(w)->deq.head]; \
192 * deq_last - get element from end of deque, deque is unchanged
193 * @w: pointer to wrapper
194 * @e: pointer to receive element
196 * Returns: 1 on success, 0 if deque is empty
198 #define deq_last(w, e) ({ \
202 if ((w)->deq.len > 0) { \
203 unsigned __i = (w)->deq.tail == 0 ? \
204 (w)->deq.cap : (w)->deq.tail; \
205 *(e) = (w)->v[__i - 1]; \
212 * deq_reset - set struct deq indexes and counters to zero, and free malloced buffer
213 * @w: pointer to wrapper
217 void deq_reset_(struct deq *q);
218 #define deq_reset(w) do { \
220 deq_reset_(&(w)->deq); \
225 * deq_free - run deq_reset and free malloced wrapper
226 * @w: pointer to wrapper
230 #define deq_free(w) do { \
237 * deq_len - return deque length
238 * @w: pointer to wrapper
242 #define deq_len(w) ({ assert(w); (w)->deq.len; })
245 * deq_cap - return deque capacity
246 * @w: pointer to wrapper
250 #define deq_cap(w) ({ assert(w); (w)->deq.cap; })