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