From aeb37e86cfcbfe76d35f60b7936d31f77db5ba83 Mon Sep 17 00:00:00 2001 From: neargye Date: Wed, 18 May 2022 17:34:03 +0400 Subject: [PATCH] add support for non-ASCII characters (UNIX/Linux) --- CMakeLists.txt | 1 + doc/reference.md | 6 +++++ example/CMakeLists.txt | 9 +++++++ example/example_nonascii_name.cpp | 44 +++++++++++++++++++++++++++++++ include/nameof.hpp | 18 ++++++++----- test/CMakeLists.txt | 8 ++++++ test/test.cpp | 15 +++++++++++ 7 files changed, 95 insertions(+), 6 deletions(-) create mode 100644 example/example_nonascii_name.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index af27a14..c1a2fbb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,7 @@ else() set(IS_TOPLEVEL_PROJECT FALSE) endif() +option(NAMEOF_OPT_ENABLE_NONASCII "Enable support for non-ASCII identifier" ${IS_TOPLEVEL_PROJECT}) option(NAMEOF_OPT_BUILD_EXAMPLES "Build nameof examples" ${IS_TOPLEVEL_PROJECT}) option(NAMEOF_OPT_BUILD_TESTS "Build and perform nameof tests" ${IS_TOPLEVEL_PROJECT}) option(NAMEOF_OPT_INSTALL "Generate and install nameof target" ${IS_TOPLEVEL_PROJECT}) diff --git a/doc/reference.md b/doc/reference.md index d0a1a28..b63d849 100644 --- a/doc/reference.md +++ b/doc/reference.md @@ -41,6 +41,12 @@ #include ``` +* To add support for non-ASCII enumeration identifier, use special macros: + ```cpp + #define NAMEOF_ENABLE_NONASCII + #include + ``` + ## `NAMEOF` * Obtains simple (unqualified) name of variable, function, macro. diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 2c6ca8e..f02db3a 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -19,3 +19,12 @@ endfunction() make_example(example) make_example(example_custom_name) + +if(NAMEOF_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() diff --git a/example/example_nonascii_name.cpp b/example/example_nonascii_name.cpp new file mode 100644 index 0000000..373707b --- /dev/null +++ b/example/example_nonascii_name.cpp @@ -0,0 +1,44 @@ +// Licensed under the MIT License . +// SPDX-License-Identifier: MIT +// Copyright (c) 2020 - 2022 Daniil Goncharov . +// +// 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 + +#include + +enum class Language : int { + 日本語 = 10, + 한국어 = 20, + English = 30, + 😃 = 40, +}; + +int main() { + std::cout << NAMEOF_ENUM(Language::日本語) << std::endl; // Japanese + std::cout << NAMEOF_ENUM(Language::한국어) << std::endl; // Korean + std::cout << NAMEOF_ENUM(Language::English) << std::endl; // English + std::cout << NAMEOF_ENUM(Language::😃) << std::endl; // Emoji + + int 😃 = 42; + std::cout << NAMEOF(😃) << std::endl; // Emoji + + return 0; +} diff --git a/include/nameof.hpp b/include/nameof.hpp index 4f143c8..790a800 100644 --- a/include/nameof.hpp +++ b/include/nameof.hpp @@ -449,6 +449,9 @@ constexpr string_view pretty_name(string_view name, bool remove_suffix = true) n 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(NAMEOF_ENABLE_NONASCII) + (name[i - 1] & 0x80) || +#endif (name[i - 1] == '_'))) { name.remove_prefix(i); break; @@ -460,6 +463,9 @@ constexpr string_view pretty_name(string_view name, bool remove_suffix = true) n if (name.size() > 0 && ((name.front() >= 'a' && name.front() <= 'z') || (name.front() >= 'A' && name.front() <= 'Z') || +#if defined(NAMEOF_ENABLE_NONASCII) + (name.front() & 0x80) || +#endif (name.front() == '_'))) { return name; } @@ -1084,18 +1090,18 @@ template // Obtains type name, reference and cv-qualifiers are ignored. #define NAMEOF_TYPE(...) ::nameof::nameof_type<__VA_ARGS__>() -// Obtains type name of expression, reference and cv-qualifiers are ignored. -#define NAMEOF_TYPE_EXPR(...) ::nameof::nameof_type() - // Obtains full type name, with reference and cv-qualifiers. #define NAMEOF_FULL_TYPE(...) ::nameof::nameof_full_type<__VA_ARGS__>() -// Obtains full type name of expression, with reference and cv-qualifiers. -#define NAMEOF_FULL_TYPE_EXPR(...) ::nameof::nameof_full_type() - // Obtains short type name. #define NAMEOF_SHORT_TYPE(...) ::nameof::nameof_short_type<__VA_ARGS__>() +// Obtains type name of expression, reference and cv-qualifiers are ignored. +#define NAMEOF_TYPE_EXPR(...) ::nameof::nameof_type() + +// Obtains full type name of expression, with reference and cv-qualifiers. +#define NAMEOF_FULL_TYPE_EXPR(...) ::nameof::nameof_full_type() + // Obtains short type name of expression. #define NAMEOF_SHORT_TYPE_EXPR(...) ::nameof::nameof_short_type() diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8be3ef8..4bae596 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -18,6 +18,14 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") check_cxx_compiler_flag(-std=c++20 HAS_CPP20_FLAG) endif() +if(NAMEOF_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 target std) add_executable(${target} ${SOURCES}) target_compile_options(${target} PRIVATE ${OPTIONS}) diff --git a/test/test.cpp b/test/test.cpp index a7d2d0a..aa00b51 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -99,6 +99,10 @@ enum class BigFlags : std::uint64_t { D = (static_cast(0x1) << 63), }; +#if defined(MAGIC_ENUM_ENABLE_NONASCII) +enum class Language : int { 日本語 = 10, 한국어 = 20, English = 30, 😃 = 40 }; +#endif + template <> struct nameof::customize::enum_range { static_assert(std::is_enum_v, "nameof::enum_range requires enum type."); @@ -380,6 +384,17 @@ TEST_CASE("NAMEOF_ENUM") { REQUIRE(nt_name == "three"); NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM(number::four).empty()); NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM(static_cast(0)).empty()); + +#if defined(MAGIC_ENUM_ENABLE_NONASCII) + constexpr Language lang = Language::日本語; + constexpr auto lang_name = NAMEOF_ENUM(lang); + Language lk = Language::한국어; + REQUIRE(NAMEOF_ENUM(lk) == "한국어"); + REQUIRE(NAMEOF_ENUM(Language::English) == "English"); + REQUIRE(lang_name == "日本語"); + REQUIRE(NAMEOF_ENUM(Language::😃) == "😃"); + REQUIRE(NAMEOF_ENUM(static_cast(0)).empty()); +#endif } TEST_CASE("NAMEOF_ENUM_CONST") {