Git Product home page Git Product logo

Comments (2)

Neargye avatar Neargye commented on June 26, 2024

I would rather suggest you make your own namespaces with the necessary overloads

This is a quick example

namespace magic_enum8 {
  template <typename E>
  std::u8string enum_name(E v) {
    std::u8string str;
    auto n = magic_enum::enum_name<E>(v);
    str.reserve(n.size());
    for (auto c : n)
      str.append(1, c);
    return str;
  }
}

namespace magic_enum16 {
  template <typename E>
  std::u16string enum_name(E v) {
    std::u16string str;
    auto n = magic_enum::enum_name<E>(v);
    str.reserve(n.size());
    for (auto c : n)
      str.append(1, c);
    return str;
  }
}

from magic_enum.

Nerixyz avatar Nerixyz commented on June 26, 2024

Thank you, I made a small adaption for Qt's QString and QStringView. It only supports Latin1 characters, but that shouldn't really be a limitation in practice. It's mostly constexpr except for getting QStrings. Should work on both Qt 6 and 5 (only tested on 6 right now).

Adaptation

We have different naming conventions, but that shouldn't be an issue.
It's using is_nothrow_invocable, enum_subtype, subtype_v, and enable_if_t from magic_enum::detail.

#include <magic_enum.hpp>
#include <QString>
#include <QStringView>

namespace qmagicenum {

namespace detail {

    template <std::size_t N>
    consteval QStringView fromArray(const std::array<char16_t, N> &arr)
    {
        return QStringView{arr.data(),
                           static_cast<QStringView::size_type>(N - 1)};
    }

    // Only the latin1 subset may be used right now, since it's easily convertible
    template <std::size_t N>
    consteval bool isLatin1(std::string_view maybe)
    {
        for (std::size_t i = 0; i < N; i++)
        {
            if (maybe[i] < 0x20 || maybe[i] > 0x7e)
            {
                return false;
            }
        }
        return true;
    }

    template <typename BinaryPredicate>
    inline constexpr bool eq(
        QStringView a, QStringView b,
        [[maybe_unused]] BinaryPredicate
            &&p) noexcept(magic_enum::detail::
                              is_nothrow_invocable<BinaryPredicate>())
    {
        // Note: operator== isn't constexpr
        if (a.size() != b.size())
        {
            return false;
        }

        for (QStringView::size_type i = 0; i < a.size(); i++)
        {
            if (!p(a[i], b[i]))
            {
                return false;
            }
        }

        return true;
    }

    template <typename C, typename E, E V>
    consteval auto enumNameStorage()
    {
        constexpr auto utf8 = magic_enum::enum_name<V>();

        static_assert(isLatin1<utf8.size()>(utf8),
                      "Can't convert non-latin1 UTF8 to UTF16");

        std::array<C, utf8.size() + 1> storage;
        for (std::size_t i = 0; i < utf8.size(); i++)
        {
            storage[i] = static_cast<C>(utf8[i]);
        }
        storage[utf8.size()] = 0;
        return storage;
    }

    template <typename E, 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>
    consteval auto namesStorage(std::index_sequence<I...> /*unused*/)
    {
        return std::array<QStringView, sizeof...(I)>{{detail::fromArray(
            ENUM_NAME_STORAGE<E, magic_enum::enum_values<E, S>()[I]>)...}};
    }

    template <typename E, magic_enum::detail::enum_subtype S =
                              magic_enum::detail::subtype_v<E>>
    inline constexpr auto NAMES_STORAGE = namesStorage<E, S>(
        std::make_index_sequence<magic_enum::enum_count<E, S>()>{});

}  // namespace detail

/// @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 magic_enum::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 magic_enum::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 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. The returned string is static.
template <auto V>
[[nodiscard]] inline magic_enum::detail::enable_if_t<decltype(V), QString>
    enumNameString() noexcept
{
    constexpr auto view = enumName<V>();
    return QString(QStringPrivate(nullptr, const_cast<char16_t *>(view.utf16()),
                                  view.size()));
}

/// @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. 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 <typename E,
          magic_enum::detail::enum_subtype S = magic_enum::detail::subtype_v<E>>
[[nodiscard]] inline magic_enum::detail::enable_if_t<E, QString> enumNameString(
    E value) noexcept
{
    using D = std::decay_t<E>;

    auto view = enumName<D, S>(value);
    return QString(QStringPrivate(nullptr, const_cast<char16_t *>(view.utf16()),
                                  view.size()));
}

/// @brief Gets the enum value from a name
///
/// @tparam E The enum type to parse the @a name as
/// @param name The name of the enum value to parse
/// @param p A predicate to compare characters of a string
///          (defaults to std::equal_to)
/// @returns A `std::optional` of the parsed value. If no value was parsed,
///          `std::nullopt` is returned.
template <typename E,
          magic_enum::detail::enum_subtype S = magic_enum::detail::subtype_v<E>,
          typename BinaryPredicate = std::equal_to<>>
[[nodiscard]] constexpr magic_enum::detail::enable_if_t<
    E, std::optional<std::decay_t<E>>, BinaryPredicate>
    enumCast(QStringView name,
             [[maybe_unused]] BinaryPredicate p =
                 {}) noexcept(magic_enum::detail::
                                  is_nothrow_invocable<BinaryPredicate>())
{
    using D = std::decay_t<E>;

    if constexpr (magic_enum::enum_count<D, S>() == 0)
    {
        static_cast<void>(name);
        return std::nullopt;  // Empty enum.
    }

    for (std::size_t i = 0; i < magic_enum::enum_count<D, S>(); i++)
    {
        if (detail::eq(name, detail::NAMES_STORAGE<D, S>[i], p))
        {
            return magic_enum::enum_value<D, S>(i);
        }
    }
    return std::nullopt;  // Invalid value or out of range.
}

/// @brief Constructs a name from the @a flags
///
/// @param flags The combined flags to construct the name from
/// @param sep A separator between each flag (defaults to u'|')
/// @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
///          is returned.
template <typename E>
[[nodiscard]] inline magic_enum::detail::enable_if_t<E, QString> enumFlagsName(
    E flags, char16_t sep = u'|')
{
    using D = std::decay_t<E>;
    using U = std::underlying_type_t<D>;
    constexpr auto S = magic_enum::detail::enum_subtype::flags;  // NOLINT

    QString name;
    auto checkValue = U{0};
    for (std::size_t i = 0; i < magic_enum::enum_count<D, S>(); ++i)
    {
        const auto v = static_cast<U>(magic_enum::enum_value<D, S>(i));
        if ((static_cast<U>(flags) & v) != 0)
        {
            const auto n = detail::NAMES_STORAGE<D, S>[i];
            if (!n.empty())
            {
                checkValue |= v;
                if (!name.isEmpty())
                {
                    name.append(sep);
                }
                name.append(n);
            }
            else
            {
                return {};  // Value out of range.
            }
        }
    }

    if (checkValue != 0 && checkValue == static_cast<U>(flags))
    {
        return name;
    }
    return {};  // Invalid value or out of range.
}

}  // namespace qmagicenum

from magic_enum.

Related Issues (20)

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.