Remove AnyMap traversal using "/" as a path delimiter

This feature was unused, and interfered with the use of "/" as a delimiter
for YAML keys indicating keys in other input files.
This commit is contained in:
Ray Speth 2018-12-21 17:48:16 -05:00
parent e28c9add21
commit a32e32b7d7
3 changed files with 39 additions and 89 deletions

View file

@ -166,8 +166,6 @@ std::vector<vector_fp>& AnyValue::asVector<vector_fp>(size_t nMin, size_t nMax);
* // Create a nested AnyMap named "beans" which has a key named "baked"
* // whose value is a vector<double>
* std::vector<double> v{3.14, 1.59, 2.65};
* breakfast["beans/baked"] = v;
* // Equivalently:
* breakfast["beans"]["baked"] = v;
*
* // Create a nested AnyMap with values of the same type

View file

@ -545,50 +545,24 @@ std::vector<vector_fp>& AnyValue::asVector<vector_fp>(size_t nMin, size_t nMax)
AnyValue& AnyMap::operator[](const std::string& key)
{
const auto& slash = boost::ifind_first(key, "/");
if (!slash) {
// Simple key
const auto& iter = m_data.find(key);
if (iter == m_data.end()) {
// Create a new key return it
// NOTE: 'insert' can be replaced with 'emplace' after support for
// G++ 4.7 is dropped.
AnyValue& value = m_data.insert({key, AnyValue()}).first->second;
value.setKey(key);
return value;
} else {
// Return an already-existing item
return iter->second;
}
const auto& iter = m_data.find(key);
if (iter == m_data.end()) {
// Create a new key return it
// NOTE: 'insert' can be replaced with 'emplace' after support for
// G++ 4.7 is dropped.
AnyValue& value = m_data.insert({key, AnyValue()}).first->second;
value.setKey(key);
return value;
} else {
// Split the first slash-delimited part of key and recurse
std::string head(key.begin(), slash.begin());
std::string tail(slash.end(), key.end());
const auto& iter = m_data.find(head);
if (iter == m_data.end()) {
// Create a new key
AnyValue& value = m_data.insert({head, AnyValue()}).first->second;
value = AnyMap();
value.setKey(head);
return value.as<AnyMap>()[tail];
} else {
// Return an already existing key
return iter->second.as<AnyMap>()[tail];
}
// Return an already-existing item
return iter->second;
}
}
const AnyValue& AnyMap::at(const std::string& key) const
{
const auto& slash = boost::ifind_first(key, "/");
try {
if (!slash) {
return m_data.at(key);
} else {
std::string head(key.begin(), slash.begin());
std::string tail(slash.end(), key.end());
return m_data.at(head).as<AnyMap>().at(tail);
}
return m_data.at(key);
} catch (std::out_of_range& err) {
throw CanteraError("AnyMap::at", "Key '{}' not found", key);
}
@ -596,39 +570,17 @@ const AnyValue& AnyMap::at(const std::string& key) const
bool AnyMap::hasKey(const std::string& key) const
{
const auto& slash = boost::ifind_first(key, "/");
if (!slash) {
return (m_data.find(key) != m_data.end());
} 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<AnyMap>()) {
return false;
} else {
return m_data.at(head).as<AnyMap>().hasKey(tail);
}
}
return (m_data.find(key) != m_data.end());
}
template<class T>
const T& AnyMap::get(const std::string& key, const T& default_,
std::function<const T&(const AnyValue*)> 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_;
}
if (m_data.find(key) != m_data.end()) {
return getter(&m_data.at(key));
} 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<AnyMap>()) {
return default_;
} else {
return m_data.at(head).as<AnyMap>().get(tail, default_, getter);
}
return default_;
}
}

View file

@ -27,28 +27,27 @@ TEST(AnyValue, is_moveable) {
TEST(AnyMap, paths) {
AnyMap m;
m["simple"] = "qux";
m["compound/first"] = "bar";
m["compound/second"] = "baz";
m["compound"]["first"] = "bar";
m["compound"]["second"] = "baz";
m["several"]["layers"]["deep"] = "foo";
EXPECT_TRUE(m.hasKey("simple"));
EXPECT_TRUE(m.hasKey("compound"));
EXPECT_TRUE(m.hasKey("compound/first"));
EXPECT_TRUE(m["compound"].hasKey("second"));
EXPECT_EQ(m["compound/first"].asString(), "bar");
EXPECT_EQ(m["compound/second"].as<std::string>(), "baz");
EXPECT_EQ(m["several/layers/deep"].asString(), "foo");
EXPECT_EQ(m["compound"]["first"].asString(), "bar");
EXPECT_EQ(m["compound"]["second"].as<std::string>(), "baz");
EXPECT_EQ(m["several"]["layers"]["deep"].asString(), "foo");
EXPECT_THROW(m.at("missing"), std::exception);
EXPECT_FALSE(m.hasKey("missing"));
EXPECT_FALSE(m.hasKey("compound/missing"));
EXPECT_FALSE(m["compound"].hasKey("missing"));
EXPECT_THROW(m["missing"].asString(), std::exception);
}
TEST(AnyMap, map_conversion) {
AnyMap m;
m["compound/first"] = "bar";
m["compound/second"] = "baz";
m["compound"]["first"] = "bar";
m["compound"]["second"] = "baz";
auto x = m["compound"].asMap<std::string>();
EXPECT_EQ(x.size(), (size_t) 2);
@ -57,7 +56,7 @@ TEST(AnyMap, map_conversion) {
std::map<std::string, double> zz{{"a", 9.0}, {"b", 13.5}};
m["foo"] = zz;
EXPECT_TRUE(m.hasKey("foo/a"));
EXPECT_TRUE(m["foo"].hasKey("a"));
EXPECT_DOUBLE_EQ(m["foo"]["b"].asDouble(), 13.5);
EXPECT_THROW(m["foo"]["a"].asString(), CanteraError);
@ -79,9 +78,9 @@ TEST(AnyMap, nested)
b["qux"] = 0.5;
m["baz"] = b;
b["late"] = "nope"; // Should have added a copy
EXPECT_EQ(m["baz/foo"].asString(), "bar");
EXPECT_EQ(m["baz"]["foo"].asString(), "bar");
EXPECT_EQ(m["baz"]["qux"].asDouble(), 0.5);
EXPECT_FALSE(m.hasKey("baz/late"));
EXPECT_FALSE(m["baz"].hasKey("late"));
}
TEST(AnyMap, vector)
@ -89,11 +88,11 @@ TEST(AnyMap, vector)
AnyMap m;
vector_fp yy{9.6, 14.4, 28.8};
m["nested"]["item"] = yy;
vector_fp& yref = m["nested/item"].asVector<double>();
vector_fp& yref = m["nested"]["item"].asVector<double>();
yref.push_back(-1);
EXPECT_EQ(yy.size(), (size_t) 3); // Should have added a copy
// Should have modified the copy in the map
EXPECT_EQ(m["nested/item"].asVector<double>().size(), (size_t) 4);
EXPECT_EQ(m["nested"]["item"].asVector<double>().size(), (size_t) 4);
}
TEST(AnyMap, vector_length)
@ -113,7 +112,7 @@ TEST(AnyMap, getters_with_defaults)
AnyMap m;
std::map<std::string, double> zz{{"a", 9.0}, {"b", 13.5}};
m["foo"] = zz;
m["foo/c"] = 4;
m["foo"]["c"] = 4;
m["bar"] = "baz";
m["qux"] = false;
EXPECT_FALSE(m.getBool("qux", true));
@ -121,9 +120,10 @@ TEST(AnyMap, getters_with_defaults)
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);
auto& f = m["foo"].as<AnyMap>();
EXPECT_EQ(f.getInt("c", 3), 4);
EXPECT_EQ(f.getDouble("missing", 3), 3);
EXPECT_EQ(f.getDouble("b", 3), 13.5);
}
TEST(AnyMap, conversion_to_double)
@ -189,12 +189,12 @@ TEST(AnyMap, loadYaml)
" flag: true\n");
EXPECT_EQ(m["name"].asString(), "NO2");
EXPECT_EQ(m["composition/N"].asInt(), 1);
EXPECT_EQ(m["thermo/reference-pressure"].asString(), "1 atm");
EXPECT_EQ(m["thermo/temperature-ranges"].asVector<long int>()[0], 200);
EXPECT_EQ(m["transport/geometry"].asString(), "nonlinear");
EXPECT_TRUE(m["transport/flag"].asBool());
auto coeffs = m["thermo/data"].asVector<vector_fp>();
EXPECT_EQ(m["composition"]["N"].asInt(), 1);
EXPECT_EQ(m["thermo"]["reference-pressure"].asString(), "1 atm");
EXPECT_EQ(m["thermo"]["temperature-ranges"].asVector<long int>()[0], 200);
EXPECT_EQ(m["transport"]["geometry"].asString(), "nonlinear");
EXPECT_TRUE(m["transport"]["flag"].asBool());
auto coeffs = m["thermo"]["data"].asVector<vector_fp>();
EXPECT_EQ(coeffs.size(), (size_t) 2);
EXPECT_EQ(coeffs[0].size(), (size_t) 7);
EXPECT_DOUBLE_EQ(coeffs[1][2], -8.280690600E-07);