Last active
April 15, 2022 09:14
-
-
Save newlawrence/fa9c7659674da48eb62657766ece7c05 to your computer and use it in GitHub Desktop.
Enhanced enums
This file contains hidden or 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 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