Giter Club home page Giter Club logo

neargye / magic_enum Goto Github PK

View Code? Open in Web Editor NEW
4.4K 4.4K 404.0 672 KB

Static reflection for enums (to string, from string, iteration) for modern C++, work with any enum type without any macro or boilerplate code

License: MIT License

CMake 6.42% C++ 92.87% Starlark 0.36% Meson 0.34%
c-plus-plus c-plus-plus-17 cplusplus cplusplus-17 cpp cpp17 enum enum-to-string header-only metaprogramming no-dependencies reflection serialization single-file string-to-enum

magic_enum's People

Contributors

abdes avatar alexkaratarakis avatar cpsauer avatar dependabot[bot] avatar diogoteles08 avatar embeddedpenguin avatar florianbecker avatar gameforpeople avatar ilobilo avatar kolanich avatar neargye avatar oficsu avatar pavelkryukov avatar pck avatar racethemase avatar ralphsteinhagen avatar randers00 avatar rpatters1 avatar ry-ds avatar schaumb avatar smertig avatar stephanlachnit avatar striezel avatar svew avatar talisein avatar timple avatar tmayoff avatar v1993 avatar vt4a2h avatar zaucy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

magic_enum's Issues

reduce memory footprint

For a runtime value to string conversion it generates a list of strings and a string_view map. In theory data usage could be reduced to 1/4 by using an index plus a small size squeezed into a uint32_t instead of string_view if the strings could be forced into a contiguous array.

Better syntax for custom enum names

Following up #47.

I'm not really happy with the current syntax for defining custom enum names, specially because you need to deal with functions defined in the namespace detail which does not seem right. Furthermore, a function named n is not a very intuitive name for people using the library.

Threrefore, I have 2 suggestions on how to improve it:

  1. Add a function template <auto V> std::string_view magic_enum::custom_name() to the API:
template <auto V>
constexpr std::string_view magic_enum::custom_name() noexcept { return ""; }
...
// a small change in `n()`
template <typename E, E V>
std::string_view magic_enum::n() { 
  if constexpr (auto s = custom_name<V>(); !s.empty())
    return s;
  else {
    ... // current `n()` implementation
  }
}
...
// example of usage
template <>
constexpr std::string_view magic_enum::custom_name<Color::red> noexcept { return "the red color"; }

Pros:

  • Removed redundant template parameter typename E.
  • Specialization defined using a function defined in magic_enum, not in magic_enum::detail
  • Intuitive function name custom_name instead of n.

Cons:

  • The if constexpr in n() is a bit ugly...
  • Very verbose if you compare with option 2.
  1. Use a macro (as suggested by @Neargye in #47):
#define MAGIC_ENUM_CUSTOM_NAME(VALUE, TEXT) \
template <> constexpr auto magic_enum::detail::n<decltype(VALUE), VALUE>() noexcept { return std::string_view{TEXT}; }
...
// example of usage
MAGIC_ENUM_CUSTOM_NAME(Color::red, "the red color")

Pros:

  • Simpler syntax.

Cons:

  • Its a macro... ¯\(ツ)
  • It might not be clear that you cannot declare it inside a class/namespace.

Let me know what you think.

Clang Defect with enums inside a templated class

There's a problem with (even the current trunk version) of clang with this code:

#include <https://raw.githubusercontent.com/Neargye/magic_enum/master/include/magic_enum.hpp>

template <typename T = int>
struct test {
    enum class Color { RED, BLUE, GREEN};
};

template <typename type>
static constexpr bool are_values_sequential = []() constexpr noexcept -> bool {
    const auto vals = magic_enum::enum_values<type>();
    for (std::size_t i = 0; i < vals.size(); ++i)
        if (magic_enum::enum_integer(vals[i]) != i)
            return false;
    return true;
}();

static_assert(are_values_sequential<test<int>::Color>);

https://godbolt.org/z/KWWE1f

https://raw.githubusercontent.com/Neargye/magic_enum/master/include/magic_enum.hpp:653:3: error: static_assert failed due to requirement 'detail::count_v<test<int>::Color, false> > 0' "magic_enum requires enum implementation and valid max and min."

The above code works in GCC though.

The problem seems to appear when the enum is inside a templated class.

the magic_enum::enum_names does not work when try to assign to global variable

magic_enum::enum_names seems only works in function.

enum class Color : int { RED = -10, BLUE = 0, GREEN = 10 };
constexpr auto color_names0 = magic_enum::enum_names<Color>();
int main()
{
constexpr auto color_names = magic_enum::enum_names<Color>();
std::cout << color_names0[0] << "\n"; // this give out some random string
std::cout << color_names[0] << "\n"; // this is fine. 
}

No name with enum values over 128

I have an enum like this:
enum QUEUE_ENTRY_TYPE : unsigned int {
QUEUE_ENTRY_UNKNOWN,
TRN_GET_PROCESS_LIST = 100,
TRN_GET_TOP_WINDOWS,
TRN_GET_PROCESS_WINDOWS = 200,
TRN_GET_CHILD_WINDOWS,
TRN_GET_POPUP_WINDOWS = 300,
TRN_GET_WINDOW_INFO,...

But when I try to get the name with the code below it does not work:
QUEUE_ENTRY_TYPE qet = TRN_GET_CHILD_WINDOWS;
auto qet_name = magic_enum::enum_name(qet);

It only works for values below 128.
In the index() function on line 349 it decides the value is bigger than max_v.
What can I do?

Compile errors on Clang 8.0.1

Hi there. I am trying to compile for PS4, using Clang 8.0.1:

-- The CXX compiler identification is Clang 8.0.1
-- The C compiler identification is Clang 8.0.1

However, I run into these errors:

[...]\magic_enum.hpp(458,23): error : constexpr variable 'values_v<ColorType, false>' must be initialized by a constant expression
[...]\magic_enum.hpp(467,23): error : constexpr variable 'min_v<ColorType, false, std::underlying_type<ColorType>::type>' must be initialized by a constant expression
[...]\magic_enum.hpp(470,23): error : constexpr variable 'max_v<ColorType, false, std::underlying_type<ColorType>::type>' must be initialized by a constant expression
[...]\magic_enum.hpp(475,18): error : constexpr variable 'max' must be initialized by a constant expression
[...]\magic_enum.hpp(476,18): error : constexpr variable 'min' must be initialized by a constant expression
[...]\magic_enum.hpp(477,18): error : constexpr variable 'range_size' must be initialized by a constant expression
[...]\magic_enum.hpp(478,17): error : static_assert expression is not an integral constant expression

Any help with this would be appreciated. Thank you!

Enchancement: custom enum names

Hi, thanks for doing a great job with this library.

magic_enum works amazingly well in most of the cases, but sometimes, the string conversion must be different from the enum value identifier.

For example, I would like to be able to convert the enum value Red to "the red color" instead of "Red" and also convert "the red color" back to Red. That's not possible in the current version of magic_enum as far as I know.

Better Enums has an alternative for this, which is depicted in the example https://github.com/aantron/better-enums/blob/master/example/5-map.cc

Would it be possible to add a feature that allows custom definitions of names for enum values?

Proposed enhancement to enum_name

EDIT: Thinking a bit harder, it might be better that this functionality be moved to a new method, perhaps called enum_name_of_bits_set or something and leave enum_name alone...

Hi, I have no clue about github or pull requests, so I thought I'd write my proposed enhancement to enum_name here...

If an enum contains bitfield values, there exists already the ability to bitwise AND and OR the values together to create flag fields. But there is no way to print such a flag.

Example :

using namespace magic_enum;
using namespace magic_enum::bitwise_operators;

enum Rooms { None = 0, Bedroom = 1 << 0, Lounge = 1 << 1, Kitchen = 1 << 2 };
Rooms toPaint = Rooms::Bedroom | Rooms::Kitchen;

std::cout << "My wife want me to paint these : " << enum_name<Rooms>(toPaint) << '\n';

Desired output :
My wife want me to paint these : Bedroom|Kitchen

Actual output :
My wife want me to paint these :

Here is a replacement

    // Returns string enum name from enum value.
    // If enum value does not have name or value out of range, returns empty string.
    template <typename E>
    [[nodiscard]] constexpr auto enum_name(E value) noexcept 
    -> detail::enable_if_enum_t<E, std::string_view>
    {
        //  Begin Changes ga2k 2020-05-29

        //  return enum_traits<E>::name(value);

        auto n = enum_traits<E>::name(value);
        if (!n.empty())
            return n;

        //  See if there is a name for each bit set in value. 
        //  If so, concatenate them with '|' separator

        //  First find largest value

        constexpr auto values = enum_values<E>();
        constexpr auto largest = values[values.size() - 1];
        static std::string s;

        for (int b = 0; (1 << b) <= largest; ++b)
        {
            if ((value & (1 << b)) == (1 << b))	// This bit is set in value
            {
                auto n2 = enum_traits<E>::name(static_cast<E>(1 << b));

                if (n2.empty())
                    return n2;	// No name at this bt value : not a bitfield value, so bail

                if (!s.empty())
                {
                    s += '|';
                }

                s += n2;
            }
        }

        return static_cast<std::string_view>(s);
            
        // End Additions ga2k 2020-05-29
    }

Thoughts?

Enum type name?

Is there a way to get the name of an enum type? E.g.:

enum class e_color { red, blue };
using my_enum = e_color;
constexpr std::string_view name = magic_enum::enum_type_name<my_enum>();

then name would be "e_color".

Trait for checking if enum fits allowed range

I need constexpr check that will tell me if for given enum, magic_enum will work:

template <typename EnumT>
(...)
EnumT v = ....;
(...)
        if constexpr (magic_enum::is_magic_enum_supported && magic_enum::is_supported_enum_v<EnumT>) {
            return format_to(ctx.out(), "{}", magic_enum::enum_name(v));
        } else {
            return format_to(ctx.out(), "{}", (int) v);
        }

Specifically EnumT in above code may have values outside scope of MAGIC_ENUM_RANGE_MIN, MAGIC_ENUM_RANGE_MAX

Example of invalid code compiling

This code should be invalid and shouldn't compile but it does, and even optimizes to have 0 be returned implying the string ":dog" is equal to the enum horse.

https://godbolt.org/z/5UvrpB

Why are we allowed to compare a enum foo vs an optional<enum foo> with boolean operations.

MAGIC_ENUM_SUPPORTED_ALIASES & magic_enum::enum_values<>()

Hello,

I wanted to write a piece of code that checks that all the values in an enum are unique.

Looking at the limitations of magic_enum, I read that "magic_enum won't work if a value is aliased". Well, that's what I want to do: detect if at least one value is aliased in my enum.

During my tests, I wrote the following code:

enum class Color {
	RED = 8, BLUE = 4, GREEN = 8
};

int main() {
#ifdef MAGIC_ENUM_SUPPORTED_ALIASES
	std::cout << "supported " << MAGIC_ENUM_SUPPORTED_ALIASES << '\n';
#else
	std::cout << "NOT supported" << '\n';
#endif

	auto colors = magic_enum::enum_values<Color>();

	for (auto& color:colors) {
		using namespace magic_enum::ostream_operators;
		std::cout << color << '\n';
	}

	return colors.size();
}

It prints:

supported 1
BLUE
RED

The problem is visible with Compiler Explorer using gcc 10.2: https://godbolt.org/z/4TTerr

The aliased value GREEN doesn't appears in the list returned by enum_values<Color>().

This seems to be a bug because MAGIC_ENUM_SUPPORTED_ALIASES is defined to be 1.

Am I missing something?

Build fails with Clang 5.0 and C++17

I'm building a cross platform program. I'm using Visual Studio to build, and VS still uses Android NDK 16b with Clang 5 to build native libs for Android. I get the following errors:

  • no template named 'is_nothrow_invocable_r_v' in namespace 'std'; did you mean '__nothrow_invokable_r'?
  • no template named 'is_invocable_r_v' in namespace 'std'; did you mean '__invokable_r'?
  • expected '(' for function-style cast or type construction

O(1) conversion to location of enum in enum_values

Is there a way to do O(1) conversion of Color::BLUE to 1 (rather than 4, as enum_integer would do)?

Motivation: I have an enum generated by an external tool which may have gaps in it, and I need to pack the enums into a contiguous sequence of integers starting at 0 (so that I can more efficiently store it in memory somewhere else). I don't need this packing to be stable across invocations of the program, but it should be stable within the program.

Released to vcpkg?

Hi, the newest version hasn't been sent to vcpkg yet. That caused me a heart attack! Namespace customize doesn't exist in the old version.

GCC 8.2 support

With imminent versions of centos, Ubuntu etc still on GCC 8.x stream, consider a workaround for the issues preventing GCC 8 support.

The patches to GCC 8 compiler to fix the issues aren't really possible to use either for a lot of organisations or individuals.

static assertion failed with gcc 9.2.1

Hello,

We have been trying to use magic_enum::enum_count. It works well with Visual Studio 2017 but does not compile with gcc 9.2.1. Here is the code:

enum class MyEnum : std::size_t
{
    Value0,
    Value1,
    Value2
};
constexpr std::size_t countEnum = magic_enum::enum_count<MyEnum>();

And with gcc 9.2.1 we have the following issue:

MagicEnum.h:442:26: error: static assertion failed: magic_enum::enum_range requires enum implementation and valid max and min.
static_assert( count > 0, "magic_enum::enum_range requires enum implementation and valid max and min." );

We have the latest version of MagicEnum as of today. We have looked at the limitations, we don't seem to be in one of those situations. Did we miss anything? It looks like it is supposed to work from gcc 9 and upward.

Thank you so much for your work and very nice contribution. Magic enum seems pretty cool.

Cheers,

Olivier

Stop use of `using` in header.

The using keyword in a header can create conflicts in other headers when magic_enum is imported :

  /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/optional:656:11: note: candidate found by name lookup is 'std::optional'
1406
      class optional
1407
            ^
1408
  ../magic_enum/include/magic_enum.hpp:99:1: note: candidate found by name lookup is 'magic_enum::optional'
1409
  using optional = std::optional<T>;

It would be preferable to use a typedef or a macro to define an other type that would be used elsewhere in the code.

If you agree I can make a PR.

compile error if enum value is 0xab

enum class Color1
{
    red  = 0xab,
    blue = 0xcd
};

enum class Color2
{
    red  = 0x12,
    blue = 0x34
};

int main()
{	
    magic_enum::enum_name(Color1::red); // compile error!
    magic_enum::enum_name(Color2::red); // okay
}

E0028 expression must have a constant value

/ E2719 integer constant must be greater than or equal to zero
on this line ...
inline constexpr auto type_name_v = n();

any ideas what these errors could be? it compiles and works ... just not sure why intellisense is unhappy

Build error

0.6.6 and master.
The latest clang, libstdc++ 10.2 (from fedora 32).

Code:

#include <magic_enum.hpp>
enum class BuildState
{
    NotStarted,
};
void f()
{
    auto state = BuildState::NotStarted;
    magic_enum::enum_name(state);
}

Error:

[sw.client.core-0.4.2]/src/sw/core/build.cpp
In file included from D:/dev/cppan2/client2/src/sw/core/build.cpp:1:
d:/temp/9/magic_enum/include\magic_enum.hpp:409:81: fatal error: instantiating fold expression with 257 arguments exceeded expression nesting limit of 256
  constexpr std::size_t count = ((valid[I] ? std::size_t{1} : std::size_t{0}) + ...);
                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~
d:/temp/9/magic_enum/include\magic_enum.hpp:428:10: note: in instantiation of function template specialization 'magic_enum::detail::values<BuildState, false, -128, 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, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
      98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133,
      134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169,
      170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205,
      206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241,
      242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256>' requested here
  return values<E, IsFlags, reflected_min_v<E, IsFlags>>(std::make_index_sequence<range_size>{});
         ^
d:/temp/9/magic_enum/include\magic_enum.hpp:432:34: note: in instantiation of function template specialization 'magic_enum::detail::values<BuildState, false, int>' requested here
inline constexpr auto values_v = values<E, IsFlags>();
                                 ^
d:/temp/9/magic_enum/include\magic_enum.hpp:438:33: note: in instantiation of variable template specialization 'magic_enum::detail::values_v' requested here
inline constexpr auto count_v = values_v<E, IsFlags>.size();
                                ^
d:/temp/9/magic_enum/include\magic_enum.hpp:559:17: note: in instantiation of variable template specialization 'magic_enum::detail::count_v' requested here
  static_assert(count_v<D, false> > 0, "magic_enum requires enum implementation and valid max and min.");
                ^
d:/temp/9/magic_enum/include\magic_enum.hpp:571:1: note: in instantiation of template class 'magic_enum::detail::enable_if_enum<true, false, BuildState, std::basic_string_view<char,
      std::char_traits<char>>>' requested here
using enable_if_enum_t = typename enable_if_enum<std::is_enum_v<std::decay_t<T>>, false, T, R>::type;
^
d:/temp/9/magic_enum/include\magic_enum.hpp:682:69: note: in instantiation of template type alias 'enable_if_enum_t' requested here
[[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_enum_t<E, string_view> {
                                                                    ^
D:/dev/cppan2/client2/src/sw/core/build.cpp:9:5: note: while substituting deduced template arguments into function template 'enum_name' [with E = BuildState]
    magic_enum::enum_name(state);
    ^
d:/temp/9/magic_enum/include\magic_enum.hpp:409:81: note: use -fbracket-depth=N to increase maximum nesting level
  constexpr std::size_t count = ((valid[I] ? std::size_t{1} : std::size_t{0}) + ...);
                                                                                ^
1 error generated.
Error code: 1

Adding -fbracket-depth=260 helps.

C++ language standard, issues with explicit setting to 17

I recently tried the library via vcpkg on MSVC. I had a problem that the following property is specified in magic_enumConfig.cmake

INTERFACE_COMPILE_FEATURES "cxx_std_17"

This is a problem as our code builds uses what MSVC calls "std::c++latest" which is newer than 17. Im not sure what should happen but it appears that the magic enum value overrides ours so we get downgraded to 17 which means a bunch of our code no longer compiles.

In the nameof library you mention in issue Neargye/nameof#12 that "I set c++17 for hand, because old cmake can't set c++17 for msvc++." I don't know if if makes sense for a package to require a specific version. If my projects use say c++ 11 and I try to include magic_enum.hpp I get a very clear error message from the compiler telling me I need to use c++ 17. I did look around vcpkg but couldn't find any documentation on best practice for settting c++ language standard.

I think what is really wanted is to require a minimum version but allow newer ones like latest or 20. I don't know how to do that in CMake/VCPKG.
For now we commented out the explicit setting of C++ 17 and things work great.

Add skill Dereferencable

I use the following skill to add the dereference operator (like in std::optional for example):

template< typename T >
struct Dereferencable;`

template< typename T, typename Parameter, template< typename > class ... Skills >
struct Dereferencable< fluent::NamedType< T, Parameter, Skills... > > : fluent::crtp< fluent::NamedType< T, Parameter, Skills... >, Dereferencable >
{
    constexpr const T& operator*() const &
    {
        return this->underlying().get();
    }

    constexpr T& operator*() &
    {
        return this->underlying().get();
    }

    constexpr T && operator*() &&
    {
        return std::move( this->underlying().get() );
    }

    constexpr const T && operator*() const&&
    {
        return std::move( this->underlying().get() );
    }
};

Example usage:

void Fct( double value );
...
Fct( *strongType );

Please improve compatibility with "degraded" C++17

Hello,

I'd like to use magic_enum on macOS but unfortunately I have to keep backward compatibility to an older 10.9 release.
That makes things like std::optional unavailable:

PacketParser.cpp:381:33: error: 'value' is unavailable: introduced in macOS 10.14
                    reasonBits).value();

I could see three ways of working around:

  1. Provide enum_foo_or_throw() methods which completely avoid using std::optional and throw instead.
  2. Provide your own optional implementation (like better enums does).
  3. Provide a way to switch to boost::optional instead of std::optional

Thanks,
Gregor

Compilation error using clang

Hi I recently switched my project from using gcc to clang, and ran into this error:

_deps/magic_enum_content-src/include/magic_enum.hpp:116:18: error: constexpr variable 'prefix' must be initialized by a constant expression
  constexpr auto prefix = name.find_last_of(" :,-)") + 1;
                 ^        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Clang version:

clang version 8.0.0 (Fedora 8.0.0-1.fc30)
Target: x86_64-unknown-linux-gnu

Gcc version:

g++ (GCC) 9.1.1 20190503 (Red Hat 9.1.1-1)

Flag list:

                          -Wall
                          -Wextra
                          -Werror
                          -Wnon-virtual-dtor
                          -Wold-style-cast
                          -Woverloaded-virtual
                          -Wsign-conversion
                          -Wconversion
                          -Wnull-dereference
                          -Wformat=2
                          -Wdouble-promotion
                          -fasynchronous-unwind-tables
                          -fstack-protector
                          -fstack-protector-strong
                          -fPIC
                          -pipe
                          -fsanitize=address
                          -fsanitize=undefined
                          -g
                          -fdiagnostics-color=always
                          -fno-omit-frame-pointer

Thank you for your work in this library, please let me know if I can provide more info.

set MAGIC_ENUM_RANGE_MAX higher than 1023

Hi there,
I had a close look at this lib and love it so far. However, I have two following questions/issues.

How to use the full potential of 16 bit?
It seems that the real Max Range Limit is 2^10 - 1. As soon you set #define MAGIC_ENUM_RANGE_MAX 1024 Following error message is shown:

  • C1202:" recursive type or function dependency context too complex"
    Linked to Line 442 in magic_enum.hpp
    Note: I used #pragma warning(push) & #pragma warning(disable : 4244)

I also tried useing enum Direction (Line 51) from https://github.com/Neargye/magic_enum/blob/master/test/test_flags.cpp and use enum_cast or enum_name with no success. I receive following error:
C2975 '_Test': invalid template argument for 'std::conditional_t', expected compile-time constant expression
I also used code exactly like it is on Line 374-376.

Why not using 32 bit?
Beside from the above issue, I tired to replace all (u)int16_t with (u)int32_t and everything looks fine so far, as long the max range is not set at 1024 or above. Is there a specific reason not to do this?

PS: I’m mainly using enum_name or enum_cast.

Thank you so much for your work.

No MinGW support

Hi,

I just tried to compile a library that used your magic_enum library with the current MinGW 64 version 8.1.0. The compilation failed because magic_enum does not propwerly support current MinGW 64 compiler. The version 8.1.0 is the latest official release and also the version that ships with Qt. So this is the version that can be considered stable.

Would be great, if it would be possible to use magic_enum with a current MinGW compiler.

Apart from that magic_enum is a great library and it is great that you made it available on GitHub.

Convenient way to heck if bitmask contains enum flag

It would be nice to have a convenient way to check if the bitmask value contains enum flag, for example:

enum class AnimalFlags : std::uint64_t { None = 0, HasClaws = 1 << 0, CanFly = 1 << 1, EatsFish = 1 << 2, Endangered = 1 << 3 };
using namespace magic_enum::bitwise_operators;
AnimalFlags animal_mask = AnimalFlags::HasClaws | AnimalFlags::CanFly;
if (animal_mask & AnimalFlags::CanFly) // compiler error here
    std::cout << "This animal can fly!";

This won't compile because there's no auomatic enum class casting to bool or uint64_t, so it won't compile without proper casting or comparison against 0 enum value of the bitwise expression result:

if (static_cast<uint64_t>(animal_mask & AnimalFlags::CanFly))
    std::cout << "This animal can fly!";

or

if ((animal_mask & AnimalFlags::CanFly) != AnimalFlags::None)
    std::cout << "This animal can fly!";

Would it be possible to support this use-case out of the box and provide more convenient way to check that bitmask contains particular flag? Maybe add a helper function magic_enum::empty(mask), for example:

if (!magic_enum::empty(animal_mask & AnimalFlags::CanFly))
    std::cout << "This animal can fly!";

MAGIC_ENUM_SUPPORTED does not check clang or MSVC versions

According to the README, magic_enum is supported by clang >= 5 and MSVS 2017, but the check to set MAGIC_ENUM_SUPPORTED only checks the version number for gcc:

#if defined(__clang__) || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER)
#  undef  MAGIC_ENUM_SUPPORTED
#  define MAGIC_ENUM_SUPPORTED 1
#endif

Shouldn't this be

#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1910
#  undef  MAGIC_ENUM_SUPPORTED
#  define MAGIC_ENUM_SUPPORTED 1
#endif

Aliased enums behaving oddly

From the limitations, I see that aliases don't work, this would be fine, but I seem to be getting an odd case where the first-use of a value, is NOT the one used, furthermore, I'm getting 0x0 for a string, instead of the alias. (Either in my case would be fine, but not an empty string)

THEN, debugging in vs17, when I look at the strings table (which I guess is all the names baked into an array) my values START at 128 instead of 0
this is the enum https://github.com/SoylentGraham/SoyLib/blob/master/src/SoyPixels.h#L22
enum strings

I've been using this library for a while now without problems, even with this enum, so perhaps I've just missed this case, or in this particular code I'm using it in a strange way... (still investigating :)

Constexpr must be initialized by constant expression error VxWorks

Hello,

I am currently using C++17 with LLVM clang version 9.0.1.1 in a VxWorks environment and when I attempt to compile example/example.cpp I am prompted with (along with many other constexpr variables):

magic_enum.hpp:281:23: Error: constexpr variable 'values_v<Color>' must be initialized by a constant expression.
inline constexpr auto values_v = values<E>(std::make_integer_sequence<int, range_size<E, reflected_min_v<E>, reflected_max_v<E>>()>{});

I have the latest version of Magic_Enum and to my understanding, it's supposed to work with clang >=5.

Thank you very much for your work, please let me know if I can provide more info.

Is it necessary to add different conversion functions to enum?

Now we have

  1. std::optional<E> enum_cast(std::string_view value) noexcept
  2. std::optional<E> enum_cast(std::underlying_type_t<E> value) noexcept

Is it necessary to add the following functions? Will it be useful to someone?

  1. std::optional<E> enum_from_string_nothrow(std::string_view value) noexcept
  2. std::optional<E> enum_from_string_nocase_nothrow(std::string_view value) noexcept
  3. E enum_from_string(std::string_view value)
  4. E enum_from_string_nocase(std::string_view value)
  5. std::optional<E> enum_from_integral_nothrow(std::underlying_type_t<E> value) noexcept
  6. E enum_from_integral(std::underlying_type_t<E> value)
  7. E enum_from_integral_unchecked(std::underlying_type_t<E> value)
    See https://github.com/Neargye/magic_enum/tree/from_functions

Fail loud on exceeded range

Currently when my enum is to big for magic_enum and I use enum_name, empty string is returned.
It would be better if magic_enum detected it and threw exception instead.
It would be best if it instead refused to compile.
https://godbolt.org/z/TTMx1v

#include <iostream>
#include "https://raw.githubusercontent.com/Neargye/magic_enum/master/include/magic_enum.hpp"

enum class Color1 {
	RED = 0, BLUE = 4, GREEN = 800 // beyond standard range
};
enum class Color2 {
	RED = 0, BLUE = 4, GREEN = 800000 // beyond max range
};

int main() {
    std::cout <<"[" << magic_enum::enum_name(Color1::GREEN) <<"]" << std::endl;
    std::cout <<"[" << magic_enum::enum_name(Color2::GREEN) <<"]" << std::endl;
    return 0;
}

Prints

[]
[]

Should fail to compile or throw

Conan - magic_enum package is not easily reachable

The recipe given in the integration section of the README file to download the library using conan is not accurate:

"If you are using Conan to manage your dependencies, merely add magic_enum/x.y.z@neargye/stable to your conan's requires, where x.y.z is the release version you want to use."

The package is not available in conan-center, so nothing is found juste by following the previous steps.

To make it work, I had to add @Neargye's personal repository (found in this closed issue #3).

It would be great if the package is pushed to conan-center to make it easily accessible.

Feature Request: optimal_index_type -- smallest size data type able to represent all possible valid indexes of an enum

In order to limit memory required to access enum values, a convenience function to get the smallest datatype able to represent all valid indexes for an enum from uint8_t, uint16_t, uint32_t, and uint64_t would be nice.

SO has a relevant page: https://stackoverflow.com/questions/7038797/automatically-pick-a-variable-type-big-enough-to-hold-a-specified-number

C++ number standards: https://en.cppreference.com/w/cpp/types/integer

I could do this one, but figure I should ask before I submit a PR out of nowhere.

Support `c_str()` for compatibility with legacy C-Style APIs

Imagine a scenario like the below test. Because magic_enum returns a string_view, it is not compatible with C-style APIs.

Can we do anything to support legacy C-style code? The below code will result in a read buffer overflow as it'll keep reading past the end of the string until it hits a null terminator.

TEST("Read buffer overflow bug")
{
    enum class TestEnum
    {
        MODE_1,
        MODE_2
    };

    TestEnum test = TestEnum::MODE_2;
    auto name = magic_enum::enum_name(test);
    printf("%s", name.data());
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.