Block-Structured AMR Software Framework
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 
15 template <typename T>
16 using amrex_enum_traits = decltype(amrex_get_enum_traits(std::declval<T>()));
17 
18 namespace amrex
19 {
20  template <typename T, typename ET = amrex_enum_traits<T>,
21  std::enable_if_t<ET::value,int> = 0>
22  std::vector<std::pair<std::string,T>> getEnumNameValuePairs ()
23  {
24  auto tmp = amrex::split(std::string(ET::enum_names), ",");
25  std::vector<std::pair<std::string,T>> r;
26  r.reserve(tmp.size());
27  int next_value = 0;
28  for (auto const& item : tmp) {
29  auto const& kv = amrex::split(item, "=");
30  if (kv.size() == 1) {
31  r.emplace_back(amrex::trim(kv[0]), static_cast<T>(next_value));
32  ++next_value;
33  } else if (kv.size() == 2) {
34  auto const& value_string = amrex::trim(kv[1]);
35  auto it = std::find_if(r.begin(), r.end(),
36  [&] (auto const& x) -> bool
37  { return x.first == value_string; });
38  auto this_value = it->second;
39  r.emplace_back(amrex::trim(kv[0]), this_value);
40  next_value = static_cast<int>(this_value) + 1;
41  } else {
42  std::string error_msg("amrex::getEnumNameIntPairs: AMREX_ENUM(");
43  error_msg.append(ET::class_name).append(", ").append(ET::enum_names)
44  .append(").");
45  throw std::runtime_error(error_msg);
46  }
47  }
48  return r;
49  }
50 
51  template <typename T, typename ET = amrex_enum_traits<T>,
52  std::enable_if_t<ET::value,int> = 0>
53  T getEnum (std::string_view const& s)
54  {
55  auto const& kv = getEnumNameValuePairs<T>();
56  auto it = std::find_if(kv.begin(), kv.end(),
57  [&] (auto const& x) -> bool
58  { return x.first == s; });
59  if (it != kv.end()) {
60  return it->second;
61  } else {
62  std::string error_msg("amrex::getEnum: Unknown enum: ");
63  error_msg.append(s).append(" in AMREX_ENUM(").append(ET::class_name)
64  .append(", ").append(ET::enum_names).append(").");
65  throw std::runtime_error(error_msg);
66  return T();
67  }
68  }
69 
70  template <typename T, typename ET = amrex_enum_traits<T>,
71  std::enable_if_t<ET::value,int> = 0>
72  T getEnumCaseInsensitive (std::string_view const& s)
73  {
74  auto const& kv = getEnumNameValuePairs<T>();
75  std::string ls = amrex::toLower(std::string(s));
76  auto it = std::find_if(kv.begin(), kv.end(),
77  [&] (auto const& x) -> bool
78  { return amrex::toLower(x.first) == ls; });
79  if (it != kv.end()) {
80  return it->second;
81  } else {
82  std::string error_msg("amrex::getEnumCaseInsensitive: Unknown enum: ");
83  error_msg.append(s).append(" in AMREX_ENUM(").append(ET::class_name)
84  .append(", ").append(ET::enum_names).append(").");
85  throw std::runtime_error(error_msg);
86  return T();
87  }
88  }
89 
90  template <typename T, typename ET = amrex_enum_traits<T>,
91  std::enable_if_t<ET::value,int> = 0>
92  std::string getEnumNameString (T const& v)
93  {
94  auto const& kv = getEnumNameValuePairs<T>();
95  auto it = std::find_if(kv.begin(), kv.end(),
96  [&] (auto const& x) -> bool
97  { return x.second == v; });
98  if (it != kv.end()) {
99  return it->first;
100  } else {
101  std::string error_msg("amrex::getEnum: Unknown enum value: ");
102  error_msg.append(std::to_string(static_cast<int>(v)))
103  .append(" in AMREX_ENUM(").append(ET::class_name).append(", ")
104  .append(ET::enum_names).append(").");
105  throw std::runtime_error(error_msg);
106  return std::string();
107  }
108  }
109 
110  template <typename T, typename ET = amrex_enum_traits<T>,
111  std::enable_if_t<ET::value,int> = 0>
112  std::vector<std::string> getEnumNameStrings ()
113  {
114  auto r = amrex::split(std::string(ET::enum_names), ",");
115  for (auto& s : r) {
116  auto found = s.find('=');
117  if (found != std::string::npos) {
118  s.erase(found);
119  }
120  s = amrex::trim(s);
121  }
122  return r;
123  }
124 
125  template <typename T, typename ET = amrex_enum_traits<T>,
126  std::enable_if_t<ET::value,int> = 0>
127  std::string getEnumClassName ()
128  {
129  return std::string(ET::class_name);
130  }
131 }
132 
133 #define AMREX_ENUM(CLASS, ...) \
134  enum class CLASS : int { __VA_ARGS__ }; \
135  struct CLASS##_EnumTraits { \
136  using enum_class_t = CLASS; \
137  static constexpr bool value = true; \
138  static constexpr std::string_view class_name{#CLASS}; \
139  static constexpr std::string_view enum_names{#__VA_ARGS__}; \
140  }; \
141  CLASS##_EnumTraits amrex_get_enum_traits(CLASS)
142 
143 #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:127
std::string getEnumNameString(T const &v)
Definition: AMReX_Enum.H:92
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:53
std::vector< std::string > getEnumNameStrings()
Definition: AMReX_Enum.H:112
T getEnumCaseInsensitive(std::string_view const &s)
Definition: AMReX_Enum.H:72
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
std::vector< std::pair< std::string, T > > getEnumNameValuePairs()
Definition: AMReX_Enum.H:22