update code base to Marlin 2.0.9.2

This commit is contained in:
Stefan Kalscheuer
2021-10-03 18:57:12 +02:00
parent b9d7ba838e
commit 7077da3591
2617 changed files with 332093 additions and 103438 deletions

View File

@@ -16,7 +16,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -33,26 +33,36 @@
#define _AXIS(A) (A##_AXIS)
#define _XMIN_ 100
#define _YMIN_ 200
#define _ZMIN_ 300
#define _XMAX_ 101
#define _YMAX_ 201
#define _ZMAX_ 301
#define _XDIAG_ 102
#define _YDIAG_ 202
#define _ZDIAG_ 302
#define _E0DIAG_ 400
#define _E1DIAG_ 401
#define _E2DIAG_ 402
#define _E3DIAG_ 403
#define _E4DIAG_ 404
#define _E5DIAG_ 405
#define _E6DIAG_ 406
#define _E7DIAG_ 407
#define _XMIN_ 0x11
#define _YMIN_ 0x12
#define _ZMIN_ 0x13
#define _IMIN_ 0x14
#define _JMIN_ 0x15
#define _KMIN_ 0x16
#define _XMAX_ 0x21
#define _YMAX_ 0x22
#define _ZMAX_ 0x23
#define _IMAX_ 0x24
#define _JMAX_ 0x25
#define _KMAX_ 0x26
#define _XDIAG_ 0x31
#define _YDIAG_ 0x32
#define _ZDIAG_ 0x33
#define _IDIAG_ 0x34
#define _JDIAG_ 0x35
#define _KDIAG_ 0x36
#define _E0DIAG_ 0xE0
#define _E1DIAG_ 0xE1
#define _E2DIAG_ 0xE2
#define _E3DIAG_ 0xE3
#define _E4DIAG_ 0xE4
#define _E5DIAG_ 0xE5
#define _E6DIAG_ 0xE6
#define _E7DIAG_ 0xE7
#define _FORCE_INLINE_ __attribute__((__always_inline__)) __inline__
#define FORCE_INLINE __attribute__((always_inline)) inline
#define NO_INLINE __attribute__((noinline))
#define _UNUSED __attribute__((unused))
#define _O0 __attribute__((optimize("O0")))
#define _Os __attribute__((optimize("Os")))
@@ -60,12 +70,10 @@
#define _O2 __attribute__((optimize("O2")))
#define _O3 __attribute__((optimize("O3")))
#define IS_CONSTEXPR(...) __builtin_constant_p(__VA_ARGS__) // Only valid solution with C++14. Should use std::is_constant_evaluated() in C++20 instead
#ifndef UNUSED
#if defined(ARDUINO_ARCH_STM32) && !defined(STM32GENERIC)
#define UNUSED(X) (void)X
#else
#define UNUSED(x) ((void)(x))
#endif
#define UNUSED(x) ((void)(x))
#endif
// Clock speed factors
@@ -76,13 +84,6 @@
// Nanoseconds per cycle
#define NANOSECONDS_PER_CYCLE (1000000000.0 / F_CPU)
// Macros to make sprintf_P read from PROGMEM (AVR extension)
#ifdef __AVR__
#define S_FMT "%S"
#else
#define S_FMT "%s"
#endif
// Macros to make a string from a macro
#define STRINGIFY_(M) #M
#define STRINGIFY(M) STRINGIFY_(M)
@@ -95,29 +96,29 @@
#define _BV(n) (1<<(n))
#define TEST(n,b) (!!((n)&_BV(b)))
#define SET_BIT_TO(N,B,TF) do{ if (TF) SBI(N,B); else CBI(N,B); }while(0)
#ifndef SBI
#define SBI(A,B) (A |= (1 << (B)))
#define SBI(A,B) (A |= _BV(B))
#endif
#ifndef CBI
#define CBI(A,B) (A &= ~(1 << (B)))
#define CBI(A,B) (A &= ~_BV(B))
#endif
#define TBI(N,B) (N ^= _BV(B))
#define _BV32(b) (1UL << (b))
#define TEST32(n,b) !!((n)&_BV32(b))
#define SBI32(n,b) (n |= _BV32(b))
#define CBI32(n,b) (n &= ~_BV32(b))
#define TBI32(N,B) (N ^= _BV32(B))
#define cu(x) ((x)*(x)*(x))
#define cu(x) ({__typeof__(x) _x = (x); (_x)*(_x)*(_x);})
#define RADIANS(d) ((d)*float(M_PI)/180.0f)
#define DEGREES(r) ((r)*180.0f/float(M_PI))
#define HYPOT2(x,y) (sq(x)+sq(y))
#define NORMSQ(x,y,z) (sq(x)+sq(y)+sq(z))
#define CIRCLE_AREA(R) (float(M_PI) * sq(float(R)))
#define CIRCLE_CIRC(R) (2 * float(M_PI) * float(R))
#define SIGN(a) ((a>0)-(a<0))
#define SIGN(a) ({__typeof__(a) _a = (a); (_a>0)-(_a<0);})
#define IS_POWER_OF_2(x) ((x) && !((x) & ((x) - 1)))
// Macros to constrain values
@@ -137,31 +138,29 @@
#else
// Using GCC extensions, but Travis GCC version does not like it and gives
// "error: statement-expressions are not allowed outside functions nor in template-argument lists"
#define NOLESS(v, n) \
do{ \
__typeof__(n) _n = (n); \
__typeof__(v) _n = (n); \
if (_n > v) v = _n; \
}while(0)
#define NOMORE(v, n) \
do{ \
__typeof__(n) _n = (n); \
__typeof__(v) _n = (n); \
if (_n < v) v = _n; \
}while(0)
#define LIMIT(v, n1, n2) \
do{ \
__typeof__(n1) _n1 = (n1); \
__typeof__(n2) _n2 = (n2); \
__typeof__(v) _n1 = (n1); \
__typeof__(v) _n2 = (n2); \
if (_n1 > v) v = _n1; \
else if (_n2 < v) v = _n2; \
}while(0)
#endif
// Macros to chain up to 12 conditions
// Macros to chain up to 14 conditions
#define _DO_1(W,C,A) (_##W##_1(A))
#define _DO_2(W,C,A,B) (_##W##_1(A) C _##W##_1(B))
#define _DO_3(W,C,A,V...) (_##W##_1(A) C _DO_2(W,C,V))
@@ -174,9 +173,12 @@
#define _DO_10(W,C,A,V...) (_##W##_1(A) C _DO_9(W,C,V))
#define _DO_11(W,C,A,V...) (_##W##_1(A) C _DO_10(W,C,V))
#define _DO_12(W,C,A,V...) (_##W##_1(A) C _DO_11(W,C,V))
#define _DO_13(W,C,A,V...) (_##W##_1(A) C _DO_12(W,C,V))
#define _DO_14(W,C,A,V...) (_##W##_1(A) C _DO_13(W,C,V))
#define _DO_15(W,C,A,V...) (_##W##_1(A) C _DO_14(W,C,V))
#define __DO_N(W,C,N,V...) _DO_##N(W,C,V)
#define _DO_N(W,C,N,V...) __DO_N(W,C,N,V)
#define DO(W,C,V...) _DO_N(W,C,NUM_ARGS(V),V)
#define DO(W,C,V...) (_DO_N(W,C,NUM_ARGS(V),V))
// Macros to support option testing
#define _CAT(a,V...) a##V
@@ -192,20 +194,37 @@
#define _DIS_1(O) NOT(_ENA_1(O))
#define ENABLED(V...) DO(ENA,&&,V)
#define DISABLED(V...) DO(DIS,&&,V)
#define COUNT_ENABLED(V...) DO(ENA,+,V)
#define TERN(O,A,B) _TERN(_ENA_1(O),B,A) // OPTION converted to '0' or '1'
#define TERN0(O,A) _TERN(_ENA_1(O),0,A) // OPTION converted to A or '0'
#define TERN1(O,A) _TERN(_ENA_1(O),1,A) // OPTION converted to A or '1'
#define TERN_(O,A) _TERN(_ENA_1(O),,A) // OPTION converted to A or '<nul>'
#define TERN(O,A,B) _TERN(_ENA_1(O),B,A) // OPTION ? 'A' : 'B'
#define TERN0(O,A) _TERN(_ENA_1(O),0,A) // OPTION ? 'A' : '0'
#define TERN1(O,A) _TERN(_ENA_1(O),1,A) // OPTION ? 'A' : '1'
#define TERN_(O,A) _TERN(_ENA_1(O),,A) // OPTION ? 'A' : '<nul>'
#define _TERN(E,V...) __TERN(_CAT(T_,E),V) // Prepend 'T_' to get 'T_0' or 'T_1'
#define __TERN(T,V...) ___TERN(_CAT(_NO,T),V) // Prepend '_NO' to get '_NOT_0' or '_NOT_1'
#define ___TERN(P,V...) THIRD(P,V) // If first argument has a comma, A. Else B.
#define _OPTARG(A...) , A
#define OPTARG(O,A...) TERN_(O,DEFER4(_OPTARG)(A))
#define _OPTCODE(A) A;
#define OPTCODE(O,A) TERN_(O,DEFER4(_OPTCODE)(A))
// Macros to avoid 'f + 0.0' which is not always optimized away. Minus included for symmetry.
// Compiler flags -fno-signed-zeros -ffinite-math-only also cover 'f * 1.0', 'f - f', etc.
#define PLUS_TERN0(O,A) _TERN(_ENA_1(O),,+ (A)) // OPTION ? '+ (A)' : '<nul>'
#define MINUS_TERN0(O,A) _TERN(_ENA_1(O),,- (A)) // OPTION ? '- (A)' : '<nul>'
#define SUM_TERN(O,B,A) ((B) PLUS_TERN0(O,A)) // ((B) (OPTION ? '+ (A)' : '<nul>'))
#define DIFF_TERN(O,B,A) ((B) MINUS_TERN0(O,A)) // ((B) (OPTION ? '- (A)' : '<nul>'))
#define IF_ENABLED TERN_
#define IF_DISABLED(O,A) TERN(O,,A)
#define ANY(V...) !DISABLED(V)
#define NONE(V...) DISABLED(V)
#define ALL(V...) ENABLED(V)
#define BOTH(V1,V2) ALL(V1,V2)
#define EITHER(V1,V2) ANY(V1,V2)
#define MANY(V...) (COUNT_ENABLED(V) > 1)
// Macros to support pins/buttons exist testing
#define PIN_EXISTS(PN) (defined(PN##_PIN) && PN##_PIN >= 0)
@@ -219,8 +238,10 @@
#define ANY_BUTTON(V...) DO(BTNEX,||,V)
#define WITHIN(N,L,H) ((N) >= (L) && (N) <= (H))
#define ISEOL(C) ((C) == '\n' || (C) == '\r')
#define NUMERIC(a) WITHIN(a, '0', '9')
#define DECIMAL(a) (NUMERIC(a) || a == '.')
#define HEXCHR(a) (NUMERIC(a) ? (a) - '0' : WITHIN(a, 'a', 'f') ? ((a) - 'a' + 10) : WITHIN(a, 'A', 'F') ? ((a) - 'A' + 10) : -1)
#define NUMERIC_SIGNED(a) (NUMERIC(a) || (a) == '-' || (a) == '+')
#define DECIMAL_SIGNED(a) (DECIMAL(a) || (a) == '-' || (a) == '+')
#define COUNT(a) (sizeof(a)/sizeof(*a))
@@ -230,7 +251,47 @@
memcpy(&a[0],&b[0],_MIN(sizeof(a),sizeof(b))); \
}while(0)
#define CODE_11( A,B,C,D,E,F,G,H,I,J,K,...) A; B; C; D; E; F; G; H; I; J; K
#define CODE_10( A,B,C,D,E,F,G,H,I,J,...) A; B; C; D; E; F; G; H; I; J
#define CODE_9( A,B,C,D,E,F,G,H,I,...) A; B; C; D; E; F; G; H; I
#define CODE_8( A,B,C,D,E,F,G,H,...) A; B; C; D; E; F; G; H
#define CODE_7( A,B,C,D,E,F,G,...) A; B; C; D; E; F; G
#define CODE_6( A,B,C,D,E,F,...) A; B; C; D; E; F
#define CODE_5( A,B,C,D,E,...) A; B; C; D; E
#define CODE_4( A,B,C,D,...) A; B; C; D
#define CODE_3( A,B,C,...) A; B; C
#define CODE_2( A,B,...) A; B
#define CODE_1( A,...) A
#define CODE_0(...)
#define _CODE_N(N,V...) CODE_##N(V)
#define CODE_N(N,V...) _CODE_N(N,V)
#define GANG_16(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,...) A B C D E F G H I J K L M N O P
#define GANG_15(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,...) A B C D E F G H I J K L M N O
#define GANG_14(A,B,C,D,E,F,G,H,I,J,K,L,M,N,...) A B C D E F G H I J K L M N
#define GANG_13(A,B,C,D,E,F,G,H,I,J,K,L,M...) A B C D E F G H I J K L M
#define GANG_12(A,B,C,D,E,F,G,H,I,J,K,L...) A B C D E F G H I J K L
#define GANG_11(A,B,C,D,E,F,G,H,I,J,K,...) A B C D E F G H I J K
#define GANG_10(A,B,C,D,E,F,G,H,I,J,...) A B C D E F G H I J
#define GANG_9( A,B,C,D,E,F,G,H,I,...) A B C D E F G H I
#define GANG_8( A,B,C,D,E,F,G,H,...) A B C D E F G H
#define GANG_7( A,B,C,D,E,F,G,...) A B C D E F G
#define GANG_6( A,B,C,D,E,F,...) A B C D E F
#define GANG_5( A,B,C,D,E,...) A B C D E
#define GANG_4( A,B,C,D,...) A B C D
#define GANG_3( A,B,C,...) A B C
#define GANG_2( A,B,...) A B
#define GANG_1( A,...) A
#define GANG_0(...)
#define _GANG_N(N,V...) GANG_##N(V)
#define GANG_N(N,V...) _GANG_N(N,V)
#define GANG_N_1(N,K) _GANG_N(N,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K)
// Macros for initializing arrays
#define LIST_20(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T
#define LIST_19(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S
#define LIST_18(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R
#define LIST_17(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q
#define LIST_16(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P
#define LIST_15(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O
#define LIST_14(A,B,C,D,E,F,G,H,I,J,K,L,M,N,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N
@@ -247,10 +308,13 @@
#define LIST_3( A,B,C,...) A,B,C
#define LIST_2( A,B,...) A,B
#define LIST_1( A,...) A
#define LIST_0(...)
#define _LIST_N(N,V...) LIST_##N(V)
#define LIST_N(N,V...) _LIST_N(N,V)
#define LIST_N_1(N,K) _LIST_N(N,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K)
#define ARRAY_N(N,V...) { _LIST_N(N,V) }
#define ARRAY_N_1(N,K) { LIST_N_1(N,K) }
#define _JOIN_1(O) (O)
#define JOIN_N(N,C,V...) (DO(JOIN,C,LIST_N(N,V)))
@@ -276,7 +340,7 @@
#define NEAR(x,y) NEAR_ZERO((x)-(y))
#define RECIPROCAL(x) (NEAR_ZERO(x) ? 0 : (1 / float(x)))
#define FIXFLOAT(f) (f + (f < 0 ? -0.00005f : 0.00005f))
#define FIXFLOAT(f) ({__typeof__(f) _f = (f); _f + (_f < 0 ? -0.0000005f : 0.0000005f);})
//
// Maths macros that can be overridden by HAL
@@ -288,19 +352,18 @@
#define RSQRT(x) (1.0f / sqrtf(x))
#define CEIL(x) ceilf(x)
#define FLOOR(x) floorf(x)
#define TRUNC(x) truncf(x)
#define LROUND(x) lroundf(x)
#define FMOD(x, y) fmodf(x, y)
#define HYPOT(x,y) SQRT(HYPOT2(x,y))
#ifdef TARGET_LPC1768
#define I2C_ADDRESS(A) ((A) << 1)
#else
#define I2C_ADDRESS(A) A
#endif
// Use NUM_ARGS(__VA_ARGS__) to get the number of variadic arguments
#define _NUM_ARGS(_,Z,Y,X,W,V,U,T,S,R,Q,P,O,N,M,L,K,J,I,H,G,F,E,D,C,B,A,OUT,...) OUT
#define NUM_ARGS(V...) _NUM_ARGS(0,V,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)
#define _NUM_ARGS(_,n,m,l,k,j,i,h,g,f,e,d,c,b,a,Z,Y,X,W,V,U,T,S,R,Q,P,O,N,M,L,K,J,I,H,G,F,E,D,C,B,A,OUT,...) OUT
#define NUM_ARGS(V...) _NUM_ARGS(0,V,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,9,8,7,6,5,4,3,2,1,0)
// Use TWO_ARGS(__VA_ARGS__) to get whether there are 1, 2, or >2 arguments
#define _TWO_ARGS(_,n,m,l,k,j,i,h,g,f,e,d,c,b,a,Z,Y,X,W,V,U,T,S,R,Q,P,O,N,M,L,K,J,I,H,G,F,E,D,C,B,A,OUT,...) OUT
#define TWO_ARGS(V...) _TWO_ARGS(0,V,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,1,0)
#ifdef __cplusplus
@@ -323,46 +386,133 @@
#endif
// Allow manipulating enumeration value like flags without ugly cast everywhere
#define ENUM_FLAGS(T) \
FORCE_INLINE constexpr T operator&(T x, T y) { return static_cast<T>(static_cast<int>(x) & static_cast<int>(y)); } \
FORCE_INLINE constexpr T operator|(T x, T y) { return static_cast<T>(static_cast<int>(x) | static_cast<int>(y)); } \
FORCE_INLINE constexpr T operator^(T x, T y) { return static_cast<T>(static_cast<int>(x) ^ static_cast<int>(y)); } \
FORCE_INLINE constexpr T operator~(T x) { return static_cast<T>(~static_cast<int>(x)); } \
FORCE_INLINE T & operator&=(T &x, T y) { return x &= y; } \
FORCE_INLINE T & operator|=(T &x, T y) { return x |= y; } \
FORCE_INLINE T & operator^=(T &x, T y) { return x ^= y; }
// C++11 solution that is standard compliant. <type_traits> is not available on all platform
namespace Private {
template<bool, typename _Tp = void> struct enable_if { };
template<typename _Tp> struct enable_if<true, _Tp> { typedef _Tp type; };
template<typename T, typename U> struct is_same { enum { value = false }; };
template<typename T> struct is_same<T, T> { enum { value = true }; };
template <typename T, typename ... Args> struct first_type_of { typedef T type; };
template <typename T> struct first_type_of<T> { typedef T type; };
}
// C++11 solution using SFINAE to detect the existence of a member in a class at compile time.
// It creates a HasMember<Type> structure containing 'value' set to true if the member exists
#define HAS_MEMBER_IMPL(Member) \
namespace Private { \
template <typename Type, typename Yes=char, typename No=long> struct HasMember_ ## Member { \
template <typename C> static Yes& test( decltype(&C::Member) ) ; \
template <typename C> static No& test(...); \
enum { value = sizeof(test<Type>(0)) == sizeof(Yes) }; }; \
}
// Call the method if it exists, but do nothing if it does not. The method is detected at compile time.
// If the method exists, this is inlined and does not cost anything. Else, an "empty" wrapper is created, returning a default value
#define CALL_IF_EXISTS_IMPL(Return, Method, ...) \
HAS_MEMBER_IMPL(Method) \
namespace Private { \
template <typename T, typename ... Args> FORCE_INLINE typename enable_if<HasMember_ ## Method <T>::value, Return>::type Call_ ## Method(T * t, Args... a) { return static_cast<Return>(t->Method(a...)); } \
_UNUSED static Return Call_ ## Method(...) { return __VA_ARGS__; } \
}
#define CALL_IF_EXISTS(Return, That, Method, ...) \
static_cast<Return>(Private::Call_ ## Method(That, ##__VA_ARGS__))
// Compile-time string manipulation
namespace CompileTimeString {
// Simple compile-time parser to find the position of the end of a string
constexpr const char* findStringEnd(const char *str) {
return *str ? findStringEnd(str + 1) : str;
}
// Check whether a string contains a specific character
constexpr bool contains(const char *str, const char ch) {
return *str == ch ? true : (*str ? contains(str + 1, ch) : false);
}
// Find the last position of the specific character (should be called with findStringEnd)
constexpr const char* findLastPos(const char *str, const char ch) {
return *str == ch ? (str + 1) : findLastPos(str - 1, ch);
}
// Compile-time evaluation of the last part of a file path
// Typically used to shorten the path to file in compiled strings
// CompileTimeString::baseName(__FILE__) returns "macros.h" and not /path/to/Marlin/src/core/macros.h
constexpr const char* baseName(const char *str) {
return contains(str, '/') ? findLastPos(findStringEnd(str), '/') : str;
}
// Find the first occurrence of a character in a string (or return the last position in the string)
constexpr const char* findFirst(const char *str, const char ch) {
return *str == ch || *str == 0 ? (str + 1) : findFirst(str + 1, ch);
}
// Compute the string length at compile time
constexpr unsigned stringLen(const char *str) {
return *str == 0 ? 0 : 1 + stringLen(str + 1);
}
}
#define ONLY_FILENAME CompileTimeString::baseName(__FILE__)
/** Get the templated type name. This does not depends on RTTI, but on the preprocessor, so it should be quite safe to use even on old compilers.
WARNING: DO NOT RENAME THIS FUNCTION (or change the text inside the function to match what the preprocessor will generate)
The name is chosen very short since the binary will store "const char* gtn(T*) [with T = YourTypeHere]" so avoid long function name here */
template <typename T>
inline const char* gtn(T*) {
// It works on GCC by instantiating __PRETTY_FUNCTION__ and parsing the result. So the syntax here is very limited to GCC output
constexpr unsigned verboseChatLen = sizeof("const char* gtn(T*) [with T = ") - 1;
static char templateType[sizeof(__PRETTY_FUNCTION__) - verboseChatLen] = {};
__builtin_memcpy(templateType, __PRETTY_FUNCTION__ + verboseChatLen, sizeof(__PRETTY_FUNCTION__) - verboseChatLen - 2);
return templateType;
}
#else
#define MIN_2(a,b) ((a)<(b)?(a):(b))
#define MIN_3(a,V...) MIN_2(a,MIN_2(V))
#define MIN_4(a,V...) MIN_2(a,MIN_3(V))
#define MIN_5(a,V...) MIN_2(a,MIN_4(V))
#define MIN_6(a,V...) MIN_2(a,MIN_5(V))
#define MIN_7(a,V...) MIN_2(a,MIN_6(V))
#define MIN_8(a,V...) MIN_2(a,MIN_7(V))
#define MIN_9(a,V...) MIN_2(a,MIN_8(V))
#define MIN_10(a,V...) MIN_2(a,MIN_9(V))
#define __MIN_N(N,V...) MIN_##N(V)
#define _MIN_N(N,V...) __MIN_N(N,V)
#define _MIN(V...) _MIN_N(NUM_ARGS(V), V)
#define _MIN_N_REF() _MIN_N
#define _MIN(V...) EVAL(_MIN_N(TWO_ARGS(V),V))
#define MIN_2(a,b) ((a)<(b)?(a):(b))
#define MIN_3(a,V...) MIN_2(a,DEFER2(_MIN_N_REF)()(TWO_ARGS(V),V))
#define MAX_2(a,b) ((a)>(b)?(a):(b))
#define MAX_3(a,V...) MAX_2(a,MAX_2(V))
#define MAX_4(a,V...) MAX_2(a,MAX_3(V))
#define MAX_5(a,V...) MAX_2(a,MAX_4(V))
#define MAX_6(a,V...) MAX_2(a,MAX_5(V))
#define MAX_7(a,V...) MAX_2(a,MAX_6(V))
#define MAX_8(a,V...) MAX_2(a,MAX_7(V))
#define MAX_9(a,V...) MAX_2(a,MAX_8(V))
#define MAX_10(a,V...) MAX_2(a,MAX_9(V))
#define __MAX_N(N,V...) MAX_##N(V)
#define _MAX_N(N,V...) __MAX_N(N,V)
#define _MAX(V...) _MAX_N(NUM_ARGS(V), V)
#define _MAX_N_REF() _MAX_N
#define _MAX(V...) EVAL(_MAX_N(TWO_ARGS(V),V))
#define MAX_2(a,b) ((a)>(b)?(a):(b))
#define MAX_3(a,V...) MAX_2(a,DEFER2(_MAX_N_REF)()(TWO_ARGS(V),V))
#endif
// Macros for adding
#define INC_0 1
#define INC_1 2
#define INC_2 3
#define INC_3 4
#define INC_4 5
#define INC_5 6
#define INC_6 7
#define INC_7 8
#define INC_8 9
#define INC_0 1
#define INC_1 2
#define INC_2 3
#define INC_3 4
#define INC_4 5
#define INC_5 6
#define INC_6 7
#define INC_7 8
#define INC_8 9
#define INC_9 10
#define INC_10 11
#define INC_11 12
#define INC_12 13
#define INC_13 14
#define INC_14 15
#define INC_15 16
#define INC_16 17
#define INC_17 18
#define INC_18 19
#define INC_19 20
#define INC_20 21
#define INCREMENT_(n) INC_##n
#define INCREMENT(n) INCREMENT_(n)
@@ -377,18 +527,27 @@
#define ADD8(N) ADD4(ADD4(N))
#define ADD9(N) ADD4(ADD5(N))
#define ADD10(N) ADD5(ADD5(N))
#define SUM(A,B) _CAT(ADD,A)(B)
#define DOUBLE_(n) ADD##n(n)
#define DOUBLE(n) DOUBLE_(n)
// Macros for subtracting
#define DEC_0 0
#define DEC_1 0
#define DEC_2 1
#define DEC_3 2
#define DEC_4 3
#define DEC_5 4
#define DEC_6 5
#define DEC_7 6
#define DEC_8 7
#define DEC_9 8
#define DEC_0 0
#define DEC_1 0
#define DEC_2 1
#define DEC_3 2
#define DEC_4 3
#define DEC_5 4
#define DEC_6 5
#define DEC_7 6
#define DEC_8 7
#define DEC_9 8
#define DEC_10 9
#define DEC_11 10
#define DEC_12 11
#define DEC_13 12
#define DEC_14 13
#define DEC_15 14
#define DECREMENT_(n) DEC_##n
#define DECREMENT(n) DECREMENT_(n)
@@ -450,6 +609,12 @@
#define HAS_ARGS(V...) _BOOL(FIRST(_END_OF_ARGUMENTS_ V)())
#define _END_OF_ARGUMENTS_() 0
// Simple Inline IF Macros, friendly to use in other macro definitions
#define IF(O, A, B) ((O) ? (A) : (B))
#define IF_0(O, A) IF(O, A, 0)
#define IF_1(O, A) IF(O, A, 1)
//
// REPEAT core macros. Recurse N times with ascending I.
//
@@ -473,6 +638,7 @@
// Repeat a macro passing S...N-1.
#define REPEAT_S(S,N,OP) EVAL(_REPEAT(S,SUB##S(N),OP))
#define REPEAT(N,OP) REPEAT_S(0,N,OP)
#define REPEAT_1(N,OP) REPEAT_S(1,INCREMENT(N),OP)
// Repeat a macro passing 0...N-1 plus additional arguments.
#define REPEAT2_S(S,N,OP,V...) EVAL(_REPEAT2(S,SUB##S(N),OP,V))
@@ -495,3 +661,14 @@
#define RREPEAT(N,OP) RREPEAT_S(0,N,OP)
#define RREPEAT2_S(S,N,OP,V...) EVAL1024(_RREPEAT2(S,SUB##S(N),OP,V))
#define RREPEAT2(N,OP,V...) RREPEAT2_S(0,N,OP,V)
// See https://github.com/swansontec/map-macro
#define MAP_OUT
#define MAP_END(...)
#define MAP_GET_END() 0, MAP_END
#define MAP_NEXT0(test, next, ...) next MAP_OUT
#define MAP_NEXT1(test, next) MAP_NEXT0 (test, next, 0)
#define MAP_NEXT(test, next) MAP_NEXT1 (MAP_GET_END test, next)
#define MAP0(f, x, peek, ...) f(x) MAP_NEXT (peek, MAP1) (f, peek, __VA_ARGS__)
#define MAP1(f, x, peek, ...) f(x) MAP_NEXT (peek, MAP0) (f, peek, __VA_ARGS__)
#define MAP(f, ...) EVAL512 (MAP1 (f, __VA_ARGS__, (), 0))