1
0
Fork 0
mirror of https://github.com/Neargye/magic_enum.git synced 2026-01-09 23:34:23 +00:00

Added support for non-ASCII characters (UNIX/Linux) (#95)

This commit is contained in:
Komachin 2021-08-09 15:44:30 +01:00 committed by GitHub
parent 5d6e0e7707
commit 38f86e4d09
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 393 additions and 3 deletions

View file

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.14)
cmake_minimum_required(VERSION 3.14)
project(magic_enum VERSION "0.7.3" LANGUAGES CXX)
@ -8,6 +8,7 @@ else()
set(IS_TOPLEVEL_PROJECT FALSE)
endif()
option(MAGIC_ENUM_OPT_ENABLE_NONASCII "Enable support for non-ASCII enumeration identifier" ${IS_TOPLEVEL_PROJECT})
option(MAGIC_ENUM_OPT_BUILD_EXAMPLES "Build magic_enum examples" ${IS_TOPLEVEL_PROJECT})
option(MAGIC_ENUM_OPT_BUILD_TESTS "Build and perform magic_enum tests" ${IS_TOPLEVEL_PROJECT})
option(MAGIC_ENUM_OPT_INSTALL "Generate and install magic_enum target" ${IS_TOPLEVEL_PROJECT})

View file

@ -56,6 +56,12 @@
#define MAGIC_ENUM_RANGE_MAX 255
```
* To add support for non-ASCII enumeration identifier, use special macros:
```cpp
#define MAGIC_ENUM_ENABLE_NONASCII
#include <magic_enum.hpp>
```
## `enum_cast`
```cpp

View file

@ -1,4 +1,4 @@
include(CheckCXXCompilerFlag)
include(CheckCXXCompilerFlag)
if((CMAKE_CXX_COMPILER_ID MATCHES "GNU") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
set(OPTIONS -Wall -Wextra -pedantic-errors -Werror)
@ -20,3 +20,11 @@ endfunction()
make_example(example)
make_example(enum_flag_example)
make_example(example_custom_name)
if(MAGIC_ENUM_OPT_ENABLE_NONASCII)
if(((CMAKE_CXX_COMPILER_ID MATCHES "GNU") AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 10.0) OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
set(OPTIONS ${OPTIONS} -DMAGIC_ENUM_ENABLE_NONASCII)
make_example(example_nonascii_name)
elseif((CMAKE_CXX_COMPILER_ID MATCHES "MSVC"))
message(WARNING "Non-ASCII feature on Windows is not supported yet")
endif()
endif()

View file

@ -0,0 +1,44 @@
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
// SPDX-License-Identifier: MIT
// Copyright (c) 2020 - 2021 Uruha Komachin <uruhakomachin@gmail.com>.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <iostream>
#include <magic_enum.hpp>
enum class Language : int {
= 10,
= 20,
English = 30,
😃 = 40,
};
int main() {
std::cout << magic_enum::enum_name(Language::) << std::endl; // Japanese
std::cout << magic_enum::enum_name(Language::) << std::endl; // Korean
std::cout << magic_enum::enum_name(Language::English) << std::endl; // English
std::cout << magic_enum::enum_name(Language::😃) << std::endl; // Emoji
std::cout << std::boolalpha;
std::cout << (magic_enum::enum_cast<Language>("日本語").value() == Language::) << std::endl; // true
return 0;
}

View file

@ -202,6 +202,9 @@ constexpr string_view pretty_name(string_view name) noexcept {
if (!((name[i - 1] >= '0' && name[i - 1] <= '9') ||
(name[i - 1] >= 'a' && name[i - 1] <= 'z') ||
(name[i - 1] >= 'A' && name[i - 1] <= 'Z') ||
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
(name[i - 1] & 0x80) ||
#endif
(name[i - 1] == '_'))) {
name.remove_prefix(i);
break;
@ -210,6 +213,9 @@ constexpr string_view pretty_name(string_view name) noexcept {
if (name.size() > 0 && ((name.front() >= 'a' && name.front() <= 'z') ||
(name.front() >= 'A' && name.front() <= 'Z') ||
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
(name.front() & 0x80) ||
#endif
(name.front() == '_'))) {
return name;
}

View file

@ -1,4 +1,4 @@
include(CheckCXXCompilerFlag)
include(CheckCXXCompilerFlag)
set(SOURCES test.cpp)
@ -18,6 +18,14 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
check_cxx_compiler_flag(-std=c++20 HAS_CPP20_FLAG)
endif()
if(MAGIC_ENUM_OPT_ENABLE_NONASCII)
if(((CMAKE_CXX_COMPILER_ID MATCHES "GNU") AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 10.0) OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
set(OPTIONS ${OPTIONS} -DMAGIC_ENUM_ENABLE_NONASCII)
elseif((CMAKE_CXX_COMPILER_ID MATCHES "MSVC"))
message(WARNING "Non-ASCII feature on Windows is not supported yet")
endif()
endif()
function(make_test src target std)
add_executable(${target} ${src})
target_compile_options(${target} PRIVATE ${OPTIONS})

View file

@ -40,6 +40,10 @@ enum class Numbers : int { one = 1, two, three, many = 127 };
enum Directions { Up = 85, Down = -42, Right = 120, Left = -120 };
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
enum class Language : int { = 10, = 20, English = 30, 😃 = 40 };
#endif
enum number : unsigned long {
one = 100,
two = 200,
@ -121,6 +125,15 @@ TEST_CASE("enum_cast") {
REQUIRE(enum_cast<Directions>("Left").value() == Directions::Left);
REQUIRE_FALSE(enum_cast<Directions>("None").has_value());
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
constexpr auto lang = enum_cast<Language>("日本語");
REQUIRE(enum_cast<Language&>("한국어").value() == Language::);
REQUIRE(enum_cast<const Language>("English").value() == Language::English);
REQUIRE(lang.value() == Language::);
REQUIRE(enum_cast<Language>("😃").value() == Language::😃);
REQUIRE_FALSE(enum_cast<Language>("Französisch").has_value());
#endif
constexpr auto nt = enum_cast<number>("three");
REQUIRE(enum_cast<number>("one").value() == number::one);
REQUIRE(enum_cast<number>("two").value() == number::two);
@ -151,6 +164,15 @@ TEST_CASE("enum_cast") {
REQUIRE(enum_cast<Directions>(-120).value() == Directions::Left);
REQUIRE_FALSE(enum_cast<Directions>(0).has_value());
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
constexpr auto lang = enum_cast<Language>(10);
REQUIRE(enum_cast<Language&>(20).value() == Language::);
REQUIRE(enum_cast<const Language>(30).value() == Language::English);
REQUIRE(lang.value() == Language::);
REQUIRE(enum_cast<Language>(40).value() == Language::😃);
REQUIRE_FALSE(enum_cast<Language>(0).has_value());
#endif
constexpr auto nt = enum_cast<number>(300);
REQUIRE(enum_cast<number>(100).value() == number::one);
REQUIRE(enum_cast<number>(200).value() == number::two);
@ -184,6 +206,16 @@ TEST_CASE("enum_integer") {
REQUIRE(dr == 120);
REQUIRE(enum_integer(static_cast<Directions>(0)) == 0);
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
constexpr auto lang = enum_integer(Language::);
Language korean = Language::;
REQUIRE(enum_integer<Language&>(korean) == 20);
REQUIRE(enum_integer<const Language>(Language::English) == 30);
REQUIRE(enum_integer(Language::😃) == 40);
REQUIRE(lang == 10);
REQUIRE(enum_integer(static_cast<Language>(0)) == 0);
#endif
constexpr auto nt = enum_integer(number::three);
REQUIRE(enum_integer(number::one) == 100);
REQUIRE(enum_integer(number::two) == 200);
@ -216,6 +248,16 @@ TEST_CASE("enum_index") {
REQUIRE(dr.value() == 3);
REQUIRE_FALSE(enum_index(static_cast<Directions>(0)).has_value());
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
constexpr auto lang = enum_index<Language>(Language::);
Language korean = Language::;
REQUIRE(enum_index<Language&>(korean) == 1);
REQUIRE(enum_index<const Language>(Language::English).value() == 2);
REQUIRE(enum_index(Language::😃) == 3);
REQUIRE(lang.value() == 0);
REQUIRE_FALSE(enum_index(static_cast<Language>(0)).has_value());
#endif
constexpr auto nt = enum_index(number::three);
REQUIRE(enum_index(number::one).value() == 0);
REQUIRE(enum_index(number::two).value() == 1);
@ -249,6 +291,16 @@ TEST_CASE("enum_contains") {
REQUIRE(dr);
REQUIRE_FALSE(enum_contains(static_cast<Directions>(0)));
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
constexpr auto lang = enum_contains(Language::);
Language korean = Language::;
REQUIRE(enum_contains<Language&>(korean));
REQUIRE(enum_contains<const Language>(Language::English));
REQUIRE(enum_contains(Language::😃));
REQUIRE(lang);
REQUIRE_FALSE(enum_contains(static_cast<Directions>(0)));
#endif
constexpr auto nt = enum_contains(number::three);
REQUIRE(enum_contains(number::one));
REQUIRE(enum_contains<number&>(number::two));
@ -277,6 +329,14 @@ TEST_CASE("enum_contains") {
REQUIRE(enum_contains<Directions>(Directions::Up));
REQUIRE_FALSE(enum_contains<Directions>(static_cast<Directions>(0)));
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
constexpr auto lang = enum_integer(Language::);
REQUIRE(enum_contains<Language&>(lang));
REQUIRE(enum_contains<const Language>(Language::));
REQUIRE(enum_contains<Language>(Language::😃));
REQUIRE_FALSE(enum_contains<Language>(static_cast<Language>(0)));
#endif
constexpr auto nt = enum_contains<number>(number::three);
REQUIRE(enum_contains<number>(number::one));
REQUIRE(enum_contains<number>(100));
@ -310,6 +370,15 @@ TEST_CASE("enum_contains") {
REQUIRE(enum_contains<Directions>("Left"));
REQUIRE_FALSE(enum_contains<Directions>("None"));
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
auto lang = std::string{"日本語"};
REQUIRE(enum_contains<Language&>("한국어"));
REQUIRE(enum_contains<Language>("English"));
REQUIRE(enum_contains<const Language>(lang));
REQUIRE(enum_contains<Language>("😃"));
REQUIRE_FALSE(enum_contains<Language>("None"));
#endif
constexpr auto nt = enum_contains<number>("three");
REQUIRE(enum_contains<number>("one"));
REQUIRE(enum_contains<number>("two"));
@ -336,6 +405,14 @@ TEST_CASE("enum_value") {
REQUIRE(enum_value<Directions>(2) == Directions::Up);
REQUIRE(dr == Directions::Right);
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
constexpr auto lang = enum_value<Language>(3);
REQUIRE(enum_value<Language&>(0) == Language::);
REQUIRE(enum_value<const Language>(1) == Language::);
REQUIRE(enum_value<Language>(2) == Language::English);
REQUIRE(lang == Language::😃);
#endif
constexpr auto nt = enum_value<number>(2);
REQUIRE(enum_value<number>(0) == number::one);
REQUIRE(enum_value<number>(1) == number::two);
@ -362,6 +439,11 @@ TEST_CASE("enum_values") {
constexpr auto& s6 = enum_values<MaxUsedAsInvalid>();
REQUIRE(s6 == std::array<MaxUsedAsInvalid, 2>{{MaxUsedAsInvalid::ONE, MaxUsedAsInvalid::TWO}});
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
constexpr auto& s7 = enum_values<const Language>();
REQUIRE(s7 == std::array<Language, 4>{{Language::, Language::, Language::English, Language::😃}});
#endif
}
TEST_CASE("enum_count") {
@ -382,6 +464,11 @@ TEST_CASE("enum_count") {
constexpr auto s6 = enum_count<MaxUsedAsInvalid>();
REQUIRE(s6 == 2);
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
constexpr auto s7 = enum_count<Language>();
REQUIRE(s7 == 4);
#endif
}
TEST_CASE("enum_name") {
@ -412,6 +499,17 @@ TEST_CASE("enum_name") {
REQUIRE(enum_name(Directions::Left) == "Left");
REQUIRE(enum_name(static_cast<Directions>(0)).empty());
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
constexpr Language lang = Language::;
constexpr auto lang_name = enum_name(lang);
Language lk = Language::;
REQUIRE(enum_name<Language&>(lk) == "한국어");
REQUIRE(enum_name<const Language>(Language::English) == "English");
REQUIRE(lang_name == "日本語");
REQUIRE(enum_name(Language::😃) == "😃");
REQUIRE(enum_name(static_cast<Language>(0)).empty());
#endif
constexpr number nt = number::three;
constexpr auto nt_name = enum_name(nt);
REQUIRE(enum_name(number::one) == "one");
@ -443,6 +541,15 @@ TEST_CASE("enum_name") {
REQUIRE(dr_name == "Right");
REQUIRE(enum_name<Directions::Left>() == "Left");
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
constexpr Language lang = Language::;
constexpr auto lang_name = enum_name<lang>();
REQUIRE(enum_name<Language::>() == "한국어");
REQUIRE(enum_name<Language::English>() == "English");
REQUIRE(lang_name == "日本語");
REQUIRE(enum_name<Language::😃>() == "😃");
#endif
constexpr number nt = number::three;
constexpr auto nt_name = enum_name<nt>();
REQUIRE(enum_name<number::one>() == "one");
@ -469,6 +576,11 @@ TEST_CASE("enum_names") {
constexpr auto& s4 = enum_names<number>();
REQUIRE(s4 == std::array<std::string_view, 3>{{"one", "two", "three"}});
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
constexpr auto& s5 = enum_names<const Language>();
REQUIRE(s5 == std::array<std::string_view, 4>{{"日本語", "한국어", "English", "😃"}});
#endif
}
TEST_CASE("enum_entries") {
@ -485,6 +597,11 @@ TEST_CASE("enum_entries") {
constexpr auto& s4 = enum_entries<number>();
REQUIRE(s4 == std::array<std::pair<number, std::string_view>, 3>{{{number::one, "one"}, {number::two, "two"}, {number::three, "three"}}});
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
constexpr auto& s5 = enum_entries<const Language>();
REQUIRE(s5 == std::array<std::pair<Language, std::string_view>, 4>{{{Language::, "日本語"}, {Language::, "한국어"}, {Language::English, "English"}, {Language::😃, "😃"}}});
#endif
}
TEST_CASE("ostream_operators") {
@ -515,6 +632,15 @@ TEST_CASE("ostream_operators") {
test_ostream(static_cast<Directions>(0), "0");
test_ostream(std::make_optional(static_cast<Directions>(0)), "0");
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
test_ostream(std::make_optional(Language::), "日本語");
test_ostream(Language::, "한국어");
test_ostream(Language::English, "English");
test_ostream(Language::😃, "😃");
test_ostream(static_cast<Language>(0), "0");
test_ostream(std::make_optional(static_cast<Language>(0)), "0");
#endif
test_ostream(std::make_optional(number::one), "one");
test_ostream(number::two, "two");
test_ostream(number::three, "three");
@ -530,6 +656,9 @@ TEST_CASE("bitwise_operators") {
REQUIRE(enum_integer(~Color::RED) == ~enum_integer(Color::RED));
REQUIRE(enum_integer(~Numbers::one) == ~enum_integer(Numbers::one));
REQUIRE(enum_integer(~Directions::Up) == ~enum_integer(Directions::Up));
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
REQUIRE(enum_integer(~Language::) == ~enum_integer(Language::));
#endif
REQUIRE(enum_integer(~number::one) == ~enum_integer(number::one));
}
@ -537,6 +666,9 @@ TEST_CASE("bitwise_operators") {
REQUIRE(enum_integer(Color::RED | Color::BLUE) == (enum_integer(Color::RED) | enum_integer(Color::BLUE)));
REQUIRE(enum_integer(Numbers::one | Numbers::two) == (enum_integer(Numbers::one) | enum_integer(Numbers::two)));
REQUIRE(enum_integer(Directions::Up | Directions::Down) == (enum_integer(Directions::Up) | enum_integer(Directions::Down)));
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
REQUIRE(enum_integer(Language:: | Language::) == (enum_integer(Language::) | enum_integer(Language::)));
#endif
REQUIRE(enum_integer(number::one | number::two) == (enum_integer(number::one) | enum_integer(number::two)));
}
@ -544,6 +676,9 @@ TEST_CASE("bitwise_operators") {
REQUIRE(enum_integer(Color::RED & Color::BLUE) == (enum_integer(Color::RED) & enum_integer(Color::BLUE)));
REQUIRE(enum_integer(Numbers::one & Numbers::two) == (enum_integer(Numbers::one) & enum_integer(Numbers::two)));
REQUIRE(enum_integer(Directions::Up & Directions::Down) == (enum_integer(Directions::Up) & enum_integer(Directions::Down)));
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
REQUIRE(enum_integer(Language:: & Language::) == (enum_integer(Language::) & enum_integer(Language::)));
#endif
REQUIRE(enum_integer(number::one & number::two) == (enum_integer(number::one) & enum_integer(number::two)));
}
@ -551,6 +686,9 @@ TEST_CASE("bitwise_operators") {
REQUIRE(enum_integer(Color::RED ^ Color::BLUE) == (enum_integer(Color::RED) ^ enum_integer(Color::BLUE)));
REQUIRE(enum_integer(Numbers::one ^ Numbers::two) == (enum_integer(Numbers::one) ^ enum_integer(Numbers::two)));
REQUIRE(enum_integer(Directions::Up ^ Directions::Down) == (enum_integer(Directions::Up) ^ enum_integer(Directions::Down)));
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
REQUIRE(enum_integer(Language:: ^ Language::) == (enum_integer(Language::) ^ enum_integer(Language::)));
#endif
REQUIRE(enum_integer(number::one ^ number::two) == (enum_integer(number::one) ^ enum_integer(number::two)));
}
@ -570,6 +708,12 @@ TEST_CASE("bitwise_operators") {
number x4 = number::one;
x4 |= number::two;
REQUIRE(enum_integer(x4) == (enum_integer(number::one) | enum_integer(number::two)));
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
Language x5 = Language::;
x5 |= Language::;
REQUIRE(enum_integer(x5) == (enum_integer(Language::) | enum_integer(Language::)));
#endif
}
SECTION("operator&=") {
@ -588,6 +732,12 @@ TEST_CASE("bitwise_operators") {
number x4 = number::one;
x4 &= number::two;
REQUIRE(enum_integer(x4) == (enum_integer(number::one) & enum_integer(number::two)));
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
Language x5 = Language::;
x5 &= Language::;
REQUIRE(enum_integer(x5) == (enum_integer(Language::) & enum_integer(Language::)));
#endif
}
SECTION("operator^=") {
@ -606,6 +756,12 @@ TEST_CASE("bitwise_operators") {
number x4 = number::one;
x4 ^= number::two;
REQUIRE(enum_integer(x4) == (enum_integer(number::one) ^ enum_integer(number::two)));
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
Language x5 = Language::;
x5 ^= Language::;
REQUIRE(enum_integer(x5) == (enum_integer(Language::) ^ enum_integer(Language::)));
#endif
}
}
@ -613,6 +769,9 @@ TEST_CASE("type_traits") {
REQUIRE_FALSE(is_unscoped_enum_v<Color>);
REQUIRE_FALSE(is_unscoped_enum_v<Numbers>);
REQUIRE(is_unscoped_enum_v<Directions>);
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
REQUIRE_FALSE(is_unscoped_enum_v<Language>);
#endif
REQUIRE(is_unscoped_enum_v<number>);
REQUIRE(is_scoped_enum_v<Color>);
@ -625,6 +784,9 @@ TEST_CASE("enum_type_name") {
REQUIRE(enum_type_name<Color&>() == "Color");
REQUIRE(enum_type_name<const Numbers>() == "Numbers");
REQUIRE(enum_type_name<const Directions&>() == "Directions");
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
REQUIRE(enum_type_name<const Language&>() == "Language");
#endif
REQUIRE(enum_type_name<number>() == "number");
}
@ -683,6 +845,12 @@ TEST_CASE("extrema") {
REQUIRE(magic_enum::detail::reflected_min_v<Directions> == MAGIC_ENUM_RANGE_MIN);
REQUIRE(magic_enum::detail::min_v<Directions> == -120);
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
REQUIRE(magic_enum::customize::enum_range<Language>::min == MAGIC_ENUM_RANGE_MIN);
REQUIRE(magic_enum::detail::reflected_min_v<Language> == MAGIC_ENUM_RANGE_MIN);
REQUIRE(magic_enum::detail::min_v<Language> == 10);
#endif
REQUIRE(magic_enum::customize::enum_range<number>::min == 100);
REQUIRE(magic_enum::detail::reflected_min_v<number> == 100);
REQUIRE(magic_enum::detail::min_v<number> == 100);
@ -711,6 +879,12 @@ TEST_CASE("extrema") {
REQUIRE(magic_enum::detail::reflected_max_v<Directions> == MAGIC_ENUM_RANGE_MAX);
REQUIRE(magic_enum::detail::max_v<Directions> == 120);
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
REQUIRE(magic_enum::customize::enum_range<Language>::max == MAGIC_ENUM_RANGE_MAX);
REQUIRE(magic_enum::detail::reflected_max_v<Language> == MAGIC_ENUM_RANGE_MAX);
REQUIRE(magic_enum::detail::max_v<Language> == 40);
#endif
REQUIRE(magic_enum::customize::enum_range<number>::max == 300);
REQUIRE(magic_enum::detail::reflected_max_v<number> == 300);
REQUIRE(magic_enum::detail::max_v<number> == 300);

View file

@ -55,6 +55,15 @@ enum Directions : std::uint64_t {
Right = std::uint64_t{1} << 63,
};
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
enum class Language : int {
= 1 << 1,
= 1 << 2,
English = 1 << 3,
😃 = 1 << 4
};
#endif
enum number : unsigned long {
one = 1 << 1,
two = 1 << 2,
@ -106,6 +115,15 @@ TEST_CASE("enum_cast") {
REQUIRE(enum_cast<Directions>("Left").value() == Directions::Left);
REQUIRE_FALSE(enum_cast<Directions>("None").has_value());
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
constexpr auto lang = enum_cast<Language>("日本語");
REQUIRE(enum_cast<Language&>("한국어").value() == Language::);
REQUIRE(enum_cast<const Language>("English").value() == Language::English);
REQUIRE(lang.value() == Language::);
REQUIRE(enum_cast<Language>("😃").value() == Language::😃);
REQUIRE_FALSE(enum_cast<Language>("None").has_value());
#endif
constexpr auto nto = enum_cast<number>("three|one");
REQUIRE(enum_cast<number>("one").value() == number::one);
REQUIRE(enum_cast<number>("two").value() == number::two);
@ -141,6 +159,15 @@ TEST_CASE("enum_cast") {
REQUIRE(enum_cast<Directions>(std::uint64_t{1} << 10).value() == Directions::Left);
REQUIRE_FALSE(enum_cast<Directions>(0).has_value());
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
constexpr auto lang = enum_cast<Language>(1 << 1);
REQUIRE(enum_cast<Language&>(1 << 2).value() == Language::);
REQUIRE(enum_cast<const Language>(1 << 3).value() == Language::English);
REQUIRE(lang.value() == Language::);
REQUIRE(enum_cast<Language>(1 << 4).value() == Language::😃);
REQUIRE_FALSE(enum_cast<Language>(0).has_value());
#endif
constexpr auto nto = enum_cast<number>(2 | 8);
REQUIRE(enum_cast<number>(1 << 1).value() == number::one);
REQUIRE(enum_cast<number>(1 << 2).value() == number::two);
@ -178,6 +205,16 @@ TEST_CASE("enum_index") {
REQUIRE(dr.value() == 3);
REQUIRE_FALSE(enum_index(static_cast<Directions>(0)).has_value());
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
constexpr auto lang = enum_index<Language>(Language::);
Language korean = Language::;
REQUIRE(enum_index<Language&>(korean).value() == 1);
REQUIRE(enum_index<const Language>(Language::English).value() == 2);
REQUIRE(enum_index(Language::😃).value() == 3);
REQUIRE(lang.value() == 0);
REQUIRE_FALSE(enum_index(static_cast<Language>(0)).has_value());
#endif
constexpr auto nto = enum_index(number::three | number::one);
REQUIRE(enum_index(number::one).value() == 0);
REQUIRE(enum_index(number::two).value() == 1);
@ -215,6 +252,16 @@ TEST_CASE("enum_contains") {
REQUIRE(dr);
REQUIRE_FALSE(enum_contains(static_cast<Directions>(0)));
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
constexpr auto lang = enum_index<Language>(Language::);
Language korean = Language::;
REQUIRE(enum_contains<Language&>(korean));
REQUIRE(enum_contains<const Language>(Language::English));
REQUIRE(enum_contains(Language::😃));
REQUIRE(lang);
REQUIRE_FALSE(enum_contains(static_cast<Language>(0)));
#endif
constexpr auto nto = enum_contains(number::three | number::one);
REQUIRE(enum_contains(number::one));
REQUIRE(enum_contains<number&>(number::two));
@ -246,6 +293,15 @@ TEST_CASE("enum_contains") {
REQUIRE(enum_contains<Directions>(std::uint64_t{1} << 31));
REQUIRE_FALSE(enum_contains<Directions>(static_cast<Directions>(0)));
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
constexpr auto lang = enum_contains<Language&>(1 << 1);
REQUIRE(lang);
REQUIRE(enum_contains<const Language>(1 << 2));
REQUIRE(enum_contains<Language>(1 << 3));
REQUIRE(enum_contains<Language>(1 << 4));
REQUIRE_FALSE(enum_contains(static_cast<Language>(0)));
#endif
constexpr auto nto = enum_contains<number>(8 | 2);
REQUIRE(enum_contains<number>(1 << 1));
REQUIRE(enum_contains<number>(1 << 2));
@ -283,6 +339,15 @@ TEST_CASE("enum_contains") {
REQUIRE(enum_contains<Directions>("Left"));
REQUIRE_FALSE(enum_contains<Directions>("None"));
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
auto lang = std::string{"日本語"};
REQUIRE(enum_contains<Language&>("한국어"));
REQUIRE(enum_contains<Language>("English"));
REQUIRE(enum_contains<const Language>(lang));
REQUIRE(enum_contains<Language>("😃"));
REQUIRE_FALSE(enum_contains<Language>("None"));
#endif
constexpr auto nto = enum_contains<number>("three|one");
REQUIRE(enum_contains<number>("one"));
REQUIRE(enum_contains<number>("two"));
@ -311,6 +376,14 @@ TEST_CASE("enum_value") {
REQUIRE(enum_value<Directions>(2) == Directions::Up);
REQUIRE(dr == Directions::Right);
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
constexpr auto lang = enum_value<Language>(3);
REQUIRE(enum_value<Language&>(0) == Language::);
REQUIRE(enum_value<const Language>(1) == Language::);
REQUIRE(enum_value<Language>(2) == Language::English);
REQUIRE(lang == Language::😃);
#endif
constexpr auto nt = enum_value<number>(2);
REQUIRE(enum_value<number>(0) == number::one);
REQUIRE(enum_value<number>(1) == number::two);
@ -332,6 +405,11 @@ TEST_CASE("enum_values") {
constexpr auto& s4 = enum_values<number>();
REQUIRE(s4 == std::array<number, 4>{{number::one, number::two, number::three, number::four}});
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
constexpr auto& s5 = enum_values<const Language>();
REQUIRE(s5 == std::array<Language, 4>{{Language::, Language::, Language::English, Language::😃}});
#endif
}
TEST_CASE("enum_count") {
@ -346,6 +424,11 @@ TEST_CASE("enum_count") {
constexpr auto s4 = enum_count<number>();
REQUIRE(s4 == 4);
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
constexpr auto s5 = enum_count<Language>();
REQUIRE(s5 == 4);
#endif
}
TEST_CASE("enum_name") {
@ -381,6 +464,17 @@ TEST_CASE("enum_name") {
REQUIRE(enum_name(Directions::Right | Directions::Up | Directions::Left | Directions::Down) == "Left|Down|Up|Right");
REQUIRE(enum_name(static_cast<Directions>(0)).empty());
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
constexpr Language lang = Language::;
auto lang_name = enum_name(lang);
Language lk = Language::;
REQUIRE(enum_name<Language&>(lk) == "한국어");
REQUIRE(enum_name<const Language>(Language::English) == "English");
REQUIRE(lang_name == "日本語");
REQUIRE(enum_name(Language::😃) == "😃");
REQUIRE(enum_name(static_cast<Language>(0)).empty());
#endif
constexpr number nto = number::three | number::one;
auto nto_name = enum_name(nto);
REQUIRE(enum_name(number::one) == "one");
@ -406,6 +500,11 @@ TEST_CASE("enum_names") {
constexpr auto& s4 = enum_names<number>();
REQUIRE(s4 == std::array<std::string_view, 4>{{"one", "two", "three", "four"}});
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
constexpr auto& s5 = enum_names<const Language>();
REQUIRE(s5 == std::array<std::string_view, 4>{{"日本語", "한국어", "English", "😃"}});
#endif
}
TEST_CASE("enum_entries") {
@ -422,6 +521,11 @@ TEST_CASE("enum_entries") {
constexpr auto& s4 = enum_entries<number>();
REQUIRE(s4 == std::array<std::pair<number, std::string_view>, 4>{{{number::one, "one"}, {number::two, "two"}, {number::three, "three"}, {number::four, "four"}}});
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
constexpr auto& s5 = enum_entries<const Language>();
REQUIRE(s5 == std::array<std::pair<Language, std::string_view>, 4>{{{Language::, "日本語"}, {Language::, "한국어"}, {Language::English, "English"}, {Language::😃, "😃"}}});
#endif
}
TEST_CASE("ostream_operators") {
@ -455,6 +559,15 @@ TEST_CASE("ostream_operators") {
test_ostream(static_cast<Directions>(0), "0");
test_ostream(std::make_optional(static_cast<Directions>(0)), "0");
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
test_ostream(std::make_optional(Language::), "日本語");
test_ostream(Language::, "한국어");
test_ostream(Language::English, "English");
test_ostream(Language::😃, "😃");
test_ostream(static_cast<Language>(0), "0");
test_ostream(std::make_optional(static_cast<Language>(0)), "0");
#endif
test_ostream(std::make_optional(number::one), "one");
test_ostream(number::two, "two");
test_ostream(number::three, "three");
@ -469,6 +582,9 @@ TEST_CASE("bitwise_operators") {
REQUIRE(enum_integer(~Color::RED) == ~enum_integer(Color::RED));
REQUIRE(enum_integer(~Numbers::one) == ~enum_integer(Numbers::one));
REQUIRE(enum_integer(~Directions::Up) == ~enum_integer(Directions::Up));
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
REQUIRE(enum_integer(~Language::) == ~enum_integer(Language::));
#endif
REQUIRE(enum_integer(~number::one) == ~enum_integer(number::one));
}
@ -476,6 +592,9 @@ TEST_CASE("bitwise_operators") {
REQUIRE(enum_integer(Color::RED | Color::BLUE) == (enum_integer(Color::RED) | enum_integer(Color::BLUE)));
REQUIRE(enum_integer(Numbers::one | Numbers::two) == (enum_integer(Numbers::one) | enum_integer(Numbers::two)));
REQUIRE(enum_integer(Directions::Up | Directions::Down) == (enum_integer(Directions::Up) | enum_integer(Directions::Down)));
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
REQUIRE(enum_integer(Language:: | Language::) == (enum_integer(Language::) | enum_integer(Language::)));
#endif
REQUIRE(enum_integer(number::one | number::two) == (enum_integer(number::one) | enum_integer(number::two)));
}
@ -483,6 +602,9 @@ TEST_CASE("bitwise_operators") {
REQUIRE(enum_integer(Color::RED & Color::BLUE) == (enum_integer(Color::RED) & enum_integer(Color::BLUE)));
REQUIRE(enum_integer(Numbers::one & Numbers::two) == (enum_integer(Numbers::one) & enum_integer(Numbers::two)));
REQUIRE(enum_integer(Directions::Up & Directions::Down) == (enum_integer(Directions::Up) & enum_integer(Directions::Down)));
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
REQUIRE(enum_integer(Language:: & Language::) == (enum_integer(Language::) & enum_integer(Language::)));
#endif
REQUIRE(enum_integer(number::one & number::two) == (enum_integer(number::one) & enum_integer(number::two)));
}
@ -490,6 +612,9 @@ TEST_CASE("bitwise_operators") {
REQUIRE(enum_integer(Color::RED ^ Color::BLUE) == (enum_integer(Color::RED) ^ enum_integer(Color::BLUE)));
REQUIRE(enum_integer(Numbers::one ^ Numbers::two) == (enum_integer(Numbers::one) ^ enum_integer(Numbers::two)));
REQUIRE(enum_integer(Directions::Up ^ Directions::Down) == (enum_integer(Directions::Up) ^ enum_integer(Directions::Down)));
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
REQUIRE(enum_integer(Language:: ^ Language::) == (enum_integer(Language::) ^ enum_integer(Language::)));
#endif
REQUIRE(enum_integer(number::one ^ number::two) == (enum_integer(number::one) ^ enum_integer(number::two)));
}
@ -509,6 +634,12 @@ TEST_CASE("bitwise_operators") {
number x4 = number::one;
x4 |= number::two;
REQUIRE(enum_integer(x4) == (enum_integer(number::one) | enum_integer(number::two)));
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
Language x5 = Language::;
x5 |= Language::;
REQUIRE(enum_integer(x5) == (enum_integer(Language::) | enum_integer(Language::)));
#endif
}
SECTION("operator&=") {
@ -527,6 +658,12 @@ TEST_CASE("bitwise_operators") {
number x4 = number::one;
x4 &= number::two;
REQUIRE(enum_integer(x4) == (enum_integer(number::one) & enum_integer(number::two)));
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
Language x5 = Language::;
x5 &= Language::;
REQUIRE(enum_integer(x5) == (enum_integer(Language::) & enum_integer(Language::)));
#endif
}
SECTION("operator^=") {
@ -545,5 +682,11 @@ TEST_CASE("bitwise_operators") {
number x4 = number::one;
x4 ^= number::two;
REQUIRE(enum_integer(x4) == (enum_integer(number::one) ^ enum_integer(number::two)));
#if defined(MAGIC_ENUM_ENABLE_NONASCII)
Language x5 = Language::;
x5 ^= Language::;
REQUIRE(enum_integer(x5) == (enum_integer(Language::) ^ enum_integer(Language::)));
#endif
}
}