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
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 this_value = static_cast<T>(std::stoi(value_string));
50 }
51 r.emplace_back(amrex::trim(kv[0]), this_value);
52 next_value = static_cast<int>(this_value) + 1;
53 } else {
54 std::string error_msg("amrex::getEnumNameIntPairs: AMREX_ENUM(");
55 error_msg.append(ET::class_name).append(", ").append(ET::enum_names)
56 .append(").");
57 throw std::runtime_error(error_msg);
58 }
59 }
60 return r;
61 }
62} // namespace detail
64
65 template <typename T, typename ET = amrex_enum_traits<T>,
66 std::enable_if_t<ET::value,int> = 0>
67 std::vector<std::pair<std::string,T>> const& getEnumNameValuePairs ()
68 {
69 // cache enum value strings for the whole type T
70 static auto r = detail::getNewEnumNameValuePairs<T>();
71 return r;
72 }
73
87 template <typename T, typename ET = amrex_enum_traits<T>,
88 std::enable_if_t<ET::value,int> = 0>
89 T getEnum (std::string_view const& s)
90 {
91 auto const& kv = getEnumNameValuePairs<T>();
92 auto it = std::find_if(kv.begin(), kv.end(),
93 [&] (auto const& x) -> bool
94 { return x.first == s; });
95 if (it != kv.end()) {
96 return it->second;
97 } else {
98 std::string error_msg("amrex::getEnum: Unknown enum: ");
99 error_msg.append(s).append(" in AMREX_ENUM(").append(ET::class_name)
100 .append(", ").append(ET::enum_names).append(").");
101 throw std::runtime_error(error_msg);
102 return T();
103 }
104 }
105
121 template <typename T, typename ET = amrex_enum_traits<T>,
122 std::enable_if_t<ET::value,int> = 0>
123 T getEnumCaseInsensitive (std::string_view const& s)
124 {
125 auto const& kv = getEnumNameValuePairs<T>();
126 std::string ls = amrex::toLower(std::string(s));
127 auto it = std::find_if(kv.begin(), kv.end(),
128 [&] (auto const& x) -> bool
129 { return amrex::toLower(x.first) == ls; });
130 if (it != kv.end()) {
131 return it->second;
132 } else {
133 std::string error_msg("amrex::getEnumCaseInsensitive: Unknown enum: ");
134 error_msg.append(s).append(" in AMREX_ENUM(").append(ET::class_name)
135 .append(", ").append(ET::enum_names).append(").");
136 throw std::runtime_error(error_msg);
137 return T();
138 }
139 }
140
154 template <typename T, typename ET = amrex_enum_traits<T>,
155 std::enable_if_t<ET::value,int> = 0>
156 std::string getEnumNameString (T const& v)
157 {
158 auto const& kv = getEnumNameValuePairs<T>();
159 auto it = std::find_if(kv.begin(), kv.end(),
160 [&] (auto const& x) -> bool
161 { return x.second == v; });
162 if (it != kv.end()) {
163 return it->first;
164 } else {
165 std::string error_msg("amrex::getEnum: Unknown enum value: ");
166 error_msg.append(std::to_string(static_cast<int>(v)))
167 .append(" in AMREX_ENUM(").append(ET::class_name).append(", ")
168 .append(ET::enum_names).append(").");
169 throw std::runtime_error(error_msg);
170 return std::string();
171 }
172 }
173
174 template <typename T, typename ET = amrex_enum_traits<T>,
175 std::enable_if_t<ET::value,int> = 0>
176 std::vector<std::string> getEnumNameStrings ()
177 {
178 auto r = amrex::split(std::string(ET::enum_names), ",");
179 for (auto& s : r) {
180 auto found = s.find('=');
181 if (found != std::string::npos) {
182 s.erase(found);
183 }
184 s = amrex::trim(s);
185 }
186 return r;
187 }
188
189 template <typename T, typename ET = amrex_enum_traits<T>,
190 std::enable_if_t<ET::value,int> = 0>
191 std::string getEnumClassName ()
192 {
193 return std::string(ET::class_name);
194 }
195
200 template <typename T, typename ET = amrex_enum_traits<T>,
201 std::enable_if_t<ET::value,int> = 0>
202 constexpr auto toUnderlying (T v) noexcept
203 {
204 return static_cast<std::underlying_type_t<T>>(v);
205 }
206}
207
208#define AMREX_ENUM(CLASS, ...) \
209 enum class CLASS : int { __VA_ARGS__ }; \
210 \
211 struct CLASS##_EnumTraits { \
212 using enum_class_t = CLASS; \
213 static constexpr bool value = true; \
214 static constexpr std::string_view class_name{#CLASS}; \
215 static constexpr std::string_view enum_names{#__VA_ARGS__}; \
216 }; \
217 \
218 CLASS##_EnumTraits amrex_get_enum_traits(CLASS)
219
220#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:191
std::string getEnumNameString(T const &v)
Definition AMReX_Enum.H:156
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:89
std::vector< std::pair< std::string, T > > const & getEnumNameValuePairs()
Definition AMReX_Enum.H:67
T getEnumCaseInsensitive(std::string_view const &s)
Definition AMReX_Enum.H:123
std::vector< std::string > getEnumNameStrings()
Definition AMReX_Enum.H:176
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:202