Cantera  3.1.0
Loading...
Searching...
No Matches
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
7
8namespace Cantera
9{
10// re-declared to avoid needing to include global.h here
11string demangle(const std::type_info& type);
12
13// Definitions for AnyValue templated functions
14
15template<class T>
16const 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
60template<class T>
61T &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
67template<class T>
68bool AnyValue::is() const {
69 return m_value.type() == typeid(T);
70}
71
72template<> bool AnyValue::is<vector<double>>() const;
73
74template<class T>
75bool AnyValue::isVector() const {
76 return m_value.type() == typeid(vector<T>);
77}
78
79template<class T>
80bool 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
101template<class T>
102AnyValue &AnyValue::operator=(const vector<T> &value) {
103 m_value = value;
104 m_equals = eq_comparer<vector<T>>;
105 return *this;
106}
107
108template<class T>
109const 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
115template<class T>
116vector<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
122template<class T>
123AnyValue& 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
133template<class T>
134AnyValue& 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
144template<>
145inline 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
161template<class T>
162map<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
171template<class T>
172void 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
186template<class T, class U>
187bool 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
198template<class T, class U>
199bool 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
215template<class T>
216bool 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 demangle(ltype), demangle(typeid(T)));
229
230 if (ltype == rtype) {
231 return any_cast<T>(lhs) == any_cast<T>(rhs);
232 } else if (ltype == typeid(double) && rtype == typeid(long int)) {
233 return any_cast<double>(lhs) == any_cast<long int>(rhs);
234 } else if (ltype == typeid(long int) && rtype == typeid(double)) {
235 return any_cast<long int>(lhs) == any_cast<double>(rhs);
236
237 } else if (ltype == typeid(vd) && rtype == typeid(vi)) {
238 return vector_eq<vd, vi>(lhs, rhs);
239 } else if (ltype == typeid(vi) && rtype == typeid(vd)) {
240 return vector_eq<vi, vd>(lhs, rhs);
241
242 } else if (ltype == typeid(va)) {
243 if (rtype == typeid(vd)) {
244 return vector_eq<va, vd>(lhs, rhs);
245 } else if (rtype == typeid(vi)) {
246 return vector_eq<va, vi>(lhs, rhs);
247 } else if (rtype == typeid(vs)) {
248 return vector_eq<va, vs>(lhs, rhs);
249 }
250 } else if (rtype == typeid(va)) {
251 if (ltype == typeid(vd)) {
252 return vector_eq<vd, va>(lhs, rhs);
253 } else if (ltype == typeid(vi)) {
254 return vector_eq<vi, va>(lhs, rhs);
255 } else if (ltype == typeid(vs)) {
256 return vector_eq<vs, va>(lhs, rhs);
257 }
258 } else if (ltype == typeid(vector<vd>) && rtype == typeid(vector<vi>)) {
259 return vector2_eq<vd, vi>(lhs, rhs);
260 } else if (ltype == typeid(vector<vi>) && rtype == typeid(vector<vd>)) {
261 return vector2_eq<vd, vi>(lhs, rhs);
262 }
263 return false;
264}
265
266}
267#endif
A wrapper for a variable whose type is determined at runtime.
Definition AnyMap.h:87
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:867
string m_key
Key of this value in a parent AnyMap
Definition AnyMap.h:305
std::any m_value
The held value.
Definition AnyMap.h:308
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:749
#define AssertThrowMsg(expr, procedure,...)
Assertion must be true or an error is thrown.
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:595
const size_t npos
index returned by functions to indicate "no position"
Definition ct_defs.h:180