Add support for merge keys
Merge keys are specified here[1] for YAML 1.1. While not part of the YAML 1.2 specification, they're very useful and are supported in other implementations[2][3][4] that target 1.2. Support for merge keys is optional and disabled by default. It can be enabled by defining YAML_CPP_SUPPORT_MERGE_KEYS, either directly or by setting the CMake option YAML_CPP_SUPPORT_MERGE_KEYS=ON. [1]: http://yaml.org/type/merge.html [2]: https://github.com/go-yaml/yaml [3]: https://github.com/ruby/psych [4]: https://bitbucket.org/ruamel/yaml
This commit is contained in:
parent
1698b47b65
commit
5d2dfe8011
@ -5,6 +5,9 @@ os:
|
|||||||
compiler:
|
compiler:
|
||||||
- clang
|
- clang
|
||||||
- gcc
|
- gcc
|
||||||
|
env:
|
||||||
|
- YAML_CPP_SUPPORT_MERGE_KEYS=ON
|
||||||
|
- YAML_CPP_SUPPORT_MERGE_KEYS=OFF
|
||||||
before_install:
|
before_install:
|
||||||
- |
|
- |
|
||||||
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
|
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
|
||||||
@ -17,7 +20,7 @@ before_install:
|
|||||||
before_script:
|
before_script:
|
||||||
- mkdir build
|
- mkdir build
|
||||||
- cd build
|
- cd build
|
||||||
- cmake ..
|
- cmake .. -DYAML_CPP_SUPPORT_MERGE_KEYS=$YAML_CPP_SUPPORT_MERGE_KEYS
|
||||||
script:
|
script:
|
||||||
- make
|
- make
|
||||||
- test/run-tests
|
- test/run-tests
|
||||||
|
|||||||
@ -41,6 +41,7 @@ enable_testing()
|
|||||||
option(YAML_CPP_BUILD_TESTS "Enable testing" ON)
|
option(YAML_CPP_BUILD_TESTS "Enable testing" ON)
|
||||||
option(YAML_CPP_BUILD_TOOLS "Enable parse tools" ON)
|
option(YAML_CPP_BUILD_TOOLS "Enable parse tools" ON)
|
||||||
option(YAML_CPP_BUILD_CONTRIB "Enable contrib stuff in library" ON)
|
option(YAML_CPP_BUILD_CONTRIB "Enable contrib stuff in library" ON)
|
||||||
|
option(YAML_CPP_SUPPORT_MERGE_KEYS "Support YAML merge keys ('<<') in yaml-cpp's executable targets. Use '#define YAML_CPP_SUPPORT_MERGE_KEYS' instead when linking from another project." OFF)
|
||||||
|
|
||||||
## Build options
|
## Build options
|
||||||
# --> General
|
# --> General
|
||||||
@ -97,6 +98,10 @@ else()
|
|||||||
add_definitions(-DYAML_CPP_NO_CONTRIB)
|
add_definitions(-DYAML_CPP_NO_CONTRIB)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (YAML_CPP_SUPPORT_MERGE_KEYS)
|
||||||
|
add_definitions(-DYAML_CPP_SUPPORT_MERGE_KEYS)
|
||||||
|
endif()
|
||||||
|
|
||||||
set(library_sources
|
set(library_sources
|
||||||
${sources}
|
${sources}
|
||||||
${public_headers}
|
${public_headers}
|
||||||
|
|||||||
@ -122,12 +122,23 @@ class node {
|
|||||||
// NOTE: this returns a non-const node so that the top-level Node can wrap
|
// NOTE: this returns a non-const node so that the top-level Node can wrap
|
||||||
// it, and returns a pointer so that it can be NULL (if there is no such
|
// it, and returns a pointer so that it can be NULL (if there is no such
|
||||||
// key).
|
// key).
|
||||||
return static_cast<const node_ref&>(*m_pRef).get(key, pMemory);
|
node* value = static_cast<const node_ref&>(*m_pRef).get(key, pMemory);
|
||||||
|
#ifdef YAML_CPP_SUPPORT_MERGE_KEYS
|
||||||
|
if (!value || value->type() == NodeType::Undefined) {
|
||||||
|
return get_value_from_merge_key(key, value, pMemory);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
template <typename Key>
|
template <typename Key>
|
||||||
node& get(const Key& key, shared_memory_holder pMemory) {
|
node& get(const Key& key, shared_memory_holder pMemory) {
|
||||||
node& value = m_pRef->get(key, pMemory);
|
node& value = m_pRef->get(key, pMemory);
|
||||||
value.add_dependency(*this);
|
value.add_dependency(*this);
|
||||||
|
#ifdef YAML_CPP_SUPPORT_MERGE_KEYS
|
||||||
|
if (value.type() == NodeType::Undefined) {
|
||||||
|
return *get_value_from_merge_key(key, &value, pMemory);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
template <typename Key>
|
template <typename Key>
|
||||||
@ -159,6 +170,33 @@ class node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
#ifdef YAML_CPP_SUPPORT_MERGE_KEYS
|
||||||
|
template <typename Key>
|
||||||
|
inline node* get_value_from_merge_key(const Key& key, node* currentValue,
|
||||||
|
shared_memory_holder pMemory) const {
|
||||||
|
node* mergeValue =
|
||||||
|
static_cast<const node_ref&>(*m_pRef).get(std::string("<<"), pMemory);
|
||||||
|
if (!mergeValue) {
|
||||||
|
return currentValue;
|
||||||
|
}
|
||||||
|
if (mergeValue->type() == NodeType::Map) {
|
||||||
|
return &mergeValue->get(key, pMemory);
|
||||||
|
}
|
||||||
|
if (mergeValue->type() == NodeType::Sequence) {
|
||||||
|
for (const_node_iterator it = mergeValue->begin();
|
||||||
|
it != mergeValue->end(); ++it) {
|
||||||
|
if (it->pNode && it->pNode->type() == NodeType::Map) {
|
||||||
|
node* value = it->pNode->get(key, pMemory);
|
||||||
|
if (value && value->type() != NodeType::Undefined) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return currentValue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
shared_node_ref m_pRef;
|
shared_node_ref m_pRef;
|
||||||
typedef std::set<node*> nodes;
|
typedef std::set<node*> nodes;
|
||||||
nodes m_dependencies;
|
nodes m_dependencies;
|
||||||
|
|||||||
@ -185,6 +185,39 @@ TEST(LoadNodeTest, DereferenceIteratorError) {
|
|||||||
EXPECT_THROW(node.begin()->begin()->Type(), InvalidNode);
|
EXPECT_THROW(node.begin()->begin()->Type(), InvalidNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef YAML_CPP_SUPPORT_MERGE_KEYS
|
||||||
|
TEST(NodeTest, MergeKeyScalarSupport) {
|
||||||
|
Node node = Load("{<<: {a: 1}}");
|
||||||
|
ASSERT_FALSE(!node["a"]);
|
||||||
|
EXPECT_EQ(1, node["a"].as<int>());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(NodeTest, MergeKeyExistingKey) {
|
||||||
|
Node node = Load("{a: 1, <<: {a: 2}}");
|
||||||
|
ASSERT_FALSE(!node["a"]);
|
||||||
|
EXPECT_EQ(1, node["a"].as<int>());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(NodeTest, MergeKeySequenceSupport) {
|
||||||
|
Node node = Load("<<: [{a: 1}, {a: 2, b: 3}]");
|
||||||
|
ASSERT_FALSE(!node["a"]);
|
||||||
|
ASSERT_FALSE(!node["b"]);
|
||||||
|
EXPECT_EQ(1, node["a"].as<int>());
|
||||||
|
EXPECT_EQ(3, node["b"].as<int>());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(NodeTest, NestedMergeKeys) {
|
||||||
|
Node node = Load("{<<: {<<: {a: 1}}}");
|
||||||
|
ASSERT_FALSE(!node["a"]);
|
||||||
|
EXPECT_EQ(1, node["a"].as<int>());
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
TEST(NodeTest, MergeKeySupport) {
|
||||||
|
Node node = Load("{<<: {a: 1}}");
|
||||||
|
ASSERT_FALSE(node["a"]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
TEST(NodeTest, EmitEmptyNode) {
|
TEST(NodeTest, EmitEmptyNode) {
|
||||||
Node node;
|
Node node;
|
||||||
Emitter emitter;
|
Emitter emitter;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user