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