AUI Framework  develop
Cross-platform base for C++ UI apps
Loading...
Searching...
No Matches
AEnumerate.h
    1/*
    2 * AUI Framework - Declarative UI toolkit for modern C++20
    3 * Copyright (C) 2020-2025 Alex2772 and Contributors
    4 *
    5 * SPDX-License-Identifier: MPL-2.0
    6 *
    7 * This Source Code Form is subject to the terms of the Mozilla Public
    8 * License, v. 2.0. If a copy of the MPL was not distributed with this
    9 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
   10 */
   11
   12//
   13// Created by alex2 on 6/24/2021.
   14//
   15
   16#pragma once
   17
   18#include <array>
   19#include <type_traits>
   20#include <AUI/Common/AString.h>
   21#include <AUI/Common/AMap.h>
   22#include <AUI/Traits/types.h>
   23#include <fmt/format.h>
   24
   25
   26//NOLINTBEGIN(modernize-*,cppcoreguidelines-macro-usage,bugprone-macro-parentheses)
   27
   28namespace aui::enumerate::basic {
   29    template<typename enum_t>
   30    struct ValueToName {
   31        template<enum_t value>
   32        static AString name() {
   33#if AUI_COMPILER_MSVC
   34            AString s = __FUNCSIG__;
   35        AString::iterator end = s.begin() + s.rfind('>');
   36        AString::iterator begin = (std::find_if(std::make_reverse_iterator(end), s.rend(), [](wchar_t c) {
   37            return c == ':' || c == '<';
   38        })).base();
   39
   40        AString result(begin, end);
   41#else
   42            AString s = __PRETTY_FUNCTION__;
   43#if AUI_COMPILER_CLANG
   44            auto end = s.rfind(']');
   45#else
   46            auto end = s.rfind(';');
   47#endif
   48            size_t begin = s.rfind("value =", end);
   49            if (begin == AString::NPOS) {
   50                begin = s.rfind('[', end) + 1;
   51            } else {
   52                begin += 8;
   53            }
   54            AString result = {s.begin() + begin, s.begin() + end};
   55
   56
   57            for (size_t p; (p = result.find("::")) != AString::NPOS;) {
   58                result = result.substr(p + 2);
   59            }
   60
   61#endif
   62            return result;
   63        }
   64    };
   65};
   66
   67namespace aui::enumerate {
   68    template<typename enum_t>
   69    struct ValueToName: basic::ValueToName<enum_t> {};
   70}
   71
   72
   78template<typename enum_t>
   80private:
   81    struct enum_less {
   82        constexpr bool operator()(enum_t l, enum_t r) const {
   83            return static_cast<std::underlying_type_t<enum_t>>(l) < static_cast<std::underlying_type_t<enum_t>>(r);
   84        }
   85    };
   86
   87public:
   88    static_assert(std::is_enum_v<enum_t>, "AEnumerate accepts only enums");
   89
   90    template<enum_t... values>
   91    struct Values {
   92
   93    };
   94
  102    template<enum_t value>
  103    static AString valueName() {
  104        return aui::enumerate::ValueToName<enum_t>::template name<value>();
  105    }
  106
  111    static const AMap<AString, enum_t>& nameToValueMap();
  112
  116    static const AMap<enum_t, AString, enum_less>& valueToNameMap();
  117
  121    static enum_t byName(const AString& name) {
  122        if (auto c = nameToValueMap().contains(name)) {
  123            return c->second;
  124        }
  125        if (auto c = nameToValueMap().contains(name.uppercase())) {
  126            return c->second;
  127        }
  128        throw AException("unknown enum value: \"{}\""_format(name));
  129    }
  130
  134    static const AString& toName(enum_t value) {
  135        if (auto c = valueToNameMap().contains(value)) {
  136            return c->second;
  137        }
  138        throw AException("unknown enum value: \"(int){}\""_format((std::underlying_type_t<enum_t>)value));
  139    }
  140
  141private:
  142    template<enum_t... values>
  143    static const AMap<AString, enum_t>& mapValueByName(const Values<values...>& v) {
  144        static AMap<AString, enum_t> map = {
  145            {valueName<values>(), values}...
  146        };
  147        return map;
  148    }
  149    template<enum_t... values>
  150    static const AMap<enum_t, AString, enum_less>& mapNameByValue(const Values<values...>& v) {
  151        static AMap<enum_t, AString, enum_less> map = {
  152            {values, valueName<values>() }...
  153        };
  154        return map;
  155    }
  156};
  157
  158template<typename enum_t>
  160
  161template<typename enum_t>
  163    static_assert(aui::is_complete<AEnumerateAllValues<enum_t>>, "AUI_ENUM_VALUES is not defined for this enum type");
  164    auto v = AEnumerateAllValues<enum_t>::get();
  165
  166    return mapValueByName(v);
  167}
  168
  169namespace aui::enumerate {
  175    template<typename enum_t> requires aui::is_complete<AEnumerateAllValues<enum_t>>
  176    inline constexpr auto ALL_VALUES = []<auto... values>(typename AEnumerate<enum_t>::template Values<values...>) {
  177        constexpr enum_t ITEMS[] = {values...};
  178        return std::to_array(ITEMS);
  180}
  181
  182template<typename enum_t>
  184    static_assert(aui::is_complete<AEnumerateAllValues<enum_t>>, "AUI_ENUM_VALUES is not defined for this enum type");
  185    auto v = AEnumerateAllValues<enum_t>::get();
  186
  187    return mapNameByValue(v);
  188}
  189
  208#define AUI_ENUM_VALUES(enum_t, ...) template<> \
  209struct AEnumerateAllValues<enum_t>{         \
  210    static inline constexpr AEnumerate<enum_t>::Values<__VA_ARGS__> get() {return {}; } \
  211};                                         \
  212namespace std { inline AString to_wstring(enum_t v) { return AEnumerate<enum_t>::valueToNameMap().optional(v).valueOr("<unknown enum value {}>"_format(int(v))); } } \
  213inline std::ostream& operator<<(std::ostream& o, enum_t v) { return o << std::to_wstring(v); }
  214
  215template <typename T> struct fmt::formatter<T, char, std::enable_if_t<aui::is_complete<AEnumerateAllValues<T>>>>: formatter<std::string> {
  216    // parse is inherited from formatter<string_view>.
  217    template <typename FormatContext>
  218    auto format(T c, FormatContext& ctx) const {
  219        return formatter<string_view>::format(AEnumerate<T>::valueToNameMap()[c].toStdString(), ctx);
  220    }
  221};
  222
  227#define AUI_ENUM_FLAG(name) enum class name: int; \
  228                            constexpr inline name operator|(name a, name b) {return static_cast<name>(static_cast<int>(a) | static_cast<int>(b));} \
  229                            constexpr inline name operator&(name a, name b) {return static_cast<name>(static_cast<int>(a) & static_cast<int>(b));} \
  230                            constexpr inline name operator^(name a, name b) {return static_cast<name>(static_cast<int>(a) ^ static_cast<int>(b));} \
  231                            constexpr inline name operator|=(name& a, name b) {return a = static_cast<name>(static_cast<int>(a) | static_cast<int>(b));} \
  232                            constexpr inline name operator&=(name& a, name b) {return a = static_cast<name>(static_cast<int>(a) & static_cast<int>(b));} \
  233                            constexpr inline name operator^=(name& a, name b) {return a = static_cast<name>(static_cast<int>(a) ^ static_cast<int>(b));} \
  234                            constexpr inline name operator~(const name& a) {return static_cast<name>(~static_cast<int>(a));} \
  235                            constexpr inline bool operator!(const name& a) {return a == static_cast<name>(0);}                                     \
  236                                                                   \
  237                            constexpr inline bool operator&&(const name& a, bool v) {return static_cast<int>(a) && v;}                                     \
  238                            constexpr inline bool operator||(const name& a, bool v) {return static_cast<int>(a) || v;}                                     \
  239\
  240                            enum class name: int
  241
  242#define AUI_ENUM_INT(name) enum class name: int; \
  243                           constexpr inline bool operator<(name a, name b) {return static_cast<int>(a) < static_cast<int>(b);} \
  244                           constexpr inline bool operator>(name a, name b) {return static_cast<int>(a) > static_cast<int>(b);} \
  245                           enum class name: int
  246
  247//NOLINTEND(modernize-*,cppcoreguidelines-macro-usage,bugprone-macro-parentheses)
Enum trait to transform enum to name, name to enum, list all enums and vise versa.
Definition AEnumerate.h:79
static const AMap< AString, enum_t > & nameToValueMap()
Get runtime name to enum value mapping.
Definition AEnumerate.h:162
static AString valueName()
Maps compile-time specified enum value to name.
Definition AEnumerate.h:103
static enum_t byName(const AString &name)
Map runtime name to enum value. Transforms name to uppercase as a fallback. Throws an exception if no...
Definition AEnumerate.h:121
static const AMap< enum_t, AString, enum_less > & valueToNameMap()
Map runtime enum value to name.
Definition AEnumerate.h:183
static const AString & toName(enum_t value)
Map runtime enum value to name. Throws an exception if no such value.
Definition AEnumerate.h:134
Abstract AUI exception.
Definition AException.h:28
A std::map with AUI extensions.
Definition AMap.h:218
Represents a Unicode character string.
Definition AString.h:38
constexpr auto ALL_VALUES
constexpr std::array of all possible enum values is the order they've been passed to AUI_ENUM_VALUES.
Definition AEnumerate.h:176
constexpr bool is_complete
Determines whether T is complete or not.
Definition types.h:23
Definition AEnumerate.h:159
Definition AEnumerate.h:91
Definition AEnumerate.h:69
Definition AEnumerate.h:30