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 "mgutility/std/optional.hpp"
30#include "mgutility/std/string_view.hpp"
31
32#include <algorithm>
33#include <array>
34
40#if defined(_MSC_VER) && _MSC_VER < 1910
41#error "Requires MSVC 2017 or newer!"
47#elif defined(__clang__) && __clang_major__ < 6
48#error "Requires clang 6 or newer!"
54#elif defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 9
55#error "Requires gcc 9 or newer!"
61#elif !defined(_MSC_VER) && !defined(__clang__) && !defined(__GNUC__)
62#error "Your compiler is not supported!"
63#endif
64
70#ifdef _MSC_VER
71#define __PRETTY_FUNCTION__ __FUNCSIG__
72#endif
73
74namespace mgutility {
75namespace detail {
76
77struct enum_type {
85 template <
86 typename Enum, Enum e,
87 detail::enable_if_t<!detail::is_scoped_enum<Enum>::value, bool> = true>
91 auto index = std::max(str.rfind(lastidxenumname[2], str.size() - offset),
92 str.rfind(lastidxenumname[3], str.size() - offset));
93 auto result = str.substr(index + 1, str.size() - offset - index);
94 return result[0] == '(' ? "" : result;
95 }
96
104 template <
105 typename Enum, Enum e,
106 detail::enable_if_t<detail::is_scoped_enum<Enum>::value, bool> = true>
109 auto index =
110 str.rfind(lastidxenumname[3], str.size() - lastidxenumname[0]) + 1;
111 auto result = str.substr(index, str.size() - lastidxenumname[0] - index);
112 return result.size() > 4 && result[4] == lastidxenumname[4] ? "" : result;
113 }
114
115private:
116 static constexpr int lastidxenumname[] =
117#if defined(__clang__)
118 {1, 1, ' ', ':', '('};
119#elif defined(_MSC_VER)
120 {21, 0, ',', ':', '<'};
121#elif defined(__GNUC__)
122 {
123#if MGUTILITY_CPLUSPLUS < 201703L
124 163,
125#else
126 157,
127#endif
128 5, ' ', ':', '('};
129#endif
130};
131
139template <typename Enum, Enum... Is>
140MGUTILITY_CNSTXPR inline auto
141get_enum_array(detail::enum_sequence<Enum, Is...> /*unused*/) noexcept
142 -> std::array<mgutility::string_view, sizeof...(Is) + 1> {
143 return std::array<mgutility::string_view, sizeof...(Is) + 1>{
144 "", enum_type::template name<Enum, Is>()...};
145}
146
155template <typename Enum, int Min = mgutility::enum_range<Enum>::min,
157MGUTILITY_CNSTXPR inline auto get_enum_array() noexcept
158 -> std::array<mgutility::string_view, Max - Min + 1> {
159 auto array =
160 get_enum_array<Enum>(detail::make_enum_sequence<Enum, Min, Max>());
161 for (auto &pair : mgutility::custom_enum<Enum>::map) {
162 const auto index{(Min < 0 ? -Min : Min) + static_cast<int>(pair.first) + 1};
163 (index < Min || index > array.size() - 1)
164 ? void()
165 : (array[index] = pair.second, void());
166 }
167 return array;
168}
169
179template <typename Enum, int Min, int Max>
180MGUTILITY_CNSTXPR inline auto to_enum_impl(mgutility::string_view str) noexcept
182 MGUTILITY_CNSTXPR_CLANG_WA auto arr = get_enum_array<Enum, Min, Max>();
183 const auto index{std::find(arr.begin() + 1, arr.end(), str)};
184 return index == arr.end() ? mgutility::nullopt
185 : mgutility::optional<Enum>{static_cast<Enum>(
186 std::distance(arr.begin(), index) + Min - 1)};
187}
188
198template <typename Enum, int Min, int Max>
199MGUTILITY_CNSTXPR auto to_enum_bitmask_impl(mgutility::string_view str) noexcept
201
202 // Check if the string contains a '|' character
203 if (str.find('|') == mgutility::string_view::npos) {
204 return to_enum_impl<Enum, Min, Max>(str);
205 }
206
208 std::size_t index = 0;
209
210 for (std::size_t i = 0; i < str.size(); ++i) {
211 if (str[i] == '|') {
212 auto name = str.substr(index, i - index);
213 auto maybe_enum = to_enum_impl<Enum, Min, Max>(name);
214
215 if (!name.empty() && maybe_enum) {
216 result.emplace(result ? static_cast<Enum>(*result | *maybe_enum)
217 : *maybe_enum);
218 }
219
220 index = i + 1;
221 }
222 }
223
224 auto maybe_enum = to_enum_impl<Enum, Min, Max>(str.substr(index));
225 if (result && maybe_enum) {
226 result.emplace(static_cast<Enum>(*result | *maybe_enum));
227 } else {
228 result.reset();
229 }
230
231 return result;
232}
233
243template <typename Enum, int Min, int Max,
244 detail::enable_if_t<!detail::has_bit_or<Enum>::value, bool> = true>
245MGUTILITY_CNSTXPR auto enum_name_impl(Enum e) noexcept
247 MGUTILITY_CNSTXPR auto arr = get_enum_array<Enum, Min, Max>();
248 const auto index{(Min < 0 ? -Min : Min) + static_cast<int>(e) + 1};
249 return arr[(index < Min || index > arr.size() - 1) ? 0 : index];
250}
251
262template <typename Enum, int Min, int Max,
263 detail::enable_if_t<detail::has_bit_or<Enum>::value, bool> = true>
264MGUTILITY_CNSTXPR_CLANG_WA inline auto enum_name_impl(Enum e) noexcept
265 -> detail::string_or_view_t<Enum> {
266
267 // Get the array of enum names
268 MGUTILITY_CNSTXPR_CLANG_WA auto arr = get_enum_array<Enum, Min, Max>();
269
270 // Calculate the index in the array
271 const auto index = (Min < 0 ? -Min : Min) + static_cast<int>(e) + 1;
272 const auto name =
273 arr[(index < Min || index >= static_cast<int>(arr.size())) ? 0 : index];
274
275 // Lambda to check if a character is a digit
276 const auto is_digit = [](char c) { return c >= '0' && c <= '9'; };
277
278 // Return the name if it's valid
279 if (!name.empty() && !is_digit(name[0])) {
280 return std::string{name};
281 }
282
283 // Construct bitmasked name
284 std::string bitmasked_name;
285 for (auto i = Min; i < Max; ++i) {
286 const auto idx = (Min < 0 ? -Min : Min) + i + 1;
287 if (idx >= 0 && idx < static_cast<int>(arr.size()) && !arr[idx].empty() &&
288 !is_digit(arr[idx][0]) &&
289 (e & static_cast<Enum>(i)) == static_cast<Enum>(i)) {
290 bitmasked_name.append(arr[idx]).append("|");
291 }
292 }
293
294 // Remove the trailing '|' if present
295 if (!bitmasked_name.empty()) {
296 bitmasked_name.pop_back();
297 }
298
299 if (bitmasked_name.find('|') != std::string::npos) {
300 return bitmasked_name;
301 }
302 return std::string{""};
303}
304} // namespace detail
305} // namespace mgutility
306
307#endif // MGUTILITY_REFLECTION_DETAIL_ENUM_NAME_IMPL_HPP
A basic string view class template.
Definition string_view.hpp:57
#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
Definition enum_name_impl.hpp:77
static MGUTILITY_CNSTXPR auto name() noexcept -> mgutility::string_view
Gets the name of an unscoped enum value.
Definition enum_name_impl.hpp:88
Provides the range for an enumeration type.
Definition meta.hpp:156
Definition meta.hpp:161