Add "get" functions to AnyMap
Simplify the common use case of checking for a key and using a default value when it is missing.
This commit is contained in:
parent
530adbb931
commit
ea88d4f9fb
3 changed files with 101 additions and 9 deletions
|
|
@ -11,6 +11,7 @@
|
|||
#include <vector>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
|
||||
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<class T>
|
||||
AnyValue& operator=(const std::vector<T>& 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 <class T>
|
||||
const T& get(const std::string& key, const T& default_,
|
||||
std::function<const T&(const AnyValue*)> getter) const;
|
||||
|
||||
std::unordered_map<std::string, AnyValue> m_data;
|
||||
friend class AnyValue;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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<long int>();
|
||||
} else {
|
||||
return as<double>();
|
||||
*m_value = static_cast<double>(as<long int>());
|
||||
}
|
||||
return as<double>();
|
||||
}
|
||||
|
||||
const double& AnyValue::asDouble() const {
|
||||
if (m_value->type() == typeid(long int)) {
|
||||
*m_value = static_cast<double>(as<long int>());
|
||||
}
|
||||
return as<double>();
|
||||
}
|
||||
|
||||
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<bool>();
|
||||
}
|
||||
|
||||
const bool& AnyValue::asBool() const {
|
||||
return as<bool>();
|
||||
}
|
||||
|
||||
|
|
@ -335,7 +345,11 @@ AnyValue &AnyValue::operator=(int value) {
|
|||
return *this;
|
||||
}
|
||||
|
||||
long int AnyValue::asInt() const {
|
||||
long int& AnyValue::asInt() {
|
||||
return as<long int>();
|
||||
}
|
||||
|
||||
const long int& AnyValue::asInt() const {
|
||||
return as<long int>();
|
||||
}
|
||||
|
||||
|
|
@ -518,6 +532,52 @@ bool AnyMap::hasKey(const std::string& key) const
|
|||
}
|
||||
}
|
||||
|
||||
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_;
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool AnyMap::getBool(const std::string& key, bool default_) const
|
||||
{
|
||||
return get<bool>(key, default_,
|
||||
std::mem_fun<const bool&, const AnyValue>(&AnyValue::asBool));
|
||||
}
|
||||
|
||||
double AnyMap::getDouble(const std::string& key, double default_) const
|
||||
{
|
||||
return get<double>(key, default_,
|
||||
std::mem_fun<const double&, const AnyValue>(&AnyValue::asDouble));
|
||||
}
|
||||
|
||||
long int AnyMap::getInt(const std::string& key, long int default_) const
|
||||
{
|
||||
return get<long int>(key, default_,
|
||||
std::mem_fun<const long int&, const AnyValue>(&AnyValue::asInt));
|
||||
}
|
||||
|
||||
const std::string& AnyMap::getString(const std::string& key,
|
||||
const std::string& default_) const
|
||||
{
|
||||
return get<std::string>(key, default_, &AnyValue::asString);
|
||||
}
|
||||
|
||||
AnyMap AnyMap::fromYamlString(const std::string& yaml) {
|
||||
YAML::Node node = YAML::Load(yaml);
|
||||
return node.as<AnyMap>();
|
||||
|
|
|
|||
|
|
@ -89,6 +89,24 @@ TEST(AnyMap, vector)
|
|||
EXPECT_EQ(m["nested/item"].asVector<double>().size(), (size_t) 4);
|
||||
}
|
||||
|
||||
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["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(
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue