Cantera  3.1.0a1
AnyMap.h
Go to the documentation of this file.
1 //! @file AnyMap.h
2 
3 // This file is part of Cantera. See License.txt in the top-level directory or
4 // at https://cantera.org/license.txt for license and copyright information.
5 
6 #ifndef CT_ANYMAP_H
7 #define CT_ANYMAP_H
8 
9 #include "cantera/base/ct_defs.h"
11 #include "cantera/base/Units.h"
12 
13 #include <unordered_map>
14 #include <filesystem>
15 #include <any>
16 
17 namespace YAML
18 {
19 class Emitter;
20 Emitter& operator<<(Emitter& out, const Cantera::AnyMap& rhs);
21 Emitter& operator<<(Emitter& out, const Cantera::AnyValue& rhs);
22 }
23 
24 namespace Cantera
25 {
26 
27 //! @defgroup anyGroup Generic Containers
28 //! Generic containers for storing data of any type.
29 //! @ingroup ioGroup
30 
31 //! Base class defining common data possessed by both AnyMap and AnyValue
32 //! objects.
33 //! @ingroup anyGroup
34 class AnyBase {
35 public:
36  AnyBase() = default;
37  virtual ~AnyBase() = default;
38 
39  //! For values which are derived from an input file, set the line and column
40  //! of this value in that file. Used for providing context for some error
41  //! messages.
42  void setLoc(int line, int column);
43 
44  //! Get a value from the metadata applicable to the AnyMap tree containing
45  //! this node.
46  const AnyValue& getMetadata(const string& key) const;
47 
48 protected:
49  //! The line where this value occurs in the input file. Set to -1 for values
50  //! that weren't created from an input file.
51  int m_line = -1;
52 
53  //! If m_line >= 0, the column where this value occurs in the input file.
54  //! If m_line == -1, a value used for determining output ordering
55  int m_column = 0;
56 
57  //! Metadata relevant to an entire AnyMap tree, such as information about
58  // the input file used to create it
59  shared_ptr<AnyMap> m_metadata;
60 
61  friend class InputFileError;
62  friend void warn_deprecated(const string& source, const AnyBase& node,
63  const string& message);
64 };
65 
66 class AnyMap;
67 
68 //! A wrapper for a variable whose type is determined at runtime
69 /*!
70  * Instances of AnyValue are used as values in an AnyMap. Values are converted
71  * to a concrete type using the templated as() method or convenience methods
72  * such as asString() and asDouble(). See AnyMap for usage examples.
73  *
74  * Elements are set using assignment, and the assignment operator has been
75  * overloaded for specific types so that only those types are allowed to be
76  * used in an AnyValue. The allowed types are:
77  * - `AnyMap`
78  * - `double`
79  * - `long int`
80  * - `bool`
81  * - `string`
82  * - `vector` of any of the above
83  * @ingroup anyGroup
84  */
85 class AnyValue : public AnyBase
86 {
87 public:
88  AnyValue();
89  ~AnyValue();
90 
91  bool operator==(const AnyValue& other) const;
92  bool operator!=(const AnyValue& other) const;
93 
94  //! If this AnyValue is an AnyMap, return the value stored in `key`.
95  AnyValue& operator[](const string& key);
96  const AnyValue& operator[](const string& key) const;
97 
98  //! Returns `true` if this AnyValue is an AnyMap and that map contains
99  //! a key with the given name.
100  bool hasKey(const string& key) const;
101 
102  //! Set the name of the key storing this value in an AnyMap. Used for
103  //! providing informative error messages in class InputFileError.
104  void setKey(const string& key);
105 
106  //! Propagate metadata to any child elements
107  void propagateMetadata(shared_ptr<AnyMap>& file);
108 
109  //! Get the value of this key as the specified type.
110  template<class T>
111  const T& as() const;
112 
113  template<class T>
114  T& as();
115 
116  //! Returns the type of the held value.
117  const std::type_info& type() const;
118 
119  //! Returns a string specifying the type of the held value.
120  string type_str() const;
121 
122  //! Return boolean indicating whether AnyValue is empty.
123  bool empty() const;
124 
125  //! Returns `true` if the held value is of the specified type.
126  template<class T>
127  bool is() const;
128 
129  //! Returns `true` if the held value is a vector of the specified type, such as
130  //! `vector<double>`.
131  //! @since New in %Cantera 3.0.
132  template<class T>
133  bool isVector() const;
134 
135  //! Returns `true` if the held value is a matrix of the specified type and a
136  //! consistent number of columns, such as `vector<vector<double>>`. If the
137  //! number of columns is provided, a match is required.
138  //! @since New in %Cantera 3.0.
139  template<class T>
140  bool isMatrix(size_t cols=npos) const;
141 
142  //! Returns `true` if the held value is a scalar type (such as `double`, `long
143  //! int`, `string`, or `bool`).
144  bool isScalar() const;
145 
146  //! Returns size of the held vector.
147  //! If not a vector or the type is not supported npos is returned.
148  //! Types considered include `vector<double>`, `vector<long int>`, `vector<string>`,
149  //! and `vector<bool`.
150  //! @since New in %Cantera 3.0.
151  size_t vectorSize() const;
152 
153  //! Returns rows and columns of a matrix.
154  //! If the number of columns is not consistent, the number of columns is set to
155  //! npos; if the type is not supported, a npos pair is returned.
156  //! Types considered include `vector<vector<double>>`, `vector<vector<long int>>`,
157  //! `vector<vector<string>>` and `vector<vector<bool>>`.
158  //! @since New in %Cantera 3.0.
159  pair<size_t, size_t> matrixShape() const;
160 
161  explicit AnyValue(const string& value);
162  explicit AnyValue(const char* value);
163  AnyValue& operator=(const string& value);
164  AnyValue& operator=(const char* value);
165  //! Return the held value, if it is a string
166  const string& asString() const;
167  bool operator==(const string& other) const;
168  bool operator!=(const string& other) const;
169  friend bool operator==(const string& lhs, const AnyValue& rhs);
170  friend bool operator!=(const string& lhs, const AnyValue& rhs);
171 
172  //! @name Quantity conversions
173  //! Assign a quantity consisting of one or more values and their
174  //! corresponding units, which will be converted to a target unit system
175  //! when the applyUnits() function is later called on the root of the
176  //! AnyMap.
177  //! @{
178 
179  //! Assign a scalar quantity with units as a string, for example
180  //! `{3.0, "m^2"}`. If the `is_act_energy` flag is set to `true`, the units
181  //! will be converted using the special rules for activation energies.
182  void setQuantity(double value, const string& units, bool is_act_energy=false);
183 
184  //! Assign a scalar quantity with units as a Units object, for cases where
185  //! the units vary and are determined dynamically, such as reaction
186  //! pre-exponential factors
187  void setQuantity(double value, const Units& units);
188 
189  //! Assign a vector where all the values have the same units
190  void setQuantity(const vector<double>& values, const string& units);
191 
192  typedef function<void(AnyValue&, const UnitSystem&)> unitConverter;
193 
194  //! Assign a value of any type where the unit conversion requires a
195  //! different behavior besides scaling all values by the same factor
196  void setQuantity(const AnyValue& value, const unitConverter& converter);
197  //! @} end group quantity conversions
198 
199  explicit AnyValue(double value);
200  AnyValue& operator=(double value);
201  //! Return the held value as a `double`, if it is a `double` or a `long
202  //! int`.
203  double& asDouble();
204  const double& asDouble() const;
205  bool operator==(const double& other) const;
206  bool operator!=(const double& other) const;
207  friend bool operator==(const double& lhs, const AnyValue& rhs);
208  friend bool operator!=(const double& lhs, const AnyValue& rhs);
209 
210  explicit AnyValue(bool value);
211  AnyValue& operator=(bool value);
212  //! Return the held value, if it is a `bool`.
213  bool& asBool();
214  const bool& asBool() const;
215 
216  explicit AnyValue(long int value);
217  explicit AnyValue(int value);
218  AnyValue& operator=(long int value);
219  AnyValue& operator=(int value);
220  //! Return the held value, if it is a `long int`.
221  long int& asInt();
222  const long int& asInt() const;
223  bool operator==(const long int& other) const;
224  bool operator!=(const long int& other) const;
225  bool operator==(const int& other) const;
226  bool operator!=(const int& other) const;
227  friend bool operator==(const long int& lhs, const AnyValue& rhs);
228  friend bool operator!=(const long int& lhs, const AnyValue& rhs);
229  friend bool operator==(const int& lhs, const AnyValue& rhs);
230  friend bool operator!=(const int& lhs, const AnyValue& rhs);
231 
232  template<class T>
233  AnyValue& operator=(const vector<T>& value);
234  //! Return the held value, if it is a vector of type `T`. If called with one
235  //! argument, requires the vector to be of the specified size. If called
236  //! with two arguments, requires the vector to be within the range specified
237  //! by the two values, inclusive.
238  template<class T>
239  const vector<T>& asVector(size_t nMin=npos, size_t nMax=npos) const;
240  template<class T>
241  vector<T>& asVector(size_t nMin=npos, size_t nMax=npos);
242 
243  explicit AnyValue(const AnyMap& value);
244  AnyValue& operator=(const AnyMap& value);
245  AnyValue& operator=(AnyMap&& value);
246 
247  template<class T>
248  AnyValue& operator=(const std::unordered_map<string, T> items);
249 
250  template<class T>
251  AnyValue& operator=(const map<string, T> items);
252 
253  //! Return the held `AnyMap` as a `map` where all of the values have
254  //! the specified type.
255  template<class T>
256  map<string, T> asMap() const;
257 
258  //! Access a `vector<AnyMap>` as a mapping using the value of `name` from
259  //! each item as the key in the new mapping.
260  /*!
261  * For example, for the list:
262  * ```
263  * [{name: O2, weight: 32}, {name: CH4, weight: 16}]
264  * ```
265  * calling `asMap("name")` will create a map with keys ``O2`` and ``CH4``.
266  */
267  std::unordered_map<string, const AnyMap*> asMap(const string& name) const;
268  std::unordered_map<string, AnyMap*> asMap(const string& name);
269 
270  //! Treating the value as `vector<AnyMap>`, return the item where the given
271  //! key has the specified value.
272  /*!
273  * If value is the empty string, returns the first item in the list.
274  *
275  * If the contained type is just `AnyMap` rather than `vector<AnyMap>`, it
276  * will be treated as a vector of length 1.
277  *
278  * If the value does not exist but the `create` flag is set to true, a new
279  * map with that key and value will be created and returned.
280  */
281  AnyMap& getMapWhere(const string& key, const string& value, bool create=false);
282  const AnyMap& getMapWhere(const string& key, const string& value) const;
283 
284  //! Returns `true` when getMapWhere() would succeed
285  bool hasMapWhere(const string& key, const string& value) const;
286 
287  //! Return values used to determine the sort order when outputting to YAML
288  pair<int, int> order() const;
289 
290  //! See AnyMap::applyUnits()
291  void applyUnits(shared_ptr<UnitSystem>& units);
292 
293  //! See AnyMap::setFlowStyle()
294  void setFlowStyle(bool flow=true);
295 
296 private:
297  template<class T>
298  void checkSize(const vector<T>& v, size_t nMin, size_t nMax) const;
299 
300  //! Key of this value in a parent `AnyMap`
301  string m_key;
302 
303  //! The held value
304  std::any m_value;
305 
306  typedef bool (*Comparer)(const std::any&, const std::any&);
307 
308  //! Equality comparison function used when *lhs* is of type *T*
309  template <typename T>
310  static bool eq_comparer(const std::any& lhs, const std::any& rhs);
311 
312  //! Helper function for comparing vectors of different (but comparable)
313  //! types, for example `vector<double>` and `vector<long int>`
314  template<class T, class U>
315  static bool vector_eq(const std::any& lhs, const std::any& rhs);
316 
317  //! Helper function for comparing nested vectors of different (but
318  //! comparable) types, for example `vector<vector<double>>` and
319  //! `vector<vector<long int>>`
320  template<class T, class U>
321  static bool vector2_eq(const std::any& lhs, const std::any& rhs);
322 
323  mutable Comparer m_equals;
324 
325  friend YAML::Emitter& YAML::operator<<(YAML::Emitter& out, const AnyValue& rhs);
326 };
327 
328 //! Implicit conversion to vector<AnyValue>
329 template<>
330 const vector<AnyValue>& AnyValue::asVector<AnyValue>(size_t nMin, size_t nMax) const;
331 
332 template<>
333 vector<AnyValue>& AnyValue::asVector<AnyValue>(size_t nMin, size_t nMax);
334 
335 //! Implicit conversion of long int to double if accessed as a vector<double>
336 template<>
337 const vector<double>& AnyValue::asVector<double>(size_t nMin, size_t nMax) const;
338 
339 template<>
340 vector<double>& AnyValue::asVector<double>(size_t nMin, size_t nMax);
341 
342 //! Implicit conversion of long int to double if accessed as a vector<vector<double>>
343 template<>
344 const vector<vector<double>>& AnyValue::asVector<vector<double>>(size_t nMin,
345  size_t nMax) const;
346 
347 template<>
348 vector<vector<double>>& AnyValue::asVector<vector<double>>(size_t nMin, size_t nMax);
349 
350 //! Implicit conversion of AnyMap to a vector<AnyMap> of length 1, or an empty
351 //! vector<AnyValue> an empty vector<AnyMap>
352 template<>
353 const vector<AnyMap>& AnyValue::asVector<AnyMap>(size_t nMin, size_t nMax) const;
354 
355 template<>
356 vector<AnyMap>& AnyValue::asVector<AnyMap>(size_t nMin, size_t nMax);
357 
358 //! A map of string keys to values whose type can vary at runtime
359 /*!
360  * Values in an AnyMap are held by instances of AnyValue. Instances of AnyMap
361  * can be nested to form a tree.
362  *
363  * ## Setting elements
364  *
365  * ```
366  * AnyMap breakfast;
367  * breakfast["spam"] = 123.4; // Creates a value of type 'double'
368  * breakfast["eggs"] = "scrambled"; // Creates a value of type 'string'
369  *
370  * // Create a nested AnyMap named "beans" which has a key named "baked"
371  * // whose value is a vector<double>
372  * vector<double> v{3.14, 1.59, 2.65};
373  * breakfast["beans"]["baked"] = v;
374  *
375  * // Create a nested AnyMap with values of the same type
376  * map<string, double> breads{{"wheat", 4.0}, {"white", 2.5}};
377  * breakfast["toast"] = breads;
378  * // Equivalent to:
379  * breakfast["toast"]["wheat"] = 4.0
380  * breakfast["toast"]["white"] = 2.5
381  * ```
382  *
383  * ## Accessing elements
384  *
385  * ```
386  * double val1 = breakfast["spam"].asDouble();
387  * string val2 = breakfast["eggs"].asString();
388  * vector<double> val3 = breakfast["beans"]["baked"].asVector<double>();
389  *
390  * map<string, double> = breakfast["toast"].asMap<double>();
391  * ```
392  *
393  * ## Checking for elements
394  *
395  * ```
396  * try {
397  * breakfast["waffle"].asDouble();
398  * } except (std::exception& err) {
399  * // Exception will be thrown.
400  * // 'breakfast' will have an empty key named 'waffle' unless 'breakfast'
401  * // is a 'const AnyMap'.
402  * }
403  *
404  * try {
405  * breakfast.at("grits").asDouble();
406  * } except (std::exception& err) {
407  * // Exception will be thrown and no new key will be added
408  * }
409  *
410  * if (breakfast.hasKey("grits")) {
411  * // do something with this entry
412  * }
413  * ```
414  *
415  * ## Checking element types
416  *
417  * ```
418  * if (breakfast["sausage"].is<vector<double>>()) {
419  * // access using asVector<double>
420  * } else if (breakfast["sausage"].type() == typeid(vector<string>)) {
421  * // access using asVector<string>
422  * }
423  * ```
424  * @ingroup anyGroup
425  */
426 class AnyMap : public AnyBase
427 {
428 public:
429  AnyMap();
430 
431  //! Create an AnyMap from a YAML file.
432  /*!
433  * Searches the directory containing the optionally-specified parent file
434  * first, followed by the current working directory and the %Cantera include
435  * path.
436  */
437  static AnyMap fromYamlFile(const string& name,
438  const string& parent_name="");
439 
440  //! Create an AnyMap from a string containing a YAML document
441  static AnyMap fromYamlString(const string& yaml);
442 
443  string toYamlString() const;
444 
445  //! Get the value of the item stored in `key`.
446  AnyValue& operator[](const string& key);
447  const AnyValue& operator[](const string& key) const;
448 
449  //! Used to create a new item which will be populated from a YAML input
450  //! string, where the item with `key` occurs at the specified line and
451  //! column within the string.
452  AnyValue& createForYaml(const string& key, int line, int column);
453 
454  //! Get the value of the item stored in `key`. Raises an exception if the
455  //! value does not exist.
456  const AnyValue& at(const string& key) const;
457 
458  //! Return boolean indicating whether AnyMap is empty.
459  bool empty() const;
460 
461  //! Returns `true` if the map contains an item named `key`.
462  bool hasKey(const string& key) const;
463 
464  //! Erase the value held by `key`.
465  void erase(const string& key);
466 
467  //! Erase all items in the mapping
468  void clear();
469 
470  //! Add items from `other` to this AnyMap. If keys in `other` also exist in
471  //! this AnyMap, the `keepExisting` option determines which item is used.
472  void update(const AnyMap& other, bool keepExisting=true);
473 
474  //! Return a string listing the keys in this AnyMap, for use in error
475  //! messages, for example
476  string keys_str() const;
477 
478  //! Return an unordered set of keys
479  //! @since New in %Cantera 3.0.
480  set<string> keys() const;
481 
482  //! Set a metadata value that applies to this AnyMap and its children.
483  //! Mainly for internal use in reading or writing from files.
484  void setMetadata(const string& key, const AnyValue& value);
485 
486  //! Copy metadata including input line/column from an existing AnyMap
487  void copyMetadata(const AnyMap& other);
488 
489  //! Propagate metadata to any child elements
490  void propagateMetadata(shared_ptr<AnyMap>& file);
491 
492  //! If `key` exists, return it as a `bool`, otherwise return `default_`.
493  bool getBool(const string& key, bool default_) const;
494 
495  //! If `key` exists, return it as a `long int`, otherwise return `default_`.
496  long int getInt(const string& key, long int default_) const;
497 
498  //! If `key` exists, return it as a `double`, otherwise return `default_`.
499  double getDouble(const string& key, double default_) const;
500 
501  //! If `key` exists, return it as a `string`, otherwise return `default_`.
502  const string& getString(const string& key,
503  const string& default_) const;
504 
505  //! Convert the item stored by the given `key` to the units specified in
506  //! `units`. If the stored value is a double, convert it using the default
507  //! units. If the input is a string, treat this as a dimensioned value, such
508  //! as '988 kg/m^3' and convert from the specified units.
509  double convert(const string& key, const string& units) const;
510  double convert(const string& key, const Units& units) const;
511 
512  //! Convert the item stored by the given `key` to the units specified in
513  //! `units`. If the stored value is a double, convert it using the default
514  //! units. If the input is a string, treat this as a dimensioned value, such
515  //! as '988 kg/m^3' and convert from the specified units. If the key is
516  //! missing, the `default_` value is returned.
517  double convert(const string& key, const string& units,
518  double default_) const;
519 
520  //! Convert a vector of dimensional values
521  /*!
522  * For each item in the vector, if the stored value is a double, convert it
523  * using the default units. If the value is a string, treat it as a
524  * dimensioned value, such as '988 kg/m^3', and convert from the specified
525  * units.
526  *
527  * @param key Location of the vector in this AnyMap
528  * @param units Units to convert to
529  * @param nMin Minimum allowed length of the vector. If `nMax` is not
530  * specified, this is also taken to be the maximum length. An exception
531  * is thrown if this condition is not met.
532  * @param nMax Maximum allowed length of the vector. An exception is
533  * thrown if this condition is not met.
534  */
535  vector<double> convertVector(const string& key, const string& units,
536  size_t nMin=npos, size_t nMax=npos) const;
537 
538  //! Defined to allow use with range-based for loops. Iteration automatically
539  //! skips over keys that start and end with double underscores.
540  class Iterator {
541  public:
542  Iterator() {}
543  Iterator(const std::unordered_map<string, AnyValue>::const_iterator& start,
544  const std::unordered_map<string, AnyValue>::const_iterator& stop);
545 
546  const pair<const string, AnyValue>& operator*() const {
547  return *m_iter;
548  }
549  const pair<const string, AnyValue>* operator->() const {
550  return &*m_iter;
551  }
552  bool operator!=(const Iterator& right) const {
553  return m_iter != right.m_iter;
554  }
555  Iterator& operator++();
556 
557  private:
558  std::unordered_map<string, AnyValue>::const_iterator m_iter;
559  std::unordered_map<string, AnyValue>::const_iterator m_stop;
560  };
561 
562  //! Defined to allow use with range-based for loops
563  Iterator begin() const {
564  return Iterator(m_data.begin(), m_data.end());
565  }
566 
567  //! Defined to allow use with range-based for loops
568  Iterator end() const {
569  return Iterator(m_data.end(), m_data.end());
570  }
571 
572  class OrderedIterator;
573 
574  //! Proxy for iterating over an AnyMap in the defined output ordering.
575  //! See ordered().
576  class OrderedProxy {
577  public:
578  OrderedProxy() {}
579  OrderedProxy(const AnyMap& data);
580  OrderedIterator begin() const;
581  OrderedIterator end() const;
582 
583  typedef vector<pair<
584  pair<int, int>,
585  const pair<const string, AnyValue>*>> OrderVector;
586  private:
587  const AnyMap* m_data;
588  OrderVector m_ordered;
589  unique_ptr<pair<const string, AnyValue>> m_units;
590  };
591 
592  //! Defined to allow the OrderedProxy class to be used with range-based
593  //! for loops.
595  public:
596  OrderedIterator() {}
597  OrderedIterator(const AnyMap::OrderedProxy::OrderVector::const_iterator& start,
598  const AnyMap::OrderedProxy::OrderVector::const_iterator& stop);
599 
600  const pair<const string, AnyValue>& operator*() const {
601  return *m_iter->second;
602  }
603  const pair<const string, AnyValue>* operator->() const {
604  return &(*m_iter->second);
605  }
606  bool operator!=(const OrderedIterator& right) const {
607  return m_iter != right.m_iter;
608  }
609  OrderedIterator& operator++() { ++m_iter; return *this; }
610 
611  private:
612  OrderedProxy::OrderVector::const_iterator m_iter;
613  OrderedProxy::OrderVector::const_iterator m_stop;
614  };
615 
616  // Return a proxy object that allows iteration in an order determined by the
617  // order of insertion, the location in an input file, and rules specified by
618  // the addOrderingRules() method.
619  OrderedProxy ordered() const { return OrderedProxy(*this); }
620 
621  //! Returns the number of elements in this map
622  size_t size() const {
623  return m_data.size();
624  };
625 
626  bool operator==(const AnyMap& other) const;
627  bool operator!=(const AnyMap& other) const;
628 
629  //! Return the default units that should be used to convert stored values
630  const UnitSystem& units() const { return *m_units; }
631 
632  //! @copydoc units()
633  shared_ptr<UnitSystem> unitsShared() const { return m_units; }
634 
635  //! Use the supplied UnitSystem to set the default units, and recursively
636  //! process overrides from nodes named `units`.
637  /*!
638  * If a `units` node is present in a map that contains other keys, the
639  * specified units are taken to be the defaults for that map. If the map
640  * contains only a `units` node, and is the first item in a list of maps,
641  * then the specified units are taken to be the defaults for all the maps in
642  * the list.
643  *
644  * After being processed, the `units` nodes are removed. This function is
645  * called automatically by the fromYamlFile() and fromYamlString()
646  * constructors.
647  *
648  * @warning This function is an experimental part of the %Cantera API and
649  * may be changed or removed without notice.
650  */
651  void applyUnits();
652 
653  //! See applyUnits()
654  void applyUnits(shared_ptr<UnitSystem>& units);
655 
656  //! Set the unit system for this AnyMap. The applyUnits() method should be
657  //! called on the root AnyMap object after all desired calls to setUnits()
658  //! in the tree have been made.
659  void setUnits(const UnitSystem& units);
660 
661  //! Use "flow" style when outputting this AnyMap to YAML
662  void setFlowStyle(bool flow=true);
663 
664  //! Add global rules for setting the order of elements when outputting
665  //! AnyMap objects to YAML
666  /*!
667  * Enables specifying keys that should appear at either the beginning
668  * or end of the generated YAML mapping. Only programmatically-added keys
669  * are rearranged. Keys which come from YAML input retain their existing
670  * ordering, and are output after programmatically-added keys.
671  *
672  * This function should be called exactly once for any given spec that
673  * is to be added. To facilitate this, the method returns a bool so that
674  * it can be called as part of initializing a static variable. To avoid
675  * spurious compiler warnings about unused variables, the following
676  * structure can be used:
677  *
678  * ```
679  * static bool reg = AnyMap::addOrderingRules("Reaction",
680  * {{"head", "equation"}, {"tail", "duplicate"}});
681  * if (reg) {
682  * reactionMap["__type__"] = "Reaction";
683  * }
684  * ```
685  *
686  * @param objectType Apply rules to maps where the hidden `__type__` key
687  * has the corresponding value.
688  * @param specs A list of rule specifications. Each rule consists of
689  * two strings. The first string is either "head" or "tail", and the
690  * second string is the name of a key
691  * @returns ``true``, to facilitate static initialization
692  */
693  static bool addOrderingRules(const string& objectType,
694  const vector<vector<string>>& specs);
695 
696  //! Remove the specified file from the input cache if it is present
697  static void clearCachedFile(const string& filename);
698 
699 private:
700  //! The stored data
701  std::unordered_map<string, AnyValue> m_data;
702 
703  //! The default units that are used to convert stored values
704  shared_ptr<UnitSystem> m_units;
705 
706  //! Cache for previously-parsed input (YAML) files. The key is the full path
707  //! to the file, and the second element of the value is the last-modified
708  //! time for the file, which is used to enable change detection.
709  static std::unordered_map<string,
710  pair<AnyMap, std::filesystem::file_time_type>> s_cache;
711 
712  //! Information about fields that should appear first when outputting to
713  //! YAML. Keys in this map are matched to `__type__` keys in AnyMap
714  //! objects, and values are a list of field names.
715  static std::unordered_map<string, vector<string>> s_headFields;
716 
717  //! Information about fields that should appear last when outputting to
718  //! YAML. Keys in this map are matched to `__type__` keys in AnyMap
719  //! objects, and values are a list of field names.
720  static std::unordered_map<string, vector<string>> s_tailFields;
721 
722  friend class AnyValue;
723  friend YAML::Emitter& YAML::operator<<(YAML::Emitter& out, const AnyMap& rhs);
724 };
725 
726 // Define begin() and end() to allow use with range-based for loops
727 AnyMap::Iterator begin(const AnyValue& v);
728 AnyMap::Iterator end(const AnyValue& v);
729 
730 //! Error thrown for problems processing information contained in an AnyMap or
731 //! AnyValue.
732 /*!
733  * This class uses the file, line, and column information stored in an AnyMap
734  * or AnyValue to provide an error message including context lines for the
735  * original user input.
736  */
738 {
739 public:
740  //! Indicate an error occurring in `procedure` while using information from
741  //! `node`. The `message` and `args` are processed as in the CanteraError
742  //! class.
743  template <typename... Args>
744  InputFileError(const string& procedure, const AnyBase& node,
745  const string& message, const Args&... args)
746  : CanteraError(
747  procedure,
748  formatError(
749  (sizeof...(args) == 0) ? message : fmt::format(message, args...),
750  node.m_line, node.m_column, node.m_metadata))
751  {
752  }
753 
754  //! Indicate an error occurring in `procedure` while using information from
755  //! `node1` and `node2`. The `message` and `args` are processed as in the
756  //! CanteraError class.
757  template <typename... Args>
758  InputFileError(const string& procedure, const AnyBase& node1,
759  const AnyBase& node2, const string& message,
760  const Args&... args)
761  : CanteraError(
762  procedure,
763  formatError2(
764  (sizeof...(args) == 0) ? message : fmt::format(message, args...),
765  node1.m_line, node1.m_column, node1.m_metadata,
766  node2.m_line, node2.m_column, node2.m_metadata))
767  {
768  }
769 
770  string getClass() const override {
771  return "InputFileError";
772  }
773 protected:
774  static string formatError(const string& message, int line, int column,
775  const shared_ptr<AnyMap>& metadata);
776  static string formatError2(const string& message,
777  int line1, int column1, const shared_ptr<AnyMap>& metadata1,
778  int line2, int column2, const shared_ptr<AnyMap>& metadata2);
779 };
780 
781 //! A deprecation warning for syntax in an input file
782 void warn_deprecated(const string& source, const AnyBase& node,
783  const string& message);
784 
785 }
786 
787 #include "cantera/base/AnyMap.inl.h"
788 
789 #endif
Header for unit conversion utilities, which are used to translate user input from input files (See In...
Base class defining common data possessed by both AnyMap and AnyValue objects.
Definition: AnyMap.h:34
int m_column
If m_line >= 0, the column where this value occurs in the input file.
Definition: AnyMap.h:55
void setLoc(int line, int column)
For values which are derived from an input file, set the line and column of this value in that file.
Definition: AnyMap.cpp:574
int m_line
The line where this value occurs in the input file.
Definition: AnyMap.h:51
friend void warn_deprecated(const string &source, const AnyBase &node, const string &message)
A deprecation warning for syntax in an input file.
Definition: AnyMap.cpp:1926
const AnyValue & getMetadata(const string &key) const
Get a value from the metadata applicable to the AnyMap tree containing this node.
Definition: AnyMap.cpp:580
shared_ptr< AnyMap > m_metadata
Metadata relevant to an entire AnyMap tree, such as information about.
Definition: AnyMap.h:59
Defined to allow use with range-based for loops.
Definition: AnyMap.h:540
Defined to allow the OrderedProxy class to be used with range-based for loops.
Definition: AnyMap.h:594
Proxy for iterating over an AnyMap in the defined output ordering.
Definition: AnyMap.h:576
A map of string keys to values whose type can vary at runtime.
Definition: AnyMap.h:427
static AnyMap fromYamlString(const string &yaml)
Create an AnyMap from a string containing a YAML document.
Definition: AnyMap.cpp:1755
Iterator begin() const
Defined to allow use with range-based for loops.
Definition: AnyMap.h:563
AnyValue & createForYaml(const string &key, int line, int column)
Used to create a new item which will be populated from a YAML input string, where the item with key o...
Definition: AnyMap.cpp:1396
set< string > keys() const
Return an unordered set of keys.
Definition: AnyMap.cpp:1462
static bool addOrderingRules(const string &objectType, const vector< vector< string >> &specs)
Add global rules for setting the order of elements when outputting AnyMap objects to YAML.
Definition: AnyMap.cpp:1730
size_t size() const
Returns the number of elements in this map.
Definition: AnyMap.h:622
long int getInt(const string &key, long int default_) const
If key exists, return it as a long int, otherwise return default_.
Definition: AnyMap.cpp:1525
void copyMetadata(const AnyMap &other)
Copy metadata including input line/column from an existing AnyMap.
Definition: AnyMap.cpp:1493
static std::unordered_map< string, pair< AnyMap, std::filesystem::file_time_type > > s_cache
Cache for previously-parsed input (YAML) files.
Definition: AnyMap.h:710
double getDouble(const string &key, double default_) const
If key exists, return it as a double, otherwise return default_.
Definition: AnyMap.cpp:1520
bool hasKey(const string &key) const
Returns true if the map contains an item named key.
Definition: AnyMap.cpp:1423
Iterator end() const
Defined to allow use with range-based for loops.
Definition: AnyMap.h:568
bool empty() const
Return boolean indicating whether AnyMap is empty.
Definition: AnyMap.cpp:1418
static void clearCachedFile(const string &filename)
Remove the specified file from the input cache if it is present.
Definition: AnyMap.cpp:1747
void applyUnits()
Use the supplied UnitSystem to set the default units, and recursively process overrides from nodes na...
Definition: AnyMap.cpp:1693
static std::unordered_map< string, vector< string > > s_headFields
Information about fields that should appear first when outputting to YAML.
Definition: AnyMap.h:715
double convert(const string &key, const string &units) const
Convert the item stored by the given key to the units specified in units.
Definition: AnyMap.cpp:1535
shared_ptr< UnitSystem > unitsShared() const
Return the default units that should be used to convert stored values.
Definition: AnyMap.h:633
void setMetadata(const string &key, const AnyValue &value)
Set a metadata value that applies to this AnyMap and its children.
Definition: AnyMap.cpp:1481
AnyValue & operator[](const string &key)
Get the value of the item stored in key.
Definition: AnyMap.cpp:1362
void setFlowStyle(bool flow=true)
Use "flow" style when outputting this AnyMap to YAML.
Definition: AnyMap.cpp:1726
void propagateMetadata(shared_ptr< AnyMap > &file)
Propagate metadata to any child elements.
Definition: AnyMap.cpp:1473
bool getBool(const string &key, bool default_) const
If key exists, return it as a bool, otherwise return default_.
Definition: AnyMap.cpp:1515
static std::unordered_map< string, vector< string > > s_tailFields
Information about fields that should appear last when outputting to YAML.
Definition: AnyMap.h:720
void clear()
Erase all items in the mapping.
Definition: AnyMap.cpp:1433
shared_ptr< UnitSystem > m_units
The default units that are used to convert stored values.
Definition: AnyMap.h:704
const string & getString(const string &key, const string &default_) const
If key exists, return it as a string, otherwise return default_.
Definition: AnyMap.cpp:1530
void erase(const string &key)
Erase the value held by key.
Definition: AnyMap.cpp:1428
const UnitSystem & units() const
Return the default units that should be used to convert stored values.
Definition: AnyMap.h:630
static AnyMap fromYamlFile(const string &name, const string &parent_name="")
Create an AnyMap from a YAML file.
Definition: AnyMap.cpp:1771
std::unordered_map< string, AnyValue > m_data
The stored data.
Definition: AnyMap.h:701
const AnyValue & at(const string &key) const
Get the value of the item stored in key.
Definition: AnyMap.cpp:1408
void update(const AnyMap &other, bool keepExisting=true)
Add items from other to this AnyMap.
Definition: AnyMap.cpp:1438
void setUnits(const UnitSystem &units)
Set the unit system for this AnyMap.
Definition: AnyMap.cpp:1714
string keys_str() const
Return a string listing the keys in this AnyMap, for use in error messages, for example.
Definition: AnyMap.cpp:1447
vector< double > convertVector(const string &key, const string &units, size_t nMin=npos, size_t nMax=npos) const
Convert a vector of dimensional values.
Definition: AnyMap.cpp:1555
A wrapper for a variable whose type is determined at runtime.
Definition: AnyMap.h:86
const string & asString() const
Return the held value, if it is a string.
Definition: AnyMap.cpp:739
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
void setKey(const string &key)
Set the name of the key storing this value in an AnyMap.
Definition: AnyMap.cpp:621
pair< int, int > order() const
Return values used to determine the sort order when outputting to YAML.
Definition: AnyMap.cpp:1107
bool hasMapWhere(const string &key, const string &value) const
Returns true when getMapWhere() would succeed.
Definition: AnyMap.cpp:1084
void setQuantity(double value, const string &units, bool is_act_energy=false)
Assign a scalar quantity with units as a string, for example {3.0, "m^2"}.
Definition: AnyMap.cpp:769
bool hasKey(const string &key) const
Returns true if this AnyValue is an AnyMap and that map contains a key with the given name.
Definition: AnyMap.cpp:617
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
bool & asBool()
Return the held value, if it is a bool.
Definition: AnyMap.cpp:871
bool empty() const
Return boolean indicating whether AnyValue is empty.
Definition: AnyMap.cpp:647
pair< size_t, size_t > matrixShape() const
Returns rows and columns of a matrix.
Definition: AnyMap.cpp:671
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
size_t vectorSize() const
Returns size of the held vector.
Definition: AnyMap.cpp:655
long int & asInt()
Return the held value, if it is a long int.
Definition: AnyMap.cpp:903
void applyUnits(shared_ptr< UnitSystem > &units)
See AnyMap::applyUnits()
Definition: AnyMap.cpp:1112
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
const std::type_info & type() const
Returns the type of the held value.
Definition: AnyMap.cpp:623
double & asDouble()
Return the held value as a double, if it is a double or a long int.
Definition: AnyMap.cpp:824
bool isScalar() const
Returns true if the held value is a scalar type (such as double, long int, string,...
Definition: AnyMap.cpp:651
AnyValue & operator[](const string &key)
If this AnyValue is an AnyMap, return the value stored in key.
Definition: AnyMap.cpp:607
string m_key
Key of this value in a parent AnyMap
Definition: AnyMap.h:301
AnyMap & getMapWhere(const string &key, const string &value, bool create=false)
Treating the value as vector<AnyMap>, return the item where the given key has the specified value.
Definition: AnyMap.cpp:1034
void setFlowStyle(bool flow=true)
See AnyMap::setFlowStyle()
Definition: AnyMap.cpp:1209
void propagateMetadata(shared_ptr< AnyMap > &file)
Propagate metadata to any child elements.
Definition: AnyMap.cpp:627
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
string type_str() const
Returns a string specifying the type of the held value.
Definition: AnyMap.cpp:643
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:66
Error thrown for problems processing information contained in an AnyMap or AnyValue.
Definition: AnyMap.h:738
InputFileError(const string &procedure, const AnyBase &node, const string &message, const Args &... args)
Indicate an error occurring in procedure while using information from node.
Definition: AnyMap.h:744
InputFileError(const string &procedure, const AnyBase &node1, const AnyBase &node2, const string &message, const Args &... args)
Indicate an error occurring in procedure while using information from node1 and node2.
Definition: AnyMap.h:758
string getClass() const override
Method overridden by derived classes to indicate their type.
Definition: AnyMap.h:770
Unit conversion utility.
Definition: Units.h:169
A representation of the units associated with a dimensional quantity.
Definition: Units.h:35
This file contains definitions of constants, types and terms that are used in internal routines and a...
Definitions for the classes that are thrown when Cantera experiences an error condition (also contain...
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
void warn_deprecated(const string &source, const AnyBase &node, const string &message)
A deprecation warning for syntax in an input file.
Definition: AnyMap.cpp:1926