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