Block-Structured AMR Software Framework
Loading...
Searching...
No Matches
AMReX_Enum.H
Go to the documentation of this file.
1#ifndef AMREX_ENUM_H_
2#define AMREX_ENUM_H_
3
9#include <AMReX_String.H>
10
11#include <algorithm>
12#include <array>
13#include <cstddef>
14#include <stdexcept>
15#include <string>
16#include <string_view>
17#include <type_traits>
18#include <utility>
19#include <vector>
20
21template <typename T>
22using amrex_enum_traits = decltype(amrex_get_enum_traits(std::declval<T>()));
23
24namespace amrex
25{
27namespace detail
28{
29 template <typename T, typename ET = amrex_enum_traits<T>>
30 requires (ET::value)
31 std::vector<std::pair<std::string,T>> getNewEnumNameValuePairs ()
32 {
33 auto tmp = amrex::split(std::string(ET::enum_names), ",");
34 std::vector<std::pair<std::string,T>> r;
35 r.reserve(tmp.size());
36 int next_value = 0;
37 for (auto const& item : tmp) {
38 auto const& kv = amrex::split(item, "=");
39 if (kv.size() == 1) {
40 r.emplace_back(amrex::trim(kv[0]), static_cast<T>(next_value));
41 ++next_value;
42 } else if (kv.size() == 2) {
43 auto const& value_string = amrex::trim(kv[1]);
44 // For k = v, find if v exists as a key. If not, v must be an int.
45 auto it = std::find_if(r.begin(), r.end(),
46 [&] (auto const& x) -> bool
47 { return x.first == value_string; });
48 T this_value;
49 if (it != r.end()) {
50 this_value = it->second;
51 } else { // v is an int literal
52 // The base of the integer is auto detected, so 0x/0 prefixes work.
53 auto s = value_string;
54 s.erase(std::remove(s.begin(), s.end(), '\''), s.end()); // digit separators
55 std::size_t pos = 0;
56 this_value = static_cast<T>(std::stoi(s, &pos, 0));
57 // Only an integer suffix may follow. Binary literals and
58 // expressions such as `1 << 2` are not supported.
59 if (s.find_first_not_of("uUlLzZ", pos) != std::string::npos) {
60 std::string error_msg("amrex::getEnumNameValuePairs: unsupported enumerator initializer `");
61 error_msg.append(value_string).append("` in AMREX_ENUM(")
62 .append(ET::class_name).append(", ").append(ET::enum_names)
63 .append(").");
64 throw std::runtime_error(error_msg);
65 }
66 }
67 r.emplace_back(amrex::trim(kv[0]), this_value);
68 next_value = static_cast<int>(this_value) + 1;
69 } else {
70 std::string error_msg("amrex::getEnumNameIntPairs: AMREX_ENUM(");
71 error_msg.append(ET::class_name).append(", ").append(ET::enum_names)
72 .append(").");
73 throw std::runtime_error(error_msg);
74 }
75 }
76 return r;
77 }
78} // namespace detail
80
89 template <typename T, typename ET = amrex_enum_traits<T>>
90 requires (ET::value)
91 std::vector<std::pair<std::string,T>> const& getEnumNameValuePairs ()
92 {
93 // cache enum value strings for the whole type T
94 static auto r = detail::getNewEnumNameValuePairs<T>();
95 return r;
96 }
97
115 template <typename T, typename ET = amrex_enum_traits<T>>
116 requires (ET::value)
117 T getEnum (std::string_view const& s)
118 {
119 auto const& kv = getEnumNameValuePairs<T>();
120 auto it = std::find_if(kv.begin(), kv.end(),
121 [&] (auto const& x) -> bool
122 { return x.first == s; });
123 if (it != kv.end()) {
124 return it->second;
125 } else {
126 std::string error_msg("amrex::getEnum: Unknown enum: ");
127 error_msg.append(s).append(" in AMREX_ENUM(").append(ET::class_name)
128 .append(", ").append(ET::enum_names).append(").");
129 throw std::runtime_error(error_msg);
130 return T();
131 }
132 }
133
151 template <typename T, typename ET = amrex_enum_traits<T>>
152 requires (ET::value)
153 T getEnumCaseInsensitive (std::string_view const& s)
154 {
155 auto const& kv = getEnumNameValuePairs<T>();
156 std::string ls = amrex::toLower(std::string(s));
157 auto it = std::find_if(kv.begin(), kv.end(),
158 [&] (auto const& x) -> bool
159 { return amrex::toLower(x.first) == ls; });
160 if (it != kv.end()) {
161 return it->second;
162 } else {
163 std::string error_msg("amrex::getEnumCaseInsensitive: Unknown enum: ");
164 error_msg.append(s).append(" in AMREX_ENUM(").append(ET::class_name)
165 .append(", ").append(ET::enum_names).append(").");
166 throw std::runtime_error(error_msg);
167 return T();
168 }
169 }
170
188 template <typename T, typename ET = amrex_enum_traits<T>>
189 requires (ET::value)
190 std::string getEnumNameString (T const& v)
191 {
192 auto const& kv = getEnumNameValuePairs<T>();
193 auto it = std::find_if(kv.begin(), kv.end(),
194 [&] (auto const& x) -> bool
195 { return x.second == v; });
196 if (it != kv.end()) {
197 return it->first;
198 } else {
199 std::string error_msg("amrex::getEnumNameString: Unknown enum value: ");
200 error_msg.append(std::to_string(static_cast<int>(v)))
201 .append(" in AMREX_ENUM(").append(ET::class_name).append(", ")
202 .append(ET::enum_names).append(").");
203 throw std::runtime_error(error_msg);
204 return std::string();
205 }
206 }
207
214 template <typename T, typename ET = amrex_enum_traits<T>>
215 requires (ET::value)
216 std::vector<std::string> getEnumNameStrings ()
217 {
218 auto r = amrex::split(std::string(ET::enum_names), ",");
219 for (auto& s : r) {
220 auto found = s.find('=');
221 if (found != std::string::npos) {
222 s.erase(found);
223 }
224 s = amrex::trim(s);
225 }
226 return r;
227 }
228
235 template <typename T, typename ET = amrex_enum_traits<T>>
236 requires (ET::value)
237 std::string getEnumClassName ()
238 {
239 return std::string(ET::class_name);
240 }
241
248 template <typename T, typename ET = amrex_enum_traits<T>>
249 requires (ET::value)
250 constexpr auto toUnderlying (T v) noexcept
251 {
252 return static_cast<std::underlying_type_t<T>>(v);
253 }
254}
255
270#define AMREX_ENUM(CLASS, ...) \
271 enum class CLASS : int { __VA_ARGS__ }; \
272 \
273 struct CLASS##_EnumTraits { \
274 using enum_class_t = CLASS; \
275 static constexpr bool value = true; \
276 static constexpr std::string_view class_name{#CLASS}; \
277 static constexpr std::string_view enum_names{#__VA_ARGS__}; \
278 }; \
279 \
280 CLASS##_EnumTraits amrex_get_enum_traits(CLASS)
281
282#define AMREX_ENUM_IN_CLASS(CLASS, ...) \
283 enum class CLASS : int { __VA_ARGS__ }; \
284 \
285 struct CLASS##_EnumTraits { \
286 using enum_class_t = CLASS; \
287 static constexpr bool value = true; \
288 static constexpr std::string_view class_name{#CLASS}; \
289 static constexpr std::string_view enum_names{#__VA_ARGS__}; \
290 }; \
291 \
292 friend CLASS##_EnumTraits amrex_get_enum_traits(CLASS) { return {}; } \
293 /* This gets rid of trailing semicolon warning. */ static_assert(true, "")
294
295#endif
decltype(amrex_get_enum_traits(std::declval< T >())) amrex_enum_traits
Definition AMReX_Enum.H:22
T getEnum(std::string_view const &s)
Convert a string to an enum value.
Definition AMReX_Enum.H:117
constexpr auto toUnderlying(T v) noexcept
Return the underlying integer value of an enum enumerator.
Definition AMReX_Enum.H:250
std::string getEnumClassName()
Return the class name string of an AMREX_ENUM-declared enum type.
Definition AMReX_Enum.H:237
std::string getEnumNameString(T const &v)
Get the name string of an enum value.
Definition AMReX_Enum.H:190
std::vector< std::string > getEnumNameStrings()
Return a list of all enumerator name strings for an AMREX_ENUM-declared type.
Definition AMReX_Enum.H:216
std::vector< std::pair< std::string, T > > const & getEnumNameValuePairs()
Return all (name, value) pairs for an AMREX_ENUM-declared enum type.
Definition AMReX_Enum.H:91
T getEnumCaseInsensitive(std::string_view const &s)
Convert a string case-insensitively to an enum value.
Definition AMReX_Enum.H:153
Definition AMReX_Amr.cpp:50
std::string trim(std::string s, std::string const &space)
Definition AMReX_String.cpp:26
std::string toLower(std::string s)
Converts all characters of the string into lower case based on std::locale.
Definition AMReX_String.cpp:12
std::vector< std::string > split(std::string const &s, std::string const &sep)
Split a string using given tokens in sep.
Definition AMReX_String.cpp:44