/* This may look like nonsense, but it really is -*- mode: C -*- */
/* */
/* Except for parts copied from previous work and as explicitly stated below, */
/* the authors and copyright holders for this work are as follows: */
/* (C) copyright 2010-2013 Jens Gustedt, INRIA, France */
/* (C) copyright 2012 William Morris */
/* */
/* This file is free software; it is part of the P99 project. */
/* You can redistribute it and/or modify it under the terms of the QPL as */
/* given in the file LICENSE. It is distributed without any warranty; */
/* without even the implied warranty of merchantability or fitness for a */
/* particular purpose. */
/* */
#ifndef P99_MAP_H_
# define P99_MAP_H_
/**
** @file
** @brief macros to produce lists of statements or declarations.
** @see statement_lists
**/
#include "p99_for.h"
/** @addtogroup statement_lists Produce C99 statements or expression lists
**
** This provides tools to produce a list of declarations (e.g @c
** typedef), list of initializers or perform a sequence of additions
** or other operations. The input usually is just a list of names, e.g.
**
** @{
**/
#define P00_ACCESSOR(NAME, X, I) P99_IF_EMPTY(NAME)([I])((NAME)[I])
#define P00_VASSIGN(NAME, X, I) X = P00_ACCESSOR(NAME, X, I)
#define P00_STRLEN(NAME, X, I) strlen(X)
#define P00_SIZEOF(NAME, X, I) sizeof(X)
#define P00_TYPD(NAME, X, I) typedef X P99_PASTE2(NAME, I)
#define P00_DESIGNATE(NAME, X, I) X = (NAME)X
#define P00_ADD(NAME, I, REC, RES) P99_ADD(RES, REC)
#define P00_STRLENS(N, ...) P99_FOR(,N, P00_SUM, P00_STRLEN, __VA_ARGS__)
#define P00_SIZEOFS(N, ...) P99_FOR(,N, P00_SUM, P00_SIZEOF, __VA_ARGS__)
#define P00_ADDS(N, ...) P99_FOR(, N, P00_ADD, P00_IDT, __VA_ARGS__)
#define P00_POW0(X, _1, _2) (X)
#define P00_POW(X, _1, REC, _3) (X) * REC
/**
** @brief Compute the @a Nth multiplicative integer power of @a X.
**
** @a N must be a decimal constant without suffixes. The value @c 0
** is special in that it evaluates to a @c 1 that is promoted to the
** promoted type of @a X.
**/
P00_DOCUMENT_NUMBER_ARGUMENT(P99_IPOW, 0)
P00_DOCUMENT_MULTIPLE_ARGUMENT(P99_IPOW, 1)
#define P99_IPOW(N, X) P99_IF_EQ(N,0)(P99_SIGN_PROMOTE(1, X))((P99_FOR(X, N, P00_POW, P00_POW0, P99_REP(N,))))
/**
** @brief Return an expression that returns the sum of the lengths of
** all strings that are given as arguments.
**/
#define P99_STRLENS(...) P00_STRLENS(P99_NARG(__VA_ARGS__),__VA_ARGS__)
/**
** @brief Return an expression that returns the sum of the size of
** all arguments.
**/
#define P99_SIZEOFS(...) P00_SIZEOFS(P99_NARG(__VA_ARGS__),__VA_ARGS__)
/**
** @brief Return a token that is the sum of all arguments.
**/
#define P99_ADDS(...) P00_ADDS(P99_NARG(__VA_ARGS__),__VA_ARGS__)
#ifndef P00_DOXYGEN
P99_DECLARE_STRUCT(p00_strcat_state);
#endif
struct p00_strcat_state {
char*restrict p00_buf;
char*restrict p00_pos;
};
#if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
p99_inline
char *p00_stpcpy(char *restrict p00_des, const char *restrict p00_src) {
return stpcpy(p00_des, p00_src);
}
#else
p99_inline
char *p00_stpcpy(char *restrict p00_des, const char *restrict p00_src) {
for (;;) {
*p00_des = *p00_src;
if (!*p00_src) break;
++p00_des; ++p00_src;
}
return p00_des;
}
#endif
p99_inline
p00_strcat_state* p00_strcat(p00_strcat_state *restrict p00_des, char const*restrict p00_src) {
if (!p00_des->p00_pos) p00_des->p00_pos = strchr(p00_des->p00_buf, 0);
p00_des->p00_pos = p00_stpcpy(p00_des->p00_pos, p00_src);
return p00_des;
}
p99_inline
char* p00_strcat_terminate(p00_strcat_state *restrict p00_des) {
return p00_des->p00_buf;
}
/**
** @brief Append all argument strings after @a TARG to @a TARG.
**
** @a TARG should be compatible with @c char* and must provide enough
** space to hold the concatenation of all strings. The remaining
** arguments must be compatible with @c const char*.
**
** This macro ensures linear complexity in the operation. In
** particular each position in the argument strings is accessed at
** most twice, once by a call to strlen and once by a call to
** memcpy.
**
** This uses some small inlined helper functions, since the repeated
** use of bare @c strcat would have quadratic complexity.
**
** The resulting replacement produced by this macro evaluates
** each of the arguments at most once.
**/
#define P99_STRCATS(TARG, ...) \
p00_strcat_terminate \
(P99_BIGFUNC \
(p00_strcat, \
P99_NARG(TARG, __VA_ARGS__), \
(&(p00_strcat_state){ .p00_buf = (TARG), .p00_pos = 0 }), \
__VA_ARGS__))
/**
** @brief Concatenate all arguments.
**
** All arguments must be strings for which the length can be computed
** at compile time.
**
** @return a temporary string that is valid in the containing block
** of the expression holding the call to this macro.
**
** @see P99_STRDUP for a variant that returns a @c malloc'ed string and
** thus can be called with any type of @c char* arguments.
**/
P00_DOCUMENT_PERMITTED_ARGUMENT(P99_JOIN, 0)
P00_DOCUMENT_PERMITTED_ARGUMENT(P99_JOIN, 1)
P00_DOCUMENT_PERMITTED_ARGUMENT(P99_JOIN, 2)
#define P99_JOIN(...) P99_STRCATS((char[P99_SIZEOFS(__VA_ARGS__) + 1]){ 0 }, __VA_ARGS__)
/**
** @brief Concatenate all arguments.
**
** @return a string that must be freed by @c free
**
** The resulting replacement produced by this macro evaluates
** each of the arguments twice; once to compute the overall length of
** the new string and then again for the duplication operation.
**/
P00_DOCUMENT_MULTIPLE_ARGUMENT(P99_STRDUP, 0)
P00_DOCUMENT_MULTIPLE_ARGUMENT(P99_STRDUP, 1)
P00_DOCUMENT_MULTIPLE_ARGUMENT(P99_STRDUP, 2)
#define P99_STRDUP(...) P99_STRCATS(calloc(P99_STRLENS(__VA_ARGS__) + 16, 1), __VA_ARGS__)
/**
** @brief Produce a list of length @a N that has the contents of 0,
** 1, , @a N-1
**/
P00_DOCUMENT_NUMBER_ARGUMENT(P99_POSS, 0)
#define P99_POSS(N) P99_FOR(,N, P00_SEQ, P00_POS,)
#define P00_ACCESSORS(X, ...) P99_FOR(X, __VA_ARGS__, P00_SEQ, P00_ACCESSOR, )
/**
** Produce a list of length @a N that has the contents of @a X[0], @a
** X [1], ,
** @a X[@a N-1]
**/
P00_DOCUMENT_MULTIPLE_ARGUMENT(P99_ACCESSORS, 0)
P00_DOCUMENT_NUMBER_ARGUMENT(P99_ACCESSORS, 1)
#define P99_ACCESSORS(X, N) P00_ACCESSORS(X, N)
/**
** @brief Vector-assign to a list
**
** Produce a list of length @c N that has the contents of @c V0 = @a
** NAME[0], @c V1 = @a NAME[1], ..., @c VN-1 = @a NAME[@a N-1], where
** V0, etc are the remaining arguments.
**/
P00_DOCUMENT_MULTIPLE_ARGUMENT(P99_VASSIGNS, 0)
#define P99_VASSIGNS(NAME, ...) \
P99_IF_LT(P99_NARG(__VA_ARGS__),2) \
(P99_IF_VOID(__VA_ARGS__)((void)0)(__VA_ARGS__ = (NAME)[0])) \
(P99_FOR(NAME, P00_NARG(__VA_ARGS__),P00_SEP, P00_VASSIGN, __VA_ARGS__))
#define P00_TYPEDEFS(NAME, N, ...) \
P99_IF_VOID(__VA_ARGS__) \
(P99_MACRO_END(NAME, _eat_the_semicolon_, N)) \
(P99_FOR(NAME, N, P00_SEP, P00_TYPD, __VA_ARGS__))
/**
** @brief Take each argument on the list and transform it into a
** @c typedef of name NAME_0, NAME_1, etc.
**
** Due to syntax problems this can't be used for function or
** array type derivatives.
**/
#define P99_TYPEDEFS(NAME, ...) \
P00_TYPEDEFS(NAME, P99_NARG(__VA_ARGS__), __VA_ARGS__)
#define P00_DESIGNATED(VAR, N, ...) P99_FOR(VAR, N, P00_SEQ, P00_DESIGNATE, __VA_ARGS__)
/**
** @brief Construct a designated initializer by copying fields of @a VAR.
**
** The argument list must be composed of designators, something like
** @code
** struct toto { int a; int b; } A = { .a = 9, .b = 7 };
** struct toto B = P99_DESIGNATED(A, .b);
** double C[4] = { 1, 2, 3, 4 };
** double D[4] = P99_DESIGNATED(C, [0], [2]);
** @endcode
**
** So here @c B.b is initialized with the value of @c A.b and @c B.a,
** since @c .a is not in the list, is initialized by 0. Likewise @c D
** gets copies of @c C[0] and @c C[2] and the other fields are
** initialized to @c 0.
** @see P99_LCOPY
**/
P00_DOCUMENT_MULTIPLE_ARGUMENT(P99_DESIGNATED, 0)
P00_DOCUMENT_DESIGNATOR_ARGUMENT(P99_DESIGNATED, 1)
P00_DOCUMENT_DESIGNATOR_ARGUMENT(P99_DESIGNATED, 2)
P00_DOCUMENT_DESIGNATOR_ARGUMENT(P99_DESIGNATED, 3)
#define P99_DESIGNATED(VAR, ...) { P00_DESIGNATED(VAR, P99_NARG(__VA_ARGS__), __VA_ARGS__) }
/**
** @brief Expand to an array initializer copying array @a VAR for @a N positions.
**
** This can be used to initialize an array with a designated
** initializer that is derived from another array.
** @code
** double B[] = P99_ADESIGNATED(A, 3);
** @endcode
**
** Would initialize @c B to be an array of 3 @c double that are
** copies of the first three values of @c A.
**/
#define P99_ADESIGNATED(VAR, N) P99_DESIGNATED(VAR, P99_ACCESSORS(, N))
/**
** @brief Construct a compound literal of type @a TYPE by copying fields of @a VAR.
**
** The argument list must be composed of designators, something like
** @code
** struct toto { int a; int b; } A = { .a = 9, .b = 7 };
** struct toto B = P99_LCOPY(struct toto, A, .b);
** double C[4] = { 1, 2, 3, 4 };
** double *D = P99_LCOPY(double[4], C, [0], [2]);
** @endcode
**
** So here @c B.b is initialized with the value of @c A.b and @c B.a,
** since @c .a is not in the list, is initialized by 0. Likewise @c D
** gets copies of @c C[0] and @c C[2] and the other fields are
** initialized to @c 0.
**
** This is probably best used indirectly inside a type specific
** macro. E.g if you know that the copy operation for @c toto as
** above should always copy only @c .b and not @c .a you could do
** @code
** #define TOTO_LCOPY(A) P99_LCOPY(struct toto, A, .b);
** struct toto B = TOTO_LCOPY(A);
** @endcode
** @see P99_DESIGNATED
**/
P00_DOCUMENT_MULTIPLE_ARGUMENT(P99_LCOPY, 1)
P00_DOCUMENT_TYPE_ARGUMENT(P99_LCOPY, 0)
P00_DOCUMENT_DESIGNATOR_ARGUMENT(P99_LCOPY, 2)
P00_DOCUMENT_DESIGNATOR_ARGUMENT(P99_LCOPY, 3)
P00_DOCUMENT_DESIGNATOR_ARGUMENT(P99_LCOPY, 4)
#define P99_LCOPY(TYPE, VAR, ...) ((TYPE)P99_DESIGNATED(VAR, __VA_ARGS__))
#define P00_ACOPY4(TYPE, N, VAR, ...) ((TYPE[N])P99_DESIGNATED(VAR, P00_ACCESSORS(, __VA_ARGS__)))
#define P00_ACOPY3(TYPE, N, VAR) P00_ACOPY4(TYPE, N, VAR, N)
#ifdef P00_DOXYGEN
/**
** @brief Expand to an array literal of type @a TYPE[@a N] copying
** from another array.
**
** The third argument is the array @a VAR to be copied from. The
** optional forth argument @a M is the number of elements from @c VAR
** that are to be copied. It defaults to @a N if omitted. Obviously
** we must always have M <= N
for this to work.
**
** This can be used to call a function with a copy of
** of @a VAR.
**
** @remark The base type of @a VAR must be assignment compatible with type @a TYPE.
**/
#define P99_ACOPY(TYPE, N, VAR, M)
#else
P00_DOCUMENT_MULTIPLE_ARGUMENT(P99_ACOPY, 2)
P00_DOCUMENT_DECLARATION_ARGUMENT(P99_ACOPY, 4)
#define P99_ACOPY(TYPE, N, ...) \
P99_IF_LT(P99_NARG(__VA_ARGS__), 2) \
(P00_ACOPY3(TYPE, N, __VA_ARGS__)) \
(P00_ACOPY4(TYPE, N, __VA_ARGS__))
#endif
#ifdef P00_DOXYGEN
/**
** @brief Assign the content of array @a SOURCE to @a TARGET.
**
** Only the @a N first elements are copied. Use it as in
** @code
** size_t B[4] = { 2, 3, 4, 5 };
** double *A = malloc(sizeof(double[4]));
** P99_AASSIGN(A, B, 4);
** @endcode
**
** @pre @a N must expand to a decimal integer constant.
**
** @pre @a SOURCE and @a TARGET must be arrays with a size of at least @a N
** or pointers that point to such arrays.
**
** @remark If @a TARGET has more than @a N elements the excess
** elements are left untouched.
**
** @remark The base types must not necessarily be the same but that
** of @a SOURCE must be assignable to that for @a TARGET. In
** particular, the type of @a TARGET should be at least as wide as
** that for @a SOURCE.
**/
#define P99_AASSIGN(TARGET, SOURCE, N)
#else
P00_DOCUMENT_MULTIPLE_ARGUMENT(P99_AASSIGN, 0)
P00_DOCUMENT_MULTIPLE_ARGUMENT(P99_AASSIGN, 1)
#define P99_AASSIGN(TARGET, SOURCE, N) P99_BLOCK(P99_VASSIGNS(SOURCE, P99_ACCESSORS(TARGET, N));)
#endif
/** @}
**/
#endif /* !P99_MAP_H_ */