enum_name
Loading...
Searching...
No Matches
enum_name_impl.hpp
1/*
2MIT License
3
4Copyright (c) 2024 mguludag
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#ifndef MGUTILITY_REFLECTION_DETAIL_ENUM_NAME_IMPL_HPP
26#define MGUTILITY_REFLECTION_DETAIL_ENUM_NAME_IMPL_HPP
27
28#include "enum_for_each.hpp"
29#include "meta.hpp"
30#include "mgutility/std/optional.hpp"
31#include "mgutility/std/string_view.hpp"
32
33#include <algorithm>
34#include <array>
35
41#if defined(_MSC_VER) && _MSC_VER < 1910
42#error "Requires MSVC 2017 or newer!"
48#elif defined(__clang__) && __clang_major__ < 6
49#error "Requires clang 6 or newer!"
55#elif defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 9
56#error "Requires gcc 9 or newer!"
62#elif !defined(_MSC_VER) && !defined(__clang__) && !defined(__GNUC__)
63#error "Your compiler is not supported!"
64#endif
65
71#ifdef _MSC_VER
72#define __PRETTY_FUNCTION__ __FUNCSIG__
73#endif
74
75namespace mgutility {
76namespace detail {
77
78struct enum_type {
86 template <
87 typename Enum, Enum e,
88 detail::enable_if_t<!detail::is_scoped_enum<Enum>::value, bool> = true>
89 MGUTILITY_CNSTXPR static auto name() noexcept -> mgutility::string_view {
91 if (pair.first == e) {
92 return pair.second;
93 }
94 }
95 MGUTILITY_CNSTXPR auto str = mgutility::string_view(__PRETTY_FUNCTION__);
96 MGUTILITY_CNSTXPR auto offset = lastidxenumname[0] + lastidxenumname[1];
97 MGUTILITY_CNSTXPR auto index =
98 std::max(str.rfind(lastidxenumname[2], str.size() - offset),
99 str.rfind(lastidxenumname[3], str.size() - offset));
100 MGUTILITY_CNSTXPR auto result =
101 str.substr(index + 1, str.size() - offset - index);
102 return result[0] == '(' ? "" : result;
103 }
104
112 template <
113 typename Enum, Enum e,
114 detail::enable_if_t<detail::is_scoped_enum<Enum>::value, bool> = true>
115 MGUTILITY_CNSTXPR static auto name() noexcept -> mgutility::string_view {
117 if (pair.first == e) {
118 return pair.second;
119 }
120 }
121 MGUTILITY_CNSTXPR auto str = mgutility::string_view(__PRETTY_FUNCTION__);
122 MGUTILITY_CNSTXPR auto index =
123 str.rfind(lastidxenumname[3], str.size() - lastidxenumname[0]) + 1;
124 MGUTILITY_CNSTXPR auto result =
125 str.substr(index, str.size() - lastidxenumname[0] - index);
126 MGUTILITY_CNSTXPR auto is_invalid =
127 result.rfind(lastidxenumname[5]) != result.npos || (result.size() > 4 && result[4] == lastidxenumname[4]);
128 return is_invalid ? "" : result;
129 }
130
131private:
132 static constexpr int lastidxenumname[] =
133#if defined(__clang__)
134 {1, 1, ' ', ':', '(',
135#if __clang_major__ < 13
136 ','
137#else
138 ')'
139#endif
140 };
141#elif defined(_MSC_VER)
142 {21, 0, ',', ':', '<', ')'};
143#elif defined(__GNUC__)
144 {
145#if MGUTILITY_CPLUSPLUS < 201703L
146 163,
147#else
148 157,
149#endif
150 5, ' ', ':', '(', ')'};
151#endif
152};
153
161template <typename Enum, Enum... Is>
162MGUTILITY_CNSTXPR inline auto
163get_enum_array(detail::enum_sequence<Enum, Is...> /*unused*/) noexcept
164 -> std::array<mgutility::string_view, sizeof...(Is) + 1> {
165 return std::array<mgutility::string_view, sizeof...(Is) + 1>{
166 "", enum_type::template name<Enum, Is>()...};
167}
168
177template <typename Enum, int Min = mgutility::enum_range<Enum>::min,
179MGUTILITY_CNSTXPR inline auto get_enum_array() noexcept
180 -> std::array<mgutility::string_view, Max - Min + 1> {
181 return get_enum_array<Enum>(detail::make_enum_sequence<Enum, Min, Max>());
182}
183
193template <typename Enum, int Min, int Max>
194MGUTILITY_CNSTXPR inline auto to_enum_impl(mgutility::string_view str) noexcept
196 MGUTILITY_CNSTXPR_CLANG_WA auto arr = get_enum_array<Enum, Min, Max>();
197 const auto index{std::find(arr.begin() + 1, arr.end(), str)};
198 return index == arr.end() ? mgutility::nullopt
199 : mgutility::optional<Enum>{static_cast<Enum>(
200 std::distance(arr.begin(), index) + Min - 1)};
201}
202
212template <typename Enum, int Min, int Max>
213MGUTILITY_CNSTXPR auto to_enum_bitmask_impl(mgutility::string_view str) noexcept
215
216 // Check if the string contains a '|' character
217 if (str.find('|') == mgutility::string_view::npos) {
218 return to_enum_impl<Enum, Min, Max>(str);
219 }
220
222 std::size_t index = 0;
223
224 for (std::size_t i = 0; i < str.size(); ++i) {
225 if (str[i] == '|') {
226 auto name = str.substr(index, i - index);
227 auto maybe_enum = to_enum_impl<Enum, Min, Max>(name);
228
229 if (!name.empty() && maybe_enum) {
230 result.emplace(result ? static_cast<Enum>(*result | *maybe_enum)
231 : *maybe_enum);
232 }
233
234 index = i + 1;
235 }
236 }
237
238 auto maybe_enum = to_enum_impl<Enum, Min, Max>(str.substr(index));
239 if (result && maybe_enum) {
240 result.emplace(static_cast<Enum>(*result | *maybe_enum));
241 } else {
242 result.reset();
243 }
244
245 return result;
246}
247
257template <typename Enum, int Min, int Max,
258 detail::enable_if_t<!detail::has_bit_or<Enum>::value, bool> = true>
259MGUTILITY_CNSTXPR auto enum_name_impl(Enum e) noexcept
261 MGUTILITY_CNSTXPR auto arr = get_enum_array<Enum, Min, Max>();
262 const auto index{(Min < 0 ? -Min : Min) + static_cast<int>(e) + 1};
263 return arr[(index < Min || index > arr.size() - 1) ? 0 : index];
264}
265
276template <typename Enum, int Min, int Max,
277 detail::enable_if_t<detail::has_bit_or<Enum>::value, bool> = true>
278MGUTILITY_CNSTXPR_CLANG_WA inline auto enum_name_impl(Enum e) noexcept
279 -> detail::string_or_view_t<Enum> {
280
281 // Get the array of enum names
282 MGUTILITY_CNSTXPR_CLANG_WA auto arr = get_enum_array<Enum, Min, Max>();
283
284 // Calculate the index in the array
285 const auto index = (Min < 0 ? -Min : Min) + static_cast<int>(e) + 1;
286 const auto name =
287 arr[(index < Min || index >= static_cast<int>(arr.size())) ? 0 : index];
288
289 // Lambda to check if a character is a digit
290 const auto is_digit = [](char c) { return c >= '0' && c <= '9'; };
291
292 // Return the name if it's valid
293 if (!name.empty() && !is_digit(name[0])) {
294 return std::string{name};
295 }
296
297 // Construct bitmasked name
298 std::string bitmasked_name;
299 for (auto i = Min; i < Max; ++i) {
300 const auto idx = (Min < 0 ? -Min : Min) + i + 1;
301 if (idx >= 0 && idx < static_cast<int>(arr.size()) && !arr[idx].empty() &&
302 !is_digit(arr[idx][0]) &&
303 (e & static_cast<Enum>(i)) == static_cast<Enum>(i)) {
304 bitmasked_name.append(arr[idx]).append("|");
305 }
306 }
307
308 // Remove the trailing '|' if present
309 if (!bitmasked_name.empty()) {
310 bitmasked_name.pop_back();
311 }
312
313 if (bitmasked_name.find('|') != std::string::npos) {
314 return bitmasked_name;
315 }
316 return std::string{""};
317}
318} // namespace detail
319} // namespace mgutility
320
321#endif // MGUTILITY_REFLECTION_DETAIL_ENUM_NAME_IMPL_HPP
A basic string view class template.
Definition string_view.hpp:57
A class template that provides optional (nullable) objects.
Definition optional.hpp:60
#define MGUTILITY_CNSTXPR_CLANG_WA
Defines the MGUTILITY_CNSTXPR macro based on the C++ standard.
Definition definitions.hpp:70
Checks for MSVC compiler version.
Definition enum_for_each.hpp:34
auto nullopt
A global instance of nullopt_t to represent null optional.
Definition optional.hpp:316
Provides the custom names map for an enumeration type.
Definition meta.hpp:178
Definition enum_name_impl.hpp:78
static MGUTILITY_CNSTXPR auto name() noexcept -> mgutility::string_view
Gets the name of an unscoped enum value.
Definition enum_name_impl.hpp:89
Provides the range for an enumeration type.
Definition meta.hpp:156
Definition meta.hpp:161