Repository: biojppm/rapidyaml (language: python)

Issue:
emit_yaml raises `id < t.size()` exception after using `remove_child`
Hi, I've stumbled into an issue using `rapidyaml` version `0.5.0`: the following code raises the following error on the `emit_yaml` statement:
`check failed: id < t.size()`

IMO, this should not happen, but I could have misunderstood how to use the library.

```
int main(int argc, char *argv[])
{
    ryml::csubstr yaml = R"(
numbers:
  one: true
  two: false
  three: false
  four: false
formats:
  rtt: json
)";

    ryml::Tree tree = ryml::parse_in_arena(yaml);
    ryml::NodeRef root = tree.rootref();
    ryml::NodeRef numbers = root["numbers"];
    numbers.remove_child("one");
    numbers.remove_child("two");
    numbers.remove_child("three");
    ryml::NodeRef formats = root["formats"];

    ryml::csubstr test = ryml::emit_yaml(tree, formats.id(), ryml::substr{}, false);
}
```

Thank you!
emit_yaml raises `id < t.size()` exception after using `remove_child`
Hi, I've stumbled into an issue using `rapidyaml` version `0.5.0`: the following code raises the following error on the `emit_yaml` statement:
`check failed: id < t.size()`

IMO, this should not happen, but I could have misunderstood how to use the library.

```
int main(int argc, char *argv[])
{
    ryml::csubstr yaml = R"(
numbers:
  one: true
  two: false
  three: false
  four: false
formats:
  rtt: json
)";

    ryml::Tree tree = ryml::parse_in_arena(yaml);
    ryml::NodeRef root = tree.rootref();
    ryml::NodeRef numbers = root["numbers"];
    numbers.remove_child("one");
    numbers.remove_child("two");
    numbers.remove_child("three");
    ryml::NodeRef formats = root["formats"];

    ryml::csubstr test = ryml::emit_yaml(tree, formats.id(), ryml::substr{}, false);
}
```

Thank you!


Discussion / hints:
Thanks for reporting, and for the MVE which is very succint. It does seem a problem with ryml. Allow some time for investigating.
Thanks for reporting, and for the MVE which is very succint. It does seem a problem with ryml. Allow some time for investigating.

Fix patch:
diff --git a/changelog/current.md b/changelog/current.md
new file mode 100644
index 000000000..13db425e5
--- /dev/null
+++ b/changelog/current.md
@@ -0,0 +1,6 @@
+
+### Fixes
+
+- Fix [#356](https://github.com/biojppm/rapidyaml/issues/356) - fix overzealous check in `emit_as()`. An id may be larger than the tree's size, eg when nodes were removed.
+([PR#357](https://github.com/biojppm/rapidyaml/pull/357)).
+
diff --git a/src/c4/yml/emit.def.hpp b/src/c4/yml/emit.def.hpp
index d262a9e2a..cf184ad77 100644
--- a/src/c4/yml/emit.def.hpp
+++ b/src/c4/yml/emit.def.hpp
@@ -16,7 +16,7 @@ substr Emitter<Writer>::emit_as(EmitType_e type, Tree const& t, size_t id, bool
         _RYML_CB_ASSERT(t.callbacks(), id == NONE);
         return {};
     }
-    _RYML_CB_CHECK(t.callbacks(), id < t.size());
+    _RYML_CB_CHECK(t.callbacks(), id < t.capacity());
     m_tree = &t;
     if(type == EMIT_YAML)
         _emit_yaml(id);


Test patch:
diff --git a/test/test_noderef.cpp b/test/test_noderef.cpp
index cfd3363c3..2745c71f2 100644
--- a/test/test_noderef.cpp
+++ b/test/test_noderef.cpp
@@ -281,6 +281,43 @@ TEST(NodeRef, remove_child)
     noderef_check_tree(root);
 }
 
+
+TEST(NodeRef, remove_child__issue_356)
+{
+    csubstr yaml = R"(
+numbers:
+  one: true
+  two: false
+  three: false
+  four: false
+formats:
+  rtt: json
+)";
+    Tree tree = parse_in_arena(yaml);
+    NodeRef root = tree.rootref();
+    const std::string expected = R"(formats:
+  rtt: json
+)";
+    auto test_formats = [&](const char *id){
+        SCOPED_TRACE(id);
+        NodeRef formats = root["formats"];
+        std::cout << id << " id=" << formats.id() << "\n";
+        EXPECT_TRUE(formats.valid());
+        print_tree(tree);
+        check_invariants(tree);
+        EXPECT_EQ(emitrs_yaml<std::string>(formats), expected);
+        EXPECT_EQ(emitrs_yaml<std::string>(tree, formats.id()), expected);
+    };
+    test_formats("0 after parse");
+    NodeRef numbers = root["numbers"];
+    numbers.remove_child("one");
+    test_formats("1 after remove one");
+    numbers.remove_child("two");
+    test_formats("2 after remove two");
+    numbers.remove_child("three");
+    test_formats("3 after remove three");
+}
+
 TEST(NodeRef, move_in_same_parent)
 {
     Tree t;