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