Cantera  3.0.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
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
48protected:
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
66class 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 */
85class AnyValue : public AnyBase
86{
87public:
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
296private:
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>
329template<>
330const vector<AnyValue>& AnyValue::asVector<AnyValue>(size_t nMin, size_t nMax) const;
331
332template<>
333vector<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>
336template<>
337const vector<double>& AnyValue::asVector<double>(size_t nMin, size_t nMax) const;
338
339template<>
340vector<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>>
343template<>
344const vector<vector<double>>& AnyValue::asVector<vector<double>>(size_t nMin,
345 size_t nMax) const;
346
347template<>
348vector<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>
352template<>
353const vector<AnyMap>& AnyValue::asVector<AnyMap>(size_t nMin, size_t nMax) const;
354
355template<>
356vector<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 */
426class AnyMap : public AnyBase
427{
428public:
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().
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
699private:
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
727AnyMap::Iterator begin(const AnyValue& v);
728AnyMap::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{
739public:
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 }
773protected:
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
782void warn_deprecated(const string& source, const AnyBase& node,
783 const string& message);
784
785}
786
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
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
const UnitSystem & units() const
Return the default units that should be used to convert stored values.
Definition AnyMap.h:630
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
shared_ptr< UnitSystem > unitsShared() const
Return the default units that should be used to convert stored values.
Definition AnyMap.h:633
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
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
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
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
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.
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:195
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