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):
|