diff --git a/README.md b/README.md index 98a49de..4c47476 100644 --- a/README.md +++ b/README.md @@ -38,4 +38,137 @@ add_subdirectory(external/enum.hpp) target_link_libraries(your_project_target enum.hpp) ``` +## Examples + +### Declarations + +```cpp +ENUM_HPP_DECL(debug_level, int, + (level_info) + (level_warning) + (level_error)) + +// equivalent to: + +enum debug_level : int { + level_info, + level_warning, + level_error, +}; + +struct debug_level_traits { + static constexpr std::size_t size = 3; + + static constexpr const debug_level values[] = { + level_info, + level_warning, + level_warning + }; + + static constexpr const std::string_view names[] = { + "level_info", + "level_warning", + "level_warning" + }; + + static constexpr std::string_view to_string( + debug_level e) noexcept; + + static debug_level from_string( + std::string_view name); + + static constexpr bool from_string_nothrow( + std::string_view name, + debug_level& result) noexcept; +}; +``` + +```cpp +ENUM_HPP_CLASS_DECL(color, unsigned, + (red = 1 << 0) + (green = 1 << 1) + (blue = 1 << 2) + (white = red | green | blue)) + +// equivalent to: + +enum class color : unsigned { + red = 1 << 0, + green = 1 << 1, + blue = 1 << 2, + white = red | green | blue, +}; + +struct color_traits { + static constexpr std::size_t size = 4; + + static constexpr const color values[] = { + color::red, + color::green, + color::blue, + color::white + }; + + static constexpr const std::string_view names[] = { + "red", + "green", + "blue", + "white" + }; + + static constexpr std::string_view to_string( + color e) noexcept; + + static color from_string( + std::string_view name); + + static constexpr bool from_string_nothrow( + std::string_view name, + color& result) noexcept; +}; +``` + +### Traits using + +```cpp +ENUM_HPP_CLASS_DECL(color, unsigned, red, green, blue) + +// size +color_traits::size; // 3 + +// to_string +color_traits::to_string(color::red); // returns "red"; +color_traits::to_string(color(42)); // returns ""; + +// from_string +color_traits::from_string("green"); // returns color::green; +color_traits::from_string("error"); // throws enum_hpp::exception + +// from_string_nothrow +color result; +bool success = color_traits::from_string_nothrow("blue", result); +// success == true, result == color::blue + +// names +for ( auto n : color_traits::names ) { + std::cout << n << ","; +} +// prints red,green,blue +``` + +## Alternatives + +[Better Enums](https://github.com/aantron/better-enums) + +- Low variadic macros limit (64) +- Replaces C++ enum semantics to custom class + +[wise_enum](https://github.com/quicknir/wise_enum) + +- Limited by variadic macros ([msvs: 127](https://docs.microsoft.com/en-us/cpp/cpp/compiler-limits?view=vs-2019)) + +[Magic Enum](https://github.com/Neargye/magic_enum) + +- Amazing but requires at least GCC 9.0 + ## [License (MIT)](./LICENSE.md) diff --git a/headers/enum.hpp/enum.hpp b/headers/enum.hpp/enum.hpp index b82503b..d4a6013 100644 --- a/headers/enum.hpp/enum.hpp +++ b/headers/enum.hpp/enum.hpp @@ -87,13 +87,30 @@ namespace enum_hpp::detail ENUM_HPP_PP_SEQ_FOR_EACH(ENUM_HPP_GENERATE_NAMES_OP, _, Fields) // -// ENUM_HPP_ENUM_CLASS +// ENUM_HPP_DECL // -#define ENUM_HPP_ENUM_CLASS(Enum, Type, Fields)\ +#define ENUM_HPP_DECL(Enum, Type, Fields)\ + enum Enum : Type {\ + ENUM_HPP_GENERATE_ENUM_FIELDS(Fields)\ + };\ + ENUM_HPP_TRAITS_IMPL(Enum, Type, Fields) + +// +// ENUM_HPP_CLASS_DECL +// + +#define ENUM_HPP_CLASS_DECL(Enum, Type, Fields)\ enum class Enum : Type {\ ENUM_HPP_GENERATE_ENUM_FIELDS(Fields)\ };\ + ENUM_HPP_TRAITS_IMPL(Enum, Type, Fields) + +// +// ENUM_HPP_TRAITS_IMPL +// + +#define ENUM_HPP_TRAITS_IMPL(Enum, Type, Fields)\ struct Enum##_traits {\ private:\ enum enum_names_for_this_score_ { ENUM_HPP_GENERATE_ENUM_FIELDS(Fields) };\ diff --git a/untests/enum_tests.cpp b/untests/enum_tests.cpp index 16b9a4b..64aea69 100644 --- a/untests/enum_tests.cpp +++ b/untests/enum_tests.cpp @@ -25,14 +25,14 @@ namespace namespace some_namespace { - ENUM_HPP_ENUM_CLASS(color, unsigned, + ENUM_HPP_CLASS_DECL(color, unsigned, (red = 2) (green) (blue = red + 4) ) struct render { - ENUM_HPP_ENUM_CLASS(mask, unsigned char, + ENUM_HPP_CLASS_DECL(mask, unsigned char, (none) (color = 1 << 0) (alpha = 1 << 1) @@ -40,7 +40,7 @@ namespace some_namespace ) }; - ENUM_HPP_ENUM_CLASS(numbers, int, + ENUM_HPP_DECL(numbers, int, (_0)(_1)(_2)(_3)(_4)(_5)(_6)(_7)(_8)(_9)(_10)(_11)(_12)(_13)(_14)(_15)(_16)(_17)(_18)(_19)(_20) (_21)(_22)(_23)(_24)(_25)(_26)(_27)(_28)(_29)(_30)(_31)(_32)(_33)(_34)(_35)(_36)(_37)(_38)(_39)(_40) (_41)(_42)(_43)(_44)(_45)(_46)(_47)(_48)(_49)(_50)(_51)(_52)(_53)(_54)(_55)(_56)(_57)(_58)(_59)(_60) @@ -83,9 +83,9 @@ TEST_CASE("enum") { std::underlying_type_t, int>); - REQUIRE(enum_to_underlying(sn::numbers::_0) == 0); - REQUIRE(enum_to_underlying(sn::numbers::_100) == 100); - REQUIRE(enum_to_underlying(sn::numbers::_240) == 240); + REQUIRE(enum_to_underlying(sn::_0) == 0); + REQUIRE(enum_to_underlying(sn::_100) == 100); + REQUIRE(enum_to_underlying(sn::_240) == 240); } } @@ -121,9 +121,9 @@ TEST_CASE("enum") { STATIC_REQUIRE(sn::render::mask_traits::to_string(sn::render::mask::all) == "all"); } { - STATIC_REQUIRE(sn::numbers_traits::to_string(sn::numbers::_0) == "_0"); - STATIC_REQUIRE(sn::numbers_traits::to_string(sn::numbers::_180) == "_180"); - STATIC_REQUIRE(sn::numbers_traits::to_string(sn::numbers::_240) == "_240"); + STATIC_REQUIRE(sn::numbers_traits::to_string(sn::_0) == "_0"); + STATIC_REQUIRE(sn::numbers_traits::to_string(sn::_180) == "_180"); + STATIC_REQUIRE(sn::numbers_traits::to_string(sn::_240) == "_240"); STATIC_REQUIRE(sn::numbers_traits::to_string(sn::numbers(100500)) == ""); } } @@ -143,8 +143,8 @@ TEST_CASE("enum") { REQUIRE_THROWS_AS(sn::render::mask_traits::from_string("42"), enum_hpp::exception); } { - REQUIRE(sn::numbers_traits::from_string("_10") == sn::numbers::_10); - REQUIRE(sn::numbers_traits::from_string("_240") == sn::numbers::_240); + REQUIRE(sn::numbers_traits::from_string("_10") == sn::_10); + REQUIRE(sn::numbers_traits::from_string("_240") == sn::_240); REQUIRE_THROWS_AS(sn::numbers_traits::from_string("error"), enum_hpp::exception); } } @@ -177,9 +177,9 @@ TEST_CASE("enum") { { sn::numbers result{100500}; REQUIRE(sn::numbers_traits::from_string_nothrow("_240", result)); - REQUIRE(result == sn::numbers::_240); + REQUIRE(result == sn::_240); REQUIRE_FALSE(sn::numbers_traits::from_string_nothrow("error", result)); - REQUIRE(result == sn::numbers::_240); + REQUIRE(result == sn::_240); } } }