1
0
Fork 0
man-db/lib/mp.h
Daniel Baumann 1fa764a8d3
Adding upstream version 2.13.1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-21 08:13:55 +02:00

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