Skip to content

Instantly share code, notes, and snippets.

@newlawrence
Last active April 15, 2022 09:14
Show Gist options
  • Save newlawrence/fa9c7659674da48eb62657766ece7c05 to your computer and use it in GitHub Desktop.
Save newlawrence/fa9c7659674da48eb62657766ece7c05 to your computer and use it in GitHub Desktop.
Enhanced enums
#define COUNT_( \
X64, X63, X62, X61, X60, X59, X58, X57, X56, X55, X54, \
X53, X52, X51, X50, X49, X48, X47, X46, X45, X44, X43, \
X42, X41, X40, X39, X38, X37, X36, X35, X34, X33, X32, \
X31, X30, X29, X28, X27, X26, X25, X24, X23, X22, X21, \
X20, X19, X18, X17, X16, X15, X14, X13, X12, X11, X10, \
X9, X8, X7, X6, X5, X4, X3, X2, X1, N, ... \
) N
#define COUNT(...) COUNT_( __VA_ARGS__, \
64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, \
53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, \
42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, \
31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, \
20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, \
9, 8, 7, 6, 5, 4, 3, 2, 1 \
)
#define STRINGIFY(X) #X
#define STRINGARG(X) #X,
#define EXPAND(X) X
#define HEAD(X, ...) (X)
#define TAIL(X, ...) (__VA_ARGS__)
#define FOREACH(MACRO, LIST) FOREACH_(COUNT LIST, MACRO, LIST)
#define FOREACH_(N, M, LIST) FOREACH__(N, M, LIST)
#define FOREACH__(N, M, LIST) FOREACH_##N(M, LIST)
#define FOREACH_1(M, LIST) M LIST
#define FOREACH_2(M, LIST) EXPAND(M HEAD LIST) FOREACH_1(M, TAIL LIST)
#define FOREACH_3(M, LIST) EXPAND(M HEAD LIST) FOREACH_2(M, TAIL LIST)
#define FOREACH_4(M, LIST) EXPAND(M HEAD LIST) FOREACH_3(M, TAIL LIST)
#define FOREACH_5(M, LIST) EXPAND(M HEAD LIST) FOREACH_4(M, TAIL LIST)
#define FOREACH_6(M, LIST) EXPAND(M HEAD LIST) FOREACH_5(M, TAIL LIST)
#define FOREACH_7(M, LIST) EXPAND(M HEAD LIST) FOREACH_6(M, TAIL LIST)
#define FOREACH_8(M, LIST) EXPAND(M HEAD LIST) FOREACH_7(M, TAIL LIST)
#define FOREACH_9(M, LIST) EXPAND(M HEAD LIST) FOREACH_8(M, TAIL LIST)
#define FOREACH_10(M, LIST) EXPAND(M HEAD LIST) FOREACH_9(M, TAIL LIST)
#define FOREACH_11(M, LIST) EXPAND(M HEAD LIST) FOREACH_10(M, TAIL LIST)
#define FOREACH_12(M, LIST) EXPAND(M HEAD LIST) FOREACH_11(M, TAIL LIST)
#define FOREACH_13(M, LIST) EXPAND(M HEAD LIST) FOREACH_12(M, TAIL LIST)
#define FOREACH_14(M, LIST) EXPAND(M HEAD LIST) FOREACH_13(M, TAIL LIST)
#define FOREACH_15(M, LIST) EXPAND(M HEAD LIST) FOREACH_14(M, TAIL LIST)
#define FOREACH_16(M, LIST) EXPAND(M HEAD LIST) FOREACH_15(M, TAIL LIST)
#define FOREACH_17(M, LIST) EXPAND(M HEAD LIST) FOREACH_16(M, TAIL LIST)
#define FOREACH_18(M, LIST) EXPAND(M HEAD LIST) FOREACH_17(M, TAIL LIST)
#define FOREACH_19(M, LIST) EXPAND(M HEAD LIST) FOREACH_18(M, TAIL LIST)
#define FOREACH_20(M, LIST) EXPAND(M HEAD LIST) FOREACH_19(M, TAIL LIST)
#define FOREACH_21(M, LIST) EXPAND(M HEAD LIST) FOREACH_20(M, TAIL LIST)
#define FOREACH_22(M, LIST) EXPAND(M HEAD LIST) FOREACH_21(M, TAIL LIST)
#define FOREACH_23(M, LIST) EXPAND(M HEAD LIST) FOREACH_22(M, TAIL LIST)
#define FOREACH_24(M, LIST) EXPAND(M HEAD LIST) FOREACH_23(M, TAIL LIST)
#define FOREACH_25(M, LIST) EXPAND(M HEAD LIST) FOREACH_24(M, TAIL LIST)
#define FOREACH_26(M, LIST) EXPAND(M HEAD LIST) FOREACH_25(M, TAIL LIST)
#define FOREACH_27(M, LIST) EXPAND(M HEAD LIST) FOREACH_26(M, TAIL LIST)
#define FOREACH_28(M, LIST) EXPAND(M HEAD LIST) FOREACH_27(M, TAIL LIST)
#define FOREACH_29(M, LIST) EXPAND(M HEAD LIST) FOREACH_28(M, TAIL LIST)
#define FOREACH_30(M, LIST) EXPAND(M HEAD LIST) FOREACH_29(M, TAIL LIST)
#define FOREACH_31(M, LIST) EXPAND(M HEAD LIST) FOREACH_30(M, TAIL LIST)
#define FOREACH_32(M, LIST) EXPAND(M HEAD LIST) FOREACH_31(M, TAIL LIST)
#define FOREACH_33(M, LIST) EXPAND(M HEAD LIST) FOREACH_32(M, TAIL LIST)
#define FOREACH_34(M, LIST) EXPAND(M HEAD LIST) FOREACH_33(M, TAIL LIST)
#define FOREACH_35(M, LIST) EXPAND(M HEAD LIST) FOREACH_34(M, TAIL LIST)
#define FOREACH_36(M, LIST) EXPAND(M HEAD LIST) FOREACH_35(M, TAIL LIST)
#define FOREACH_37(M, LIST) EXPAND(M HEAD LIST) FOREACH_36(M, TAIL LIST)
#define FOREACH_38(M, LIST) EXPAND(M HEAD LIST) FOREACH_37(M, TAIL LIST)
#define FOREACH_39(M, LIST) EXPAND(M HEAD LIST) FOREACH_38(M, TAIL LIST)
#define FOREACH_40(M, LIST) EXPAND(M HEAD LIST) FOREACH_39(M, TAIL LIST)
#define FOREACH_41(M, LIST) EXPAND(M HEAD LIST) FOREACH_40(M, TAIL LIST)
#define FOREACH_42(M, LIST) EXPAND(M HEAD LIST) FOREACH_41(M, TAIL LIST)
#define FOREACH_43(M, LIST) EXPAND(M HEAD LIST) FOREACH_42(M, TAIL LIST)
#define FOREACH_44(M, LIST) EXPAND(M HEAD LIST) FOREACH_43(M, TAIL LIST)
#define FOREACH_45(M, LIST) EXPAND(M HEAD LIST) FOREACH_44(M, TAIL LIST)
#define FOREACH_46(M, LIST) EXPAND(M HEAD LIST) FOREACH_45(M, TAIL LIST)
#define FOREACH_47(M, LIST) EXPAND(M HEAD LIST) FOREACH_46(M, TAIL LIST)
#define FOREACH_48(M, LIST) EXPAND(M HEAD LIST) FOREACH_47(M, TAIL LIST)
#define FOREACH_49(M, LIST) EXPAND(M HEAD LIST) FOREACH_48(M, TAIL LIST)
#define FOREACH_50(M, LIST) EXPAND(M HEAD LIST) FOREACH_49(M, TAIL LIST)
#define FOREACH_51(M, LIST) EXPAND(M HEAD LIST) FOREACH_50(M, TAIL LIST)
#define FOREACH_52(M, LIST) EXPAND(M HEAD LIST) FOREACH_51(M, TAIL LIST)
#define FOREACH_53(M, LIST) EXPAND(M HEAD LIST) FOREACH_52(M, TAIL LIST)
#define FOREACH_54(M, LIST) EXPAND(M HEAD LIST) FOREACH_53(M, TAIL LIST)
#define FOREACH_55(M, LIST) EXPAND(M HEAD LIST) FOREACH_54(M, TAIL LIST)
#define FOREACH_56(M, LIST) EXPAND(M HEAD LIST) FOREACH_55(M, TAIL LIST)
#define FOREACH_57(M, LIST) EXPAND(M HEAD LIST) FOREACH_56(M, TAIL LIST)
#define FOREACH_58(M, LIST) EXPAND(M HEAD LIST) FOREACH_57(M, TAIL LIST)
#define FOREACH_59(M, LIST) EXPAND(M HEAD LIST) FOREACH_58(M, TAIL LIST)
#define FOREACH_60(M, LIST) EXPAND(M HEAD LIST) FOREACH_59(M, TAIL LIST)
#define FOREACH_61(M, LIST) EXPAND(M HEAD LIST) FOREACH_60(M, TAIL LIST)
#define FOREACH_62(M, LIST) EXPAND(M HEAD LIST) FOREACH_61(M, TAIL LIST)
#define FOREACH_63(M, LIST) EXPAND(M HEAD LIST) FOREACH_62(M, TAIL LIST)
#define FOREACH_64(M, LIST) EXPAND(M HEAD LIST) FOREACH_63(M, TAIL LIST)
#include <ostream>
#include <iterator>
#include <utility>
template<typename T> class enum_iterator;
template<typename T>
static constexpr std::size_t enum_count = get_count(T{});
template<typename T>
static const enum_iterator<T> enum_iterate = enum_iterator<T>{};
template<typename T>
class enum_iterator {
explicit enum_iterator(std::size_t i) noexcept : pos_{i} {}
std::size_t pos_;
public:
using iterator_category = std::input_iterator_tag;
using value_type = T;
using difference_type = void;
using pointer = T*;
using reference = T&;
explicit enum_iterator(T const& t={}) noexcept
: pos_{static_cast<std::size_t>(t)}
{}
value_type operator*() const noexcept { return static_cast<T>(pos_); }
enum_iterator operator++() noexcept { return enum_iterator{++pos_}; }
enum_iterator operator++(int) noexcept { return enum_iterator{pos_++}; }
bool operator==(enum_iterator const& i) noexcept { return i.pos_ == pos_; }
bool operator!=(enum_iterator const& i) noexcept { return i.pos_ != pos_; }
static enum_iterator cbegin() noexcept { return enum_iterator{T{}}; }
static enum_iterator begin() noexcept { return enum_iterator{T{}}; }
static enum_iterator cend() noexcept { return enum_iterator{enum_count<T>}; }
static enum_iterator end() noexcept { return enum_iterator{enum_count<T>}; }
};
#define ENUM(NAME, ...) \
enum class NAME : std::size_t { \
__VA_ARGS__ \
}; \
static constexpr char const* NAME##_names_[] = { \
FOREACH(STRINGARG, (__VA_ARGS__)) \
}; \
inline constexpr std::size_t get_count(NAME) noexcept { \
return COUNT(__VA_ARGS__); \
} \
inline constexpr char const* to_string(NAME e) noexcept { \
return NAME##_names_[static_cast<std::size_t>(e)]; \
} \
inline std::ostream& operator<<(std::ostream& os, NAME e) { \
return os << NAME##_names_[static_cast<std::size_t>(e)]; \
}
/*
Features:
ENUM(numbers, one, two, three) // create the enum
enum_count<numbers> // get number of elements
for (auto n : enum_count<numbers>) // iterate over elements
to_string(numbers::one) // convert to c string
std::cout << numbers::two // print
*/
#include <iostream>
namespace test {
ENUM(numbers, one, two, three)
}
int main() {
for (auto n : enum_iterate<test::numbers>)
std::cout << n << std::endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment