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
4#include <AMReX_String.H>
5
6#include <algorithm>
7#include <array>
8#include <stdexcept>
9#include <string>
10#include <string_view>
11#include <type_traits>
12#include <utility>
13#include <vector>
14
15template <typename T>
16using amrex_enum_traits = decltype(amrex_get_enum_traits(std::declval<T>()));
17
18namespace amrex
19{
21namespace detail
22{
23 template <typename T, typename ET = amrex_enum_traits<T>,
24 std::enable_if_t<ET::value,int> = 0>
25 std::vector<std::pair<std::string,T>> getNewEnumNameValuePairs ()
26 {
27 auto tmp = amrex::split(std::string(ET::enum_names), ",");
28 std::vector<std::pair<std::string,T>> r;
29 r.reserve(tmp.size());
30 int next_value = 0;
31 for (auto const& item : tmp) {
32 auto const& kv = amrex::split(item, "=");
33 if (kv.size() == 1) {
34 r.emplace_back(amrex::trim(kv[0]), static_cast<T>(next_value));
35 ++next_value;
36 } else if (kv.size() == 2) {
37 auto const& value_string = amrex::trim(kv[1]);
38 // For k = v, find if v exists as a key. If not, v must be an int.
39 auto it = std::find_if(r.begin(), r.end(),
40 [&] (auto const& x) -> bool
41 { return x.first == value_string; });
42 T this_value;
43 if (it != r.end()) {
44 this_value = it->second;
45 } else { // v is an int literal
46 // Note that if value_string is not a valid string for int,
47 // it will fail at compile time, because the compiler
48 // will not allow something like `enum FOO : int { x = 3% }`.
49 // The base of the integer is auto detected, so 0x/0 prefixes work.
50 this_value = static_cast<T>(std::stoi(value_string, nullptr, 0));
51 }
52 r.emplace_back(amrex::trim(kv[0]), this_value);
53 next_value = static_cast<int>(this_value) + 1;
54 } else {
55 std::string error_msg("amrex::getEnumNameIntPairs: AMREX_ENUM(");
56 error_msg.append(ET::class_name).append(", ").append(ET::enum_names)
57 .append(").");
58 throw std::runtime_error(error_msg);
59 }
60 }
61 return r;
62 }
63} // namespace detail
65
66 template <typename T, typename ET = amrex_enum_traits<T>,
67 std::enable_if_t<ET::value,int> = 0>
68 std::vector<std::pair<std::string,T>> const& getEnumNameValuePairs ()
69 {
70 // cache enum value strings for the whole type T
71 static auto r = detail::getNewEnumNameValuePairs<T>();
72 return r;
73 }
74
88 template <typename T, typename ET = amrex_enum_traits<T>,
89 std::enable_if_t<ET::value,int> = 0>
90 T getEnum (std::string_view const& s)
91 {
92 auto const& kv = getEnumNameValuePairs<T>();
93 auto it = std::find_if(kv.begin(), kv.end(),
94 [&] (auto const& x) -> bool
95 { return x.first == s; });
96 if (it != kv.end()) {
97 return it->second;
98 } else {
99 std::string error_msg("amrex::getEnum: Unknown enum: ");
100 error_msg.append(s).append(" in AMREX_ENUM(").append(ET::class_name)
101 .append(", ").append(ET::enum_names).append(").");
102 throw std::runtime_error(error_msg);
103 return T();
104 }
105 }
106
122 template <typename T, typename ET = amrex_enum_traits<T>,
123 std::enable_if_t<ET::value,int> = 0>
124 T getEnumCaseInsensitive (std::string_view const& s)
125 {
126 auto const& kv = getEnumNameValuePairs<T>();
127 std::string ls = amrex::toLower(std::string(s));
128 auto it = std::find_if(kv.begin(), kv.end(),
129 [&] (auto const& x) -> bool
130 { return amrex::toLower(x.first) == ls; });
131 if (it != kv.end()) {
132 return it->second;
133 } else {
134 std::string error_msg("amrex::getEnumCaseInsensitive: Unknown enum: ");
135 error_msg.append(s).append(" in AMREX_ENUM(").append(ET::class_name)
136 .append(", ").append(ET::enum_names).append(").");
137 throw std::runtime_error(error_msg);
138 return T();
139 }
140 }
141
155 template <typename T, typename ET = amrex_enum_traits<T>,
156 std::enable_if_t<ET::value,int> = 0>
157 std::string getEnumNameString (T const& v)
158 {
159 auto const& kv = getEnumNameValuePairs<T>();
160 auto it = std::find_if(kv.begin(), kv.end(),
161 [&] (auto const& x) -> bool
162 { return x.second == v; });
163 if (it != kv.end()) {
164 return it->first;
165 } else {
166 std::string error_msg("amrex::getEnum: Unknown enum value: ");
167 error_msg.append(std::to_string(static_cast<int>(v)))
168 .append(" in AMREX_ENUM(").append(ET::class_name).append(", ")
169 .append(ET::enum_names).append(").");
170 throw std::runtime_error(error_msg);
171 return std::string();
172 }
173 }
174
175 template <typename T, typename ET = amrex_enum_traits<T>,
176 std::enable_if_t<ET::value,int> = 0>
177 std::vector<std::string> getEnumNameStrings ()
178 {
179 auto r = amrex::split(std::string(ET::enum_names), ",");
180 for (auto& s : r) {
181 auto found = s.find('=');
182 if (found != std::string::npos) {
183 s.erase(found);
184 }
185 s = amrex::trim(s);
186 }
187 return r;
188 }
189
190 template <typename T, typename ET = amrex_enum_traits<T>,
191 std::enable_if_t<ET::value,int> = 0>
192 std::string getEnumClassName ()
193 {
194 return std::string(ET::class_name);
195 }
196
201 template <typename T, typename ET = amrex_enum_traits<T>,
202 std::enable_if_t<ET::value,int> = 0>
203 constexpr auto toUnderlying (T v) noexcept
204 {
205 return static_cast<std::underlying_type_t<T>>(v);
206 }
207}
208
209#define AMREX_ENUM(CLASS, ...) \
210 enum class CLASS : int { __VA_ARGS__ }; \
211 \
212 struct CLASS##_EnumTraits { \
213 using enum_class_t = CLASS; \
214 static constexpr bool value = true; \
215 static constexpr std::string_view class_name{#CLASS}; \
216 static constexpr std::string_view enum_names{#__VA_ARGS__}; \
217 }; \
218 \
219 CLASS##_EnumTraits amrex_get_enum_traits(CLASS)
220
221#endif
decltype(amrex_get_enum_traits(std::declval< T >())) amrex_enum_traits
Definition AMReX_Enum.H:16
Definition AMReX_Amr.cpp:49
std::string getEnumClassName()
Definition AMReX_Enum.H:192
std::string getEnumNameString(T const &v)
Definition AMReX_Enum.H:157
std::string trim(std::string s, std::string const &space)
Definition AMReX_String.cpp:25
std::string toLower(std::string s)
Converts all characters of the string into lower case based on std::locale.
Definition AMReX_String.cpp:11
T getEnum(std::string_view const &s)
Definition AMReX_Enum.H:90
std::vector< std::pair< std::string, T > > const & getEnumNameValuePairs()
Definition AMReX_Enum.H:68
T getEnumCaseInsensitive(std::string_view const &s)
Definition AMReX_Enum.H:124
std::vector< std::string > getEnumNameStrings()
Definition AMReX_Enum.H:177
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:42
constexpr auto toUnderlying(T v) noexcept
Definition AMReX_Enum.H:203