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// NOLINTNEXTLINE [unused-includes]
29#include "enum_for_each.hpp"
30#include "meta.hpp"
31#include "mgutility/_common/definitions.hpp"
32#include "mgutility/std/optional.hpp"
33#include "mgutility/std/string_view.hpp"
34
35#include <algorithm>
36#include <array>
37
43#if defined(_MSC_VER) && _MSC_VER < 1910
44#error "Requires MSVC 2017 or newer!"
50#elif defined(__clang__) && __clang_major__ < 6
51#error "Requires clang 6 or newer!"
57#elif defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 9
58#error "Requires gcc 9 or newer!"
64#elif !defined(_MSC_VER) && !defined(__clang__) && !defined(__GNUC__)
65#error "Your compiler is not supported!"
66#endif
67
73#ifdef _MSC_VER
74#define __PRETTY_FUNCTION__ __FUNCSIG__
75#endif
76
77// NOLINTNEXTLINE [modernize-concat-nested-namespaces]
78namespace mgutility {
79namespace detail {
80
81struct enum_type {
89 template <
90 typename Enum, Enum e,
91 detail::enable_if_t<!detail::is_scoped_enum<Enum>::value, bool> = true>
92 MGUTILITY_CNSTXPR static auto name() noexcept -> mgutility::string_view {
93 for (const auto &pair : mgutility::custom_enum<Enum>::map) {
94 if (pair.first == e) {
95 return pair.second;
96 }
97 }
98 MGUTILITY_CNSTXPR auto str = mgutility::string_view(__PRETTY_FUNCTION__);
99 MGUTILITY_CNSTXPR auto offset = lastidxenumname[0] + lastidxenumname[1];
100 MGUTILITY_CNSTXPR auto index =
101 std::max(str.rfind(lastidxenumname[2], str.size() - offset),
102 str.rfind(lastidxenumname[3], str.size() - offset));
103 MGUTILITY_CNSTXPR auto result =
104 str.substr(index + 1, str.size() - offset - index);
105 return result[0] == '(' ? "" : result;
106 }
107
115 template <
116 typename Enum, Enum e,
117 detail::enable_if_t<detail::is_scoped_enum<Enum>::value, bool> = true>
118 MGUTILITY_CNSTXPR static auto name() noexcept -> mgutility::string_view {
119 for (const auto &pair : mgutility::custom_enum<Enum>::map) {
120 if (pair.first == e) {
121 return pair.second;
122 }
123 }
124 MGUTILITY_CNSTXPR auto str = mgutility::string_view(__PRETTY_FUNCTION__);
125 MGUTILITY_CNSTXPR auto index =
126 str.rfind(lastidxenumname[3], str.size() - lastidxenumname[0]) + 1;
127 MGUTILITY_CNSTXPR auto result =
128 str.substr(index, str.size() - lastidxenumname[0] - index);
129 MGUTILITY_CNSTXPR auto is_invalid =
130 result.rfind(lastidxenumname[5]) != mgutility::string_view::npos ||
131 (result.size() > 4 && result[4] == lastidxenumname[4]);
132 return is_invalid ? "" : result;
133 }
134
135private:
136 // NOLINTNEXTLINE [cppcoreguidelines-avoid-c-arrays]
137 static constexpr int lastidxenumname[] =
138#if defined(__clang__)
139 {1, 1, ' ', ':', '(',
140#if __clang_major__ < 13
141 ','
142#else
143 ')'
144#endif
145 };
146#elif defined(_MSC_VER)
147 {21, 0, ',', ':', '<', ')'};
148#elif defined(__GNUC__)
149 {
150#if MGUTILITY_CPLUSPLUS < 201703L
151 163,
152#else
153 157,
154#endif
155 5, ' ', ':', '(', ')'};
156#endif
157};
158
166template <typename Enum, Enum... Is>
167MGUTILITY_CNSTXPR inline auto
168get_enum_array(detail::enum_sequence<Enum, Is...> /*unused*/) noexcept
169 -> std::array<mgutility::string_view, sizeof...(Is) + 1> {
170 return std::array<mgutility::string_view, sizeof...(Is) + 1>{
171 "", enum_type::template name<Enum, Is>()...};
172}
173
182template <typename Enum, int Min = mgutility::enum_range<Enum>::min,
184MGUTILITY_CNSTXPR inline auto get_enum_array() noexcept
185 -> std::array<mgutility::string_view, Max - Min + 2> {
186 return get_enum_array<Enum>(detail::make_enum_sequence<Enum, Min, Max>());
187}
188
198template <typename Enum, int Min, int Max>
199MGUTILITY_CNSTXPR inline auto to_enum_impl(mgutility::string_view str) noexcept
200 -> mgutility::optional<Enum> {
201 MGUTILITY_CNSTXPR_CLANG_WA auto arr = get_enum_array<Enum, Min, Max>();
202
203 const auto index{detail::find(arr, str)};
204 return index == 0
205 ? mgutility::nullopt
206 : mgutility::optional<Enum>{static_cast<Enum>(index + Min - 1)};
207}
208
218template <typename Enum, int Min, int Max>
219MGUTILITY_CNSTXPR auto to_enum_bitmask_impl(mgutility::string_view str) noexcept
220 -> mgutility::optional<Enum> {
221
222 // Check if the string contains a '|' character
223 if (str.find('|') == mgutility::string_view::npos) {
224 return to_enum_impl<Enum, Min, Max>(str);
225 }
226
227 mgutility::optional<Enum> result{mgutility::nullopt};
228 std::size_t index = 0;
229
230 for (std::size_t i = 0; i < str.size(); ++i) {
231 if (str[i] == '|') {
232 auto name = str.substr(index, i - index);
233 auto maybe_enum = to_enum_impl<Enum, Min, Max>(name);
234
235 if (!name.empty() && maybe_enum) {
236 result.emplace(result ? static_cast<Enum>(*result | *maybe_enum)
237 : *maybe_enum);
238 }
239
240 index = i + 1;
241 }
242 }
243
244 auto maybe_enum = to_enum_impl<Enum, Min, Max>(str.substr(index));
245 if (result && maybe_enum) {
246 result.emplace(static_cast<Enum>(*result | *maybe_enum));
247 } else {
248 result.reset();
249 }
250
251 return result;
252}
253
263template <typename Enum, int Min, int Max,
264 detail::enable_if_t<!detail::has_bit_or<Enum>::value, bool> = true>
265MGUTILITY_CNSTXPR auto enum_name_impl(Enum enumValue) noexcept
266 -> mgutility::string_view {
267 MGUTILITY_CNSTXPR_CLANG_WA auto arr = get_enum_array<Enum, Min, Max>();
268 const auto index{(Min < 0 ? -Min : Min) + static_cast<int>(enumValue) + 1};
269 return arr[(index < Min || index > arr.size() - 1) ? 0 : index];
270}
271
282// NOLINTNEXTLINE [modernize-use-constraints]
283template <typename Enum, int Min, int Max,
284 detail::enable_if_t<detail::has_bit_or<Enum>::value, bool> = true>
285MGUTILITY_CNSTXPR_CLANG_WA auto enum_name_impl(Enum enumValue) noexcept
286 -> mgutility::fixed_string<enum_name_buffer<Enum>::size> {
287
288 // Get the array of enum names
289 MGUTILITY_CNSTXPR_CLANG_WA auto arr = get_enum_array<Enum, Min, Max>();
290
291 // Calculate the index in the array
292 const auto index = (Min < 0 ? -Min : Min) + static_cast<int>(enumValue) + 1;
293 const auto name =
294 arr[(index < Min || index >= static_cast<int>(arr.size())) ? 0 : index];
295
296 // Return the name if it's valid
297 if (!name.empty() && !is_digit(name[0])) {
298 return mgutility::fixed_string<enum_name_buffer<Enum>::size>{}.append(name);
299 }
300
301 // Construct bitmasked name
302 mgutility::fixed_string<enum_name_buffer<Enum>::size> bitmasked_name;
303 for (auto i = Min; i < Max; ++i) {
304 const auto idx = (Min < 0 ? -Min : Min) + i + 1;
305 if (idx >= 0 && idx < static_cast<int>(arr.size()) && !arr[idx].empty() &&
306 !detail::is_digit(arr[idx][0]) &&
307 (enumValue & static_cast<Enum>(i)) == static_cast<Enum>(i)) {
308 bitmasked_name.append(arr[idx]).append("|");
309 }
310 }
311
312 // Remove the trailing '|' if present
313 if (!bitmasked_name.empty()) {
314 bitmasked_name.pop_back();
315 }
316
317 return bitmasked_name;
318}
319} // namespace detail
320} // namespace mgutility
321
322#endif // MGUTILITY_REFLECTION_DETAIL_ENUM_NAME_IMPL_HPP
Checks for MSVC compiler version.
Definition enum_for_each.hpp:35
Provides the custom names map for an enumeration type.
Definition meta.hpp:196
Definition enum_name_impl.hpp:81
static MGUTILITY_CNSTXPR auto name() noexcept -> mgutility::string_view
Gets the name of an unscoped enum value.
Definition enum_name_impl.hpp:92
Provides the range for an enumeration type.
Definition meta.hpp:173
Definition meta.hpp:178