diff --git a/include/cantera/base/AnyMap.h b/include/cantera/base/AnyMap.h index dfccc5e81..0decf3d04 100644 --- a/include/cantera/base/AnyMap.h +++ b/include/cantera/base/AnyMap.h @@ -11,6 +11,7 @@ #include #include #include +#include namespace boost { @@ -68,16 +69,19 @@ public: explicit AnyValue(double value); AnyValue& operator=(double value); - double asDouble() const; + double& asDouble(); + const double& asDouble() const; explicit AnyValue(bool value); AnyValue& operator=(bool value); - bool asBool() const; + bool& asBool(); + const bool& asBool() const; explicit AnyValue(long int value); AnyValue& operator=(long int value); AnyValue& operator=(int value); - long int asInt() const; + long int& asInt(); + const long int& asInt() const; template AnyValue& operator=(const std::vector& value); @@ -216,7 +220,17 @@ public: bool hasKey(const std::string& key) const; + bool getBool(const std::string& key, bool default_) const; + long int getInt(const std::string& key, long int default_) const; + double getDouble(const std::string& key, double default_) const; + const std::string& getString(const std::string& key, + const std::string& default_) const; + private: + template + const T& get(const std::string& key, const T& default_, + std::function getter) const; + std::unordered_map m_data; friend class AnyValue; }; diff --git a/src/base/AnyMap.cpp b/src/base/AnyMap.cpp index 6958d06fd..1037d1c82 100644 --- a/src/base/AnyMap.cpp +++ b/src/base/AnyMap.cpp @@ -304,12 +304,18 @@ AnyValue &AnyValue::operator=(double value) { return *this; } -double AnyValue::asDouble() const { +double& AnyValue::asDouble() { if (m_value->type() == typeid(long int)) { - return as(); - } else { - return as(); + *m_value = static_cast(as()); } + return as(); +} + +const double& AnyValue::asDouble() const { + if (m_value->type() == typeid(long int)) { + *m_value = static_cast(as()); + } + return as(); } AnyValue::AnyValue(bool value) : m_value(new boost::any{value}) {} @@ -319,7 +325,11 @@ AnyValue &AnyValue::operator=(bool value) { return *this; } -bool AnyValue::asBool() const { +bool& AnyValue::asBool() { + return as(); +} + +const bool& AnyValue::asBool() const { return as(); } @@ -335,7 +345,11 @@ AnyValue &AnyValue::operator=(int value) { return *this; } -long int AnyValue::asInt() const { +long int& AnyValue::asInt() { + return as(); +} + +const long int& AnyValue::asInt() const { return as(); } @@ -518,6 +532,52 @@ bool AnyMap::hasKey(const std::string& key) const } } +template +const T& AnyMap::get(const std::string& key, const T& default_, + std::function getter) const +{ + const auto& slash = boost::ifind_first(key, "/"); + if (!slash) { + if (m_data.find(key) != m_data.end()) { + return getter(&m_data.at(key)); + } else { + return default_; + } + } else { + std::string head(key.begin(), slash.begin()); + std::string tail(slash.end(), key.end()); + if (m_data.find(head) == m_data.end() || !m_data.at(head).is()) { + return default_; + } else { + return m_data.at(head).as().get(tail, default_, getter); + } + } +} + +bool AnyMap::getBool(const std::string& key, bool default_) const +{ + return get(key, default_, + std::mem_fun(&AnyValue::asBool)); +} + +double AnyMap::getDouble(const std::string& key, double default_) const +{ + return get(key, default_, + std::mem_fun(&AnyValue::asDouble)); +} + +long int AnyMap::getInt(const std::string& key, long int default_) const +{ + return get(key, default_, + std::mem_fun(&AnyValue::asInt)); +} + +const std::string& AnyMap::getString(const std::string& key, + const std::string& default_) const +{ + return get(key, default_, &AnyValue::asString); +} + AnyMap AnyMap::fromYamlString(const std::string& yaml) { YAML::Node node = YAML::Load(yaml); return node.as(); diff --git a/test/general/test_containers.cpp b/test/general/test_containers.cpp index 62a75fcd9..23248ea13 100644 --- a/test/general/test_containers.cpp +++ b/test/general/test_containers.cpp @@ -89,6 +89,24 @@ TEST(AnyMap, vector) EXPECT_EQ(m["nested/item"].asVector().size(), (size_t) 4); } +TEST(AnyMap, getters_with_defaults) +{ + AnyMap m; + std::map zz{{"a", 9.0}, {"b", 13.5}}; + m["foo"] = zz; + m["foo/c"] = 4; + m["bar"] = "baz"; + m["qux"] = false; + EXPECT_FALSE(m.getBool("qux", true)); + EXPECT_TRUE(m.getBool("missing", true)); + EXPECT_EQ(m.getString("missing", "hi"), "hi"); + EXPECT_EQ(m.getString("bar", "hi"), "baz"); + EXPECT_EQ(m.getInt("missing", 3), 3); + EXPECT_EQ(m.getInt("foo/c", 3), 4); + EXPECT_EQ(m.getDouble("foo/missing", 3), 3); + EXPECT_EQ(m.getDouble("foo/b", 3), 13.5); +} + TEST(AnyMap, conversion_to_double) { AnyMap m = AnyMap::fromYamlString(