Project

General

Profile

Statistics
| Revision:

root / lab4 / .minix-src / include / sys / gcq.h @ 13

History | View | Annotate | Download (15.8 KB)

1
/* $NetBSD: gcq.h,v 1.2 2007/08/19 07:35:32 kiyohara 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 */