Skip to content

Commit 0febd0f

Browse files
committed
Improve behaviour of tree creation and Tree::root_id().
`Tree` is now non-empty by default, and `Tree::root_id()` will no longer modify the tree when it is empty. To create an empty tree now it is necessary to use the capacity constructor with a capacity of zero: ```c++ // default-constructed tree is now non-empty Tree tree; assert(!tree.empty()); // MODIFIED! was empty on previous version id_type root = tree.root_id(); // OK. default-constructed tree is now non-empty // to create an empty tree: Tree tree(0); // pass capacity of zero assert(tree.empty()); // as expected // but watchout, this is no longer possible: //id_type root = tree.root_id(); // ERROR: cannot get root of empty tree. ``` This changeset also enables the python library to call `root_id()` on a default-constructed tree re #556
1 parent f110282 commit 0febd0f

File tree

12 files changed

+105
-54
lines changed

12 files changed

+105
-54
lines changed

api/python/tests/test_basic.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import ryml
2+
3+
4+
def test_create_empty_tree():
5+
tree = ryml.Tree(0)
6+
assert tree.empty()
7+
8+
9+
def test_create_tree():
10+
tree = ryml.Tree()
11+
assert not tree.empty()
12+
root = tree.root_id()
13+
tree.to_seq(root)

api/ryml.i

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -597,10 +597,11 @@ using id_type = RYML_ID_TYPE;
597597
struct Tree
598598
{
599599
Tree();
600+
Tree(id_type node_type, size_t arena_capacity=RYML_DEFAULT_TREE_ARENA_CAPACITY);
600601
~Tree();
601602

602-
void reserve(id_type node_capacity);
603-
void reserve_arena(size_t arena_capacity);
603+
void reserve(id_type node_capacity=RYML_DEFAULT_TREE_CAPACITY);
604+
void reserve_arena(size_t arena_capacity=RYML_DEFAULT_TREE_ARENA_CAPACITY);
604605
void clear();
605606
void clear_arena();
606607

changelog/current.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,17 @@
66
---
77
more data here
88
```
9+
- [PR#557](https://github.com/biojppm/rapidyaml/pull/557) - `Tree` is now non-empty by default, and `Tree::root_id()` will no longer modify the tree when it is empty. To create an empty tree now it is necessary to use the capacity constructor with a capacity of zero:
10+
```c++
11+
// default-constructed tree is now non-empty
12+
Tree tree;
13+
assert(!tree.empty()); // MODIFIED! was empty on previous version
14+
id_type root = tree.root_id(); // OK. default-constructed tree is now non-empty
15+
16+
// to create an empty tree:
17+
Tree tree(0); // pass capacity of zero
18+
assert(tree.empty()); // as expected
19+
// but watchout, this is no longer possible:
20+
//id_type root = tree.root_id(); // ERROR: cannot get root of empty tree.
21+
```
22+
This changeset also enables the python library to call `root_id()` on a default-constructed tree (fixes [#556](https://github.com/biojppm/rapidyaml/issues/556)).

samples/quickstart.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3911,7 +3911,7 @@ void sample_float_precision()
39113911
// have to build the container.
39123912
//
39133913
// First a function to check the result:
3914-
auto check_precision = [&](ryml::Tree serialized){
3914+
auto check_precision = [&](ryml::Tree const& serialized){
39153915
std::cout << serialized;
39163916
// now it works!
39173917
CHECK((ryml::emitrs_yaml<std::string>(serialized) == R"(- 1.23234412342131239

src/c4/yml/common.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@
2222

2323
//-----------------------------------------------------------------------------
2424

25+
#ifndef RYML_DEFAULT_TREE_CAPACITY
26+
/// default capacity for the tree when not set explicitly
27+
#define RYML_DEFAULT_TREE_CAPACITY (16)
28+
#endif
29+
30+
#ifndef RYML_DEFAULT_TREE_ARENA_CAPACITY
31+
/// default capacity for the tree's arena when not set explicitly
32+
#define RYML_DEFAULT_TREE_ARENA_CAPACITY (0)
33+
#endif
34+
2535
#ifndef RYML_ERRMSG_SIZE
2636
/// size for the error message buffer
2737
#define RYML_ERRMSG_SIZE (1024)

src/c4/yml/parse.cpp

Lines changed: 16 additions & 16 deletions
Large diffs are not rendered by default.

src/c4/yml/tree.cpp

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
1010
C4_SUPPRESS_WARNING_GCC("-Wtype-limits")
1111
C4_SUPPRESS_WARNING_GCC("-Wuseless-cast")
1212

13+
1314
namespace c4 {
1415
namespace yml {
1516

@@ -82,6 +83,11 @@ ConstNodeRef Tree::cdocref(id_type i) const
8283

8384
//-----------------------------------------------------------------------------
8485
Tree::Tree(Callbacks const& cb)
86+
: Tree(RYML_DEFAULT_TREE_CAPACITY, RYML_DEFAULT_TREE_ARENA_CAPACITY, cb)
87+
{
88+
}
89+
90+
Tree::Tree(id_type node_capacity, size_t arena_capacity, Callbacks const& cb)
8591
: m_buf(nullptr)
8692
, m_cap(0)
8793
, m_size(0)
@@ -92,13 +98,10 @@ Tree::Tree(Callbacks const& cb)
9298
, m_callbacks(cb)
9399
, m_tag_directives()
94100
{
95-
}
96-
97-
Tree::Tree(id_type node_capacity, size_t arena_capacity, Callbacks const& cb)
98-
: Tree(cb)
99-
{
100-
reserve(node_capacity);
101-
reserve_arena(arena_capacity);
101+
if(node_capacity)
102+
reserve(node_capacity);
103+
if(arena_capacity)
104+
reserve_arena(arena_capacity);
102105
}
103106

104107
Tree::~Tree()
@@ -107,11 +110,18 @@ Tree::~Tree()
107110
}
108111

109112

110-
Tree::Tree(Tree const& that) : Tree(that.m_callbacks)
113+
Tree::Tree(Tree const& that) : m_callbacks(that.m_callbacks)
111114
{
115+
_clear();
112116
_copy(that);
113117
}
114118

119+
Tree::Tree(Tree && that) noexcept : m_callbacks(that.m_callbacks)
120+
{
121+
_clear();
122+
_move(that);
123+
}
124+
115125
Tree& Tree::operator= (Tree const& that)
116126
{
117127
if(&that != this)
@@ -123,11 +133,6 @@ Tree& Tree::operator= (Tree const& that)
123133
return *this;
124134
}
125135

126-
Tree::Tree(Tree && that) noexcept : Tree(that.m_callbacks)
127-
{
128-
_move(that);
129-
}
130-
131136
Tree& Tree::operator= (Tree && that) noexcept
132137
{
133138
if(&that != this)

src/c4/yml/tree.hpp

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ C4_SUPPRESS_WARNING_GCC_CLANG("-Wold-style-cast")
3333
C4_SUPPRESS_WARNING_GCC("-Wuseless-cast")
3434
C4_SUPPRESS_WARNING_GCC("-Wtype-limits")
3535

36-
3736
namespace c4 {
3837
namespace yml {
3938

@@ -206,7 +205,7 @@ class RYML_EXPORT Tree
206205

207206
Tree() : Tree(get_callbacks()) {}
208207
Tree(Callbacks const& cb);
209-
Tree(id_type node_capacity, size_t arena_capacity=0) : Tree(node_capacity, arena_capacity, get_callbacks()) {}
208+
Tree(id_type node_capacity, size_t arena_capacity=RYML_DEFAULT_TREE_ARENA_CAPACITY) : Tree(node_capacity, arena_capacity, get_callbacks()) {}
210209
Tree(id_type node_capacity, size_t arena_capacity, Callbacks const& cb);
211210

212211
~Tree();
@@ -224,7 +223,7 @@ class RYML_EXPORT Tree
224223
/** @name memory and sizing */
225224
/** @{ */
226225

227-
void reserve(id_type node_capacity);
226+
void reserve(id_type node_capacity=RYML_DEFAULT_TREE_CAPACITY);
228227

229228
/** clear the tree and zero every node
230229
* @note does NOT clear the arena
@@ -284,10 +283,8 @@ class RYML_EXPORT Tree
284283
//! This function is implementation only; use at your own risk.
285284
NodeData const * _p(id_type node) const { _RYML_CB_ASSERT(m_callbacks, node != NONE && node >= 0 && node < m_cap); return m_buf + node; }
286285

287-
//! Get the id of the root node
288-
id_type root_id() { if(m_cap == 0) { reserve(16); } _RYML_CB_ASSERT(m_callbacks, m_cap > 0 && m_size > 0); return 0; }
289-
//! Get the id of the root node
290-
id_type root_id() const { _RYML_CB_ASSERT(m_callbacks, m_cap > 0 && m_size > 0); return 0; }
286+
//! Get the id of the root node. The tree must not be empty.
287+
id_type root_id() const { _RYML_CB_ASSERT(m_callbacks, m_cap > 0 && m_size > 0); return 0; }
291288

292289
//! Get a NodeRef of a node by id
293290
NodeRef ref(id_type node);
@@ -313,17 +310,17 @@ class RYML_EXPORT Tree
313310
//! @note @p i is NOT the node id, but the doc position within the stream
314311
ConstNodeRef cdocref(id_type i) const;
315312

316-
//! find a root child by name, return it as a NodeRef
313+
//! find a root child (ie child of root) by name, return it as a NodeRef
317314
//! @note requires the root to be a map.
318315
NodeRef operator[] (csubstr key);
319-
//! find a root child by name, return it as a NodeRef
316+
//! find a root child (ie child of root) by name, return it as a NodeRef
320317
//! @note requires the root to be a map.
321318
ConstNodeRef operator[] (csubstr key) const;
322319

323-
//! find a root child by index: return the root node's @p i-th child as a NodeRef
320+
//! find a root child (ie child of root) by index: return the root node's @p i-th child as a NodeRef
324321
//! @note @p i is NOT the node id, but the child's position
325322
NodeRef operator[] (id_type i);
326-
//! find a root child by index: return the root node's @p i-th child as a NodeRef
323+
//! find a root child (ie child of root) by index: return the root node's @p i-th child as a NodeRef
327324
//! @note @p i is NOT the node id, but the child's position
328325
ConstNodeRef operator[] (id_type i) const;
329326

@@ -971,7 +968,7 @@ class RYML_EXPORT Tree
971968
* @warning This operation may be expensive, with a potential complexity of O(numNodes)+O(arenasize).
972969
* @warning Growing the arena may cause relocation of the entire
973970
* existing arena, and thus change the contents of individual nodes. */
974-
void reserve_arena(size_t arena_cap)
971+
void reserve_arena(size_t arena_cap=RYML_DEFAULT_TREE_ARENA_CAPACITY)
975972
{
976973
if(arena_cap > m_arena.len)
977974
{

test/test_anchor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,7 @@ TEST(CaseNode, anchors)
492492

493493
TEST(simple_anchor, resolve_works_on_an_empty_tree)
494494
{
495-
Tree t;
495+
Tree t(0);
496496
t.resolve();
497497
EXPECT_TRUE(t.empty());
498498
}

test/test_lib/test_case.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ struct CaseDataLineEndings
310310
std::vector<char> src_buf;
311311
substr src;
312312

313-
Tree parsed_tree;
313+
Tree parsed_tree{0};
314314

315315
size_t numbytes_stdout;
316316
size_t numbytes_stdout_json;
@@ -327,10 +327,10 @@ struct CaseDataLineEndings
327327
std::string parse_buf_json;
328328
substr parsed_json;
329329

330-
Tree emitted_tree;
331-
Tree emitted_tree_json;
330+
Tree emitted_tree{0};
331+
Tree emitted_tree_json{0};
332332

333-
Tree recreated;
333+
Tree recreated{0};
334334

335335
std::string parse_buf_ints;
336336
std::vector<int> parsed_ints;

0 commit comments

Comments
 (0)