plugify 1.2.8
Loading...
Searching...
No Matches
enum.hpp
1#pragma once
2
3#include <algorithm>
4#include <array>
5#include <cstdio>
6#include <iostream>
7#include <string_view>
8
9#include "plg/config.hpp"
10
11// from
12// https://web.archive.org/web/20230212183620/https://blog.rink.nu/2023/02/12/behind-the-magic-of-magic_enum/
13namespace plg {
14 constexpr auto ENUM_MIN_VALUE = -128;
15 constexpr auto ENUM_MAX_VALUE = 128;
16
17 template <std::size_t N>
19 constexpr static_string(std::string_view sv) noexcept {
20 std::copy(sv.begin(), sv.end(), content_.begin());
21 }
22
23 constexpr operator std::string_view() const noexcept {
24 return { content_.data(), N };
25 }
26
27 private:
28 std::array<char, N + 1> content_{};
29 };
30
31 constexpr auto is_pretty(char ch) noexcept {
32 return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
33 }
34
35 constexpr auto pretty_name(std::string_view sv) noexcept {
36 for (std::size_t n = sv.size() - 1; n > 0; --n) {
37 if (!is_pretty(sv[n])) {
38 sv.remove_prefix(n + 1);
39 break;
40 }
41 }
42 return sv;
43 }
44
45 template <typename E, E V>
46 constexpr auto n() noexcept {
47#if PLUGIFY_COMPILER_GCC || PLUGIFY_COMPILER_CLANG
48 return pretty_name({ __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2 });
49#elif PLUGIFY_COMPILER_MSVC
50 return pretty_name({ __FUNCSIG__, sizeof(__FUNCSIG__) - 17 });
51#endif
52 }
53
54 template <typename E, E V>
55 constexpr auto is_valid() {
56 [[maybe_unused]] constexpr E v = static_cast<E>(V);
57 return !n<E, V>().empty();
58 }
59
60 template <typename E>
61 constexpr auto value(std::size_t v) {
62 return static_cast<E>(ENUM_MIN_VALUE + static_cast<int>(v));
63 }
64
65 template <std::size_t N>
66 constexpr auto count_values(const bool (&valid)[N]) {
67 std::size_t count = 0;
68 for (std::size_t n = 0; n < N; ++n) {
69 if (valid[n]) {
70 ++count;
71 }
72 }
73 return count;
74 }
75
76 template <typename E, std::size_t... I>
77 constexpr auto values(std::index_sequence<I...>) noexcept {
78 constexpr bool valid[sizeof...(I)] = { is_valid<E, value<E>(I)>()... };
79 constexpr auto num_valid = count_values(valid);
80 static_assert(num_valid > 0, "no support for empty enums");
81
82 std::array<E, num_valid> values = {};
83 for (std::size_t offset = 0, n = 0; n < num_valid; ++offset) {
84 if (valid[offset]) {
85 values[n] = value<E>(offset);
86 ++n;
87 }
88 }
89
90 return values;
91 }
92
93 template <typename E>
94 constexpr auto values() noexcept {
95 constexpr auto enum_size = ENUM_MAX_VALUE - ENUM_MIN_VALUE + 1;
96 return values<E>(std::make_index_sequence<enum_size>({}));
97 }
98
99 template <typename E>
100 inline constexpr auto values_v = values<E>();
101
102 template <typename E, E V>
103 constexpr auto enum_name() {
104 constexpr auto name = n<E, V>();
105 return static_string<name.size()>(name);
106 }
107
108 template <typename E, E V>
109 inline constexpr auto enum_name_v = enum_name<E, V>();
110
111 template <typename E, std::size_t... I>
112 constexpr auto entries(std::index_sequence<I...>) noexcept {
113 return std::array<std::pair<E, std::string_view>, sizeof...(I)>{
114 { { values_v<E>[I], enum_name_v<E, values_v<E>[I]> }... }
115 };
116 }
117
118 template <typename E>
119 inline constexpr auto entries_v = entries<E>(std::make_index_sequence<values_v<E>.size()>());
120
121 template <typename E>
122 constexpr std::string_view enum_to_string(E value) {
123 for (const auto& [key, name] : entries_v<E>) {
124 if (value == key) {
125 return name;
126 }
127 }
128 return {};
129 }
130}