summaryrefslogtreecommitdiffstats
path: root/lib/mp.h
blob: df31eaed29b9104181d6cc840dae9fdded25b385 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
/*
 * mp.h: header file providing macros for 'metaprogramming' custom
 * loop constructions in standard C.
 *
 * Accompanies the article on the web at
 *   https://www.chiark.greenend.org.uk/~sgtatham/mp/
 */

/*
 * mp.h is copyright 2012 Simon Tatham.
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT.  IN NO EVENT SHALL SIMON TATHAM BE LIABLE FOR
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * $Id$
 */

/*
 * Macros beginning with 'MPI_' are internal to this header file, and
 * intended only to be used by other macros defined _in_ this header
 * file. Do not refer to them externally.
 */

/* Standard trickery to allow us to macro-expand and then token-paste */
#define MPI_TOKPASTEINNER(x,y) x ## y
#define MPI_TOKPASTE(x,y) MPI_TOKPASTEINNER(x,y)

/* Method of constructing line-unique labels */
#define MPI_LABEL(id1,id2)                                      \
    MPI_TOKPASTE(MPI_LABEL_ ## id1 ## _ ## id2 ## _, __LINE__)

/*
 * Macros beginning with 'MPP_' and 'MPS_' are building blocks
 * intended for metaprogrammers to make useful control constructions
 * from.
 *
 * The prefixes distinguish their syntactic role. MPP_ macros are
 * statement _prefixes_; you would typically build a custom control
 * structure by defining a macro expanding to a sequence of them. MPS_
 * macros are actual statements, which you might use in the various
 * parameters of MPP_ macros that are expected to be statement-shaped.
 */

/*
 * Safety considerations:
 *
 *  - All of these macros are C89-safe, except for MPP_DECLARE if you
 *    pass an actual declaration and not just an assignment, since
 *    that one relies on the C99 (and C++) extension of being able to
 *    write a declaration in the initialisation clause of a for
 *    statement.
 *
 *  - None of these macros uses switch, so case labels from a switch
 *    outside the whole lot may be written inside the suffixed
 *    statement/block.
 *
 *  - All of these constructions use 'goto' with labels constructed
 *    programmatically, using __LINE__ to make them unique between
 *    multiple invocations of the same loop macro. So don't put two
 *    loop macros defined using these building blocks on the same
 *    source line.
 *
 *  - All of these constructions can be prefixed to something that is
 *    syntactically a single C statement, and generate something that
 *    is also a single C statement. So they're if-else safe - you can
 *    use an unbraced one of these constructs followed by an unbraced
 *    statement within the then-clause of an outer if, and the else
 *    will still bind to what it looks as if it ought to.
 *
 *  - Controlling what happens if the user writes a 'break' in the
 *    suffixed statement is unavoidably rather fiddly. The macros
 *    below fall into a few categories:
 *
 *     + naturally transparent to 'break' (MPP_BEFORE, MPP_IF). Macros
 *       of this type will not affect the semantics of 'break' in the
 *       suffixed statement at all - it will terminate the next
 *       innermost loop or switch outside the construction.
 *
 *     + artificially transparent to 'break', by means of deliberately
 *       catching and 'rethrowing' it. (MPP_BREAK_{THROW,CATCH};
 *       MPP_BREAK_HANDLER; MPP_FINALLY.) These macros will propagate
 *       a break outwards to the next containing loop, but in order to
 *       do so they require that there _be_ a next containing loop,
 *       since their expansion can't avoid including a break statement
 *       which they themselves do not wrap in a loop. So you should
 *       only use these when you know there is a containing loop (e.g.
 *       because MPP_WHILE or MPP_DO_WHILE precedes them in your
 *       construction).
 *
 *     + loop constructions. (MPP_WHILE and MPP_DO_WHILE). These
 *       macros give 'break' the obvious semantics of terminating the
 *       loop they define.
 *
 *     + break-unsafe macros, which have to include a C looping
 *       construction to do something not essentially loopy, and hence
 *       have the unfortunate side effect of causing 'break' to only
 *       terminate the suffixed statement itself. On the other hand,
 *       they can be used in contexts where there is no surrounding
 *       loop at all (which is why I don't just fix them to contain a
 *       built-in MPP_BREAK_{THROW,CATCH}).
 *
 *    If you are using these macros to build a looping construct, then
 *    you will probably include an MPP_WHILE or MPP_DO_WHILE in your
 *    stack, and you'll want 'break' to terminate that. So you just
 *    need to be sure that break is correctly propagated from the
 *    suffixed statement back to that loop, which you can do by
 *    sticking to the break-transparent macros where possible and
 *    using MPP_BREAK_{THROW,CATCH} to bypass any break-unsafe macro
 *    such as MPP_DECLARE that you might need to use. Having done
 *    that, 'break' will do what the user expects.
 *
 *    But if you're using the macros to wrap some context around a
 *    statement you still intend to be executed only once, there will
 *    be unavoidable side effects on 'break': you can't use the
 *    artificially break-unsafe macros because the user might use your
 *    construction in a context with no surrounding loop at all, so
 *    you must stick to the naturally break-transparent and the
 *    break-unsafe, and there aren't enough of the former to be really
 *    useful. So you must just live with 'break' acquiring unhelpful
 *    behaviour inside such a macro.
 *
 *  - Almost none of these macros is transparent to 'continue'. The
 *    naturally break-transparent MPP_BEFORE is, but none of the rest
 *    can possibly be, because as soon as you include any loop
 *    construction in the stuff being prefixed to a statement, you
 *    introduce the invariant that 'continue' is equivalent to jumping
 *    to the end of the suffixed statement or block. This is not too
 *    bad if you're defining a custom loop construction (it was quite
 *    likely the behaviour you wanted for continue anyway), but if you
 *    were trying to use MPP_DECLARE and/or MPP_BEFORE_AND_AFTER to
 *    wrap a statement in some context but still only execute it once,
 *    you'd have to be aware of that limitation.
 *
 *  - MPP_FINALLY and MPP_BREAK_HANDLER can only catch non-local exits
 *    from the block _by break_. They are not true C++ try/finally, so
 *    they can't catch other kinds of exit such as return, goto,
 *    longjmp or exit.
 *
 *  - Finally, it almost goes without saying, but don't forget that
 *    snippets of code you use as parameters to these macros must
 *    avoid using commas not contained inside parentheses, or else the
 *    C preprocessor will consider the comma to end that macro
 *    parameter and start the next one. If there is any reason you
 *    really need an unbracketed comma, you can work around this by
 *    one of two methods:
 *     - define a macro that expands to a comma ('#define COMMA ,')
 *       and then use that macro in place of commas in your macro
 *       argument. It won't be expanded to an actual comma until after
 *       the argument-separation has finished.
 *     - if you're allowed to use C99, define a variadic macro that
 *       expands to its unmodified input argument list ('#define
 *       WRAP(...) __VA_ARGS__') and then enclose comma-using code in
 *       WRAP(). Again, this will protect the commas for just long
 *       enough.
 */

/*
 * MPP_BEFORE: run the code given in the argument 'before' and then
 * the suffixed statement.
 *
 * 'before' should have the syntactic form of one or more declarations
 * and statements, except that a trailing semicolon may be omitted.
 * Any declarations will be in scope only within 'before', not within
 * the suffixed statement.
 *
 * This macro, unusually among the collection, is naturally
 * transparent to 'break' and also transparent to 'continue'.
 */
#define MPP_BEFORE(labid,before)                \
    if (1) {                                    \
        before;                                 \
        goto MPI_LABEL(labid, body);            \
    } else                                      \
    MPI_LABEL(labid, body):

/*
 * MPP_AFTER: run the suffixed statement, and then the code given in
 * the argument 'after'.
 *
 * 'after' should have the syntactic form of one or more declarations
 * and statements, except that a trailing semicolon may be omitted.
 * Any declaration in 'after' will be in scope only within 'after'.
 *
 * This macro is break-unsafe - it causes a 'break' to terminate the
 * suffixed statement only. If you need different behaviour, you can
 * use MPP_BREAK_CATCH and MPP_BREAK_THROW to pass a break past it -
 * but beware that in that case the 'after' clause will not be
 * executed, so MPP_FINALLY or MPP_BREAK_HANDLER may be useful too.
 */
#define MPP_AFTER(labid,after)                  \
    if (1)                                      \
        goto MPI_LABEL(labid, body);            \
    else                                        \
        while (1)                               \
            if (1) {                            \
                after;                          \
                break;                          \
            } else                              \
            MPI_LABEL(labid, body):

/*
 * MPP_DECLARE: run the 'declaration' argument before the suffixed
 * statement. The argument may have the form of either a C expression
 * (e.g. an assignment) or a declaration; if the latter, it will be in
 * scope within the suffixed statement.
 *
 * This macro is break-unsafe - it causes a 'break' to terminate the
 * suffixed statement only. If you need different behaviour, you can
 * use MPP_BREAK_CATCH and MPP_BREAK_THROW to pass a break past it.
 */
#define MPP_DECLARE(labid, declaration)                 \
    if (0)                                              \
        ;                                               \
    else                                                \
        for (declaration;;)                             \
            if (1) {                                    \
                goto MPI_LABEL(labid, body);            \
              MPI_LABEL(labid, done): break;            \
            } else                                      \
                while (1)                               \
                    if (1)                              \
                        goto MPI_LABEL(labid, done);    \
                    else                                \
                    MPI_LABEL(labid, body):
/* (The 'if(0) ; else' at the start of the above is just in case we
 * encounter an old-style compiler that considers variables declared
 * in for statements to have scope extending beyond the for statement.
 * Putting another layer outside the 'for' ensures that the variable's
 * scope is constrained to _that_ layer even if not to the for itself,
 * and it doesn't leak into the calling scope. */

/*
 * MPP_WHILE: run the suffixed statement within a 'while (condition)'
 * loop.
 *
 * In fact, just writing 'while (condition)' works fine for this, but
 * it's nice to make it look like the rest of these macros!
 *
 * This macro defines an actual loop, and 'break' in the suffixed
 * statement terminates that loop as you would expect.
 */
#define MPP_WHILE(labid, condition)             \
    while (condition)

/*
 * MPP_DO_WHILE: run the suffixed statement within a loop with the
 * semantics of 'do suffixed-statement while (condition)'.
 *
 * This macro defines an actual loop, and 'break' in the suffixed
 * statement terminates that loop as you would expect.
 */
#define MPP_DO_WHILE(labid, condition)          \
    if (1)                                      \
        goto MPI_LABEL(labid, body);            \
    else                                        \
        while (condition)                       \
        MPI_LABEL(labid, body):

/*
 * MPP_IF: run the suffixed statement only if 'condition' is true.
 *
 * This macro is naturally transparent to 'break' and also transparent
 * to 'continue'.
 */
#define MPP_IF(labid, condition)                \
    if (!(condition))                           \
        ;                                       \
    else

/*
 * MPP_BREAK_THROW and MPP_BREAK_CATCH: propagate 'break' control flow
 * transfers past other prefixes that mess about with them.
 *
 * Write an MPP_BREAK_CATCH, then other metaprogramming prefixes from
 * this collection, and then an MPP_BREAK_THROW with the same label
 * id. If the statement following the MPP_BREAK_THROW terminates by
 * 'break', then the effect will be as if the MPP_BREAK_CATCH had
 * terminated by 'break', regardless of how the in-between prefixes
 * would have handled a 'break'.
 *
 * These macros are artificially transparent to 'break': they pass
 * break through, but include a 'break' statement at the top level of
 * MPP_BREAK_CATCH, so that must always be contained inside some loop
 * or switch construction.
 *
 * We also provide MPS_BREAK_THROW, which is a statement-type macro
 * that manufactures a break event and passes it to a specified
 * MPP_BREAK_CATCH.
 */
#define MPP_BREAK_CATCH(labid)                  \
    if (0)                                      \
    MPI_LABEL(labid, catch): break;             \
    else

#define MPP_BREAK_THROW(labid)                          \
    if (1) {                                            \
        goto MPI_LABEL(labid, body);                    \
      MPI_LABEL(labid, finish):;                        \
    } else                                              \
        while (1)                                       \
            if (1)                                      \
                goto MPI_LABEL(labid, catch);           \
            else                                        \
                while (1)                               \
                    if (1)                              \
                        goto MPI_LABEL(labid, finish);  \
                    else                                \
                    MPI_LABEL(labid, body):

#define MPS_BREAK_THROW(labid) goto MPI_LABEL(labid, catch)

/*
 * MPP_BREAK_HANDLER: handle a 'break' in the suffixed statement by
 * executing the provided handler code and then terminating as if by
 * break.
 *
 * 'handler' should have the syntactic form of one or more
 * declarations and statements, except that a trailing semicolon may
 * be omitted.
 *
 * This macro is artificially transparent to 'break': it passes break
 * through, but includes a 'break' statement at the top level, so it
 * must always be contained inside some loop or switch construction.
 */
#define MPP_BREAK_HANDLER(labid, handler)               \
    if (1) {                                            \
        goto MPI_LABEL(labid, body);                    \
      MPI_LABEL(labid, break):                          \
        {handler;}                                      \
        break;                                          \
      MPI_LABEL(labid, finish):;                        \
    } else                                              \
        while (1)                                       \
            if (1)                                      \
                goto MPI_LABEL(labid, break);           \
            else                                        \
                while (1)                               \
                    if (1)                              \
                        goto MPI_LABEL(labid, finish);  \
                    else                                \
                    MPI_LABEL(labid, body):

/*
 * MPP_FINALLY: execute the suffixed statement, and execute the
 * provided 'finally' clause after it finishes. If it terminates by
 * 'break', execute the same 'finally' clause but propagate the break
 * to the containing statement.
 *
 * 'finally' should have the syntactic form of one or more
 * declarations and statements, except that a trailing semicolon may
 * be omitted.
 *
 * The 'finally' argument will be double-expanded. Of course it'll
 * only be executed once in any given run, so that's not a concern for
 * function side effects, but don't do anything fiddly like declaring
 * a static variable to which you return a pointer and then expecting
 * the pointer to be the same no matter which copy of 'finally' it
 * came from.
 *
 * This macro is artificially transparent to 'break': it passes break
 * through, but includes a 'break' statement at the top level, so it
 * must always be contained inside some loop or switch construction.
 */
#define MPP_FINALLY(labid, finally)                     \
    if (1) {                                            \
        goto MPI_LABEL(labid, body);                    \
      MPI_LABEL(labid, break):                          \
        {finally;}                                      \
        break;                                          \
      MPI_LABEL(labid, finish):                         \
        {finally;}                                      \
    } else                                              \
        while (1)                                       \
            if (1)                                      \
                goto MPI_LABEL(labid, break);           \
            else                                        \
                while (1)                               \
                    if (1)                              \
                        goto MPI_LABEL(labid, finish);  \
                    else                                \
                    MPI_LABEL(labid, body):

/*
 * MPP_BREAK_STOP: handle a 'break' in the suffixed statement by
 * executing the provided handler code and then terminating as if
 * normally.
 *
 * 'handler' should have the syntactic form of one or more
 * declarations and statements, except that a trailing semicolon may
 * be omitted.
 */
#define MPP_BREAK_STOP(labid, handler)                  \
    if (1) {                                            \
        goto MPI_LABEL(labid, body);                    \
      MPI_LABEL(labid, break):                          \
        {handler;}                                      \
      MPI_LABEL(labid, finish):;                        \
    } else                                              \
        while (1)                                       \
            if (1)                                      \
                goto MPI_LABEL(labid, break);           \
            else                                        \
                while (1)                               \
                    if (1)                              \
                        goto MPI_LABEL(labid, finish);  \
                    else                                \
                    MPI_LABEL(labid, body):

/*
 * MPP_ELSE_ACCEPT, MPS_MAIN_INVOKE, MPS_ELSE_INVOKE: arrange to
 * accept an optional 'else' clause after the suffixed statement, and
 * provide two statement macros which jump to the main clause and the
 * else clause. The main (non-else) clause will be be executed in the
 * default case, and can be invoked again using MPS_MAIN_INVOKE;
 * MPS_ELSE_INVOKE will invoke the else clause.
 *
 * Like MPP_BREAK_THROW and MPP_BREAK_CATCH, these macros should be
 * used in groups with the same label id, so as to match them up to
 * each other. MPS_ELSE_INVOKE and MPS_MAIN_INVOKE will go to the
 * appropriate clauses corresponding to the MPP_ELSE_ACCEPT with the
 * same id.
 */
#define MPP_ELSE_ACCEPT(labid)                  \
    if (1)                                      \
        goto MPI_LABEL(labid, body);            \
    else                                        \
    MPI_LABEL(labid, else):                     \
        if (0)                                  \
        MPI_LABEL(labid, body):

#define MPS_MAIN_INVOKE(labid)                  \
    goto MPI_LABEL(labid, body)

#define MPS_ELSE_INVOKE(labid)                  \
    goto MPI_LABEL(labid, else)

/*
 * MPP_ELSE_GENERAL: like MPP_ELSE_ACCEPT, but also lets you provide a
 * snippet of code that will be run after the else clause terminates
 * and one which will be run after the else clause breaks.
 *
 * You can use MPS_MAIN_INVOKE and MPS_ELSE_INVOKE with this as well
 * as with MPP_ELSE_ACCEPT.
 *
 * Will mess up what happens after the main body, so you'll probably
 * want to follow this macro with others such as MPP_AFTER and
 * something to catch break in the main body too.
 */
#define MPP_ELSE_GENERAL(labid, after, breakhandler)    \
    if (1)                                              \
        goto MPI_LABEL(labid, body);                    \
    else                                                \
        while (1)                                       \
            if (1) {                                    \
                {breakhandler;}                         \
                break;                                  \
            } else                                      \
                while (1)                               \
                    if (1) {                            \
                        {after;}                        \
                        break;                          \
                    } else                              \
                    MPI_LABEL(labid, else):             \
                        if (0)                          \
                        MPI_LABEL(labid, body):