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