Cantera  3.1.0a1
AnyMap.inl.h
Go to the documentation of this file.
1 //! @file AnyMap.inl.h
2 
3 #ifndef CT_ANYMAP_INL_H
4 #define CT_ANYMAP_INL_H
5 
6 #include "cantera/base/AnyMap.h"
7 
8 namespace Cantera
9 {
10 // re-declared to avoid needing to include global.h here
11 string demangle(const std::type_info& type);
12 
13 // Definitions for AnyValue templated functions
14 
15 template<class T>
16 const T &AnyValue::as() const {
17  try {
18  if (typeid(T) == typeid(double) && m_value.type() == typeid(long int)) {
19  // Implicit conversion of long int to double
20  const_cast<AnyValue*>(this)->m_value = static_cast<double>(as<long int>());
21  m_equals = eq_comparer<double>;
22  } else if (typeid(T) == typeid(string) && m_value.type() == typeid(double)) {
23  // Implicit conversion of double to string
24  const_cast<AnyValue*>(this)->m_value = fmt::format("{}", as<double>());
25  m_equals = eq_comparer<string>;
26  } else if (typeid(T) == typeid(string) && m_value.type() == typeid(long int)) {
27  // Implicit conversion of long int to string
28  const_cast<AnyValue*>(this)->m_value = fmt::format("{}", as<long int>());
29  m_equals = eq_comparer<string>;
30  } else if (typeid(T) == typeid(vector<double>)
31  && m_value.type() == typeid(vector<AnyValue>)) {
32  // Implicit conversion of vector<AnyValue> to vector<double>
33  auto& asAny = as<vector<AnyValue>>();
34  vector<double> asDouble(asAny.size());
35  for (size_t i = 0; i < asAny.size(); i++) {
36  asDouble[i] = asAny[i].as<double>();
37  }
38  const_cast<AnyValue*>(this)->m_value = std::move(asDouble);
39  m_equals = eq_comparer<vector<double>>;
40  }
41  return std::any_cast<const T&>(m_value);
42  } catch (std::bad_any_cast&) {
43  if (m_value.type() == typeid(void)) {
44  // Values that have not been set are of type 'void'
45  throw InputFileError("AnyValue::as", *this,
46  "Key '{}' not found or contains no value", m_key);
47  } else {
48  if (m_key == "") {
49  throw InputFileError("AnyValue::as", *this,
50  "Unable to convert '{}' to '{}'.",
51  demangle(m_value.type()), demangle(typeid(T)));
52  }
53  throw InputFileError("AnyValue::as", *this,
54  "Key '{}' contains a '{}',\nnot a '{}'",
55  m_key, demangle(m_value.type()), demangle(typeid(T)));
56  }
57  }
58 }
59 
60 template<class T>
61 T &AnyValue::as() {
62  // To avoid duplicating the code from the const version, call that version
63  // and just remove the const specifier from the return value
64  return const_cast<T&>(const_cast<const AnyValue*>(this)->as<T>());
65 }
66 
67 template<class T>
68 bool AnyValue::is() const {
69  return m_value.type() == typeid(T);
70 }
71 
72 template<> bool AnyValue::is<vector<double>>() const;
73 
74 template<class T>
75 bool AnyValue::isVector() const {
76  return m_value.type() == typeid(vector<T>);
77 }
78 
79 template<class T>
80 bool AnyValue::isMatrix(size_t cols) const {
81  if (m_value.type() != typeid(vector<vector<T>>)) {
82  // not a matrix
83  return false;
84  }
85  auto& asMatrix = as<vector<vector<T>>>();
86  if (!asMatrix.size()) {
87  // empty matrix
88  return true;
89  }
90  if (cols == npos) {
91  cols = asMatrix[0].size();
92  }
93  for (const auto& row : asMatrix) {
94  if (row.size() != cols) {
95  return false;
96  }
97  }
98  return true;
99 }
100 
101 template<class T>
102 AnyValue &AnyValue::operator=(const vector<T> &value) {
103  m_value = value;
104  m_equals = eq_comparer<vector<T>>;
105  return *this;
106 }
107 
108 template<class T>
109 const vector<T> &AnyValue::asVector(size_t nMin, size_t nMax) const {
110  const auto& v = as<vector<T>>();
111  checkSize(v, nMin, nMax);
112  return v;
113 }
114 
115 template<class T>
116 vector<T> &AnyValue::asVector(size_t nMin, size_t nMax) {
117  auto& v = as<vector<T>>();
118  checkSize(v, nMin, nMax);
119  return v;
120 }
121 
122 template<class T>
123 AnyValue& AnyValue::operator=(const std::unordered_map<string, T> items) {
124  m_value = AnyMap();
125  m_equals = eq_comparer<AnyMap>;
126  AnyMap& dest = as<AnyMap>();
127  for (const auto& [key, value] : items) {
128  dest[key] = value;
129  }
130  return *this;
131 }
132 
133 template<class T>
134 AnyValue& AnyValue::operator=(const map<string, T> items) {
135  m_value = AnyMap();
136  m_equals = eq_comparer<AnyMap>;
137  AnyMap& dest = as<AnyMap>();
138  for (const auto& [key, value] : items) {
139  dest[key] = value;
140  }
141  return *this;
142 }
143 
144 template<>
145 inline AnyMap& AnyValue::as<AnyMap>() {
146  try {
147  // This is where nested AnyMaps are created when the syntax
148  // m[key1][key2] is used.
149  if (m_value.type() == typeid(void)) {
150  m_value = AnyMap();
151  m_equals = eq_comparer<AnyMap>;
152  }
153  return std::any_cast<AnyMap&>(m_value);
154  } catch (std::bad_any_cast&) {
155  throw InputFileError("AnyValue::as", *this,
156  "value of key '{}' is a '{}',\nnot an 'AnyMap'.",
157  m_key, demangle(m_value.type()));
158  }
159 }
160 
161 template<class T>
162 map<string, T> AnyValue::asMap() const
163 {
164  map<string, T> dest;
165  for (const auto& item : as<AnyMap>()) {
166  dest[item.first] = item.second.as<T>();
167  }
168  return dest;
169 }
170 
171 template<class T>
172 void AnyValue::checkSize(const vector<T>& v, size_t nMin, size_t nMax) const
173 {
174  if (nMin != npos && nMax == npos && v.size() != nMin) {
175  throw InputFileError("AnyValue::checkSize", *this,
176  "Expected array '{}' to have length {}, but found "
177  "an array of length {}.", m_key, nMin, v.size());
178  } else if (nMin != npos && nMax != npos
179  && (v.size() < nMin || v.size() > nMax)) {
180  throw InputFileError("AnyValue::checkSize", *this,
181  "Expected array '{}' to have from {} to {} elements, but found "
182  "an array of length {}.", m_key, nMin, nMax, v.size());
183  }
184 }
185 
186 template<class T, class U>
187 bool AnyValue::vector_eq(const std::any& lhs, const std::any& rhs)
188 {
189  const auto& lvec = std::any_cast<T>(lhs);
190  const auto& rvec = std::any_cast<U>(rhs);
191  if (lvec.size() != rvec.size()) {
192  return false;
193  } else {
194  return std::equal(lvec.begin(), lvec.end(), rvec.begin());
195  }
196 }
197 
198 template<class T, class U>
199 bool AnyValue::vector2_eq(const std::any& lhs, const std::any& rhs)
200 {
201  const auto& lvec = std::any_cast<vector<T>>(lhs);
202  const auto& rvec = std::any_cast<vector<U>>(rhs);
203  if (lvec.size() != rvec.size()) {
204  return false;
205  } else {
206  for (size_t i = 0; i < lvec.size(); i++) {
207  if (!std::equal(lvec[i].begin(), lvec[i].end(), rvec[i].begin())) {
208  return false;
209  }
210  }
211  return true;
212  }
213 }
214 
215 template<class T>
216 bool AnyValue::eq_comparer(const std::any& lhs, const std::any& rhs)
217 {
218  using std::any_cast;
219  typedef vector<double> vd;
220  typedef vector<long int> vi;
221  typedef vector<AnyValue> va;
222  typedef vector<string> vs;
223 
224  auto& ltype = lhs.type();
225  auto& rtype = rhs.type();
226  AssertThrowMsg(ltype == typeid(T),
227  "AnyValue::eq_comparer", "Compare function does not match held type");
228 
229  if (ltype == rtype) {
230  return any_cast<T>(lhs) == any_cast<T>(rhs);
231  } else if (ltype == typeid(double) && rtype == typeid(long int)) {
232  return any_cast<double>(lhs) == any_cast<long int>(rhs);
233  } else if (ltype == typeid(long int) && rtype == typeid(double)) {
234  return any_cast<long int>(lhs) == any_cast<double>(rhs);
235 
236  } else if (ltype == typeid(vd) && rtype == typeid(vi)) {
237  return vector_eq<vd, vi>(lhs, rhs);
238  } else if (ltype == typeid(vi) && rtype == typeid(vd)) {
239  return vector_eq<vi, vd>(lhs, rhs);
240 
241  } else if (ltype == typeid(va)) {
242  if (rtype == typeid(vd)) {
243  return vector_eq<va, vd>(lhs, rhs);
244  } else if (rtype == typeid(vi)) {
245  return vector_eq<va, vi>(lhs, rhs);
246  } else if (rtype == typeid(vs)) {
247  return vector_eq<va, vs>(lhs, rhs);
248  }
249  } else if (rtype == typeid(va)) {
250  if (ltype == typeid(vd)) {
251  return vector_eq<vd, va>(lhs, rhs);
252  } else if (ltype == typeid(vi)) {
253  return vector_eq<vi, va>(lhs, rhs);
254  } else if (ltype == typeid(vs)) {
255  return vector_eq<vs, va>(lhs, rhs);
256  }
257  } else if (ltype == typeid(vector<vd>) && rtype == typeid(vector<vi>)) {
258  return vector2_eq<vd, vi>(lhs, rhs);
259  } else if (ltype == typeid(vector<vi>) && rtype == typeid(vector<vd>)) {
260  return vector2_eq<vd, vi>(lhs, rhs);
261  }
262  return false;
263 }
264 
265 }
266 #endif
A wrapper for a variable whose type is determined at runtime.
Definition: AnyMap.h:86
bool isVector() const
Returns true if the held value is a vector of the specified type, such as vector<double>.
Definition: AnyMap.inl.h:75
map< string, T > asMap() const
Return the held AnyMap as a map where all of the values have the specified type.
Definition: AnyMap.inl.h:162
static bool vector2_eq(const std::any &lhs, const std::any &rhs)
Helper function for comparing nested vectors of different (but comparable) types, for example vector<...
Definition: AnyMap.inl.h:199
bool isMatrix(size_t cols=npos) const
Returns true if the held value is a matrix of the specified type and a consistent number of columns,...
Definition: AnyMap.inl.h:80
static bool eq_comparer(const std::any &lhs, const std::any &rhs)
Equality comparison function used when lhs is of type T
Definition: AnyMap.inl.h:216
double & asDouble()
Return the held value as a double, if it is a double or a long int.
Definition: AnyMap.cpp:824
string m_key
Key of this value in a parent AnyMap
Definition: AnyMap.h:301
std::any m_value
The held value.
Definition: AnyMap.h:304
bool is() const
Returns true if the held value is of the specified type.
Definition: AnyMap.inl.h:68
const vector< T > & asVector(size_t nMin=npos, size_t nMax=npos) const
Return the held value, if it is a vector of type T.
Definition: AnyMap.inl.h:109
static bool vector_eq(const std::any &lhs, const std::any &rhs)
Helper function for comparing vectors of different (but comparable) types, for example vector<double>...
Definition: AnyMap.inl.h:187
const T & as() const
Get the value of this key as the specified type.
Definition: AnyMap.inl.h:16
Error thrown for problems processing information contained in an AnyMap or AnyValue.
Definition: AnyMap.h:738
#define AssertThrowMsg(expr, procedure,...)
Assertion must be true or an error is thrown.
Definition: ctexceptions.h:278
string demangle(const std::type_info &type)
Convert a type name to a human readable string, using boost::core::demangle if available.
Definition: global.cpp:213
Namespace for the Cantera kernel.
Definition: AnyMap.cpp:564
const size_t npos
index returned by functions to indicate "no position"
Definition: ct_defs.h:180