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 <stdexcept>
14#include <string>
15#include <string_view>
16#include <type_traits>
17#include <utility>
18#include <vector>
19
20template <typename T>
21using amrex_enum_traits = decltype(amrex_get_enum_traits(std::declval<T>()));
22
23namespace amrex
24{
26namespace detail
27{
28 template <typename T, typename ET = amrex_enum_traits<T>>
29 requires (ET::value)
30 std::vector<std::pair<std::string,T>> getNewEnumNameValuePairs ()
31 {
32 auto tmp = amrex::split(std::string(ET::enum_names), ",");
33 std::vector<std::pair<std::string,T>> r;
34 r.reserve(tmp.size());
35 int next_value = 0;
36 for (auto const& item : tmp) {
37 auto const& kv = amrex::split(item, "=");
38 if (kv.size() == 1) {
39 r.emplace_back(amrex::trim(kv[0]), static_cast<T>(next_value));
40 ++next_value;
41 } else if (kv.size() == 2) {
42 auto const& value_string = amrex::trim(kv[1]);
43 // For k = v, find if v exists as a key. If not, v must be an int.
44 auto it = std::find_if(r.begin(), r.end(),
45 [&] (auto const& x) -> bool
46 { return x.first == value_string; });
47 T this_value;
48 if (it != r.end()) {
49 this_value = it->second;
50 } else { // v is an int literal
51 // Note that if value_string is not a valid string for int,
52 // it will fail at compile time, because the compiler
53 // will not allow something like `enum FOO : int { x = 3% }`.
54 // The base of the integer is auto detected, so 0x/0 prefixes work.
55 this_value = static_cast<T>(std::stoi(value_string, nullptr, 0));
56 }
57 r.emplace_back(amrex::trim(kv[0]), this_value);
58 next_value = static_cast<int>(this_value) + 1;
59 } else {
60 std::string error_msg("amrex::getEnumNameIntPairs: AMREX_ENUM(");
61 error_msg.append(ET::class_name).append(", ").append(ET::enum_names)
62 .append(").");
63 throw std::runtime_error(error_msg);
64 }
65 }
66 return r;
67 }
68} // namespace detail
70
79 template <typename T, typename ET = amrex_enum_traits<T>>
80 requires (ET::value)
81 std::vector<std::pair<std::string,T>> const& getEnumNameValuePairs ()
82 {
83 // cache enum value strings for the whole type T
84 static auto r = detail::getNewEnumNameValuePairs<T>();
85 return r;
86 }
87
105 template <typename T, typename ET = amrex_enum_traits<T>>
106 requires (ET::value)
107 T getEnum (std::string_view const& s)
108 {
109 auto const& kv = getEnumNameValuePairs<T>();
110 auto it = std::find_if(kv.begin(), kv.end(),
111 [&] (auto const& x) -> bool
112 { return x.first == s; });
113 if (it != kv.end()) {
114 return it->second;
115 } else {
116 std::string error_msg("amrex::getEnum: Unknown enum: ");
117 error_msg.append(s).append(" in AMREX_ENUM(").append(ET::class_name)
118 .append(", ").append(ET::enum_names).append(").");
119 throw std::runtime_error(error_msg);
120 return T();
121 }
122 }
123
141 template <typename T, typename ET = amrex_enum_traits<T>>
142 requires (ET::value)
143 T getEnumCaseInsensitive (std::string_view const& s)
144 {
145 auto const& kv = getEnumNameValuePairs<T>();
146 std::string ls = amrex::toLower(std::string(s));
147 auto it = std::find_if(kv.begin(), kv.end(),
148 [&] (auto const& x) -> bool
149 { return amrex::toLower(x.first) == ls; });
150 if (it != kv.end()) {
151 return it->second;
152 } else {
153 std::string error_msg("amrex::getEnumCaseInsensitive: Unknown enum: ");
154 error_msg.append(s).append(" in AMREX_ENUM(").append(ET::class_name)
155 .append(", ").append(ET::enum_names).append(").");
156 throw std::runtime_error(error_msg);
157 return T();
158 }
159 }
160
178 template <typename T, typename ET = amrex_enum_traits<T>>
179 requires (ET::value)
180 std::string getEnumNameString (T const& v)
181 {
182 auto const& kv = getEnumNameValuePairs<T>();
183 auto it = std::find_if(kv.begin(), kv.end(),
184 [&] (auto const& x) -> bool
185 { return x.second == v; });
186 if (it != kv.end()) {
187 return it->first;
188 } else {
189 std::string error_msg("amrex::getEnumNameString: Unknown enum value: ");
190 error_msg.append(std::to_string(static_cast<int>(v)))
191 .append(" in AMREX_ENUM(").append(ET::class_name).append(", ")
192 .append(ET::enum_names).append(").");
193 throw std::runtime_error(error_msg);
194 return std::string();
195 }
196 }
197
204 template <typename T, typename ET = amrex_enum_traits<T>>
205 requires (ET::value)
206 std::vector<std::string> getEnumNameStrings ()
207 {
208 auto r = amrex::split(std::string(ET::enum_names), ",");
209 for (auto& s : r) {
210 auto found = s.find('=');
211 if (found != std::string::npos) {
212 s.erase(found);
213 }
214 s = amrex::trim(s);
215 }
216 return r;
217 }
218
225 template <typename T, typename ET = amrex_enum_traits<T>>
226 requires (ET::value)
227 std::string getEnumClassName ()
228 {
229 return std::string(ET::class_name);
230 }
231
238 template <typename T, typename ET = amrex_enum_traits<T>>
239 requires (ET::value)
240 constexpr auto toUnderlying (T v) noexcept
241 {
242 return static_cast<std::underlying_type_t<T>>(v);
243 }
244}
245
260#define AMREX_ENUM(CLASS, ...) \
261 enum class CLASS : int { __VA_ARGS__ }; \
262 \
263 struct CLASS##_EnumTraits { \
264 using enum_class_t = CLASS; \
265 static constexpr bool value = true; \
266 static constexpr std::string_view class_name{#CLASS}; \
267 static constexpr std::string_view enum_names{#__VA_ARGS__}; \
268 }; \
269 \
270 CLASS##_EnumTraits amrex_get_enum_traits(CLASS)
271
272#define AMREX_ENUM_IN_CLASS(CLASS, ...) \
273 enum class CLASS : int { __VA_ARGS__ }; \
274 \
275 struct CLASS##_EnumTraits { \
276 using enum_class_t = CLASS; \
277 static constexpr bool value = true; \
278 static constexpr std::string_view class_name{#CLASS}; \
279 static constexpr std::string_view enum_names{#__VA_ARGS__}; \
280 }; \
281 \
282 friend CLASS##_EnumTraits amrex_get_enum_traits(CLASS) { return {}; } \
283 /* This gets rid of trailing semicolon warning. */ static_assert(true, "")
284
285#endif
decltype(amrex_get_enum_traits(std::declval< T >())) amrex_enum_traits
Definition AMReX_Enum.H:21
T getEnum(std::string_view const &s)
Convert a string to an enum value.
Definition AMReX_Enum.H:107
constexpr auto toUnderlying(T v) noexcept
Return the underlying integer value of an enum enumerator.
Definition AMReX_Enum.H:240
std::string getEnumClassName()
Return the class name string of an AMREX_ENUM-declared enum type.
Definition AMReX_Enum.H:227
std::string getEnumNameString(T const &v)
Get the name string of an enum value.
Definition AMReX_Enum.H:180
std::vector< std::string > getEnumNameStrings()
Return a list of all enumerator name strings for an AMREX_ENUM-declared type.
Definition AMReX_Enum.H:206
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:81
T getEnumCaseInsensitive(std::string_view const &s)
Convert a string case-insensitively to an enum value.
Definition AMReX_Enum.H:143
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