Skip to content

Instantly share code, notes, and snippets.

@m1lkweed
Last active March 3, 2024 07:42
Show Gist options
  • Save m1lkweed/7657fbbc3b91da87af3c620d3d14544c to your computer and use it in GitHub Desktop.
Save m1lkweed/7657fbbc3b91da87af3c620d3d14544c to your computer and use it in GitHub Desktop.
Type-generic `range()` macro in GNU C, inspired by Python
#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