Last active
March 3, 2024 07:42
-
-
Save m1lkweed/7657fbbc3b91da87af3c620d3d14544c to your computer and use it in GitHub Desktop.
Type-generic `range()` macro in GNU C, inspired by Python
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
#define COUNTOF(x) (sizeof(x) / sizeof*(x)) | |
#define NEEDED_SIZE_HELPER(start, stop, step, X) ( \ | |
((((start) > (stop))?(start):(stop)) - \ | |
(((start) < (stop))?(start):(stop))) / ((step) X) \ | |
) | |
#define NEEDED_SIZE(start, stop, step) ( \ | |
NEEDED_SIZE_HELPER(start, stop, step,) + \ | |
((NEEDED_SIZE_HELPER(start, stop, step, + 0.) - \ | |
NEEDED_SIZE_HELPER(start, stop, step,)) != 0) \ | |
) | |
#define _range0(x) _Static_assert(0); | |
#define _range1(...) _range2(0, __VA_ARGS__) | |
#define _range2(...) _range3(__VA_ARGS__, 1) | |
#define _range3(y, x, z) (({ \ | |
_Static_assert(__builtin_constant_p((x) + (y) + (z)), "arguments to \'range()\' must be constants"); \ | |
struct{typeof((x) - (y) - (z)) arr[(typeof(sizeof 0))NEEDED_SIZE(y, x, z)];}range_ret = {}; \ | |
typeof(sizeof 0) range_PP_count = COUNTOF(range_ret.arr); \ | |
typeof((x) + (y) + (z)) range_PP_i = (y); \ | |
for(typeof(sizeof 0) range_PP_idx = 0; range_PP_idx < range_PP_count; ++range_PP_idx, range_PP_i += ((x) > (y))?(z):(-(z))) \ | |
range_ret.arr[range_PP_idx] = range_PP_i; \ | |
range_ret;}).arr) | |
//This pre-processor block calls a different function | |
//depending on the number of arguments to range(). | |
#define PP_HAS_ARGS_IMPL2(_1, _2, _3, _4 , N, ...) N | |
#define PP_HAS_ARGS_SOURCE() _ERROR, 3, 2, 1, _ERROR, _ERROR | |
#define PP_HAS_ARGS_IMPL(...) PP_HAS_ARGS_IMPL2(__VA_ARGS__) | |
#define PP_HAS_ARGS(...) PP_HAS_ARGS_IMPL(__VA_ARGS__, PP_HAS_ARGS_SOURCE()) | |
#define _range_ERROR(...) ({_Static_assert(0, "\'range()\' takes either 1, 2, or 3 arguments");}) //failure | |
#define RANGE_DISAMBIGUATE2(has_args, ...) _range ## has_args(__VA_ARGS__) | |
#define RANGE_DISAMBIGUATE(has_args, ...) RANGE_DISAMBIGUATE2(has_args, __VA_ARGS__) | |
#define range(...) RANGE_DISAMBIGUATE(PP_HAS_ARGS(__VA_ARGS__), __VA_ARGS__) | |
#include <stdio.h> | |
int main(){ | |
https://gist.github.com/m1lkweed/064ff717d38a7959c2861ccb2b9a936c for the "for each" macro | |
for each(x, range(2, -6, 2)){ | |
printf("%d\n", x); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment