Skip to content

Instantly share code, notes, and snippets.

@alpha123
Last active August 1, 2016 04:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alpha123/5caf7be0fa13aeec9d6f7ab054fd3559 to your computer and use it in GitHub Desktop.
Save alpha123/5caf7be0fa13aeec9d6f7ab054fd3559 to your computer and use it in GitHub Desktop.
Magic C preprocessor stuff
#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