Add automatic conversions to vector<AnyValue>

This commit is contained in:
Ray Speth 2018-01-30 15:01:06 -05:00
parent e5bd0b136f
commit 530adbb931
3 changed files with 65 additions and 0 deletions

View file

@ -61,16 +61,20 @@ public:
template<class T>
bool is() const;
explicit AnyValue(const std::string& value);
AnyValue& operator=(const std::string& value);
AnyValue& operator=(const char* value);
const std::string& asString() const;
explicit AnyValue(double value);
AnyValue& operator=(double value);
double asDouble() const;
explicit AnyValue(bool value);
AnyValue& operator=(bool value);
bool asBool() const;
explicit AnyValue(long int value);
AnyValue& operator=(long int value);
AnyValue& operator=(int value);
long int asInt() const;
@ -102,6 +106,13 @@ private:
static std::map<std::string, std::string> s_typenames;
};
// Implicit conversion to vector<AnyValue>
template<>
const std::vector<AnyValue>& AnyValue::asVector<AnyValue>() const;
template<>
std::vector<AnyValue>& AnyValue::asVector<AnyValue>();
// Implicit conversion of long int to double if accessed as a vector<double>
template<>
const std::vector<double>& AnyValue::asVector<double>() const;

View file

@ -281,6 +281,8 @@ const std::type_info &AnyValue::type() {
return m_value->type();
}
AnyValue::AnyValue(const std::string& value) : m_value(new boost::any{value}) {}
AnyValue &AnyValue::operator=(const std::string &value) {
*m_value = value;
return *this;
@ -295,6 +297,8 @@ const std::string &AnyValue::asString() const {
return as<std::string>();
}
AnyValue::AnyValue(double value) : m_value(new boost::any{value}) {}
AnyValue &AnyValue::operator=(double value) {
*m_value = value;
return *this;
@ -308,6 +312,8 @@ double AnyValue::asDouble() const {
}
}
AnyValue::AnyValue(bool value) : m_value(new boost::any{value}) {}
AnyValue &AnyValue::operator=(bool value) {
*m_value = value;
return *this;
@ -317,6 +323,8 @@ bool AnyValue::asBool() const {
return as<bool>();
}
AnyValue::AnyValue(long int value) : m_value(new boost::any{value}) {}
AnyValue &AnyValue::operator=(long int value) {
*m_value = value;
return *this;
@ -352,6 +360,40 @@ std::string AnyValue::demangle(const std::type_info& type) const
// Explicit template specializations to allow certain conversions
template<>
const std::vector<AnyValue>& AnyValue::asVector<AnyValue>() const
{
if (!is<std::vector<AnyValue>>()) {
std::vector<AnyValue> v;
if (is<std::vector<double>>()) {
for (const auto& el : asVector<double>()) {
v.push_back(AnyValue(el));
}
*m_value = v;
} else if (is<std::vector<long int>>()) {
for (const auto& el : asVector<long int>()) {
v.push_back(AnyValue(el));
}
*m_value = v;
} else if (is<std::vector<std::string>>()) {
for (const auto& el : asVector<std::string>()) {
v.push_back(AnyValue(el));
}
*m_value = v;
}
// If none of these special cases match, the value won't be replaced,
// and an exception will be thrown.
}
return as<std::vector<AnyValue>>();
}
template<>
std::vector<AnyValue>& AnyValue::asVector<AnyValue>()
{
return const_cast<std::vector<AnyValue>&>(
const_cast<const AnyValue*>(this)->asVector<AnyValue>());
}
template<>
const std::vector<double>& AnyValue::asVector<double>() const
{

View file

@ -102,6 +102,18 @@ TEST(AnyMap, conversion_to_double)
EXPECT_EQ(n.at("nested").asVector<vector_fp>()[0][2], 5);
}
TEST(AnyMap, conversion_to_anyvalue)
{
AnyMap m = AnyMap::fromYamlString(
"{floats: [7.5, 40, -3.14], strings: [foo, bar]}");
const AnyMap n = m;
EXPECT_EQ(m["floats"].asVector<AnyValue>()[0].asDouble(), 7.5);
EXPECT_EQ(m["strings"].asVector<AnyValue>()[1].asString(), "bar");
EXPECT_EQ(n.at("floats").asVector<AnyValue>()[2].asDouble(), -3.14);
EXPECT_EQ(n.at("strings").asVector<AnyValue>()[0].asString(), "foo");
}
TEST(AnyMap, loadYaml)
{
AnyMap m = AnyMap::fromYamlString(