-
-
Save qrealka/ac92636753388a7dab897b860dbadd0b to your computer and use it in GitHub Desktop.
Implement static_if using C11 generic selection
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
#include <type_traits> | |
#include <tuple> | |
#include <iostream> | |
// Link: https://github.com/aeyakovenko/notes | |
//count arguments | |
//COUNT_ARGS :: ... -> Int | |
#define COUNT_ARGS(...) COUNT_ARGS_(,##__VA_ARGS__,6,5,4,3,2,1,0) | |
#define COUNT_ARGS_(z,a,b,c,d,e,f,cnt,...) cnt | |
//call an object | |
//CALL :: (... -> a) -> (...) -> a | |
#define CALL(x,y) x y | |
//HEAD :: [a] -> a | |
#define HEAD(args) CALL(HEAD_,args) | |
#define HEAD_(a,...) a | |
//TAIL :: [a] -> [a] | |
#define TAIL(args) (CALL(TAIL_,args)) | |
#define TAIL_(a,...) __VA_ARGS__ | |
//UNPACK :: (...) -> ... | |
#define UNPACK(args) CALL(UNPACK_,args) | |
#define UNPACK_(...) __VA_ARGS__ | |
#define ISEMPTY(ls) PASTE(ISEMPTY_,CALL_(COUNT_ARGS,PASTE(ISEMPTY_,CALL(COUNT_ARGS,ls)))) | |
#define CALL_(f,a) f(a) | |
#define ISEMPTY_0 a,b | |
#define ISEMPTY_2 1 | |
#define ISEMPTY_1 0 | |
//JOIN :: (...) -> (...) -> (...) | |
#define JOIN(l1,l2) PASTE(JOIN_,PASTE(ISEMPTY(l1),ISEMPTY(l2)))(l1,l2) | |
#define JOIN_00(l1,l2) (UNPACK(l1),UNPACK(l2)) | |
#define JOIN_10(l1,l2) l2 | |
#define JOIN_01(l1,l2) l1 | |
#define JOIN_11(l1,l2) () | |
//curry a function to it arguments | |
#define CURRY(f,args) JOIN(f,args) | |
//evaluate a function object | |
#define EVAL(f) EVAL_ f | |
#define EVAL_(f,...) f(__VA_ARGS__) | |
//PASTE :: a -> b -> c | |
//this is really in the preprocessor domain, so hard to type | |
#define PASTE(aa,bb) PASTE_(aa,bb) | |
#define PASTE_(aa,bb) aa ## bb | |
//FOLDR :: (a -> b -> b) -> b -> [a] -> b | |
#define FOLDR(func,accum,lst) PASTE(FOLDR_,CALL(COUNT_ARGS,lst))(func,accum,lst) | |
#define FOLDR_0(func,accum,lst) accum | |
#define FOLDR_1(func,accum,lst) EVAL_FR(CURRY(func,(HEAD(lst), accum))) | |
#define FOLDR_2(func,accum,lst) EVAL_FR(CURRY(func,(HEAD(lst),FOLDR_1(func,accum,TAIL(lst))))) | |
#define FOLDR_3(func,accum,lst) EVAL_FR(CURRY(func,(HEAD(lst),FOLDR_2(func,accum,TAIL(lst))))) | |
#define FOLDR_4(func,accum,lst) EVAL_FR(CURRY(func,(HEAD(lst),FOLDR_3(func,accum,TAIL(lst))))) | |
#define FOLDR_5(func,accum,lst) EVAL_FR(CURRY(func,(HEAD(lst),FOLDR_4(func,accum,TAIL(lst))))) | |
#define FOLDR_6(func,accum,lst) EVAL_FR(CURRY(func,(HEAD(lst),FOLDR_5(func,accum,TAIL(lst))))) | |
//the map needs a different eval then the foldr | |
//i dont fully grok this part yet | |
#define EVAL_FR(f) EVAL_FR_ f | |
#define EVAL_FR_(f,...) f(__VA_ARGS__) | |
//MAP :: (a -> b) -> [a] -> b | |
#define MAP(func,lst) FOLDR((MAP_,func),(),lst) | |
#define MAP_(func,aa,acc) JOIN((EVAL_MP(CURRY(func,(aa)))), acc) | |
#define EVAL_MP(f) EVAL_MP_ f | |
#define EVAL_MP_(f,...) f(__VA_ARGS__) | |
#define static_if(...) static_if__(__VA_ARGS__, \ | |
static_if_4, static_if_3)(__VA_ARGS__) | |
#define static_if__(_1,_2,_3,_4,f,...) f | |
#define static_if_3(capture, cond, true_branch) \ | |
_Generic(std::integral_constant<bool, bool(cond)>{}, \ | |
std::true_type: []_as_glargs(capture) true_branch, \ | |
default: []_as_glargs(capture) {})_as_ids(capture) | |
#define static_if_4(capture, cond, true_branch, false_branch) \ | |
_Generic(std::integral_constant<bool, bool(cond)>{}, \ | |
std::true_type: []_as_glargs(capture) true_branch, \ | |
std::false_type: []_as_glargs(capture) false_branch)_as_ids(capture) | |
#define _as_ids(lst) MAP((_as_id), lst) | |
#define _as_id(a) _as_id_(a,) | |
#define _as_id_(a, b) a ## b | |
#define _as_glargs(lst) MAP((_as_glarg), lst) | |
#define _as_glarg(a) auto&& _as_id(a) | |
template <typename T> | |
void test_strlen(T const& s) | |
{ | |
static_if((s), (std::is_same<T, std::string>{}), | |
{ | |
std::cout << s.size() << std::endl; | |
}, | |
{ | |
std::cout << std::char_traits<char>::length(s) << std::endl; | |
}); | |
} | |
template <int flag> | |
void test_empty() | |
{ | |
static_if((), flag, | |
{ | |
std::cout << "called" << std::endl; | |
}); | |
} | |
void test_multi() | |
{ | |
int a, b, c, d, e, f; | |
static_if((a, b, c, d, e, f), true, | |
{ | |
std::tie(a, b, c, d, e, f) = std::make_tuple(1, 2, 3, 4, 5, 6); | |
}); | |
std::cout << a << b << c << d << e << f << std::endl; | |
} | |
int main() | |
{ | |
test_empty<1>(); | |
test_empty<0>(); | |
test_multi(); | |
test_strlen("wor\0d"); | |
test_strlen(std::string("wor\0d", 5)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment