1 /* $NetBSD: gcq.h,v 1.2 2007/08/19 07:35:32 kiyohara Exp $ */
3 * Not (c) 2007 Matthew Orgass
4 * This file is public domain, meaning anyone can make any use of part or all
5 * of this file including copying into other works without credit. Any use,
6 * modified or not, is solely the responsibility of the user. If this file is
7 * part of a collection then use in the collection is governed by the terms of
12 * Generic Circular Queues: Pointer arithmetic is used to recover the
13 * enclosing object. Merge operation is provided. Items can be multiply
14 * removed, but queue traversal requires separate knowledge of the queue head.
21 #include <sys/types.h>
23 #include <lib/libkern/libkern.h>
32 #define GCQ_ASSERT(x) assert(x)
35 #define GCQ_ASSERT(x) KASSERT(x)
37 #define GCQ_ASSERT(x) _DIAGASSERT(x)
50 #define GCQ_INIT(q) { &(q), &(q) }
51 #define GCQ_INIT_HEAD(head) { GCQ_INIT((head).hq) }
53 __attribute__((nonnull
, always_inline
)) static inline void
54 gcq_init(struct gcq
*q
)
56 q
->q_next
= q
->q_prev
= q
;
59 __attribute__((nonnull
, const, warn_unused_result
, always_inline
))
60 static inline struct gcq
*
66 __attribute__((nonnull
, const, warn_unused_result
, always_inline
))
67 static inline struct gcq
*
68 gcq_hq(struct gcq_head
*head
)
70 return (struct gcq
*)head
;
73 __attribute__((nonnull
, const, warn_unused_result
, always_inline
))
74 static inline struct gcq_head
*
75 gcq_head(struct gcq
*q
)
77 return (struct gcq_head
*)q
;
80 __attribute__((nonnull
, always_inline
)) static inline void
81 gcq_init_head(struct gcq_head
*head
)
83 gcq_init(gcq_hq(head
));
86 __attribute__((nonnull
, pure
, warn_unused_result
, always_inline
))
88 gcq_onlist(struct gcq
*q
)
90 return (q
->q_next
!= q
);
93 __attribute__((nonnull
, pure
, warn_unused_result
, always_inline
))
95 gcq_empty(struct gcq_head
*head
)
97 return (!gcq_onlist(gcq_hq(head
)));
100 __attribute__((nonnull
, pure
, warn_unused_result
, always_inline
))
102 gcq_linked(struct gcq
*prev
, struct gcq
*next
)
104 return (prev
->q_next
== next
&& next
->q_prev
== prev
);
107 __attribute__((nonnull
, always_inline
)) static inline void
108 gcq_insert_after(struct gcq
*on
, struct gcq
*off
)
111 GCQ_ASSERT(off
->q_next
== off
&& off
->q_prev
== off
);
112 on_next
= on
->q_next
;
115 off
->q_next
= on_next
;
116 on_next
->q_prev
= off
;
120 __attribute__((nonnull
)) static inline void
121 gcq_insert_before(struct gcq
*on
, struct gcq
*off
)
124 GCQ_ASSERT(off
->q_next
== off
&& off
->q_prev
== off
);
125 on_prev
= on
->q_prev
;
128 off
->q_prev
= on_prev
;
129 on_prev
->q_next
= off
;
133 __attribute__((nonnull
, always_inline
)) static inline void
134 gcq_insert_head(struct gcq_head
*head
, struct gcq
*q
)
136 gcq_insert_after(gcq_hq(head
), q
);
139 __attribute__((nonnull
, always_inline
)) static inline void
140 gcq_insert_tail(struct gcq_head
*head
, struct gcq
*q
)
142 gcq_insert_before(gcq_hq(head
), q
);
145 __attribute__((nonnull
)) static inline void
146 gcq_tie(struct gcq
*dst
, struct gcq
*src
)
148 struct gcq
*dst_next
, *src_prev
;
149 dst_next
= dst
->q_next
;
150 src_prev
= src
->q_prev
;
152 src_prev
->q_next
= dst_next
;
153 dst_next
->q_prev
= src_prev
;
158 __attribute__((nonnull
, always_inline
)) static inline void
159 gcq_tie_after(struct gcq
*dst
, struct gcq
*src
)
161 GCQ_ASSERT(dst
!= src
&& dst
->q_prev
!= src
);
165 __attribute__((nonnull
, always_inline
)) static inline void
166 gcq_tie_before(struct gcq
*dst
, struct gcq
*src
)
168 gcq_tie_after(dst
->q_prev
, src
);
171 __attribute__((nonnull
)) static inline struct gcq
*
172 gcq_remove(struct gcq
*q
)
174 struct gcq
*next
, *prev
;
184 #ifdef GCQ_UNCONDITIONAL_MERGE
185 __attribute__((nonnull
)) static inline void
186 gcq_merge(struct gcq
*dst
, struct gcq
*src
)
188 GCQ_ASSERT(dst
!= src
&& dst
->q_prev
!= src
);
193 __attribute__((nonnull
, always_inline
)) static inline void
194 gcq_merge_head(struct gcq_head
*dst
, struct gcq_head
*src
)
196 gcq_merge(gcq_hq(dst
), gcq_hq(src
));
199 __attribute__((nonnull
, always_inline
)) static inline void
200 gcq_merge_tail(struct gcq_head
*dst
, struct gcq_head
*src
)
202 gcq_merge(gcq_hq(dst
)->q_prev
, gcq_hq(src
));
205 __attribute__((nonnull
)) static inline void
206 gcq_merge(struct gcq
*dst
, struct gcq
*src
)
208 struct gcq
*dst_next
, *src_prev
, *src_next
;
209 GCQ_ASSERT(dst
!= src
&& dst
->q_prev
!= src
);
211 if (gcq_onlist(src
)) {
212 dst_next
= dst
->q_next
;
213 src_prev
= src
->q_prev
;
214 src_next
= src
->q_next
;
216 dst_next
->q_prev
= src_prev
;
217 src_prev
->q_next
= dst_next
;
218 dst
->q_next
= src_next
;
219 src_next
->q_prev
= dst
;
224 __attribute__((nonnull
, always_inline
)) static inline void
225 gcq_merge_head(struct gcq_head
*dst
, struct gcq_head
*src
)
227 gcq_merge(gcq_hq(dst
), gcq_hq(src
));
230 __attribute__((nonnull
, always_inline
)) static inline void
231 gcq_merge_tail(struct gcq_head
*dst
, struct gcq_head
*src
)
233 gcq_merge(gcq_hq(dst
)->q_prev
, gcq_hq(src
));
237 __attribute__((nonnull
)) static inline void
238 gcq_clear(struct gcq
*q
)
240 struct gcq
*nq
, *next
;
249 __attribute__((nonnull
, always_inline
)) static inline void
250 gcq_remove_all(struct gcq_head
*head
)
252 gcq_clear(gcq_hq(head
));
255 __attribute__((nonnull
, always_inline
)) static inline struct gcq
*
256 _gcq_next(struct gcq
*current
, struct gcq_head
*head
, struct gcq
*start
)
261 if (hq
!= start
&& q
== hq
)
263 if (current
!= start
)
264 GCQ_ASSERT(gcq_onlist(current
));
268 __attribute__((nonnull
, always_inline
)) static inline struct gcq
*
269 _gcq_prev(struct gcq
*current
, struct gcq_head
*head
, struct gcq
*start
)
274 if (hq
!= start
&& q
== hq
)
276 if (current
!= start
)
277 GCQ_ASSERT(gcq_onlist(current
));
282 #define GCQ_ITEM(q, type, name) \
283 ((type *)(void *)((uint8_t *)gcq_q(q) - offsetof(type, name)))
286 #define _GCQ_GDQ(var, h, ptr, fn) (gcq_hq(h)->ptr != gcq_hq(h) ? \
287 (var = fn(gcq_hq(h)->ptr), true) : (var = NULL, false))
288 #define _GCQ_GDQ_TYPED(tvar, h, type, name, ptr, fn) \
289 (gcq_hq(h)->ptr != gcq_hq(h) ? (tvar = GCQ_ITEM(fn(gcq_hq(h)->ptr), \
290 type, name), true) : (tvar = NULL, false))
291 #define _GCQ_NP(var, current, head, start, np, fn) \
292 (np(current, head, start) != (start) ? \
293 (var = fn(np(current, head, start)), true) : (var = NULL, false))
294 #define _GCQ_NP_TYPED(tvar, current, head, start, type, name, np, fn) \
295 (np(current, head, start) != (start) ? \
296 (tvar = GCQ_ITEM(fn(np(current, head, start)), type, name), true) : \
297 (tvar = NULL, false))
299 #define _GCQ_GDQ_COND(var, h, ptr, rem, cond) \
300 (gcq_hq(h)->ptr != gcq_hq(h) ? (var = gcq_hq(h)->ptr, \
301 ((cond) ? (rem, true) : (var = NULL, false))) : \
303 #define _GCQ_GDQ_COND_TYPED(tvar, h, type, name, ptr, rem, cond) \
304 (gcq_hq(h)->ptr != gcq_hq(h) ? (tvar = GCQ_ITEM(gcq_hq(h)->ptr, \
305 type, name), ((cond) ? (rem, true) : (tvar = NULL, false))) : \
306 (tvar = NULL, false))
307 #define _GCQ_NP_COND(var, current, head, start, np, rem, cond) \
308 (np(current, head, start) != (start) ? \
309 (var = fn(np(current, head, start)), ((cond) ? (rem), true) : \
310 (var = NULL, false))) : (var = NULL, false))
311 #define _GCQ_NP_COND_TYPED(tvar, current, head, start, type, name, np, \
312 rem, cond) (np(current, head, start) != (start) ? \
313 (tvar = GCQ_ITEM(fn(np(current, head, start)), type, name), \
314 ((cond) ? (rem, true) : (var = NULL, false))) : \
315 (tvar = NULL, false))
317 #define GCQ_GOT_FIRST(var, h) _GCQ_GDQ(var, h, q_next, gcq_q)
318 #define GCQ_GOT_LAST(var, h) _GCQ_GDQ(var, h, q_prev, gcq_q)
319 #define GCQ_DEQUEUED_FIRST(var, h) _GCQ_GDQ(var, h, q_next, gcq_remove)
320 #define GCQ_DEQUEUED_LAST(var, h) _GCQ_GDQ(var, h, q_prev, gcq_remove)
321 #define GCQ_GOT_FIRST_TYPED(tvar, h, type, name) \
322 _GCQ_GDQ_TYPED(tvar, h, type, name, q_next, gcq_q)
323 #define GCQ_GOT_LAST_TYPED(tvar, h, type, name) \
324 _GCQ_GDQ_TYPED(tvar, h, type, name, q_prev, gcq_q)
325 #define GCQ_DEQUEUED_FIRST_TYPED(tvar, h, type, name) \
326 _GCQ_GDQ_TYPED(tvar, h, type, name, q_next, gcq_remove)
327 #define GCQ_DEQUEUED_LAST_TYPED(tvar, h, type, name) \
328 _GCQ_GDQ_TYPED(tvar, h, type, name, q_prev, gcq_remove)
329 #define GCQ_GOT_NEXT(var, current, head, start) \
330 _GCQ_NP(var, current, head, start, _gcq_next, gcq_q)
331 #define GCQ_GOT_PREV(var, current, head, start) \
332 _GCQ_NP(var, current, head, start, _gcq_prev, gcq_q)
333 #define GCQ_DEQUEUED_NEXT(var, current, head, start) \
334 _GCQ_NP(var, current, head, start, _gcq_next, gcq_remove)
335 #define GCQ_DEQUEUED_PREV(var, current, head, start) \
336 _GCQ_NP(var, current, head, start, _gcq_prev, gcq_remove)
337 #define GCQ_GOT_NEXT_TYPED(tvar, current, head, start, type, name) \
338 _GCQ_NP_TYPED(tvar, current, head, start, type, name, \
340 #define GCQ_GOT_PREV_TYPED(tvar, current, head, start, type, name) \
341 _GCQ_NP_TYPED(tvar, current, head, start, type, name, \
343 #define GCQ_DEQUEUED_NEXT_TYPED(tvar, current, head, start, type, name) \
344 _GCQ_NP_TYPED(tvar, current, head, start, type, name, \
345 _gcq_next, gcq_remove)
346 #define GCQ_DEQUEUED_PREV_TYPED(tvar, current, head, start, type, name) \
347 _GCQ_NP_TYPED(tvar, current, head, start, type, name, \
348 _gcq_prev, gcq_remove)
350 #define GCQ_GOT_FIRST_COND(var, h, cond) \
351 _GCQ_GDQ_COND(var, h, q_next, ((void)0), cond)
352 #define GCQ_GOT_LAST_COND(var, h, cond) \
353 _GCQ_GDQ_COND(var, h, q_prev, ((void)0), cond)
354 #define GCQ_DEQUEUED_FIRST_COND(var, h, cond) \
355 _GCQ_GDQ_COND(var, h, q_next, gcq_remove(var), cond)
356 #define GCQ_DEQUEUED_LAST_COND(var, h, cond) \
357 _GCQ_GDQ_COND(var, h, q_prev, gcq_remove(var), cond)
358 #define GCQ_GOT_FIRST_COND_TYPED(tvar, h, type, name, cond) \
359 _GCQ_GDQ_COND_TYPED(tvar, h, type, name, q_next, ((void)0), cond)
360 #define GCQ_GOT_LAST_COND_TYPED(tvar, h, type, name, cond) \
361 _GCQ_GDQ_COND_TYPED(tvar, h, type, name, q_prev, ((void)0), cond)
362 #define GCQ_DEQUEUED_FIRST_COND_TYPED(tvar, h, type, name, cond) \
363 _GCQ_GDQ_COND_TYPED(tvar, h, type, name, q_next, \
364 gcq_remove(&(tvar)->name), cond)
365 #define GCQ_DEQUEUED_LAST_COND_TYPED(tvar, h, type, name, cond) \
366 _GCQ_GDQ_COND_TYPED(tvar, h, type, name, q_prev, \
367 gcq_remove(&(tvar)->name), cond)
368 #define GCQ_GOT_NEXT_COND(var, current, head, start, cond) \
369 _GCQ_NP_COND(var, current, head, start, _gcq_next, ((void)0), cond)
370 #define GCQ_GOT_PREV_COND(var, current, head, start, cond) \
371 _GCQ_NP_COND(var, current, head, start, _gcq_prev, ((void)0), cond)
372 #define GCQ_DEQUEUED_NEXT_COND(var, current, head, start, cond) \
373 _GCQ_NP_COND(var, current, head, start, _gcq_next, gcq_remove(var), \
375 #define GCQ_DEQUEUED_PREV_COND(var, current, head, start, cond) \
376 _GCQ_NP_COND(var, current, head, start, _gcq_prev, gcq_remove(var), \
378 #define GCQ_GOT_NEXT_COND_TYPED(tvar, current, head, start, type, name, \
379 cond) _GCQ_NP_COND_TYPED(tvar, current, head, start, type, name, \
380 _gcq_next, ((void)0), cond)
381 #define GCQ_GOT_PREV_COND_TYPED(tvar, current, head, start, type, name, \
382 cond) _GCQ_NP_COND_TYPED(tvar, current, head, start, type, name, \
383 _gcq_prev, ((void)0), cond)
384 #define GCQ_DEQUEUED_NEXT_COND_TYPED(tvar, current, head, start, type, \
385 name, cond) _GCQ_NP_COND_TYPED(tvar, current, head, start, type, \
386 name, _gcq_next, gcq_remove(&(tvar)->name), cond)
387 #define GCQ_DEQUEUED_PREV_COND_TYPED(tvar, current, head, start, type, \
388 name, cond) _GCQ_NP_COND_TYPED(tvar, current, head, start, type, \
389 name, _gcq_prev, gcq_remove(&(tvar)->name), cond)
392 #define _GCQ_FOREACH(var, h, tnull, item, ptr) \
393 for ((var)=gcq_hq(h)->ptr; ((var) != gcq_hq(h) && \
394 (GCQ_ASSERT(gcq_onlist(var)), item, true)) || \
395 (tnull, false); (var)=(var)->ptr)
396 #define _GCQ_FOREACH_NVAR(var, nvar, h, tnull, item, ptr, ol, rem, ro) \
397 for ((nvar)=gcq_hq(h)->ptr; (((var)=(nvar), (nvar) != gcq_hq(h)) && \
398 (ol, (nvar)=(nvar)->ptr, rem, item, true)) || (tnull, false); ro)
400 #define GCQ_FOREACH(var, h) \
401 _GCQ_FOREACH(var, h, ((void)0), ((void)0), q_next)
402 #define GCQ_FOREACH_REV(var, h) \
403 _GCQ_FOREACH(var, h, ((void)0), ((void)0), q_prev)
404 #define GCQ_FOREACH_NVAR(var, nvar, h) \
405 _GCQ_FOREACH_NVAR(var, nvar, h, ((void)0), ((void)0), \
406 q_next, GCQ_ASSERT(gcq_onlist(nvar)), ((void)0), ((void)0))
407 #define GCQ_FOREACH_NVAR_REV(var, nvar, h) \
408 _GCQ_FOREACH_NVAR(var, nvar, h, ((void)0), ((void)0), \
409 q_prev, GCQ_ASSERT(gcq_onlist(nvar)), ((void)0), ((void)0))
410 #define GCQ_FOREACH_RO(var, nvar, h) \
411 _GCQ_FOREACH_NVAR(var, nvar, h, ((void)0), ((void)0), \
412 q_next, ((void)0), ((void)0), GCQ_ASSERT(gcq_linked(var, nvar)))
413 #define GCQ_FOREACH_RO_REV(var, nvar, h) \
414 _GCQ_FOREACH_NVAR(var, nvar, h, ((void)0), ((void)0), \
415 q_prev, ((void)0), ((void)0), GCQ_ASSERT(gcq_linked(nvar, var)))
416 #define GCQ_FOREACH_DEQUEUED(var, nvar, h) \
417 _GCQ_FOREACH_NVAR(var, nvar, h, ((void)0), ((void)0), \
418 q_next, GCQ_ASSERT(gcq_onlist(nvar)), gcq_remove(var), ((void)0)
419 #define GCQ_FOREACH_DEQUEUED_REV(var, nvar, h) \
420 _GCQ_FOREACH_NVAR(var, nvar, h, ((void)0), ((void)0), \
421 q_prev, GCQ_ASSERT(gcq_onlist(nvar)), gcq_remove(var), ((void)0)
423 #define GCQ_FOREACH_TYPED(var, h, tvar, type, name) \
424 _GCQ_FOREACH(var, h, (tvar)=NULL, (tvar)=GCQ_ITEM(var, type, name), \
426 #define GCQ_FOREACH_TYPED_REV(var, h, tvar, type, name) \
427 _GCQ_FOREACH(var, h, (tvar)=NULL, (tvar)=GCQ_ITEM(var, type, name), \
429 #define GCQ_FOREACH_NVAR_TYPED(var, nvar, h, tvar, type, name) \
430 _GCQ_FOREACH_NVAR(var, nvar, h, (tvar)=NULL, \
431 (tvar)=GCQ_ITEM(var, type, name), \
432 q_next, GCQ_ASSERT(gcq_onlist(nvar)), ((void)0), ((void)0))
433 #define GCQ_FOREACH_NVAR_REV_TYPED(var, nvar, h, tvar, type, name) \
434 _GCQ_FOREACH_NVAR(var, nvar, h, (tvar)=NULL, \
435 (tvar)=GCQ_ITEM(var, type, name), \
436 q_prev, GCQ_ASSERT(gcq_onlist(nvar)), ((void)0), ((void)0))
437 #define GCQ_FOREACH_RO_TYPED(var, nvar, h, tvar, type, name) \
438 _GCQ_FOREACH_NVAR(var, nvar, h, (tvar)=NULL, \
439 (tvar)=GCQ_ITEM(var, type, name), \
440 q_next, ((void)0), ((void)0), GCQ_ASSERT(gcq_lined(var, nvar)))
441 #define GCQ_FOREACH_RO_REV_TYPED(var, nvar, h, tvar, type, name) \
442 _GCQ_FOREACH_NVAR(var, nvar, h, (tvar)=NULL, \
443 (tvar)=GCQ_ITEM(var, type, name), \
444 q_prev, ((void)0), ((void)0), GCQ_ASSERT(gcq_linked(nvar, var)))
445 #define GCQ_FOREACH_DEQUEUED_TYPED(var, nvar, h, tvar, type, name) \
446 _GCQ_FOREACH_NVAR(var, nvar, h, (tvar)=NULL, \
447 (tvar)=GCQ_ITEM(var, type, name), \
448 q_next, GCQ_ASSERT(gcq_onlist(nvar)), gcq_remove(var), ((void)0))
449 #define GCQ_FOREACH_DEQUEUED_REV_TYPED(var, nvar, h, tvar, type, name) \
450 _GCQ_FOREACH_NVAR(var, nvar, h, (tvar)=NULL, \
451 (tvar)=GCQ_ITEM(var, type, name), \
452 q_prev, GCQ_ASSERT(gcq_onlist(nvar)), gcq_remove(var), ((void)0))
454 #define _GCQ_COND(fe, cond) do { fe { if (cond) break; } } while (0)
456 #define GCQ_FIND(var, h, cond) _GCQ_COND(GCQ_FOREACH(var, h), cond)
457 #define GCQ_FIND_REV(var, h, cond) _GCQ_COND(GCQ_FOREACH_REV(var, h), cond)
458 #define GCQ_FIND_TYPED(var, h, tvar, type, name, cond) \
459 _GCQ_COND(GCQ_FOREACH_TYPED(var, h, tvar, type, name), cond)
460 #define GCQ_FIND_TYPED_REV(var, h, tvar, type, name, cond) \
461 _GCQ_COND(GCQ_FOREACH_REV_TYPED(var, h, tvar, type, name), cond)