From 2afa2271399a6a7f7eca01e7a97ee459bd94ba3d Mon Sep 17 00:00:00 2001 From: nerix Date: Mon, 9 Sep 2024 19:16:36 +0200 Subject: [PATCH] chore: cleanup some parts of qmagicenum (#5587) --- CHANGELOG.md | 1 + src/util/QMagicEnum.hpp | 191 +++++++++++++++++++-------------------- tests/src/QMagicEnum.cpp | 5 +- 3 files changed, 96 insertions(+), 101 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff3d55259..11cd23378 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -85,6 +85,7 @@ - Dev: Refactored `MessageBuilder` to be a single class. (#5548) - Dev: Recent changes are now shown in the nightly release description. (#5553, #5554) - Dev: The timer for `StreamerMode` is now destroyed on the correct thread. (#5571) +- Dev: Cleanup some parts of the `magic_enum` adaptation for Qt. (#5587) ## 2.5.1 diff --git a/src/util/QMagicEnum.hpp b/src/util/QMagicEnum.hpp index 0325102e3..2e1d7a730 100644 --- a/src/util/QMagicEnum.hpp +++ b/src/util/QMagicEnum.hpp @@ -4,23 +4,30 @@ #include #include +#include + namespace chatterino::qmagicenum::detail { -template -struct EnableIfEnum { -}; +template +concept DecaysTo = std::same_as, U>; -template -struct EnableIfEnum { - using type = R; -}; +template +concept IsEnum = std::is_enum_v; -template , - typename D = std::decay_t> -using enable_if_t = typename EnableIfEnum< - std::is_enum_v && - std::is_invocable_r_v, - R>::type; +template +consteval bool isDefaultPredicate() noexcept +{ + return std::is_same_v, + std::equal_to> || + std::is_same_v, std::equal_to<>>; +} + +template +consteval bool isNothrowInvocable() +{ + return isDefaultPredicate() || + std::is_nothrow_invocable_r_v; +} template consteval QStringView fromArray(const std::array &arr) @@ -43,12 +50,12 @@ consteval bool isLatin1(std::string_view maybe) } template -inline constexpr bool eq( +constexpr bool eq( QStringView a, QStringView b, [[maybe_unused]] BinaryPredicate && p) noexcept(magic_enum::detail::is_nothrow_invocable()) { - // Note: operator== isn't constexpr + // Note: QStringView::operator== isn't constexpr if (a.size() != b.size()) { return false; @@ -82,24 +89,22 @@ consteval auto enumNameStorage() return storage; } +/// This contains a std::array for each enum value (V) with the +/// corresponding name. template inline constexpr auto ENUM_NAME_STORAGE = enumNameStorage(); -template +template consteval auto namesStorage(std::index_sequence /*unused*/) { return std::array{{detail::fromArray( - ENUM_NAME_STORAGE()[I]>)...}}; + ENUM_NAME_STORAGE()[I]>)...}}; } -template > -inline constexpr auto NAMES_STORAGE = namesStorage( - std::make_index_sequence()>{}); - -template > -using NamesStorage = decltype((NAMES_STORAGE)); +/// This contains a std::array for each enum (E). +template +inline constexpr auto NAMES_STORAGE = + namesStorage(std::make_index_sequence()>{}); template > class CaseInsensitive @@ -112,53 +117,13 @@ class CaseInsensitive } public: - template - constexpr std::enable_if_t, QChar> && - std::is_same_v, QChar>, - bool> - operator()(L lhs, R rhs) const noexcept + template L, DecaysTo R> + constexpr bool operator()(L lhs, R rhs) const noexcept { return Op{}(toLower(lhs), toLower(rhs)); } }; -} // namespace chatterino::qmagicenum::detail - -namespace chatterino::qmagicenum { - -/// @brief Get the name of an enum value -/// -/// This version is much lighter on the compile times and is not restricted to the enum_range limitation. -/// -/// @tparam V The enum value -/// @returns The name as a string view -template -[[nodiscard]] consteval detail::enable_if_t - enumName() noexcept -{ - return QStringView{ - detail::fromArray(detail::ENUM_NAME_STORAGE)}; -} - -/// @brief Get the name of an enum value -/// -/// @param value The enum value -/// @returns The name as a string view. If @a value does not have name or the -/// value is out of range an empty string is returned. -template > -[[nodiscard]] constexpr detail::enable_if_t enumName( - E value) noexcept -{ - using D = std::decay_t; - - if (const auto i = magic_enum::enum_index(value)) - { - return detail::NAMES_STORAGE[*i]; - } - return {}; -} - /// @brief Gets a static QString from @a view. /// /// @pre @a view must be a static string view (i.e. it must be valid throughout @@ -180,6 +145,40 @@ template +[[nodiscard]] consteval QStringView enumName() noexcept +{ + return QStringView{ + detail::fromArray(detail::ENUM_NAME_STORAGE)}; +} + +/// @brief Get the name of an enum value +/// +/// @param value The enum value +/// @returns The name as a string view. If @a value does not have name or the +/// value is out of range an empty string is returned. +template +[[nodiscard]] constexpr QStringView enumName(E value) noexcept +{ + using D = std::decay_t; + + if (const auto i = magic_enum::enum_index(value)) + { + return detail::NAMES_STORAGE[*i]; + } + return {}; +} + /// @brief Get the name of an enum value /// /// This version is much lighter on the compile times and is not restricted to @@ -187,11 +186,10 @@ template -[[nodiscard]] inline detail::enable_if_t - enumNameString() noexcept +template +[[nodiscard]] inline QString enumNameString() noexcept { - return staticString(enumName()); + return detail::staticString(enumName()); } /// @brief Get the name of an enum value @@ -203,14 +201,12 @@ template /// @returns The name as a string. If @a value does not have name or the /// value is out of range an empty string is returned. /// The returned string is static. -template > -[[nodiscard]] inline detail::enable_if_t enumNameString( - E value) noexcept +template +[[nodiscard]] inline QString enumNameString(E value) noexcept { using D = std::decay_t; - return staticString(enumName(value)); + return detail::staticString(enumName(value)); } /// @brief Gets the enum value from a name @@ -221,29 +217,25 @@ template , - typename BinaryPredicate = std::equal_to<>> -[[nodiscard]] constexpr detail::enable_if_t>, - BinaryPredicate> - enumCast(QStringView name, - [[maybe_unused]] BinaryPredicate p = - {}) noexcept(magic_enum::detail:: - is_nothrow_invocable()) +template > +[[nodiscard]] constexpr std::optional> + enumCast(QStringView name, BinaryPredicate p = {}) noexcept( + detail::isNothrowInvocable()) + requires std::is_invocable_r_v { using D = std::decay_t; - if constexpr (magic_enum::enum_count() == 0) + if constexpr (magic_enum::enum_count() == 0) { static_cast(name); return std::nullopt; // Empty enum. } - for (std::size_t i = 0; i < magic_enum::enum_count(); i++) + for (std::size_t i = 0; i < magic_enum::enum_count(); i++) { - if (detail::eq(name, detail::NAMES_STORAGE[i], p)) + if (detail::eq(name, detail::NAMES_STORAGE[i], p)) { - return magic_enum::enum_value(i); + return magic_enum::enum_value(i); } } return std::nullopt; // Invalid value or out of range. @@ -256,22 +248,23 @@ template -[[nodiscard]] inline detail::enable_if_t enumFlagsName( - E flags, char16_t sep = u'|') +template +[[nodiscard]] inline QString enumFlagsName(E flags, char16_t sep = u'|') { using D = std::decay_t; using U = std::underlying_type_t; - constexpr auto S = magic_enum::detail::enum_subtype::flags; // NOLINT + static_assert(magic_enum::detail::subtype_v == + magic_enum::detail::enum_subtype::flags, + "enumFlagsName used for non-flags enum"); QString name; auto checkValue = U{0}; - for (std::size_t i = 0; i < magic_enum::enum_count(); ++i) + for (std::size_t i = 0; i < magic_enum::enum_count(); ++i) { - const auto v = static_cast(magic_enum::enum_value(i)); + const auto v = static_cast(magic_enum::enum_value(i)); if ((static_cast(flags) & v) != 0) { - const auto n = detail::NAMES_STORAGE[i]; + const auto n = detail::NAMES_STORAGE[i]; if (!n.empty()) { checkValue |= v; @@ -299,12 +292,10 @@ template /// /// @tparam E The enum type /// @returns A `std::array` of all names (`QStringView`s) -template > +template [[nodiscard]] constexpr auto enumNames() noexcept - -> detail::enable_if_t> { - return detail::NAMES_STORAGE, S>; + return detail::NAMES_STORAGE>; } /// Allows you to write qmagicenum::enumCast("bar", qmagicenum::CASE_INSENSITIVE) diff --git a/tests/src/QMagicEnum.cpp b/tests/src/QMagicEnum.cpp index 6778427fe..17acc9863 100644 --- a/tests/src/QMagicEnum.cpp +++ b/tests/src/QMagicEnum.cpp @@ -27,6 +27,8 @@ enum class MyFlag { Two = 2, Four = 4, Eight = 8, + TwoPow9 = 512, + TwoPow10 = 1024, }; using MyFlags = chatterino::FlagsEnum; @@ -130,7 +132,8 @@ TEST(QMagicEnum, flags) static_assert(checkConst(MyFlag::Eight, u"Eight")); static_assert(checkConst(MyFlag::Eight, u"Eight")); static_assert(eq(enumName(static_cast(16)), u"")); - static_assert(checkValues({u"One", u"Two", u"Four", u"Eight"})); + static_assert(checkValues( + {u"One", u"Two", u"Four", u"Eight", u"TwoPow9", u"TwoPow10"})); } TEST(QMagicEnum, enumNameString)