preprocessor: add variadic REDUCE for PASTE

This commit is contained in:
Danny Robson 2017-09-05 14:29:58 +10:00
parent 40c4fbc5ed
commit 9cfaade94b

View File

@ -11,17 +11,32 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2012-2016 Danny Robson <danny@nerdcruft.net>
* Copyright 2012-2017 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_PREPROCESSOR_HPP
#define __UTIL_PREPROCESSOR_HPP
#ifndef CRUFT_UTIL_PREPROCESSOR_HPP
#define CRUFT_UTIL_PREPROCESSOR_HPP
//-----------------------------------------------------------------------------
//
// HERE BE DRAGONS.
//
// Don't use this code unless you need to do minor token pasting.
// Don't judge me...
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
// token concatenation operations. you should probably prefer PASTE over
// PASTE2. PASTE2 is defined purely so that PASTE can make use of this macro
// (because it clearly can't use itself).
//
// do not use PASTE_DETAIL directly.
#define PASTE_DETAIL(x, y) x##y
#define PASTE(x, y) PASTE_DETAIL(x, y)
#define PASTE2(x, y) PASTE_DETAIL(x, y)
#define PASTE_LIST(x,y) PASTE(x,y),
#define PASTE_LIST(x,y) PASTE2(x,y),
#define NAMESPACE_LIST(x,y) x::y,
@ -37,6 +52,18 @@
//
// Based off a technique seen on StackOverflow:
// http://stackoverflow.com/questions/11761703/overloading-macro-on-number-of-arguments
#define REDUCE_2_01(F,X, ...) X
#define REDUCE_2_02(F,X,Y,...) F(X,Y)
#define REDUCE_2_03(F,X,Y,...) REDUCE_2_02(F,F(X,Y),__VA_ARGS__)
#define REDUCE_2_04(F,X,Y,...) REDUCE_2_03(F,F(X,Y),__VA_ARGS__)
#define REDUCE_2_05(F,X,Y,...) REDUCE_2_04(F,F(X,Y),__VA_ARGS__)
#define REDUCE_2_06(F,X,Y,...) REDUCE_2_05(F,F(X,Y),__VA_ARGS__)
#define REDUCE_2_07(F,X,Y,...) REDUCE_2_06(F,F(X,Y),__VA_ARGS__)
#define REDUCE_2_08(F,X,Y,...) REDUCE_2_07(F,F(X,Y),__VA_ARGS__)
//-----------------------------------------------------------------------------
#define MAP_0_01(F, X) F(X)
#define MAP_0_02(F, X, ...) F(X)MAP_0_01(F, __VA_ARGS__)
#define MAP_0_03(F, X, ...) F(X)MAP_0_02(F, __VA_ARGS__)
@ -146,6 +173,7 @@
#define MAP_0_96(F, X, ...) F(X)MAP_0_95(F, __VA_ARGS__)
//-----------------------------------------------------------------------------
#define MAP_1_01(F, A, X) F(A, X)
#define MAP_1_02(F, A, X, ...) F(A, X)MAP_1_01(F, A, __VA_ARGS__)
#define MAP_1_03(F, A, X, ...) F(A, X)MAP_1_02(F, A, __VA_ARGS__)
@ -254,6 +282,8 @@
#define MAP_1_95(F, A, X, ...) F(A, X)MAP_1_94(F, A, __VA_ARGS__)
#define MAP_1_96(F, A, X, ...) F(A, X)MAP_1_95(F, A, __VA_ARGS__)
//-----------------------------------------------------------------------------
// Uses the sliding pairs dispatch technique: by passing __VA_ARGS__ as the
// first set of variables and appending (reverse orderred) names of the
// corresponding macros, we get the name of the correct arity macro.
@ -277,6 +307,37 @@
) NAME
//-----------------------------------------------------------------------------
// reduces a series of values by repeated application of some macro 'func'.
//
// useful for things like variadic 'paste'
//
// it's only implemented for up to 8 arguments (because that's all you should
// need you monster...) but we need to have enough arguments to make
// ARITY_DISPATCH work so we fill it with nonces.
#define REDUCE(FUNC,...) \
ARITY_DISPATCH(__VA_ARGS__, \
_96, _95, _94, _93, _92, _91, _90, _89, \
_88, _87, _86, _85, _84, _83, _82, _81, \
_80, _79, _78, _77, _76, _75, _74, _73, \
_72, _71, _70, _69, _68, _67, _66, _65, \
_64, _63, _62, _61, _60, _59, _58, _57, \
_56, _55, _54, _53, _52, _51, _50, _49, \
_48, _47, _46, _45, _44, _43, _42, _41, \
_40, _39, _38, _37, _36, _35, _34, _33, \
_32, _31, _30, _29, _28, _27, _26, _25, \
_24, _23, _22, _21, _20, _19, _18, _17, \
_16, _15, _14, _13, _12, _11, _10, _09, \
REDUCE_2_08, REDUCE_2_07, REDUCE_2_06, REDUCE_2_05, \
REDUCE_2_04, REDUCE_2_03, REDUCE_2_02, REDUCE_2_01, \
STATIC_ASSERT("invalid arity for REDUCE") \
)(FUNC,__VA_ARGS__)
// concatenate a series of tokens
#define PASTE(...) REDUCE(PASTE2,__VA_ARGS__)
// Map a macro across __VA_ARGS__. Can be easily expanded, but has non-obvious
// failure mode when supported arity is exceeded.
//