chore: cleanup some parts of qmagicenum (#5587)
This commit is contained in:
@@ -85,6 +85,7 @@
|
|||||||
- Dev: Refactored `MessageBuilder` to be a single class. (#5548)
|
- Dev: Refactored `MessageBuilder` to be a single class. (#5548)
|
||||||
- Dev: Recent changes are now shown in the nightly release description. (#5553, #5554)
|
- 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: 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
|
## 2.5.1
|
||||||
|
|
||||||
|
|||||||
+91
-100
@@ -4,23 +4,30 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringView>
|
#include <QStringView>
|
||||||
|
|
||||||
|
#include <concepts>
|
||||||
|
|
||||||
namespace chatterino::qmagicenum::detail {
|
namespace chatterino::qmagicenum::detail {
|
||||||
|
|
||||||
template <bool, typename R>
|
template <typename T, typename U>
|
||||||
struct EnableIfEnum {
|
concept DecaysTo = std::same_as<std::decay_t<T>, U>;
|
||||||
};
|
|
||||||
|
|
||||||
template <typename R>
|
template <typename T>
|
||||||
struct EnableIfEnum<true, R> {
|
concept IsEnum = std::is_enum_v<T>;
|
||||||
using type = R;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T, typename R, typename BinaryPredicate = std::equal_to<>,
|
template <typename BinaryPredicate>
|
||||||
typename D = std::decay_t<T>>
|
consteval bool isDefaultPredicate() noexcept
|
||||||
using enable_if_t = typename EnableIfEnum<
|
{
|
||||||
std::is_enum_v<D> &&
|
return std::is_same_v<std::decay_t<BinaryPredicate>,
|
||||||
std::is_invocable_r_v<bool, BinaryPredicate, QChar, QChar>,
|
std::equal_to<QChar>> ||
|
||||||
R>::type;
|
std::is_same_v<std::decay_t<BinaryPredicate>, std::equal_to<>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename BinaryPredicate>
|
||||||
|
consteval bool isNothrowInvocable()
|
||||||
|
{
|
||||||
|
return isDefaultPredicate<BinaryPredicate>() ||
|
||||||
|
std::is_nothrow_invocable_r_v<bool, BinaryPredicate, QChar, QChar>;
|
||||||
|
}
|
||||||
|
|
||||||
template <std::size_t N>
|
template <std::size_t N>
|
||||||
consteval QStringView fromArray(const std::array<char16_t, N> &arr)
|
consteval QStringView fromArray(const std::array<char16_t, N> &arr)
|
||||||
@@ -43,12 +50,12 @@ consteval bool isLatin1(std::string_view maybe)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename BinaryPredicate>
|
template <typename BinaryPredicate>
|
||||||
inline constexpr bool eq(
|
constexpr bool eq(
|
||||||
QStringView a, QStringView b,
|
QStringView a, QStringView b,
|
||||||
[[maybe_unused]] BinaryPredicate &&
|
[[maybe_unused]] BinaryPredicate &&
|
||||||
p) noexcept(magic_enum::detail::is_nothrow_invocable<BinaryPredicate>())
|
p) noexcept(magic_enum::detail::is_nothrow_invocable<BinaryPredicate>())
|
||||||
{
|
{
|
||||||
// Note: operator== isn't constexpr
|
// Note: QStringView::operator== isn't constexpr
|
||||||
if (a.size() != b.size())
|
if (a.size() != b.size())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -82,24 +89,22 @@ consteval auto enumNameStorage()
|
|||||||
return storage;
|
return storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This contains a std::array<char16_t> for each enum value (V) with the
|
||||||
|
/// corresponding name.
|
||||||
template <typename E, E V>
|
template <typename E, E V>
|
||||||
inline constexpr auto ENUM_NAME_STORAGE = enumNameStorage<char16_t, E, V>();
|
inline constexpr auto ENUM_NAME_STORAGE = enumNameStorage<char16_t, E, V>();
|
||||||
|
|
||||||
template <typename E, magic_enum::detail::enum_subtype S, std::size_t... I>
|
template <typename E, std::size_t... I>
|
||||||
consteval auto namesStorage(std::index_sequence<I...> /*unused*/)
|
consteval auto namesStorage(std::index_sequence<I...> /*unused*/)
|
||||||
{
|
{
|
||||||
return std::array<QStringView, sizeof...(I)>{{detail::fromArray(
|
return std::array<QStringView, sizeof...(I)>{{detail::fromArray(
|
||||||
ENUM_NAME_STORAGE<E, magic_enum::enum_values<E, S>()[I]>)...}};
|
ENUM_NAME_STORAGE<E, magic_enum::enum_values<E>()[I]>)...}};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename E,
|
/// This contains a std::array<QStringView> for each enum (E).
|
||||||
magic_enum::detail::enum_subtype S = magic_enum::detail::subtype_v<E>>
|
template <typename E>
|
||||||
inline constexpr auto NAMES_STORAGE = namesStorage<E, S>(
|
inline constexpr auto NAMES_STORAGE =
|
||||||
std::make_index_sequence<magic_enum::enum_count<E, S>()>{});
|
namesStorage<E>(std::make_index_sequence<magic_enum::enum_count<E>()>{});
|
||||||
|
|
||||||
template <typename E, magic_enum::detail::enum_subtype S,
|
|
||||||
typename D = std::decay_t<E>>
|
|
||||||
using NamesStorage = decltype((NAMES_STORAGE<D, S>));
|
|
||||||
|
|
||||||
template <typename Op = std::equal_to<>>
|
template <typename Op = std::equal_to<>>
|
||||||
class CaseInsensitive
|
class CaseInsensitive
|
||||||
@@ -112,53 +117,13 @@ class CaseInsensitive
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template <typename L, typename R>
|
template <DecaysTo<QChar> L, DecaysTo<QChar> R>
|
||||||
constexpr std::enable_if_t<std::is_same_v<std::decay_t<L>, QChar> &&
|
constexpr bool operator()(L lhs, R rhs) const noexcept
|
||||||
std::is_same_v<std::decay_t<R>, QChar>,
|
|
||||||
bool>
|
|
||||||
operator()(L lhs, R rhs) const noexcept
|
|
||||||
{
|
{
|
||||||
return Op{}(toLower(lhs), toLower(rhs));
|
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 <auto V>
|
|
||||||
[[nodiscard]] consteval detail::enable_if_t<decltype(V), QStringView>
|
|
||||||
enumName() noexcept
|
|
||||||
{
|
|
||||||
return QStringView{
|
|
||||||
detail::fromArray(detail::ENUM_NAME_STORAGE<decltype(V), V>)};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @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 <typename E,
|
|
||||||
magic_enum::detail::enum_subtype S = magic_enum::detail::subtype_v<E>>
|
|
||||||
[[nodiscard]] constexpr detail::enable_if_t<E, QStringView> enumName(
|
|
||||||
E value) noexcept
|
|
||||||
{
|
|
||||||
using D = std::decay_t<E>;
|
|
||||||
|
|
||||||
if (const auto i = magic_enum::enum_index<D, S>(value))
|
|
||||||
{
|
|
||||||
return detail::NAMES_STORAGE<D, S>[*i];
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief Gets a static QString from @a view.
|
/// @brief Gets a static QString from @a view.
|
||||||
///
|
///
|
||||||
/// @pre @a view must be a static string view (i.e. it must be valid throughout
|
/// @pre @a view must be a static string view (i.e. it must be valid throughout
|
||||||
@@ -180,6 +145,40 @@ template <typename E,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
} // 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 <detail::IsEnum auto V>
|
||||||
|
[[nodiscard]] consteval QStringView enumName() noexcept
|
||||||
|
{
|
||||||
|
return QStringView{
|
||||||
|
detail::fromArray(detail::ENUM_NAME_STORAGE<decltype(V), V>)};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @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 <detail::IsEnum E>
|
||||||
|
[[nodiscard]] constexpr QStringView enumName(E value) noexcept
|
||||||
|
{
|
||||||
|
using D = std::decay_t<E>;
|
||||||
|
|
||||||
|
if (const auto i = magic_enum::enum_index<D>(value))
|
||||||
|
{
|
||||||
|
return detail::NAMES_STORAGE<D>[*i];
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief Get the name of an enum value
|
/// @brief Get the name of an enum value
|
||||||
///
|
///
|
||||||
/// This version is much lighter on the compile times and is not restricted to
|
/// This version is much lighter on the compile times and is not restricted to
|
||||||
@@ -187,11 +186,10 @@ template <typename E,
|
|||||||
///
|
///
|
||||||
/// @tparam V The enum value
|
/// @tparam V The enum value
|
||||||
/// @returns The name as a string. The returned string is static.
|
/// @returns The name as a string. The returned string is static.
|
||||||
template <auto V>
|
template <detail::IsEnum auto V>
|
||||||
[[nodiscard]] inline detail::enable_if_t<decltype(V), QString>
|
[[nodiscard]] inline QString enumNameString() noexcept
|
||||||
enumNameString() noexcept
|
|
||||||
{
|
{
|
||||||
return staticString(enumName<V>());
|
return detail::staticString(enumName<V>());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Get the name of an enum value
|
/// @brief Get the name of an enum value
|
||||||
@@ -203,14 +201,12 @@ template <auto V>
|
|||||||
/// @returns The name as a string. If @a value does not have name or the
|
/// @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.
|
/// value is out of range an empty string is returned.
|
||||||
/// The returned string is static.
|
/// The returned string is static.
|
||||||
template <typename E,
|
template <detail::IsEnum E>
|
||||||
magic_enum::detail::enum_subtype S = magic_enum::detail::subtype_v<E>>
|
[[nodiscard]] inline QString enumNameString(E value) noexcept
|
||||||
[[nodiscard]] inline detail::enable_if_t<E, QString> enumNameString(
|
|
||||||
E value) noexcept
|
|
||||||
{
|
{
|
||||||
using D = std::decay_t<E>;
|
using D = std::decay_t<E>;
|
||||||
|
|
||||||
return staticString(enumName<D, S>(value));
|
return detail::staticString(enumName<D>(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Gets the enum value from a name
|
/// @brief Gets the enum value from a name
|
||||||
@@ -221,29 +217,25 @@ template <typename E,
|
|||||||
/// (defaults to std::equal_to)
|
/// (defaults to std::equal_to)
|
||||||
/// @returns A `std::optional` of the parsed value. If no value was parsed,
|
/// @returns A `std::optional` of the parsed value. If no value was parsed,
|
||||||
/// `std::nullopt` is returned.
|
/// `std::nullopt` is returned.
|
||||||
template <typename E,
|
template <detail::IsEnum E, typename BinaryPredicate = std::equal_to<>>
|
||||||
magic_enum::detail::enum_subtype S = magic_enum::detail::subtype_v<E>,
|
[[nodiscard]] constexpr std::optional<std::decay_t<E>>
|
||||||
typename BinaryPredicate = std::equal_to<>>
|
enumCast(QStringView name, BinaryPredicate p = {}) noexcept(
|
||||||
[[nodiscard]] constexpr detail::enable_if_t<E, std::optional<std::decay_t<E>>,
|
detail::isNothrowInvocable<BinaryPredicate>())
|
||||||
BinaryPredicate>
|
requires std::is_invocable_r_v<bool, BinaryPredicate, QChar, QChar>
|
||||||
enumCast(QStringView name,
|
|
||||||
[[maybe_unused]] BinaryPredicate p =
|
|
||||||
{}) noexcept(magic_enum::detail::
|
|
||||||
is_nothrow_invocable<BinaryPredicate>())
|
|
||||||
{
|
{
|
||||||
using D = std::decay_t<E>;
|
using D = std::decay_t<E>;
|
||||||
|
|
||||||
if constexpr (magic_enum::enum_count<D, S>() == 0)
|
if constexpr (magic_enum::enum_count<D>() == 0)
|
||||||
{
|
{
|
||||||
static_cast<void>(name);
|
static_cast<void>(name);
|
||||||
return std::nullopt; // Empty enum.
|
return std::nullopt; // Empty enum.
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::size_t i = 0; i < magic_enum::enum_count<D, S>(); i++)
|
for (std::size_t i = 0; i < magic_enum::enum_count<D>(); i++)
|
||||||
{
|
{
|
||||||
if (detail::eq(name, detail::NAMES_STORAGE<D, S>[i], p))
|
if (detail::eq(name, detail::NAMES_STORAGE<D>[i], p))
|
||||||
{
|
{
|
||||||
return magic_enum::enum_value<D, S>(i);
|
return magic_enum::enum_value<D>(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return std::nullopt; // Invalid value or out of range.
|
return std::nullopt; // Invalid value or out of range.
|
||||||
@@ -256,22 +248,23 @@ template <typename E,
|
|||||||
/// @returns A string containing all names separated by @a sep. If any flag in
|
/// @returns A string containing all names separated by @a sep. If any flag in
|
||||||
/// @a flags is out of rage or does not have a name, an empty string
|
/// @a flags is out of rage or does not have a name, an empty string
|
||||||
/// is returned.
|
/// is returned.
|
||||||
template <typename E>
|
template <detail::IsEnum E>
|
||||||
[[nodiscard]] inline detail::enable_if_t<E, QString> enumFlagsName(
|
[[nodiscard]] inline QString enumFlagsName(E flags, char16_t sep = u'|')
|
||||||
E flags, char16_t sep = u'|')
|
|
||||||
{
|
{
|
||||||
using D = std::decay_t<E>;
|
using D = std::decay_t<E>;
|
||||||
using U = std::underlying_type_t<D>;
|
using U = std::underlying_type_t<D>;
|
||||||
constexpr auto S = magic_enum::detail::enum_subtype::flags; // NOLINT
|
static_assert(magic_enum::detail::subtype_v<E> ==
|
||||||
|
magic_enum::detail::enum_subtype::flags,
|
||||||
|
"enumFlagsName used for non-flags enum");
|
||||||
|
|
||||||
QString name;
|
QString name;
|
||||||
auto checkValue = U{0};
|
auto checkValue = U{0};
|
||||||
for (std::size_t i = 0; i < magic_enum::enum_count<D, S>(); ++i)
|
for (std::size_t i = 0; i < magic_enum::enum_count<D>(); ++i)
|
||||||
{
|
{
|
||||||
const auto v = static_cast<U>(magic_enum::enum_value<D, S>(i));
|
const auto v = static_cast<U>(magic_enum::enum_value<D>(i));
|
||||||
if ((static_cast<U>(flags) & v) != 0)
|
if ((static_cast<U>(flags) & v) != 0)
|
||||||
{
|
{
|
||||||
const auto n = detail::NAMES_STORAGE<D, S>[i];
|
const auto n = detail::NAMES_STORAGE<D>[i];
|
||||||
if (!n.empty())
|
if (!n.empty())
|
||||||
{
|
{
|
||||||
checkValue |= v;
|
checkValue |= v;
|
||||||
@@ -299,12 +292,10 @@ template <typename E>
|
|||||||
///
|
///
|
||||||
/// @tparam E The enum type
|
/// @tparam E The enum type
|
||||||
/// @returns A `std::array` of all names (`QStringView`s)
|
/// @returns A `std::array` of all names (`QStringView`s)
|
||||||
template <typename E,
|
template <detail::IsEnum E>
|
||||||
magic_enum::detail::enum_subtype S = magic_enum::detail::subtype_v<E>>
|
|
||||||
[[nodiscard]] constexpr auto enumNames() noexcept
|
[[nodiscard]] constexpr auto enumNames() noexcept
|
||||||
-> detail::enable_if_t<E, detail::NamesStorage<E, S>>
|
|
||||||
{
|
{
|
||||||
return detail::NAMES_STORAGE<std::decay_t<E>, S>;
|
return detail::NAMES_STORAGE<std::decay_t<E>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allows you to write qmagicenum::enumCast<foo>("bar", qmagicenum::CASE_INSENSITIVE)
|
/// Allows you to write qmagicenum::enumCast<foo>("bar", qmagicenum::CASE_INSENSITIVE)
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ enum class MyFlag {
|
|||||||
Two = 2,
|
Two = 2,
|
||||||
Four = 4,
|
Four = 4,
|
||||||
Eight = 8,
|
Eight = 8,
|
||||||
|
TwoPow9 = 512,
|
||||||
|
TwoPow10 = 1024,
|
||||||
};
|
};
|
||||||
using MyFlags = chatterino::FlagsEnum<MyFlag>;
|
using MyFlags = chatterino::FlagsEnum<MyFlag>;
|
||||||
|
|
||||||
@@ -130,7 +132,8 @@ TEST(QMagicEnum, flags)
|
|||||||
static_assert(checkConst(MyFlag::Eight, u"Eight"));
|
static_assert(checkConst(MyFlag::Eight, u"Eight"));
|
||||||
static_assert(checkConst(MyFlag::Eight, u"Eight"));
|
static_assert(checkConst(MyFlag::Eight, u"Eight"));
|
||||||
static_assert(eq(enumName(static_cast<MyFlag>(16)), u""));
|
static_assert(eq(enumName(static_cast<MyFlag>(16)), u""));
|
||||||
static_assert(checkValues<MyFlag>({u"One", u"Two", u"Four", u"Eight"}));
|
static_assert(checkValues<MyFlag>(
|
||||||
|
{u"One", u"Two", u"Four", u"Eight", u"TwoPow9", u"TwoPow10"}));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(QMagicEnum, enumNameString)
|
TEST(QMagicEnum, enumNameString)
|
||||||
|
|||||||
Reference in New Issue
Block a user