diff --git a/include/cantera/base/AnyMap.h b/include/cantera/base/AnyMap.h index dab7240c1..9b35ad0b5 100644 --- a/include/cantera/base/AnyMap.h +++ b/include/cantera/base/AnyMap.h @@ -237,6 +237,10 @@ public: bool hasKey(const std::string& key) const; + //! Return a string listing the keys in this AnyMap, e.g. for use in error + //! messages + std::string keys_str() 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; diff --git a/src/base/AnyMap.cpp b/src/base/AnyMap.cpp index 8ce0997e0..e0fa4355d 100644 --- a/src/base/AnyMap.cpp +++ b/src/base/AnyMap.cpp @@ -565,7 +565,8 @@ const AnyValue& AnyMap::at(const std::string& key) const try { return m_data.at(key); } catch (std::out_of_range& err) { - throw CanteraError("AnyMap::at", "Key '{}' not found", key); + throw CanteraError("AnyMap::at", + "Key '{}' not found.\nExisting keys: {}", key, keys_str()); } } @@ -574,6 +575,21 @@ bool AnyMap::hasKey(const std::string& key) const return (m_data.find(key) != m_data.end()); } +std::string AnyMap::keys_str() const +{ + fmt::memory_buffer b; + auto iter = this->begin(); + if (iter != this->end()) { + format_to(b, "{}", iter->first); + ++iter; + } + while (iter != this->end()) { + format_to(b, ", {}", iter->first); + ++iter; + } + return to_string(b); +} + template const T& AnyMap::get(const std::string& key, const T& default_, std::function getter) const diff --git a/test/general/test_containers.cpp b/test/general/test_containers.cpp index 680dc530b..0591f50e2 100644 --- a/test/general/test_containers.cpp +++ b/test/general/test_containers.cpp @@ -48,11 +48,17 @@ TEST(AnyMap, map_conversion) { AnyMap m; m["compound"]["first"] = "bar"; m["compound"]["second"] = "baz"; + m["empty"] = AnyMap(); auto x = m["compound"].asMap(); EXPECT_EQ(x.size(), (size_t) 2); EXPECT_EQ(x["first"], "bar"); EXPECT_EQ(x["second"], "baz"); + std::string keys = m["compound"].as().keys_str(); + EXPECT_NE(keys.find("first"), npos); + EXPECT_NE(keys.find("second"), npos); + EXPECT_EQ(keys.size(), (size_t) 13); + EXPECT_EQ(m["empty"].as().keys_str(), ""); std::map zz{{"a", 9.0}, {"b", 13.5}}; m["foo"] = zz;