Last active
August 1, 2016 04:27
-
-
Save alpha123/5caf7be0fa13aeec9d6f7ab054fd3559 to your computer and use it in GitHub Desktop.
Magic C preprocessor stuff
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <memory> | |
#include <utility> | |
/** | |
* π¬ππππππ πππ ππππ, ππ πππ πππππ ππππ | |
* | |
* | |
* You have been WARNED | |
* | |
* Many of the preprocessor metaprogramming techniques used here are from this | |
* excellent article: | |
* https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms | |
* | |
* In general, it's best not to try to decipher this. | |
*/ | |
#define PSL_PASTE(a,...) a ## __VA_ARGS__ | |
#define PSL_CAT(a,...) PSL_PASTE(a,__VA_ARGS__) | |
#define PSL_EMPTY() | |
#define PSL_BLOCK_EXPANSION(x) x PSL_EMPTY() | |
#define PSL_DEFER(...) __VA_ARGS__ PSL_BLOCK_EXPANSION(PSL_EMPTY)() | |
#define PSL_EXPAND(...) __VA_ARGS__ | |
#define PSL_EAT(...) | |
// While adding more expansions here would allow more arguments to make_unique | |
// below, it also tends to kill compile time. | |
#define PSL_EVAL(...) PSL_EVAL1(PSL_EVAL1(PSL_EVAL1(__VA_ARGS__))) | |
#define PSL_EVAL1(...) PSL_EVAL2(PSL_EVAL2(PSL_EVAL2(__VA_ARGS__))) | |
#define PSL_EVAL2(...) PSL_EVAL3(PSL_EVAL3(PSL_EVAL3(__VA_ARGS__))) | |
#define PSL_EVAL3(...) PSL_EVAL4(PSL_EVAL4(PSL_EVAL4(__VA_ARGS__))) | |
#define PSL_EVAL4(...) PSL_EVAL5(PSL_EVAL5(PSL_EVAL5(__VA_ARGS__))) | |
#define PSL_EVAL5(...) PSL_EXPAND(PSL_EXPAND(PSL_EXPAND(__VA_ARGS__))) | |
#define PSL_IF_(bool) PSL_PASTE(PSL_IF__,bool) | |
#define PSL_IF__0(t,...) __VA_ARGS__ | |
#define PSL_IF__1(t,...) t | |
#define PSL_NEGATE(x) PSL_PASTE(PSL_NEGATE_,x) | |
#define PSL_NEGATE_0 1 | |
#define PSL_NEGATE_1 0 | |
// Lord knows how this works or how I once understood it. | |
#define PSL_CHECK_N(x,n,...) n | |
#define PSL_CHECK(...) PSL_CHECK_N(__VA_ARGS__,0,) | |
#define PSL_PROBE(x) x, 1, | |
#define PSL_NOT(x) PSL_CHECK(PSL_PASTE(PSL_NOT_,x)) | |
#define PSL_NOT_0 PSL_PROBE(~) | |
#define PSL_IS_TRUTHY(x) PSL_NEGATE(PSL_NOT(x)) | |
#define PSL_IF(pred) PSL_IF_(PSL_IS_TRUTHY(pred)) | |
#define PSL_WHEN(pred) PSL_IF(pred)(PSL_EXPAND,PSL_EAT) | |
#define PSL_UNLESS(pred) PSL_IF(pred)(PSL_EAT,PSL_EXPAND) | |
#define PSL_REPEAT(n,f,...) \ | |
PSL_WHEN(n) \ | |
( \ | |
PSL_DEFER(PSL_REPEAT_) () \ | |
( \ | |
PSL_DEC(n), f, __VA_ARGS__ \ | |
) \ | |
PSL_DEFER(f) \ | |
( \ | |
PSL_DEC(n), __VA_ARGS__ \ | |
) \ | |
) | |
#define PSL_REPEAT_() PSL_REPEAT | |
// No nicer way to write this. More cases can be added on an as-needed basis. | |
// Saturate instead of wraparound; mostly because DEC(0) == 0 tends to be useful | |
// for loops. | |
#define PSL_INC(x) PSL_PASTE(PSL_INC_,x) | |
#define PSL_INC_0 1 | |
#define PSL_INC_1 2 | |
#define PSL_INC_2 3 | |
#define PSL_INC_3 4 | |
#define PSL_INC_4 5 | |
#define PSL_INC_5 6 | |
#define PSL_INC_6 7 | |
#define PSL_INC_7 8 | |
#define PSL_INC_8 9 | |
#define PSL_INC_9 10 | |
#define PSL_INC_10 10 | |
#define PSL_DEC(x) PSL_PASTE(PSL_DEC_,x) | |
#define PSL_DEC_0 0 | |
#define PSL_DEC_1 0 | |
#define PSL_DEC_2 1 | |
#define PSL_DEC_3 2 | |
#define PSL_DEC_4 3 | |
#define PSL_DEC_5 4 | |
#define PSL_DEC_6 5 | |
#define PSL_DEC_7 6 | |
#define PSL_DEC_8 7 | |
#define PSL_DEC_9 8 | |
#define PSL_DEC_10 9 | |
#define PSL_T_PARAM(i,_) typename T##i, | |
#define PSL_F_PARAM(i,_) PSL_CAT(T,PSL_INC(i)) &&a##i, | |
#define PSL_C_PARAM(i,_) std::forward<PSL_CAT(T,PSL_INC(i))>(a##i), | |
/******************************************************** | |
* * | |
* π·π'πππππ ππππ'ππππ πͺππππππ πΉ'ππππ ππππ'ππππ ππππππ * | |
* * | |
********************************************************/ | |
#define PSL_MAKE_FN(i,_) \ | |
template< \ | |
PSL_REPEAT(i,PSL_T_PARAM,~) typename T##i \ | |
> \ | |
std::unique_ptr<T0> std::make_unique( \ | |
PSL_REPEAT(PSL_DEC(i),PSL_F_PARAM,~) \ | |
PSL_WHEN(i)(T##i &&PSL_CAT(a,PSL_DEC(i))) \ | |
) \ | |
{ \ | |
T0 *inst = new T0(PSL_REPEAT(PSL_DEC(i),PSL_C_PARAM,~) \ | |
PSL_WHEN(i)(std::forward<T##i>(PSL_CAT(a,PSL_DEC(i))))); \ | |
return std::unique_ptr<T0>(inst); \ | |
} | |
namespace psl { | |
// NOTE can't go 8 or higher because of the expansion limit of EVAL above; | |
// raising it causes preprocessor time to become rather slow. | |
PSL_EVAL(PSL_REPEAT(7,PSL_MAKE_FN,~)) | |
template<typename T, typename U = T> | |
T exchange(T &x, U &&y) | |
{ | |
T old = std::move(y); | |
x = std::forward<U>(y); | |
return old; | |
} | |
template<typename T> | |
class comparison_ops { | |
public: | |
friend bool operator!=(const T &a, const T &b) const | |
{ | |
return !(a == b); | |
} | |
friend bool operator>(const T &a, const T &b) const | |
{ | |
return operator<(b, a); | |
} | |
friend bool operator>=(const T &a, const T &b) const | |
{ | |
return !(a < b); | |
} | |
friend bool operator<=(const T &a, const T &b) const | |
{ | |
return !(b < a); | |
} | |
}; | |
} | |
// Looks yucky but slightly better than my::long::type<name>::foo bar = baz; | |
#define PSL_AUTO(var,expr) decltype((expr)) var = (expr) | |
// Don't mistake this for BOOST_FOREACH, it's much simpler and less powerful. | |
#define PSL_FOREACH(var,expr) \ | |
if (PSL_AUTO(PSL_TMP_EXPR, (expr))) \ | |
for (decltype(PSL_TMP_EXPR.begin()) var = PSL_TMP_EXPR.begin(), PSL_TMP_END = PSL_TMP_EXPR.end(); var != PSL_TMP_END; ++var) | |
#define PSL_SWAPPABLE(cls) \ | |
cls(cls &&other) { swap(*this, other); } \ | |
cls &operator=(cls other) { swap(*this, other); return *this; } \ | |
friend void swap(cls &a, cls &b) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment