From 21e588101f950c3820bd07af3abbf1655dc55cdb Mon Sep 17 00:00:00 2001 From: Joao Paulo Magalhaes Date: Fri, 3 Dec 2021 22:42:48 +0000 Subject: [PATCH 1/5] [refac] (c)substr: prefer passing by value --- src/c4/yml/node.hpp | 42 +++++++++++++++++++++--------------------- src/c4/yml/tree.cpp | 8 ++++---- src/c4/yml/tree.hpp | 14 +++++++------- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/c4/yml/node.hpp b/src/c4/yml/node.hpp index ca5676d72..320af17da 100644 --- a/src/c4/yml/node.hpp +++ b/src/c4/yml/node.hpp @@ -249,20 +249,20 @@ class RYML_EXPORT NodeRef m_tree->_set_flags(m_id, t); } - inline void set_key(csubstr const& key) + inline void set_key(csubstr key) { _C4RV(); m_tree->_set_key(m_id, key); } - inline void set_val(csubstr const& val) + inline void set_val(csubstr val) { _C4RV(); m_tree->_set_val(m_id, val); } template - inline size_t set_key_serialized(T const& k) + inline size_t set_key_serialized(T const& C4_RESTRICT k) { _C4RV(); csubstr s = m_tree->to_arena(k); @@ -271,7 +271,7 @@ class RYML_EXPORT NodeRef } template - inline size_t set_val_serialized(T const& v) + inline size_t set_val_serialized(T const& C4_RESTRICT v) { _C4RV(); csubstr s = m_tree->to_arena(v); @@ -295,37 +295,37 @@ class RYML_EXPORT NodeRef * @return the size of base64-decoded blob */ size_t deserialize_val(fmt::base64_wrapper v) const; - inline void set_key_tag(csubstr const& key_tag) + inline void set_key_tag(csubstr key_tag) { _C4RV(); m_tree->set_key_tag(m_id, key_tag); } - inline void set_val_tag(csubstr const& val_tag) const + inline void set_val_tag(csubstr val_tag) const { _C4RV(); m_tree->set_val_tag(m_id, val_tag); } - inline void set_key_anchor(csubstr const& key_anchor) + inline void set_key_anchor(csubstr key_anchor) { _C4RV(); m_tree->set_key_anchor(m_id, key_anchor); } - inline void set_val_anchor(csubstr const& val_anchor) const + inline void set_val_anchor(csubstr val_anchor) const { _C4RV(); m_tree->set_val_anchor(m_id, val_anchor); } - inline void set_key_ref(csubstr const& key_ref) + inline void set_key_ref(csubstr key_ref) { _C4RV(); m_tree->set_key_ref(m_id, key_ref); } - inline void set_val_ref(csubstr const& val_ref) const + inline void set_val_ref(csubstr val_ref) const { _C4RV(); m_tree->set_val_ref(m_id, val_ref); @@ -334,7 +334,7 @@ class RYML_EXPORT NodeRef public: template - inline csubstr to_arena(T const& s) const + inline csubstr to_arena(T const& C4_RESTRICT s) const { _C4RV(); return m_tree->to_arena(s); @@ -372,7 +372,7 @@ class RYML_EXPORT NodeRef public: /** O(num_children) */ - NodeRef operator[] (csubstr const& k) + NodeRef operator[] (csubstr k) { RYML_ASSERT( ! is_seed()); RYML_ASSERT(valid()); @@ -394,7 +394,7 @@ class RYML_EXPORT NodeRef public: /** O(num_children) */ - NodeRef const operator[] (csubstr const& k) const + NodeRef const operator[] (csubstr k) const { RYML_ASSERT( ! is_seed()); RYML_ASSERT(valid()); @@ -441,7 +441,7 @@ class RYML_EXPORT NodeRef _apply(v); } - inline void operator= (csubstr const& v) + inline void operator= (csubstr v) { _apply_seed(); _apply(v); @@ -459,7 +459,7 @@ class RYML_EXPORT NodeRef public: /** serialize a variable, then assign the result to the node's key */ - inline NodeRef& operator<< (csubstr const& s) + inline NodeRef& operator<< (csubstr s) { // this overload is needed to prevent ambiguity (there's also // operator<< for writing a substr to a stream) @@ -470,7 +470,7 @@ class RYML_EXPORT NodeRef } template - inline NodeRef& operator<< (T const& v) + inline NodeRef& operator<< (T const& C4_RESTRICT v) { _apply_seed(); write(this, v); @@ -494,7 +494,7 @@ class RYML_EXPORT NodeRef /** serialize a variable, then assign the result to the node's key */ template - inline NodeRef& operator<< (Key const& v) + inline NodeRef& operator<< (Key const& C4_RESTRICT v) { _apply_seed(); set_key_serialized(v.k); @@ -503,7 +503,7 @@ class RYML_EXPORT NodeRef /** serialize a variable, then assign the result to the node's key */ template - inline NodeRef& operator<< (Key const& v) + inline NodeRef& operator<< (Key const& C4_RESTRICT v) { _apply_seed(); set_key_serialized(v.k); @@ -550,7 +550,7 @@ class RYML_EXPORT NodeRef public: template - void get_if(csubstr const& name, T *var) const + void get_if(csubstr name, T *var) const { auto ch = find_child(name); if(ch.valid()) @@ -560,7 +560,7 @@ class RYML_EXPORT NodeRef } template - void get_if(csubstr const& name, T *var, T const& fallback) const + void get_if(csubstr name, T *var, T fallback) const { auto ch = find_child(name); if(ch.valid()) @@ -600,7 +600,7 @@ class RYML_EXPORT NodeRef } } - inline void _apply(csubstr const& v) + inline void _apply(csubstr v) { m_tree->_set_val(m_id, v); } diff --git a/src/c4/yml/tree.cpp b/src/c4/yml/tree.cpp index 1860c8a4d..82b546743 100644 --- a/src/c4/yml/tree.cpp +++ b/src/c4/yml/tree.cpp @@ -1497,7 +1497,7 @@ size_t Tree::find_child(size_t node, csubstr const& name) const //----------------------------------------------------------------------------- -void Tree::to_val(size_t node, csubstr const& val, type_bits more_flags) +void Tree::to_val(size_t node, csubstr val, type_bits more_flags) { RYML_ASSERT( ! has_children(node)); RYML_ASSERT(parent(node) == NONE || ! parent_is_map(node)); @@ -1506,7 +1506,7 @@ void Tree::to_val(size_t node, csubstr const& val, type_bits more_flags) _p(node)->m_val = val; } -void Tree::to_keyval(size_t node, csubstr const& key, csubstr const& val, type_bits more_flags) +void Tree::to_keyval(size_t node, csubstr key, csubstr val, type_bits more_flags) { RYML_ASSERT( ! has_children(node)); RYML_ASSERT(parent(node) == NONE || parent_is_map(node)); @@ -1524,7 +1524,7 @@ void Tree::to_map(size_t node, type_bits more_flags) _p(node)->m_val.clear(); } -void Tree::to_map(size_t node, csubstr const& key, type_bits more_flags) +void Tree::to_map(size_t node, csubstr key, type_bits more_flags) { RYML_ASSERT( ! has_children(node)); RYML_ASSERT(parent(node) == NONE || parent_is_map(node)); @@ -1542,7 +1542,7 @@ void Tree::to_seq(size_t node, type_bits more_flags) _p(node)->m_val.clear(); } -void Tree::to_seq(size_t node, csubstr const& key, type_bits more_flags) +void Tree::to_seq(size_t node, csubstr key, type_bits more_flags) { RYML_ASSERT( ! has_children(node)); RYML_ASSERT(parent(node) == NONE || parent_is_map(node)); diff --git a/src/c4/yml/tree.hpp b/src/c4/yml/tree.hpp index 8c05c6364..9e567ce70 100644 --- a/src/c4/yml/tree.hpp +++ b/src/c4/yml/tree.hpp @@ -673,10 +673,10 @@ class Tree /** @name node modifiers */ /** @{ */ - void to_keyval(size_t node, csubstr const& key, csubstr const& val, type_bits more_flags=0); - void to_map(size_t node, csubstr const& key, type_bits more_flags=0); - void to_seq(size_t node, csubstr const& key, type_bits more_flags=0); - void to_val(size_t node, csubstr const& val, type_bits more_flags=0); + void to_keyval(size_t node, csubstr key, csubstr val, type_bits more_flags=0); + void to_map(size_t node, csubstr key, type_bits more_flags=0); + void to_seq(size_t node, csubstr key, type_bits more_flags=0); + void to_val(size_t node, csubstr val, type_bits more_flags=0); void to_map(size_t node, type_bits more_flags=0); void to_seq(size_t node, type_bits more_flags=0); void to_doc(size_t node, type_bits more_flags=0); @@ -1103,7 +1103,7 @@ class Tree #if ! RYML_USE_ASSERT C4_ALWAYS_INLINE void _check_next_flags(size_t, type_bits) {} #else - inline void _check_next_flags(size_t node, type_bits f) + void _check_next_flags(size_t node, type_bits f) { auto n = _p(node); type_bits o = n->m_type; // old @@ -1145,7 +1145,7 @@ class Tree inline void _rem_flags(size_t node, NodeType_e f) { NodeData *d = _p(node); type_bits fb = d->m_type & ~f; _check_next_flags(node, fb); d->m_type = (NodeType_e) fb; } inline void _rem_flags(size_t node, type_bits f) { NodeData *d = _p(node); f = d->m_type & ~f; _check_next_flags(node, f); d->m_type = f; } - void _set_key(size_t node, csubstr const& key, type_bits more_flags=0) + void _set_key(size_t node, csubstr key, type_bits more_flags=0) { _p(node)->m_key.scalar = key; _add_flags(node, KEY|more_flags); @@ -1156,7 +1156,7 @@ class Tree _add_flags(node, KEY|more_flags); } - void _set_val(size_t node, csubstr const& val, type_bits more_flags=0) + void _set_val(size_t node, csubstr val, type_bits more_flags=0) { RYML_ASSERT(num_children(node) == 0); RYML_ASSERT(!is_seq(node) && !is_map(node)); From 7a67ca2356b430fc54c0e5fc704eb1e022116965 Mon Sep 17 00:00:00 2001 From: Joao Paulo Magalhaes Date: Fri, 3 Dec 2021 22:43:30 +0000 Subject: [PATCH 2/5] [refac] expose coverage misses --- src/c4/yml/node.hpp | 12 ++++++++---- src/c4/yml/tree.hpp | 3 ++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/c4/yml/node.hpp b/src/c4/yml/node.hpp index 320af17da..b820a656e 100644 --- a/src/c4/yml/node.hpp +++ b/src/c4/yml/node.hpp @@ -344,26 +344,30 @@ class RYML_EXPORT NodeRef inline void clear() { - if(is_seed()) return; + if(is_seed()) + return; m_tree->remove_children(m_id); m_tree->_clear(m_id); } inline void clear_key() { - if(is_seed()) return; + if(is_seed()) + return; m_tree->_clear_key(m_id); } inline void clear_val() { - if(is_seed()) return; + if(is_seed()) + return; m_tree->_clear_val(m_id); } inline void clear_children() { - if(is_seed()) return; + if(is_seed()) + return; m_tree->remove_children(m_id); } diff --git a/src/c4/yml/tree.hpp b/src/c4/yml/tree.hpp index 9e567ce70..d47cc3f0c 100644 --- a/src/c4/yml/tree.hpp +++ b/src/c4/yml/tree.hpp @@ -1217,7 +1217,8 @@ class Tree for(size_t i = first_child(node); i != NONE; i = next_sibling(i)) { NodeData *C4_RESTRICT ch = _p(i); - if(ch->m_type.is_keyval()) continue; + if(ch->m_type.is_keyval()) + continue; ch->m_type.add(KEY); ch->m_key = ch->m_val; } From 638a7c215e7665e8a91dc3294c69af347e3edc90 Mon Sep 17 00:00:00 2001 From: Joao Paulo Magalhaes Date: Fri, 3 Dec 2021 22:40:01 +0000 Subject: [PATCH 3/5] [impl] add Tree::change_type() --- changelog/current.md | 16 ++++++++++ src/c4/yml/detail/print.hpp | 10 +++--- src/c4/yml/node.hpp | 6 ++++ src/c4/yml/tree.cpp | 35 +++++++++++++++++++++ src/c4/yml/tree.hpp | 31 ++++++++++--------- test/test_basic.cpp | 61 +++++++++++++++++++++++++++++++++++++ 6 files changed, 141 insertions(+), 18 deletions(-) diff --git a/changelog/current.md b/changelog/current.md index e69de29bb..d95d105ae 100644 --- a/changelog/current.md +++ b/changelog/current.md @@ -0,0 +1,16 @@ + +### New features +- Add `Tree::change_type()` and `NodeRef::change_type()` ([PR #171](https://github.com/biojppm/rapidyaml/pull/171)): + ```c++ + // clears a node and sets its type to a different type (one of `VAL`, `SEQ`, `MAP`): + Tree t = parse("{keyval0: val0, keyval1: val1, keyval2: val2}"); + t[0].change_type(VAL); + t[1].change_type(MAP); + t[2].change_type(SEQ); + Tree expected = parse("{keyval0: val0, keyval1: {}, keyval2: []}"); + assert(emitrs(t) == emitrs(expected)); + ``` + +### Fixes + +- prefer passing `substr` and `csubstr` by value instead of const reference ([PR #171](https://github.com/biojppm/rapidyaml/pull/171)) diff --git a/src/c4/yml/detail/print.hpp b/src/c4/yml/detail/print.hpp index 355697221..df9ad25c5 100644 --- a/src/c4/yml/detail/print.hpp +++ b/src/c4/yml/detail/print.hpp @@ -107,12 +107,14 @@ inline void print_node(NodeRef const& p, int level=0) inline size_t print_tree(Tree const& p, size_t node=NONE) { - if(node == NONE) + printf("--------------------------------------\n"); + size_t ret = 0; + if(!p.empty()) { - node = p.root_id(); + if(node == NONE) + node = p.root_id(); + ret = print_node(p, node, 0, 0, true); } - printf("--------------------------------------\n"); - size_t ret = print_node(p, node, 0, 0, true); printf("#nodes=%zd vs #printed=%zd\n", p.size(), ret); printf("--------------------------------------\n"); return ret; diff --git a/src/c4/yml/node.hpp b/src/c4/yml/node.hpp index b820a656e..d6357819c 100644 --- a/src/c4/yml/node.hpp +++ b/src/c4/yml/node.hpp @@ -243,6 +243,12 @@ class RYML_EXPORT NodeRef /** @name node modifiers */ /** @{ */ + inline void change_type(NodeType t) + { + _C4RV(); + m_tree->change_type(m_id, t); + } + inline void set_type(NodeType t) { _C4RV(); diff --git a/src/c4/yml/tree.cpp b/src/c4/yml/tree.cpp index 82b546743..98b6dc6ca 100644 --- a/src/c4/yml/tree.cpp +++ b/src/c4/yml/tree.cpp @@ -954,6 +954,41 @@ void Tree::set_root_as_stream() } +//----------------------------------------------------------------------------- +void Tree::remove_children(size_t node) +{ + RYML_ASSERT(get(node) != nullptr); + size_t ich = get(node)->m_first_child; + while(ich != NONE) + { + remove_children(ich); + RYML_ASSERT(get(ich) != nullptr); + size_t next = get(ich)->m_next_sibling; + _release(ich); + if(ich == get(node)->m_last_child) + break; + ich = next; + } +} + +bool Tree::change_type(size_t node, NodeType type) +{ + RYML_ASSERT(type.is_val() || type.is_map() || type.is_seq()); + RYML_ASSERT(type.is_val() + type.is_map() + type.is_seq() == 1); + RYML_ASSERT(type.has_key() == has_key(node) || (has_key(node) && !type.has_key())); + NodeData *d = _p(node); + if(type.is_map() && is_map(node)) + return false; + else if(type.is_seq() && is_seq(node)) + return false; + else if(type.is_val() && is_val(node)) + return false; + d->m_type = (d->m_type & (~(MAP|SEQ|VAL))) | type; + remove_children(node); + return true; +} + + //----------------------------------------------------------------------------- size_t Tree::duplicate(size_t node, size_t parent, size_t after) { diff --git a/src/c4/yml/tree.hpp b/src/c4/yml/tree.hpp index d47cc3f0c..1de80d91d 100644 --- a/src/c4/yml/tree.hpp +++ b/src/c4/yml/tree.hpp @@ -781,27 +781,30 @@ class Tree public: - //! remove an entire branch at once: ie remove the children and the node itself + /** remove an entire branch at once: ie remove the children and the node itself */ inline void remove(size_t node) { remove_children(node); _release(node); } - //! remove all the node's children, but keep the node itself - void remove_children(size_t node) + /** remove all the node's children, but keep the node itself */ + void remove_children(size_t node); + + /** change the @p type of the node to one of MAP, SEQ or VAL. @p + * type must have one and only one of MAP,SEQ,VAL; @p type may + * possibly have KEY, but if it does, then the @p node must also + * have KEY. Changing to the same type is a no-op. Otherwise, + * changing to a different type will initialize the node with an + * empty value of the desired type: changing to VAL will + * initialize with a null scalar (~), changing to MAP will + * initialize with an empty map ({), and changing to SEQ will + * initialize with an empty seq ([]). */ + bool change_type(size_t node, NodeType type); + + bool change_type(size_t node, type_bits type) { - RYML_ASSERT(get(node) != nullptr); - size_t ich = get(node)->m_first_child; - while(ich != NONE) - { - remove_children(ich); - RYML_ASSERT(get(ich) != nullptr); - size_t next = get(ich)->m_next_sibling; - _release(ich); - if(ich == get(node)->m_last_child) break; - ich = next; - } + return change_type(node, (NodeType)type); } #if defined(__clang__) diff --git a/test/test_basic.cpp b/test/test_basic.cpp index 040b9924f..0e472640b 100644 --- a/test/test_basic.cpp +++ b/test/test_basic.cpp @@ -2827,6 +2827,67 @@ TEST(NodeInit, ctor__val_only) } +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +TEST(change_type, from_val) +{ + Tree t = parse("[val0, val1, val2]"); + t[0].change_type(VAL); + t[1].change_type(MAP); + t[2].change_type(SEQ); + Tree expected = parse("[val0, {}, []]"); + EXPECT_EQ(emitrs(t), emitrs(expected)); +} +TEST(change_type, from_keyval) +{ + Tree t = parse("{keyval0: val0, keyval1: val1, keyval2: val2}"); + t[0].change_type(VAL); + t[1].change_type(MAP); + t[2].change_type(SEQ); + Tree expected = parse("{keyval0: val0, keyval1: {}, keyval2: []}"); + EXPECT_EQ(emitrs(t), emitrs(expected)); +} + +TEST(change_type, from_map) +{ + Tree t = parse("[{map0: val0}, {map1: {map1key0: a, map1key1: b}}, {map2: [map2val0, map2val1]}]"); + t[0].change_type(VAL); + t[1].change_type(MAP); + t[2].change_type(SEQ); + Tree expected = parse("[~, {map1: {map1key0: a, map1key1: b}}, []]"); + EXPECT_EQ(emitrs(t), emitrs(expected)); +} +TEST(change_type, from_keymap) +{ + Tree t = parse("{map0: {map0: val0}, map1: {map1: {map1key0: a, map1key1: b}}, map2: {map2: [map2val0, map2val1]}}"); + t[0].change_type(VAL); + t[1].change_type(MAP); + t[2].change_type(SEQ); + Tree expected = parse("{map0: ~, map1: {map1: {map1key0: a, map1key1: b}}, map2: []}"); + EXPECT_EQ(emitrs(t), emitrs(expected)); +} + +TEST(change_type, from_seq) +{ + Tree t = parse("[[seq00, seq01], [seq10, seq11], [seq20, seq21]]"); + t[0].change_type(VAL); + t[1].change_type(MAP); + t[2].change_type(SEQ); + Tree expected = parse("[~, {}, [seq20, seq21]]"); + EXPECT_EQ(emitrs(t), emitrs(expected)); +} +TEST(change_type, from_keyseq) +{ + Tree t = parse("{map0: [seq00, seq01], map1: [seq10, seq11], map2: [seq20, seq21]}"); + t[0].change_type(VAL); + t[1].change_type(MAP); + t[2].change_type(SEQ); + Tree expected = parse("{map0: ~, map1: {}, map2: [seq20, seq21]}"); + EXPECT_EQ(emitrs(t), emitrs(expected)); +} + + //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- From cf902dc49ccee49fae8defd9f0f8afcd07e4097c Mon Sep 17 00:00:00 2001 From: Joao Paulo Magalhaes Date: Sat, 4 Dec 2021 16:42:16 +0000 Subject: [PATCH 4/5] [chore] update c4core --- ext/c4core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/c4core b/ext/c4core index 231185eeb..503d38c5a 160000 --- a/ext/c4core +++ b/ext/c4core @@ -1 +1 @@ -Subproject commit 231185eeb8d2e85db1e7d9810a34664f039fa176 +Subproject commit 503d38c5aa44a2e6af8b1963e54c343ae234bacb From ec2c13c25052e887c735f711ce9a453db6e1876e Mon Sep 17 00:00:00 2001 From: Joao Paulo Magalhaes Date: Wed, 8 Dec 2021 23:28:50 +0000 Subject: [PATCH 5/5] [chore] update c4core --- ext/c4core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/c4core b/ext/c4core index 503d38c5a..1f8664198 160000 --- a/ext/c4core +++ b/ext/c4core @@ -1 +1 @@ -Subproject commit 503d38c5aa44a2e6af8b1963e54c343ae234bacb +Subproject commit 1f86641984110788ff5a172b913d3aac5ec51bc0