Add an into() operator on Node to do optional assignment.

This adds an `into()` operator to the Node class modeled off
the `get_to()` operator in the popular nlohmann::json library.
(See: https://github.com/nlohmann/json#basic-usage)

This operator assigns a casted value to an existing variable
if that node has a defined value, and otherwise leaves the
variable unchanged.  It returns `true` if the variable was
overwritten and `false` if the variable was unchanged.

This operator is extremely useful in applications where YAML
is being used as a configuration source that overrides
default values coming from another source, e.g.:

```c++
struct MyConfig {
  int foo = 4;
  double bar = 5.0;
  std::string baz = "six";
};

MyConfig config;
node["foo"].into(config.foo);
node["bar"].into(config.bar);

if (!node["baz"].into(config.baz))
  std::cerr << "Using default value for .baz!" << std::endl;
```
This commit is contained in:
Pras Velagapudi 2021-11-25 09:08:28 -05:00
parent 5057a53293
commit ff9a466152
3 changed files with 33 additions and 0 deletions

View File

@ -163,6 +163,14 @@ inline T Node::as(const S& fallback) const {
return as_if<T, S>(*this)(fallback);
}
template <typename T>
inline bool Node::into(T& target) const {
if (!this->IsDefined())
return false;
target = this->as<T>();
return true;
}
inline const std::string& Node::Scalar() const {
if (!m_isValid)
throw InvalidNode(m_invalidKey);

View File

@ -66,6 +66,9 @@ class YAML_CPP_API Node {
T as() const;
template <typename T, typename S>
T as(const S& fallback) const;
template <typename T>
bool into(T& target) const;
const std::string& Scalar() const;
const std::string& Tag() const;

View File

@ -645,6 +645,28 @@ TEST(NodeTest, AccessNonexistentKeyOnConstNode) {
ASSERT_FALSE(other["5"]);
}
TEST(NodeTest, IntoExists) {
Node node;
node["A"] = 4;
int dest = 5;
bool res = node["A"].into(dest);
ASSERT_TRUE(res);
EXPECT_EQ(dest, 4);
}
TEST(NodeTest, IntoMissing) {
Node node;
node["A"] = 4;
int dest = 5;
bool res = node["B"].into(dest);
ASSERT_FALSE(res);
EXPECT_EQ(dest, 5);
}
class NodeEmitterTest : public ::testing::Test {
protected:
void ExpectOutput(const std::string& output, const Node& node) {