483 lines
22 KiB
C
483 lines
22 KiB
C
/*
|
|
* 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):
|