Home | History | Annotate | Line # | Download | only in sys
      1 /* $NetBSD: gcq.h,v 1.3 2018/04/19 21:19:07 christos Exp $ */
      2 /*
      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
      8  * the collection.
      9  */
     10 
     11 /*
     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.
     15  */
     16 
     17 #ifndef _GCQ_H
     18 #define _GCQ_H
     19 
     20 #ifdef _KERNEL
     21 #include <sys/types.h>
     22 #include <sys/null.h>
     23 #include <lib/libkern/libkern.h>
     24 #else
     25 #include <stdbool.h>
     26 #include <stdint.h>
     27 #include <stddef.h>
     28 #include <assert.h>
     29 #endif
     30 
     31 #ifdef GCQ_USE_ASSERT
     32 #define GCQ_ASSERT(x) assert(x)
     33 #else
     34 #ifdef _KERNEL
     35 #define GCQ_ASSERT(x) KASSERT(x)
     36 #else
     37 #define GCQ_ASSERT(x) _DIAGASSERT(x)
     38 #endif
     39 #endif
     40 
     41 struct gcq {
     42 	struct gcq *q_next;
     43 	struct gcq *q_prev;
     44 };
     45 
     46 struct gcq_head {
     47 	struct gcq hq;
     48 };
     49 
     50 #define GCQ_INIT(q) { &(q), &(q) }
     51 #define GCQ_INIT_HEAD(head) { GCQ_INIT((head).hq) }
     52 
     53 __attribute__((nonnull, always_inline)) static __inline void
     54 gcq_init(struct gcq *q)
     55 {
     56 	q->q_next = q->q_prev = q;
     57 }
     58 
     59 __attribute__((nonnull, const, warn_unused_result, always_inline))
     60 static __inline struct gcq *
     61 gcq_q(struct gcq *q)
     62 {
     63 	return q;
     64 }
     65 
     66 __attribute__((nonnull, const, warn_unused_result, always_inline))
     67 static __inline struct gcq *
     68 gcq_hq(struct gcq_head *head)
     69 {
     70 	return (struct gcq *)head;
     71 }
     72 
     73 __attribute__((nonnull, const, warn_unused_result, always_inline))
     74 static __inline struct gcq_head *
     75 gcq_head(struct gcq *q)
     76 {
     77 	return (struct gcq_head *)q;
     78 }
     79 
     80 __attribute__((nonnull, always_inline)) static __inline void
     81 gcq_init_head(struct gcq_head *head)
     82 {
     83 	gcq_init(gcq_hq(head));
     84 }
     85 
     86 __attribute__((nonnull, pure, warn_unused_result, always_inline))
     87 static __inline bool
     88 gcq_onlist(struct gcq *q)
     89 {
     90 	return (q->q_next != q);
     91 }
     92 
     93 __attribute__((nonnull, pure, warn_unused_result, always_inline))
     94 static __inline bool
     95 gcq_empty(struct gcq_head *head)
     96 {
     97 	return (!gcq_onlist(gcq_hq(head)));
     98 }
     99 
    100 __attribute__((nonnull, pure, warn_unused_result, always_inline))
    101 static __inline bool
    102 gcq_linked(struct gcq *prev, struct gcq *next)
    103 {
    104 	return (prev->q_next == next && next->q_prev == prev);
    105 }
    106 
    107 __attribute__((nonnull, always_inline)) static __inline void
    108 gcq_insert_after(struct gcq *on, struct gcq *off)
    109 {
    110 	struct gcq *on_next;
    111 	GCQ_ASSERT(off->q_next == off && off->q_prev == off);
    112 	on_next = on->q_next;
    113 
    114 	off->q_prev = on;
    115 	off->q_next = on_next;
    116 	on_next->q_prev = off;
    117 	on->q_next = off;
    118 }
    119 
    120 __attribute__((nonnull)) static __inline void
    121 gcq_insert_before(struct gcq *on, struct gcq *off)
    122 {
    123 	struct gcq *on_prev;
    124 	GCQ_ASSERT(off->q_next == off && off->q_prev == off);
    125 	on_prev = on->q_prev;
    126 
    127 	off->q_next = on;
    128 	off->q_prev = on_prev;
    129 	on_prev->q_next = off;
    130 	on->q_prev = off;
    131 }
    132 
    133 __attribute__((nonnull, always_inline)) static __inline void
    134 gcq_insert_head(struct gcq_head *head, struct gcq *q)
    135 {
    136 	gcq_insert_after(gcq_hq(head), q);
    137 }
    138 
    139 __attribute__((nonnull, always_inline)) static __inline void
    140 gcq_insert_tail(struct gcq_head *head, struct gcq *q)
    141 {
    142 	gcq_insert_before(gcq_hq(head), q);
    143 }
    144 
    145 __attribute__((nonnull)) static __inline void
    146 gcq_tie(struct gcq *dst, struct gcq *src)
    147 {
    148 	struct gcq *dst_next, *src_prev;
    149 	dst_next = dst->q_next;
    150 	src_prev = src->q_prev;
    151 
    152 	src_prev->q_next = dst_next;
    153 	dst_next->q_prev = src_prev;
    154 	src->q_prev = dst;
    155 	dst->q_next = src;
    156 }
    157 
    158 __attribute__((nonnull, always_inline)) static __inline void
    159 gcq_tie_after(struct gcq *dst, struct gcq *src)
    160 {
    161 	GCQ_ASSERT(dst != src && dst->q_prev != src);
    162 	gcq_tie(dst, src);
    163 }
    164 
    165 __attribute__((nonnull, always_inline)) static __inline void
    166 gcq_tie_before(struct gcq *dst, struct gcq *src)
    167 {
    168 	gcq_tie_after(dst->q_prev, src);
    169 }
    170 
    171 __attribute__((nonnull)) static __inline struct gcq *
    172 gcq_remove(struct gcq *q)
    173 {
    174 	struct gcq *next, *prev;
    175 	next = q->q_next;
    176 	prev = q->q_prev;
    177 
    178 	prev->q_next = next;
    179 	next->q_prev = prev;
    180 	gcq_init(q);
    181 	return q;
    182 }
    183 
    184 #ifdef GCQ_UNCONDITIONAL_MERGE
    185 __attribute__((nonnull)) static __inline void
    186 gcq_merge(struct gcq *dst, struct gcq *src)
    187 {
    188 	GCQ_ASSERT(dst != src && dst->q_prev != src);
    189 	gcq_tie(dst, src);
    190 	gcq_tie(src, src);
    191 }
    192 
    193 __attribute__((nonnull, always_inline)) static __inline void
    194 gcq_merge_head(struct gcq_head *dst, struct gcq_head *src)
    195 {
    196 	gcq_merge(gcq_hq(dst), gcq_hq(src));
    197 }
    198 
    199 __attribute__((nonnull, always_inline)) static __inline void
    200 gcq_merge_tail(struct gcq_head *dst, struct gcq_head *src)
    201 {
    202 	gcq_merge(gcq_hq(dst)->q_prev, gcq_hq(src));
    203 }
    204 #else
    205 __attribute__((nonnull)) static __inline void
    206 gcq_merge(struct gcq *dst, struct gcq *src)
    207 {
    208 	struct gcq *dst_next, *src_prev, *src_next;
    209 	GCQ_ASSERT(dst != src && dst->q_prev != src);
    210 
    211 	if (gcq_onlist(src)) {
    212 		dst_next = dst->q_next;
    213 		src_prev = src->q_prev;
    214 		src_next = src->q_next;
    215 
    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;
    220 		gcq_init(src);
    221 	}
    222 }
    223 
    224 __attribute__((nonnull, always_inline)) static __inline void
    225 gcq_merge_head(struct gcq_head *dst, struct gcq_head *src)
    226 {
    227 	gcq_merge(gcq_hq(dst), gcq_hq(src));
    228 }
    229 
    230 __attribute__((nonnull, always_inline)) static __inline void
    231 gcq_merge_tail(struct gcq_head *dst, struct gcq_head *src)
    232 {
    233 	gcq_merge(gcq_hq(dst)->q_prev, gcq_hq(src));
    234 }
    235 #endif
    236 
    237 __attribute__((nonnull)) static __inline void
    238 gcq_clear(struct gcq *q)
    239 {
    240 	struct gcq *nq, *next;
    241 	nq=q;
    242 	do {
    243 		next = nq->q_next;
    244 		gcq_init(nq);
    245 		nq = next;
    246 	} while (next != q);
    247 }
    248 
    249 __attribute__((nonnull, always_inline)) static __inline void
    250 gcq_remove_all(struct gcq_head *head)
    251 {
    252 	gcq_clear(gcq_hq(head));
    253 }
    254 
    255 __attribute__((nonnull, always_inline)) static __inline struct gcq *
    256 _gcq_next(struct gcq *current, struct gcq_head *head, struct gcq *start)
    257 {
    258 	struct gcq *q, *hq;
    259 	hq = gcq_hq(head);
    260 	q = current->q_next;
    261 	if (hq != start && q == hq)
    262 		q = hq->q_next;
    263 	if (current != start)
    264 		GCQ_ASSERT(gcq_onlist(current));
    265 	return q;
    266 }
    267 
    268 __attribute__((nonnull, always_inline)) static __inline struct gcq *
    269 _gcq_prev(struct gcq *current, struct gcq_head *head, struct gcq *start)
    270 {
    271 	struct gcq *q, *hq;
    272 	hq = gcq_hq(head);
    273 	q = current->q_prev;
    274 	if (hq != start && q == hq)
    275 		q = hq->q_prev;
    276 	if (current != start)
    277 		GCQ_ASSERT(gcq_onlist(current));
    278 	return q;
    279 }
    280 
    281 
    282 #define GCQ_ITEM(q, type, name) 					\
    283     ((type *)(void *)((uint8_t *)gcq_q(q) - offsetof(type, name)))
    284 
    285 
    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))
    298 
    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))) : 			\
    302     (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))
    316 
    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,		\
    339     _gcq_next, gcq_q)
    340 #define GCQ_GOT_PREV_TYPED(tvar, current, head, start, type, name)	\
    341     _GCQ_NP_TYPED(tvar, current, head, start, type, name,		\
    342     _gcq_prev, gcq_q)
    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)
    349 
    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), \
    374     cond)
    375 #define GCQ_DEQUEUED_PREV_COND(var, current, head, start, cond)		\
    376     _GCQ_NP_COND(var, current, head, start, _gcq_prev, gcq_remove(var), \
    377     cond)
    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)
    390 
    391 
    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)
    399 
    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)
    422 
    423 #define GCQ_FOREACH_TYPED(var, h, tvar, type, name)			\
    424     _GCQ_FOREACH(var, h, (tvar)=NULL, (tvar)=GCQ_ITEM(var, type, name), \
    425     q_next)
    426 #define GCQ_FOREACH_TYPED_REV(var, h, tvar, type, name)			\
    427     _GCQ_FOREACH(var, h, (tvar)=NULL, (tvar)=GCQ_ITEM(var, type, name), \
    428     q_prev)
    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))
    453 
    454 #define _GCQ_COND(fe, cond) do { fe { if (cond) break; } } while (0)
    455 
    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)
    462 
    463 #endif /* _GCQ_H */
    464