rapidyaml  0.12.0
parse and emit YAML, and do it fast
tree.cpp
Go to the documentation of this file.
1 #include "c4/yml/tree.hpp"
2 #include "c4/yml/detail/dbgprint.hpp"
3 #include "c4/yml/node.hpp"
5 
6 
7 C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(4296/*expression is always 'boolean_value'*/)
8 C4_SUPPRESS_WARNING_MSVC(4702/*unreachable code*/)
9 C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
10 C4_SUPPRESS_WARNING_GCC("-Wtype-limits")
11 C4_SUPPRESS_WARNING_GCC("-Wuseless-cast")
12 // NOLINTBEGIN(modernize-avoid-c-style-cast)
13 
14 
15 namespace c4 {
16 namespace yml {
17 
18 
19 csubstr serialize_to_arena(Tree * C4_RESTRICT tree, csubstr a)
20 {
21  if(a.len > 0)
22  {
23  substr rem(tree->m_arena.sub(tree->m_arena_pos));
24  size_t num = to_chars(rem, a);
25  if(num > rem.len)
26  {
27  rem = tree->_grow_arena(num);
28  num = to_chars(rem, a);
29  _RYML_ASSERT_VISIT_(tree->m_callbacks, num <= rem.len, tree, NONE);
30  }
31  return tree->_request_span(num);
32  }
33  else
34  {
35  if(a.str == nullptr)
36  {
37  return csubstr{};
38  }
39  else if(tree->m_arena.str == nullptr)
40  {
41  // Arena is empty and we want to store a non-null
42  // zero-length string.
43  // Even though the string has zero length, we need
44  // some "memory" to store a non-nullptr string
45  tree->_grow_arena(1);
46  }
47  return tree->_request_span(0);
48  }
49 }
50 
51 
52 //-----------------------------------------------------------------------------
53 //-----------------------------------------------------------------------------
54 //-----------------------------------------------------------------------------
55 
56 NodeRef Tree::rootref()
57 {
58  return NodeRef(this, root_id());
59 }
60 ConstNodeRef Tree::rootref() const
61 {
62  return ConstNodeRef(this, root_id());
63 }
64 
65 ConstNodeRef Tree::crootref() const
66 {
67  return ConstNodeRef(this, root_id());
68 }
69 
70 NodeRef Tree::ref(id_type id)
71 {
72  _RYML_ASSERT_VISIT_(m_callbacks, id != NONE && id >= 0 && id < m_cap, this, id);
73  return NodeRef(this, id);
74 }
75 ConstNodeRef Tree::ref(id_type id) const
76 {
77  _RYML_ASSERT_VISIT_(m_callbacks, id != NONE && id >= 0 && id < m_cap, this, id);
78  return ConstNodeRef(this, id);
79 }
80 ConstNodeRef Tree::cref(id_type id) const
81 {
82  _RYML_ASSERT_VISIT_(m_callbacks, id != NONE && id >= 0 && id < m_cap, this, id);
83  return ConstNodeRef(this, id);
84 }
85 
86 NodeRef Tree::operator[] (csubstr key)
87 {
88  return rootref()[key];
89 }
90 ConstNodeRef Tree::operator[] (csubstr key) const
91 {
92  return rootref()[key];
93 }
94 
95 NodeRef Tree::operator[] (id_type i)
96 {
97  return rootref()[i];
98 }
99 ConstNodeRef Tree::operator[] (id_type i) const
100 {
101  return rootref()[i];
102 }
103 
104 NodeRef Tree::docref(id_type i)
105 {
106  return ref(doc(i));
107 }
108 ConstNodeRef Tree::docref(id_type i) const
109 {
110  return cref(doc(i));
111 }
112 ConstNodeRef Tree::cdocref(id_type i) const
113 {
114  return cref(doc(i));
115 }
116 
117 
118 //-----------------------------------------------------------------------------
119 Tree::Tree(Callbacks const& cb)
121 {
122 }
123 
124 Tree::Tree(id_type node_capacity, size_t arena_capacity, Callbacks const& cb)
125  : m_buf(nullptr)
126  , m_cap(0)
127  , m_size(0)
128  , m_free_head(NONE)
129  , m_free_tail(NONE)
130  , m_arena()
131  , m_arena_pos(0)
132  , m_callbacks(cb)
133  , m_tag_directives()
134 {
135  if(node_capacity)
136  reserve(node_capacity);
137  if(arena_capacity)
139 }
140 
142 {
143  _free();
144 }
145 
146 
147 Tree::Tree(Tree const& that) : m_callbacks(that.m_callbacks)
148 {
149  _clear();
150  _copy(that);
151 }
152 
153 Tree::Tree(Tree && that) noexcept : m_callbacks(that.m_callbacks)
154 {
155  _clear();
156  _move(that);
157 }
158 
160 {
161  if(&that != this)
162  {
163  _free();
164  m_callbacks = that.m_callbacks;
165  _copy(that);
166  }
167  return *this;
168 }
169 
170 Tree& Tree::operator= (Tree && that) noexcept
171 {
172  if(&that != this)
173  {
174  _free();
175  m_callbacks = that.m_callbacks;
176  _move(that);
177  }
178  return *this;
179 }
180 
181 void Tree::_free()
182 {
183  if(m_buf)
184  {
185  _RYML_ASSERT_VISIT_(m_callbacks, m_cap > 0, this, NONE);
186  _RYML_CB_FREE(m_callbacks, m_buf, NodeData, (size_t)m_cap);
187  }
188  if(m_arena.str)
189  {
190  _RYML_ASSERT_VISIT_(m_callbacks, m_arena.len > 0, this, NONE);
191  _RYML_CB_FREE(m_callbacks, m_arena.str, char, m_arena.len);
192  }
193  _clear();
194 }
195 
196 
197 C4_SUPPRESS_WARNING_GCC_PUSH
198 #if defined(__GNUC__) && __GNUC__>= 8
199  C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wclass-memaccess") // error: ‘void* memset(void*, int, size_t)’ clearing an object of type ‘class c4::yml::Tree’ with no trivial copy-assignment; use assignment or value-initialization instead
200 #endif
201 
202 void Tree::_clear()
203 {
204  m_buf = nullptr;
205  m_cap = 0;
206  m_size = 0;
207  m_free_head = 0;
208  m_free_tail = 0;
209  m_arena = {};
210  m_arena_pos = 0;
212 }
213 
214 void Tree::_copy(Tree const& that)
215 {
216  _RYML_ASSERT_VISIT_(m_callbacks, m_buf == nullptr, this, NONE);
217  _RYML_ASSERT_VISIT_(m_callbacks, m_arena.str == nullptr, this, NONE);
218  _RYML_ASSERT_VISIT_(m_callbacks, m_arena.len == 0, this, NONE);
219  if(that.m_cap)
220  {
221  m_buf = _RYML_CB_ALLOC_HINT(m_callbacks, NodeData, (size_t)that.m_cap, that.m_buf);
222  memcpy(m_buf, that.m_buf, (size_t)that.m_cap * sizeof(NodeData));
223  }
224  m_cap = that.m_cap;
225  m_size = that.m_size;
226  m_free_head = that.m_free_head;
227  m_free_tail = that.m_free_tail;
228  m_arena_pos = that.m_arena_pos;
229  m_arena = that.m_arena;
230  m_tag_directives = that.m_tag_directives;
231  if(that.m_arena.str)
232  {
233  _RYML_ASSERT_VISIT_(m_callbacks, that.m_arena.len > 0, this, NONE);
234  substr arena;
235  arena.str = _RYML_CB_ALLOC_HINT(m_callbacks, char, that.m_arena.len, that.m_arena.str);
236  arena.len = that.m_arena.len;
237  _relocate(arena); // does a memcpy of the arena and updates nodes using the old arena
238  m_arena = arena;
239  }
240 }
241 
242 void Tree::_move(Tree & that) noexcept
243 {
244  _RYML_ASSERT_VISIT_(m_callbacks, m_buf == nullptr, this, NONE);
245  _RYML_ASSERT_VISIT_(m_callbacks, m_arena.str == nullptr, this, NONE);
246  _RYML_ASSERT_VISIT_(m_callbacks, m_arena.len == 0, this, NONE);
247  m_buf = that.m_buf;
248  m_cap = that.m_cap;
249  m_size = that.m_size;
250  m_free_head = that.m_free_head;
251  m_free_tail = that.m_free_tail;
252  m_arena = that.m_arena;
253  m_arena_pos = that.m_arena_pos;
254  m_tag_directives = that.m_tag_directives;
255  that._clear();
256 }
257 
258 void Tree::_relocate(substr next_arena)
259 {
260  _RYML_ASSERT_VISIT_(m_callbacks, next_arena.not_empty(), this, NONE);
261  _RYML_ASSERT_VISIT_(m_callbacks, next_arena.len >= m_arena.len, this, NONE);
262  if(m_arena_pos)
263  {
264  memcpy(next_arena.str, m_arena.str, m_arena_pos);
265  }
266  for(NodeData *C4_RESTRICT n = m_buf, *e = m_buf + m_cap; n != e; ++n)
267  {
268  if(in_arena(n->m_key.scalar))
269  n->m_key.scalar = _relocated(n->m_key.scalar, next_arena);
270  if(in_arena(n->m_key.tag))
271  n->m_key.tag = _relocated(n->m_key.tag, next_arena);
272  if(in_arena(n->m_key.anchor))
273  n->m_key.anchor = _relocated(n->m_key.anchor, next_arena);
274  if(in_arena(n->m_val.scalar))
275  n->m_val.scalar = _relocated(n->m_val.scalar, next_arena);
276  if(in_arena(n->m_val.tag))
277  n->m_val.tag = _relocated(n->m_val.tag, next_arena);
278  if(in_arena(n->m_val.anchor))
279  n->m_val.anchor = _relocated(n->m_val.anchor, next_arena);
280  }
281  for(TagDirective &C4_RESTRICT td : m_tag_directives)
282  {
283  if(in_arena(td.prefix))
284  td.prefix = _relocated(td.prefix, next_arena);
285  if(in_arena(td.handle))
286  td.handle = _relocated(td.handle, next_arena);
287  }
288 }
289 
290 
291 //-----------------------------------------------------------------------------
293 {
294  if(cap > m_cap)
295  {
296  NodeData *buf = _RYML_CB_ALLOC_HINT(m_callbacks, NodeData, (size_t)cap, m_buf);
297  if(m_buf)
298  {
299  memcpy(buf, m_buf, (size_t)m_cap * sizeof(NodeData));
300  _RYML_CB_FREE(m_callbacks, m_buf, NodeData, (size_t)m_cap);
301  }
302  id_type first = m_cap, del = cap - m_cap;
303  m_cap = cap;
304  m_buf = buf;
305  _clear_range(first, del);
306  if(m_free_head != NONE)
307  {
308  _RYML_ASSERT_VISIT_(m_callbacks, m_buf != nullptr, this, NONE);
309  _RYML_ASSERT_VISIT_(m_callbacks, m_free_tail != NONE, this, NONE);
312  m_free_tail = cap-1;
313  }
314  else
315  {
316  _RYML_ASSERT_VISIT_(m_callbacks, m_free_tail == NONE, this, NONE);
317  m_free_head = first;
318  m_free_tail = cap-1;
319  }
320  _RYML_ASSERT_VISIT_(m_callbacks, m_free_head == NONE || (m_free_head >= 0 && m_free_head < cap), this, NONE);
321  _RYML_ASSERT_VISIT_(m_callbacks, m_free_tail == NONE || (m_free_tail >= 0 && m_free_tail < cap), this, NONE);
322 
323  if( ! m_size)
324  _claim_root();
325  }
326 }
327 
328 
329 //-----------------------------------------------------------------------------
331 {
332  _clear_range(0, m_cap);
333  m_size = 0;
334  if(m_buf)
335  {
336  _RYML_ASSERT_VISIT_(m_callbacks, m_cap >= 0, this, NONE);
337  m_free_head = 0;
338  m_free_tail = m_cap-1;
339  _claim_root();
340  }
341  else
342  {
343  m_free_head = NONE;
344  m_free_tail = NONE;
345  }
347 }
348 
349 void Tree::_claim_root()
350 {
351  id_type r = _claim();
352  _RYML_ASSERT_VISIT_(m_callbacks, r == 0, this, r);
353  _set_hierarchy(r, NONE, NONE);
354 }
355 
356 
357 //-----------------------------------------------------------------------------
358 void Tree::_clear_range(id_type first, id_type num)
359 {
360  if(num == 0)
361  return; // prevent overflow when subtracting
362  _RYML_ASSERT_VISIT_(m_callbacks, first >= 0 && first + num <= m_cap, this, first);
363  memset(m_buf + first, 0, (size_t)num * sizeof(NodeData)); // TODO we should not need this
364  for(id_type i = first, e = first + num; i < e; ++i)
365  {
366  _clear(i);
367  NodeData *n = m_buf + i;
368  n->m_prev_sibling = i - 1;
369  n->m_next_sibling = i + 1;
370  }
371  m_buf[first + num - 1].m_next_sibling = NONE;
372 }
373 
374 C4_SUPPRESS_WARNING_GCC_POP
375 
376 
377 //-----------------------------------------------------------------------------
378 void Tree::_release(id_type i)
379 {
380  _RYML_ASSERT_VISIT_(m_callbacks, i >= 0 && i < m_cap, this, i);
381 
382  _rem_hierarchy(i);
383  _free_list_add(i);
384  _clear(i);
385 
386  --m_size;
387 }
388 
389 //-----------------------------------------------------------------------------
390 // add to the front of the free list
391 void Tree::_free_list_add(id_type i)
392 {
393  _RYML_ASSERT_VISIT_(m_callbacks, i >= 0 && i < m_cap, this, i);
394  NodeData &C4_RESTRICT w = m_buf[i];
395 
396  w.m_parent = NONE;
397  w.m_next_sibling = m_free_head;
398  w.m_prev_sibling = NONE;
399  if(m_free_head != NONE)
401  m_free_head = i;
402  if(m_free_tail == NONE)
404 }
405 
406 void Tree::_free_list_rem(id_type i)
407 {
408  if(m_free_head == i)
410  _rem_hierarchy(i);
411 }
412 
413 //-----------------------------------------------------------------------------
415 {
416  if(m_free_head == NONE || m_buf == nullptr)
417  {
418  id_type sz = 2 * m_cap;
419  sz = sz ? sz : 16;
420  reserve(sz);
421  _RYML_ASSERT_VISIT_(m_callbacks, m_free_head != NONE, this, NONE);
422  }
423 
424  _RYML_ASSERT_VISIT_(m_callbacks, m_size < m_cap, this, NONE);
425  _RYML_ASSERT_VISIT_(m_callbacks, m_free_head >= 0 && m_free_head < m_cap, this, NONE);
426 
427  id_type ichild = m_free_head;
428  NodeData *child = m_buf + ichild;
429 
430  ++m_size;
431  m_free_head = child->m_next_sibling;
432  if(m_free_head == NONE)
433  {
434  m_free_tail = NONE;
435  _RYML_ASSERT_VISIT_(m_callbacks, m_size == m_cap, this, NONE);
436  }
437 
438  _clear(ichild);
439 
440  return ichild;
441 }
442 
443 //-----------------------------------------------------------------------------
444 
445 C4_SUPPRESS_WARNING_GCC_PUSH
446 C4_SUPPRESS_WARNING_CLANG_PUSH
447 C4_SUPPRESS_WARNING_CLANG("-Wnull-dereference")
448 #if defined(__GNUC__)
449 #if (__GNUC__ >= 6)
450 C4_SUPPRESS_WARNING_GCC("-Wnull-dereference")
451 #endif
452 #if (__GNUC__ > 9)
453 C4_SUPPRESS_WARNING_GCC("-Wanalyzer-fd-leak")
454 #endif
455 #endif
456 
457 void Tree::_set_hierarchy(id_type ichild, id_type iparent, id_type iprev_sibling)
458 {
459  _RYML_ASSERT_VISIT_(m_callbacks, ichild >= 0 && ichild < m_cap, this, ichild);
460  _RYML_ASSERT_VISIT_(m_callbacks, iparent == NONE || (iparent >= 0 && iparent < m_cap), this, iparent);
461  _RYML_ASSERT_VISIT_(m_callbacks, iprev_sibling == NONE || (iprev_sibling >= 0 && iprev_sibling < m_cap), this, iprev_sibling);
462 
463  NodeData *C4_RESTRICT child = _p(ichild);
464 
465  child->m_parent = iparent;
466  child->m_prev_sibling = NONE;
467  child->m_next_sibling = NONE;
468 
469  if(iparent == NONE)
470  {
471  _RYML_ASSERT_VISIT_(m_callbacks, ichild == 0, this, ichild);
472  _RYML_ASSERT_VISIT_(m_callbacks, iprev_sibling == NONE, this, iprev_sibling);
473  }
474 
475  if(iparent == NONE)
476  return;
477 
478  id_type inext_sibling = iprev_sibling != NONE ? next_sibling(iprev_sibling) : first_child(iparent);
479  NodeData *C4_RESTRICT parent = get(iparent);
480  NodeData *C4_RESTRICT psib = get(iprev_sibling);
481  NodeData *C4_RESTRICT nsib = get(inext_sibling);
482 
483  if(psib)
484  {
485  _RYML_ASSERT_VISIT_(m_callbacks, next_sibling(iprev_sibling) == id(nsib), this, iprev_sibling);
486  child->m_prev_sibling = id(psib);
487  psib->m_next_sibling = id(child);
488  _RYML_ASSERT_VISIT_(m_callbacks, psib->m_prev_sibling != psib->m_next_sibling || psib->m_prev_sibling == NONE, this, iprev_sibling);
489  }
490 
491  if(nsib)
492  {
493  _RYML_ASSERT_VISIT_(m_callbacks, prev_sibling(inext_sibling) == id(psib), this, inext_sibling);
494  child->m_next_sibling = id(nsib);
495  nsib->m_prev_sibling = id(child);
496  _RYML_ASSERT_VISIT_(m_callbacks, nsib->m_prev_sibling != nsib->m_next_sibling || nsib->m_prev_sibling == NONE, this, inext_sibling);
497  }
498 
499  if(parent->m_first_child == NONE)
500  {
501  _RYML_ASSERT_VISIT_(m_callbacks, parent->m_last_child == NONE, this, parent->m_last_child);
502  parent->m_first_child = id(child);
503  parent->m_last_child = id(child);
504  }
505  else
506  {
507  if(child->m_next_sibling == parent->m_first_child)
508  parent->m_first_child = id(child);
509 
510  if(child->m_prev_sibling == parent->m_last_child)
511  parent->m_last_child = id(child);
512  }
513 }
514 
515 C4_SUPPRESS_WARNING_GCC_POP
516 C4_SUPPRESS_WARNING_CLANG_POP
517 
518 
519 //-----------------------------------------------------------------------------
520 void Tree::_rem_hierarchy(id_type i)
521 {
522  _RYML_ASSERT_VISIT_(m_callbacks, i >= 0 && i < m_cap, this, i);
523 
524  NodeData &C4_RESTRICT w = m_buf[i];
525 
526  // remove from the parent
527  if(w.m_parent != NONE)
528  {
529  NodeData &C4_RESTRICT p = m_buf[w.m_parent];
530  if(p.m_first_child == i)
531  {
532  p.m_first_child = w.m_next_sibling;
533  }
534  if(p.m_last_child == i)
535  {
536  p.m_last_child = w.m_prev_sibling;
537  }
538  }
539 
540  // remove from the used list
541  if(w.m_prev_sibling != NONE)
542  {
543  NodeData *C4_RESTRICT prev = get(w.m_prev_sibling);
544  prev->m_next_sibling = w.m_next_sibling;
545  }
546  if(w.m_next_sibling != NONE)
547  {
548  NodeData *C4_RESTRICT next = get(w.m_next_sibling);
549  next->m_prev_sibling = w.m_prev_sibling;
550  }
551 }
552 
553 //-----------------------------------------------------------------------------
554 /** @cond dev */
555 id_type Tree::_do_reorder(id_type *node, id_type count)
556 {
557  // swap this node if it's not in place
558  if(*node != count)
559  {
560  _swap(*node, count);
561  *node = count;
562  }
563  ++count; // bump the count from this node
564 
565  // now descend in the hierarchy
566  for(id_type i = first_child(*node); i != NONE; i = next_sibling(i))
567  {
568  // this child may have been relocated to a different index,
569  // so get an updated version
570  count = _do_reorder(&i, count);
571  }
572  return count;
573 }
574 /** @endcond */
575 
577 {
578  id_type r = root_id();
579  _do_reorder(&r, 0);
580 }
581 
582 
583 //-----------------------------------------------------------------------------
584 /** @cond dev */
585 void Tree::_swap(id_type n_, id_type m_)
586 {
587  _RYML_ASSERT_VISIT_(m_callbacks, (parent(n_) != NONE) || type(n_) == NOTYPE, this, n_);
588  _RYML_ASSERT_VISIT_(m_callbacks, (parent(m_) != NONE) || type(m_) == NOTYPE, this, m_);
589  NodeType tn = type(n_);
590  NodeType tm = type(m_);
591  if(tn != NOTYPE && tm != NOTYPE)
592  {
593  _swap_props(n_, m_);
594  _swap_hierarchy(n_, m_);
595  }
596  else if(tn == NOTYPE && tm != NOTYPE)
597  {
598  _copy_props(n_, m_);
599  _free_list_rem(n_);
600  _copy_hierarchy(n_, m_);
601  _clear(m_);
602  _free_list_add(m_);
603  }
604  else if(tn != NOTYPE && tm == NOTYPE)
605  {
606  _copy_props(m_, n_);
607  _free_list_rem(m_);
608  _copy_hierarchy(m_, n_);
609  _clear(n_);
610  _free_list_add(n_);
611  }
612  else
613  {
614  C4_NEVER_REACH();
615  }
616 }
617 
618 //-----------------------------------------------------------------------------
619 void Tree::_swap_hierarchy(id_type ia, id_type ib)
620 {
621  if(ia == ib) return;
622 
623  for(id_type i = first_child(ia); i != NONE; i = next_sibling(i))
624  {
625  if(i == ib || i == ia)
626  continue;
627  _p(i)->m_parent = ib;
628  }
629 
630  for(id_type i = first_child(ib); i != NONE; i = next_sibling(i))
631  {
632  if(i == ib || i == ia)
633  continue;
634  _p(i)->m_parent = ia;
635  }
636 
637  auto & C4_RESTRICT a = *_p(ia);
638  auto & C4_RESTRICT b = *_p(ib);
639  auto & C4_RESTRICT pa = *_p(a.m_parent);
640  auto & C4_RESTRICT pb = *_p(b.m_parent);
641 
642  if(&pa == &pb)
643  {
644  if((pa.m_first_child == ib && pa.m_last_child == ia)
645  ||
646  (pa.m_first_child == ia && pa.m_last_child == ib))
647  {
648  std::swap(pa.m_first_child, pa.m_last_child);
649  }
650  else
651  {
652  bool changed = false;
653  if(pa.m_first_child == ia)
654  {
655  pa.m_first_child = ib;
656  changed = true;
657  }
658  if(pa.m_last_child == ia)
659  {
660  pa.m_last_child = ib;
661  changed = true;
662  }
663  if(pb.m_first_child == ib && !changed)
664  {
665  pb.m_first_child = ia;
666  }
667  if(pb.m_last_child == ib && !changed)
668  {
669  pb.m_last_child = ia;
670  }
671  }
672  }
673  else
674  {
675  if(pa.m_first_child == ia)
676  pa.m_first_child = ib;
677  if(pa.m_last_child == ia)
678  pa.m_last_child = ib;
679  if(pb.m_first_child == ib)
680  pb.m_first_child = ia;
681  if(pb.m_last_child == ib)
682  pb.m_last_child = ia;
683  }
684  std::swap(a.m_first_child , b.m_first_child);
685  std::swap(a.m_last_child , b.m_last_child);
686 
687  if(a.m_prev_sibling != ib && b.m_prev_sibling != ia &&
688  a.m_next_sibling != ib && b.m_next_sibling != ia)
689  {
690  if(a.m_prev_sibling != NONE && a.m_prev_sibling != ib)
691  _p(a.m_prev_sibling)->m_next_sibling = ib;
692  if(a.m_next_sibling != NONE && a.m_next_sibling != ib)
693  _p(a.m_next_sibling)->m_prev_sibling = ib;
694  if(b.m_prev_sibling != NONE && b.m_prev_sibling != ia)
695  _p(b.m_prev_sibling)->m_next_sibling = ia;
696  if(b.m_next_sibling != NONE && b.m_next_sibling != ia)
697  _p(b.m_next_sibling)->m_prev_sibling = ia;
698  std::swap(a.m_prev_sibling, b.m_prev_sibling);
699  std::swap(a.m_next_sibling, b.m_next_sibling);
700  }
701  else
702  {
703  if(a.m_next_sibling == ib) // n will go after m
704  {
705  _RYML_ASSERT_VISIT_(m_callbacks, b.m_prev_sibling == ia, this, ia);
706  if(a.m_prev_sibling != NONE)
707  {
708  _RYML_ASSERT_VISIT_(m_callbacks, a.m_prev_sibling != ib, this, ib);
709  _p(a.m_prev_sibling)->m_next_sibling = ib;
710  }
711  if(b.m_next_sibling != NONE)
712  {
713  _RYML_ASSERT_VISIT_(m_callbacks, b.m_next_sibling != ia, this, ia);
714  _p(b.m_next_sibling)->m_prev_sibling = ia;
715  }
716  id_type ns = b.m_next_sibling;
717  b.m_prev_sibling = a.m_prev_sibling;
718  b.m_next_sibling = ia;
719  a.m_prev_sibling = ib;
720  a.m_next_sibling = ns;
721  }
722  else if(a.m_prev_sibling == ib) // m will go after n
723  {
724  _RYML_ASSERT_VISIT_(m_callbacks, b.m_next_sibling == ia, this, ia);
725  if(b.m_prev_sibling != NONE)
726  {
727  _RYML_ASSERT_VISIT_(m_callbacks, b.m_prev_sibling != ia, this, ia);
728  _p(b.m_prev_sibling)->m_next_sibling = ia;
729  }
730  if(a.m_next_sibling != NONE)
731  {
732  _RYML_ASSERT_VISIT_(m_callbacks, a.m_next_sibling != ib, this, ib);
733  _p(a.m_next_sibling)->m_prev_sibling = ib;
734  }
735  id_type ns = b.m_prev_sibling;
736  a.m_prev_sibling = b.m_prev_sibling;
737  a.m_next_sibling = ib;
738  b.m_prev_sibling = ia;
739  b.m_next_sibling = ns;
740  }
741  else
742  {
743  C4_NEVER_REACH();
744  }
745  }
746  _RYML_ASSERT_VISIT_(m_callbacks, a.m_next_sibling != ia, this, ia);
747  _RYML_ASSERT_VISIT_(m_callbacks, a.m_prev_sibling != ia, this, ia);
748  _RYML_ASSERT_VISIT_(m_callbacks, b.m_next_sibling != ib, this, ib);
749  _RYML_ASSERT_VISIT_(m_callbacks, b.m_prev_sibling != ib, this, ib);
750 
751  if(a.m_parent != ib && b.m_parent != ia)
752  {
753  std::swap(a.m_parent, b.m_parent);
754  }
755  else
756  {
757  if(a.m_parent == ib && b.m_parent != ia)
758  {
759  a.m_parent = b.m_parent;
760  b.m_parent = ia;
761  }
762  else if(a.m_parent != ib && b.m_parent == ia)
763  {
764  b.m_parent = a.m_parent;
765  a.m_parent = ib;
766  }
767  else
768  {
769  C4_NEVER_REACH();
770  }
771  }
772 }
773 
774 //-----------------------------------------------------------------------------
775 void Tree::_copy_hierarchy(id_type dst_, id_type src_)
776 {
777  auto const& C4_RESTRICT src = *_p(src_);
778  auto & C4_RESTRICT dst = *_p(dst_);
779  auto & C4_RESTRICT prt = *_p(src.m_parent);
780  for(id_type i = src.m_first_child; i != NONE; i = next_sibling(i))
781  {
782  _p(i)->m_parent = dst_;
783  }
784  if(src.m_prev_sibling != NONE)
785  {
786  _p(src.m_prev_sibling)->m_next_sibling = dst_;
787  }
788  if(src.m_next_sibling != NONE)
789  {
790  _p(src.m_next_sibling)->m_prev_sibling = dst_;
791  }
792  if(prt.m_first_child == src_)
793  {
794  prt.m_first_child = dst_;
795  }
796  if(prt.m_last_child == src_)
797  {
798  prt.m_last_child = dst_;
799  }
800  dst.m_parent = src.m_parent;
801  dst.m_first_child = src.m_first_child;
802  dst.m_last_child = src.m_last_child;
803  dst.m_prev_sibling = src.m_prev_sibling;
804  dst.m_next_sibling = src.m_next_sibling;
805 }
806 
807 //-----------------------------------------------------------------------------
808 void Tree::_swap_props(id_type n_, id_type m_)
809 {
810  NodeData &C4_RESTRICT n = *_p(n_);
811  NodeData &C4_RESTRICT m = *_p(m_);
812  std::swap(n.m_type, m.m_type);
813  std::swap(n.m_key, m.m_key);
814  std::swap(n.m_val, m.m_val);
815 }
816 /** @endcond */
817 
818 //-----------------------------------------------------------------------------
819 void Tree::move(id_type node, id_type after)
820 {
821  _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
822  _RYML_ASSERT_VISIT_(m_callbacks, node != after, this, node);
823  _RYML_ASSERT_VISIT_(m_callbacks, ! is_root(node), this, node);
824  _RYML_ASSERT_VISIT_(m_callbacks, (after == NONE) || (has_sibling(node, after) && has_sibling(after, node)), this, node);
825 
826  _rem_hierarchy(node);
827  _set_hierarchy(node, parent(node), after);
828 }
829 
830 //-----------------------------------------------------------------------------
831 
832 void Tree::move(id_type node, id_type new_parent, id_type after)
833 {
834  _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
835  _RYML_ASSERT_VISIT_(m_callbacks, node != after, this, node);
836  _RYML_ASSERT_VISIT_(m_callbacks, new_parent != NONE, this, new_parent);
837  _RYML_ASSERT_VISIT_(m_callbacks, new_parent != node, this, new_parent);
838  _RYML_ASSERT_VISIT_(m_callbacks, new_parent != after, this, new_parent);
839  _RYML_ASSERT_VISIT_(m_callbacks, ! is_root(node), this, node);
840 
841  _rem_hierarchy(node);
842  _set_hierarchy(node, new_parent, after);
843 }
844 
845 id_type Tree::move(Tree *src, id_type node, id_type new_parent, id_type after)
846 {
847  _RYML_ASSERT_VISIT_(m_callbacks, src != nullptr, this, new_parent);
848  _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, new_parent);
849  _RYML_ASSERT_VISIT_(m_callbacks, new_parent != NONE, this, new_parent);
850  _RYML_ASSERT_VISIT_(m_callbacks, new_parent != after, this, new_parent);
851 
852  id_type dup = duplicate(src, node, new_parent, after);
853  src->remove(node);
854  return dup;
855 }
856 
858 {
859  id_type root = root_id();
860  if(is_stream(root))
861  return;
862  _c4dbgpf("set_root_as_stream. rootty={}", type(root).type);
863  bool empty_root = ((type(root) & (SEQ|MAP|VAL)) == 0);
864  for(TagDirective &C4_RESTRICT td : m_tag_directives)
865  {
866  if(td.doc_id >= m_cap || _p(td.doc_id)->m_parent == NONE)
867  {
868  _c4dbgpf("tagd[{}]: id={}->NONE", &td-m_tag_directives.m_directives, td.doc_id);
869  td.doc_id = NONE;
870  }
871  }
872  // don't use _add_flags() because it's checked and will fail
873  id_type next_doc;
874  if(!has_children(root))
875  {
876  if(is_container(root))
877  {
878  next_doc = append_child(root);
879  _copy_props_wo_key(next_doc, root);
880  _p(next_doc)->m_type.add(DOC);
881  }
882  else
883  {
884  _p(root)->m_type.add(SEQ);
885  next_doc = append_child(root);
886  _copy_props_wo_key(next_doc, root);
887  _p(next_doc)->m_type.add(DOC);
888  _p(next_doc)->m_type.rem(SEQ);
889  }
890  }
891  else
892  {
893  _RYML_ASSERT_VISIT_(m_callbacks, !has_key(root), this, root);
894  next_doc = append_child(root);
895  _copy_props_wo_key(next_doc, root);
896  _add_flags(next_doc, DOC);
897  for(id_type prev = NONE, ch = first_child(root), next = next_sibling(ch); ch != NONE; )
898  {
899  if(ch == next_doc)
900  break;
901  move(ch, next_doc, prev);
902  prev = ch;
903  ch = next;
904  next = next_sibling(next);
905  }
906  }
907  _p(root)->m_type = STREAM;
908  for(TagDirective &C4_RESTRICT td : m_tag_directives)
909  {
910  id_type id = (td.doc_id != NONE) ? next_doc : (empty_root ? first_child(root) : m_free_head);
911  _c4dbgpf("tagd[{}]: id={}->{}", &td-m_tag_directives.m_directives, td.doc_id, id);
912  td.doc_id = id;
913  }
914 }
915 
916 
917 //-----------------------------------------------------------------------------
919 {
920  _RYML_ASSERT_VISIT_(m_callbacks, get(node) != nullptr, this, node);
921  #if __GNUC__ >= 6
922  C4_SUPPRESS_WARNING_GCC_WITH_PUSH("-Wnull-dereference")
923  #endif
924  id_type ich = get(node)->m_first_child;
925  #if __GNUC__ >= 6
926  C4_SUPPRESS_WARNING_GCC_POP
927  #endif
928  while(ich != NONE)
929  {
930  remove_children(ich);
931  _RYML_ASSERT_VISIT_(m_callbacks, get(ich) != nullptr, this, node);
932  id_type next = get(ich)->m_next_sibling;
933  _release(ich);
934  if(ich == get(node)->m_last_child)
935  break;
936  ich = next;
937  }
938 }
939 
941 {
942  _RYML_ASSERT_VISIT_(m_callbacks, type.is_val() || type.is_map() || type.is_seq(), this, node);
943  _RYML_ASSERT_VISIT_(m_callbacks, type.is_val() + type.is_map() + type.is_seq() == 1, this, node);
944  _RYML_ASSERT_VISIT_(m_callbacks, type.has_key() == has_key(node) || (has_key(node) && !type.has_key()), this, node);
945  NodeData *d = _p(node);
946  if(type.is_map() && is_map(node))
947  return false;
948  else if(type.is_seq() && is_seq(node))
949  return false;
950  else if(type.is_val() && is_val(node))
951  return false;
953  remove_children(node);
954  return true;
955 }
956 
957 
958 //-----------------------------------------------------------------------------
960 {
961  return duplicate(this, node, parent, after);
962 }
963 
964 id_type Tree::duplicate(Tree const* src, id_type node, id_type parent, id_type after)
965 {
966  _RYML_ASSERT_VISIT_(m_callbacks, src != nullptr, src, node);
967  _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, src, node);
968  _RYML_ASSERT_VISIT_(m_callbacks, parent != NONE, this, parent);
969  _RYML_ASSERT_VISIT_(m_callbacks, ! src->is_root(node), src, node);
970 
971  id_type copy = _claim();
972 
973  _copy_props(copy, src, node);
974  _set_hierarchy(copy, parent, after);
975  duplicate_children(src, node, copy, NONE);
976 
977  return copy;
978 }
979 
980 //-----------------------------------------------------------------------------
982 {
983  return duplicate_children(this, node, parent, after);
984 }
985 
986 id_type Tree::duplicate_children(Tree const* src, id_type node, id_type parent, id_type after)
987 {
988  _RYML_ASSERT_VISIT_(m_callbacks, src != nullptr, src, node);
989  _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, src, node);
990  _RYML_ASSERT_VISIT_(m_callbacks, parent != NONE, this, parent);
991  _RYML_ASSERT_VISIT_(m_callbacks, after == NONE || has_child(parent, after), this, parent);
992 
993  id_type prev = after;
994  for(id_type i = src->first_child(node); i != NONE; i = src->next_sibling(i))
995  {
996  prev = duplicate(src, i, parent, prev);
997  }
998 
999  return prev;
1000 }
1001 
1002 //-----------------------------------------------------------------------------
1004 {
1005  duplicate_contents(this, node, where);
1006 }
1007 
1008 void Tree::duplicate_contents(Tree const *src, id_type node, id_type where)
1009 {
1010  _RYML_ASSERT_VISIT_(m_callbacks, src != nullptr, src, node);
1011  _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, src, node);
1012  _RYML_ASSERT_VISIT_(m_callbacks, where != NONE, this, where);
1013  _copy_props_wo_key(where, src, node);
1014  duplicate_children(src, node, where, last_child(where));
1015 }
1016 
1017 //-----------------------------------------------------------------------------
1019 {
1020  return duplicate_children_no_rep(this, node, parent, after);
1021 }
1022 
1024 {
1025  _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, src, node);
1026  _RYML_ASSERT_VISIT_(m_callbacks, parent != NONE, this, parent);
1027  _RYML_ASSERT_VISIT_(m_callbacks, after == NONE || has_child(parent, after), this, parent);
1028 
1029  // don't loop using pointers as there may be a relocation
1030 
1031  // find the position where "after" is
1032  id_type after_pos = NONE;
1033  if(after != NONE)
1034  {
1035  for(id_type i = first_child(parent), icount = 0; i != NONE; ++icount, i = next_sibling(i))
1036  {
1037  if(i == after)
1038  {
1039  after_pos = icount;
1040  break;
1041  }
1042  }
1043  _RYML_ASSERT_VISIT_(m_callbacks, after_pos != NONE, this, node);
1044  }
1045 
1046  // for each child to be duplicated...
1047  id_type prev = after;
1048  for(id_type i = src->first_child(node); i != NONE; i = src->next_sibling(i))
1049  {
1050  _c4dbgpf("duplicate_no_rep: {} -> {}/{}", i, parent, prev);
1051  _RYML_CHECK_VISIT_(m_callbacks, this != src || (parent != i && !is_ancestor(parent, i)), this, parent);
1052  if(is_seq(parent))
1053  {
1054  _c4dbgpf("duplicate_no_rep: {} is seq", parent);
1055  prev = duplicate(src, i, parent, prev);
1056  }
1057  else
1058  {
1059  _c4dbgpf("duplicate_no_rep: {} is map", parent);
1060  _RYML_ASSERT_VISIT_(m_callbacks, is_map(parent), this, parent);
1061  // does the parent already have a node with key equal to that of the current duplicate?
1062  id_type dstnode_dup = NONE, dstnode_dup_pos = NONE;
1063  {
1064  csubstr srckey = src->key(i);
1065  for(id_type j = first_child(parent), jcount = 0; j != NONE; ++jcount, j = next_sibling(j))
1066  {
1067  if(key(j) == srckey)
1068  {
1069  _c4dbgpf("duplicate_no_rep: found matching key '{}' src={}/{} dst={}/{}", srckey, node, i, parent, j);
1070  dstnode_dup = j;
1071  dstnode_dup_pos = jcount;
1072  break;
1073  }
1074  }
1075  }
1076  _c4dbgpf("duplicate_no_rep: dstnode_dup={} dstnode_dup_pos={} after_pos={}", dstnode_dup, dstnode_dup_pos, after_pos);
1077  if(dstnode_dup == NONE) // there is no repetition; just duplicate
1078  {
1079  _c4dbgpf("duplicate_no_rep: no repetition, just duplicate i={} parent={} prev={}", i, parent, prev);
1080  prev = duplicate(src, i, parent, prev);
1081  }
1082  else // yes, there is a repetition
1083  {
1084  if(after_pos != NONE && dstnode_dup_pos <= after_pos)
1085  {
1086  // the dst duplicate is located before the node which will be inserted,
1087  // and will be overridden by the duplicate. So replace it.
1088  _c4dbgpf("duplicate_no_dstnode_dup: replace {}/{} with {}/{}", parent, dstnode_dup, node, i);
1089  if(prev == dstnode_dup)
1090  prev = prev_sibling(dstnode_dup);
1091  remove(dstnode_dup);
1092  prev = duplicate(src, i, parent, prev);
1093  }
1094  else if(prev == NONE)
1095  {
1096  _c4dbgpf("duplicate_no_dstnode_dup: {}=prev <- {}", prev, dstnode_dup);
1097  // first iteration with prev = after = NONE and dstnode_dupetition
1098  prev = dstnode_dup;
1099  }
1100  else if(dstnode_dup != prev)
1101  {
1102  // dstnode_dup is located after the node which will be inserted
1103  // and overrides it. So move the dstnode_dup into this node's place.
1104  _c4dbgpf("duplicate_no_dstnode_dup: move({}, {})", dstnode_dup, prev);
1105  move(dstnode_dup, prev);
1106  prev = dstnode_dup;
1107  }
1108  } // there's a dstnode_dupetition
1109  }
1110  }
1111 
1112  return prev;
1113 }
1114 
1115 
1116 //-----------------------------------------------------------------------------
1117 
1118 void Tree::merge_with(Tree const *src, id_type src_node, id_type dst_node)
1119 {
1120  _RYML_ASSERT_VISIT_(m_callbacks, src != nullptr, src, src_node);
1121  if(src_node == NONE)
1122  src_node = src->root_id();
1123  if(dst_node == NONE)
1124  dst_node = root_id();
1125  _RYML_ASSERT_VISIT_(m_callbacks, src->has_val(src_node) || src->is_seq(src_node) || src->is_map(src_node), src, src_node);
1126  if(src->has_val(src_node))
1127  {
1128  type_bits mask_src = ~STYLE; // keep the existing style if it is already a val
1129  if( ! has_val(dst_node))
1130  {
1131  if(has_children(dst_node))
1132  remove_children(dst_node);
1133  mask_src |= VAL_STYLE; // copy the src style
1134  }
1135  if(src->is_keyval(src_node))
1136  {
1137  _copy_props(dst_node, src, src_node, mask_src);
1138  }
1139  else
1140  {
1141  _RYML_ASSERT_VISIT_(m_callbacks, src->is_val(src_node), src, src_node);
1142  _copy_props_wo_key(dst_node, src, src_node, mask_src);
1143  }
1144  }
1145  else if(src->is_seq(src_node))
1146  {
1147  if( ! is_seq(dst_node))
1148  {
1149  if(has_children(dst_node))
1150  remove_children(dst_node);
1151  _clear_type(dst_node);
1152  if(src->has_key(src_node))
1153  to_seq(dst_node, src->key(src_node));
1154  else
1155  to_seq(dst_node);
1156  _p(dst_node)->m_type = src->_p(src_node)->m_type;
1157  }
1158  for(id_type sch = src->first_child(src_node); sch != NONE; sch = src->next_sibling(sch))
1159  {
1160  id_type dch = append_child(dst_node);
1161  _copy_props_wo_key(dch, src, sch);
1162  merge_with(src, sch, dch);
1163  }
1164  }
1165  else
1166  {
1167  _RYML_ASSERT_VISIT_(m_callbacks, src->is_map(src_node), src, src_node);
1168  if( ! is_map(dst_node))
1169  {
1170  if(has_children(dst_node))
1171  remove_children(dst_node);
1172  _clear_type(dst_node);
1173  if(src->has_key(src_node))
1174  to_map(dst_node, src->key(src_node));
1175  else
1176  to_map(dst_node);
1177  _p(dst_node)->m_type = src->_p(src_node)->m_type;
1178  }
1179  for(id_type sch = src->first_child(src_node); sch != NONE; sch = src->next_sibling(sch))
1180  {
1181  id_type dch = find_child(dst_node, src->key(sch));
1182  if(dch == NONE)
1183  {
1184  dch = append_child(dst_node);
1185  _copy_props(dch, src, sch);
1186  }
1187  merge_with(src, sch, dch);
1188  }
1189  }
1190 }
1191 
1192 
1193 //-----------------------------------------------------------------------------
1194 
1195 void Tree::resolve(bool clear_anchors)
1196 {
1197  if(m_size == 0)
1198  return;
1199  ReferenceResolver rr;
1200  resolve(&rr, clear_anchors);
1201 }
1202 
1203 void Tree::resolve(ReferenceResolver *C4_RESTRICT rr, bool clear_anchors)
1204 {
1205  if(m_size == 0)
1206  return;
1207  rr->resolve(this, clear_anchors);
1208 }
1209 
1210 
1211 //-----------------------------------------------------------------------------
1212 
1214 {
1215  id_type count = 0;
1216  for(id_type i = first_child(node); i != NONE; i = next_sibling(i))
1217  ++count;
1218  return count;
1219 }
1220 
1222 {
1223  _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
1224  id_type count = 0;
1225  for(id_type i = first_child(node); i != NONE; i = next_sibling(i))
1226  {
1227  if(count++ == pos)
1228  return i;
1229  }
1230  return NONE;
1231 }
1232 
1234 {
1235  _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
1236  id_type count = 0;
1237  for(id_type i = first_child(node); i != NONE; i = next_sibling(i))
1238  {
1239  if(i == ch)
1240  return count;
1241  ++count;
1242  }
1243  return NONE;
1244 }
1245 
1246 #if defined(__clang__)
1247 # pragma clang diagnostic push
1248 #elif defined(__GNUC__)
1249 # pragma GCC diagnostic push
1250 # if __GNUC__ >= 6
1251 # pragma GCC diagnostic ignored "-Wnull-dereference"
1252 # endif
1253 # if __GNUC__ > 9
1254 # pragma GCC diagnostic ignored "-Wanalyzer-null-dereference"
1255 # endif
1256 #endif
1257 
1258 id_type Tree::find_child(id_type node, csubstr const& name) const
1259 {
1260  _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
1261  _RYML_ASSERT_VISIT_(m_callbacks, is_map(node), this, node);
1262  if(get(node)->m_first_child == NONE)
1263  {
1264  _RYML_ASSERT_VISIT_(m_callbacks, _p(node)->m_last_child == NONE, this, node);
1265  return NONE;
1266  }
1267  else
1268  {
1269  _RYML_ASSERT_VISIT_(m_callbacks, _p(node)->m_last_child != NONE, this, node);
1270  }
1271  for(id_type i = first_child(node); i != NONE; i = next_sibling(i))
1272  {
1273  if(_p(i)->m_key.scalar == name)
1274  {
1275  return i;
1276  }
1277  }
1278  return NONE;
1279 }
1280 
1281 #if defined(__clang__)
1282 # pragma clang diagnostic pop
1283 #elif defined(__GNUC__)
1284 # pragma GCC diagnostic pop
1285 #endif
1286 
1287 namespace {
1288 id_type depth_desc_(Tree const& C4_RESTRICT t, id_type id, id_type currdepth=0, id_type maxdepth=0)
1289 {
1290  maxdepth = currdepth > maxdepth ? currdepth : maxdepth;
1291  for(id_type child = t.first_child(id); child != NONE; child = t.next_sibling(child))
1292  {
1293  const id_type d = depth_desc_(t, child, currdepth+1, maxdepth);
1294  maxdepth = d > maxdepth ? d : maxdepth;
1295  }
1296  return maxdepth;
1297 }
1298 }
1299 
1301 {
1302  _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
1303  return depth_desc_(*this, node);
1304 }
1305 
1307 {
1308  _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
1309  id_type depth = 0;
1310  while(!is_root(node))
1311  {
1312  ++depth;
1313  node = parent(node);
1314  }
1315  return depth;
1316 }
1317 
1318 bool Tree::is_ancestor(id_type node, id_type ancestor) const
1319 {
1320  _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
1321  id_type p = parent(node);
1322  while(p != NONE)
1323  {
1324  if(p == ancestor)
1325  return true;
1326  p = parent(p);
1327  }
1328  return false;
1329 }
1330 
1331 
1332 //-----------------------------------------------------------------------------
1333 
1334 void Tree::to_val(id_type node, csubstr val, type_bits more_flags)
1335 {
1336  _RYML_ASSERT_VISIT_(m_callbacks, ! has_children(node), this, node);
1337  _RYML_ASSERT_VISIT_(m_callbacks, parent(node) == NONE || ! parent_is_map(node), this, node);
1338  _set_flags(node, VAL|more_flags);
1339  _p(node)->m_key.clear();
1340  _p(node)->m_val = val;
1341 }
1342 
1343 void Tree::to_keyval(id_type node, csubstr key, csubstr val, type_bits more_flags)
1344 {
1345  _RYML_ASSERT_VISIT_(m_callbacks, ! has_children(node), this, node);
1346  _RYML_ASSERT_VISIT_(m_callbacks, parent(node) == NONE || parent_is_map(node), this, node);
1347  _set_flags(node, KEYVAL|more_flags);
1348  _p(node)->m_key = key;
1349  _p(node)->m_val = val;
1350 }
1351 
1352 void Tree::to_map(id_type node, type_bits more_flags)
1353 {
1354  _RYML_ASSERT_VISIT_(m_callbacks, ! has_children(node), this, node);
1355  _RYML_ASSERT_VISIT_(m_callbacks, parent(node) == NONE || ! parent_is_map(node), this, node); // parent must not have children with keys
1356  _set_flags(node, MAP|more_flags);
1357  _p(node)->m_key.clear();
1358  _p(node)->m_val.clear();
1359 }
1360 
1361 void Tree::to_map(id_type node, csubstr key, type_bits more_flags)
1362 {
1363  _RYML_ASSERT_VISIT_(m_callbacks, ! has_children(node), this, node);
1364  _RYML_ASSERT_VISIT_(m_callbacks, parent(node) == NONE || parent_is_map(node), this, node);
1365  _set_flags(node, KEY|MAP|more_flags);
1366  _p(node)->m_key = key;
1367  _p(node)->m_val.clear();
1368 }
1369 
1370 void Tree::to_seq(id_type node, type_bits more_flags)
1371 {
1372  _RYML_ASSERT_VISIT_(m_callbacks, ! has_children(node), this, node);
1373  _RYML_ASSERT_VISIT_(m_callbacks, parent(node) == NONE || parent_is_seq(node), this, node);
1374  _set_flags(node, SEQ|more_flags);
1375  _p(node)->m_key.clear();
1376  _p(node)->m_val.clear();
1377 }
1378 
1379 void Tree::to_seq(id_type node, csubstr key, type_bits more_flags)
1380 {
1381  _RYML_ASSERT_VISIT_(m_callbacks, ! has_children(node), this, node);
1382  _RYML_ASSERT_VISIT_(m_callbacks, parent(node) == NONE || parent_is_map(node), this, node);
1383  _set_flags(node, KEY|SEQ|more_flags);
1384  _p(node)->m_key = key;
1385  _p(node)->m_val.clear();
1386 }
1387 
1388 void Tree::to_doc(id_type node, type_bits more_flags)
1389 {
1390  _RYML_ASSERT_VISIT_(m_callbacks, ! has_children(node), this, node);
1391  _set_flags(node, DOC|more_flags);
1392  _p(node)->m_key.clear();
1393  _p(node)->m_val.clear();
1394 }
1395 
1396 void Tree::to_stream(id_type node, type_bits more_flags)
1397 {
1398  _RYML_ASSERT_VISIT_(m_callbacks, ! has_children(node), this, node);
1399  _set_flags(node, STREAM|more_flags);
1400  _p(node)->m_key.clear();
1401  _p(node)->m_val.clear();
1402 }
1403 
1404 
1405 //-----------------------------------------------------------------------------
1406 
1407 void Tree::clear_style(id_type node, bool recurse)
1408 {
1409  NodeData *C4_RESTRICT d = _p(node);
1410  d->m_type.clear_style();
1411  if(!recurse)
1412  return;
1413  for(id_type child = d->m_first_child; child != NONE; child = next_sibling(child))
1414  clear_style(child, recurse);
1415 }
1416 
1418  NodeType type_mask,
1419  NodeType rem_style_flags,
1420  NodeType add_style_flags,
1421  bool recurse)
1422 {
1423  NodeData *C4_RESTRICT d = _p(node);
1424  if((d->m_type & type_mask) == type_mask)
1425  {
1426  d->m_type &= ~(NodeType)rem_style_flags;
1427  d->m_type |= (NodeType)add_style_flags;
1428  }
1429  if(!recurse)
1430  return;
1431  for(id_type child = d->m_first_child; child != NONE; child = next_sibling(child))
1432  set_style_conditionally(child, type_mask, rem_style_flags, add_style_flags, recurse);
1433 }
1434 
1435 
1436 //-----------------------------------------------------------------------------
1438 {
1439  return m_tag_directives.size();
1440 }
1441 
1443 {
1445 }
1446 
1447 void Tree::add_tag_directive(csubstr handle, csubstr prefix, id_type id)
1448 {
1449  _RYML_CHECK_BASIC_(m_callbacks,
1450  !handle.empty()
1451  &&
1452  !prefix.empty()
1453  &&
1454  is_valid_tag_handle(handle)
1455  &&
1456  m_tag_directives.add(handle, prefix, id));
1457 }
1458 
1459 size_t Tree::resolve_tag(substr output, csubstr tag, id_type node_id) const
1460 {
1461  size_t reqsz = 0;
1462  m_tag_directives.resolve(output, &reqsz, tag, node_id, Location{}, callbacks());
1463  return reqsz;
1464 }
1465 
1466 namespace {
1467 // return the extra size needed for the arena to accomodate the resolved tag
1468 size_t _transform_tag(Tree *t, id_type node_id, id_type doc_id, TagCache &cache, csubstr tag, csubstr *resolved)
1469 {
1470  _c4dbgpf("tag: doc={} node={} resolving tag ~~~{}~~~", doc_id, node_id, tag);
1471  (void)node_id;
1472  size_t reqsize = 0;
1473  if(tag.begins_with('<'))
1474  {
1475  *resolved = tag;
1476  }
1477  else
1478  {
1479  _RYML_ASSERT_VISIT_(t->callbacks(), !tag.begins_with("!<"), t, node_id); // this should have been handled elsewhere
1480  TagCache::LookupResult ret = cache.find(tag, doc_id);
1481  if(ret)
1482  {
1483  _c4dbgpf("tag: doc={} node={} resolving tag: found in cache[{}]: {}", doc_id, node_id, ret.pos, _prs(ret.resolved));
1484  *resolved = ret.resolved;
1485  }
1486  else
1487  {
1488  _c4dbgpf("tag: doc={} node={} tag not in cache ~~~{}~~~", doc_id, node_id, tag);
1489  substr buf = t->m_arena.sub(t->m_arena_pos);
1490  reqsize = t->resolve_tag(buf, tag, doc_id);
1491  if(!reqsize)
1492  {
1493  *resolved = tag;
1494  }
1495  else if(reqsize <= buf.len)
1496  {
1497  t->m_arena_pos += reqsize;
1498  *resolved = buf.first(reqsize);
1499  cache.add(tag, *resolved, doc_id, ret.pos);
1500  reqsize = 0;
1501  }
1502  else
1503  {
1504  _c4dbgpf("tag: doc={} node={} extra size needed: {}", doc_id, node_id, reqsize);
1505  }
1506  _c4dbgpf("tag: doc={} node={} resolved tag: ~~~{}~~~", doc_id, node_id, *resolved);
1507  }
1508  }
1509  return reqsize;
1510 }
1511 size_t _resolve_tags(Tree *t, id_type node, id_type doc_id, TagCache &cache, bool all=true)
1512 {
1513  NodeData *C4_RESTRICT d = t->_p(node);
1514  size_t extra_size = 0;
1515  if((d->m_type & KEYTAG) && (all || is_custom_tag(d->m_key.tag)))
1516  extra_size += _transform_tag(t, node, doc_id, cache, d->m_key.tag, &d->m_key.tag);
1517  if((d->m_type & VALTAG) && (all || is_custom_tag(d->m_val.tag)))
1518  extra_size += _transform_tag(t, node, doc_id, cache, d->m_val.tag, &d->m_val.tag);
1519  for(id_type child = t->first_child(node); child != NONE; child = t->next_sibling(child))
1520  extra_size += _resolve_tags(t, child, doc_id, cache);
1521  return extra_size;
1522 }
1523 size_t _resolve_tags(Tree *t, TagCache &cache, bool all)
1524 {
1525  id_type r = t->root_id();
1526  size_t extra_size = 0;
1527  if(!t->is_stream(r))
1528  extra_size += _resolve_tags(t, r, r, cache, all);
1529  else
1530  for(id_type doc_id = t->first_child(r); doc_id != NONE; doc_id = t->next_sibling(doc_id))
1531  extra_size += _resolve_tags(t, doc_id, doc_id, cache, all);
1532  return extra_size;
1533 }
1534 void _normalize_tags(Tree *t, id_type node)
1535 {
1536  NodeData *C4_RESTRICT d = t->_p(node);
1537  if(d->m_type & KEYTAG)
1538  d->m_key.tag = normalize_tag(d->m_key.tag);
1539  if(d->m_type & VALTAG)
1540  d->m_val.tag = normalize_tag(d->m_val.tag);
1541  for(id_type child = t->first_child(node); child != NONE; child = t->next_sibling(child))
1542  _normalize_tags(t, child);
1543 }
1544 void _normalize_tags_long(Tree *t, id_type node)
1545 {
1546  NodeData *C4_RESTRICT d = t->_p(node);
1547  if(d->m_type & KEYTAG)
1548  d->m_key.tag = normalize_tag_long(d->m_key.tag);
1549  if(d->m_type & VALTAG)
1550  d->m_val.tag = normalize_tag_long(d->m_val.tag);
1551  for(id_type child = t->first_child(node); child != NONE; child = t->next_sibling(child))
1552  _normalize_tags_long(t, child);
1553 }
1554 } // namespace
1555 
1556 void Tree::resolve_tags(TagCache &cache, bool all)
1557 {
1558  if(empty())
1559  return;
1560  // try to resolve. While doing so, get the extra size needed for
1561  // the arena, if the arena is currently too small.
1562  size_t extra_size = _resolve_tags(this, cache, all);
1563  // if the arena requires extra size, grow it and then resolve the
1564  // missing entries
1565  if(extra_size)
1566  {
1567  _c4dbgpf("tag: extrasize={} -- retry! {}->{}", extra_size, m_arena.len, m_arena.len + extra_size);
1568  _grow_arena(extra_size);
1569  extra_size = _resolve_tags(this, cache, all);
1570  _RYML_ASSERT_BASIC_(callbacks(), extra_size == 0);
1571  }
1572 }
1573 
1575 {
1576  if(empty())
1577  return;
1578  _normalize_tags(this, root_id());
1579 }
1580 
1582 {
1583  if(empty())
1584  return;
1585  _normalize_tags_long(this, root_id());
1586 }
1587 
1588 
1589 //-----------------------------------------------------------------------------
1590 
1592 {
1593  csubstr p = path.first(path_pos);
1594  if(p.ends_with('.'))
1595  p = p.first(p.len-1);
1596  return p;
1597 }
1598 
1600 {
1601  return path.sub(path_pos);
1602 }
1603 
1604 void Tree::_advance(lookup_result *r, size_t more)
1605 {
1606  r->path_pos += more;
1607  if(r->path.sub(r->path_pos).begins_with('.'))
1608  ++r->path_pos;
1609 }
1610 
1612 {
1613  if(start == NONE)
1614  start = root_id();
1615  lookup_result r(path, start);
1616  if(path.empty())
1617  return r;
1618  _lookup_path(&r);
1619  if(r.target == NONE && r.closest == start)
1620  r.closest = NONE;
1621  return r;
1622 }
1623 
1624 id_type Tree::lookup_path_or_modify(csubstr default_value, csubstr path, id_type start)
1625 {
1626  id_type target = _lookup_path_or_create(path, start);
1627  if(parent_is_map(target))
1628  to_keyval(target, key(target), default_value);
1629  else
1630  to_val(target, default_value);
1631  return target;
1632 }
1633 
1634 id_type Tree::lookup_path_or_modify(Tree const *src, id_type src_node, csubstr path, id_type start)
1635 {
1636  id_type target = _lookup_path_or_create(path, start);
1637  merge_with(src, src_node, target);
1638  return target;
1639 }
1640 
1641 id_type Tree::_lookup_path_or_create(csubstr path, id_type start)
1642 {
1643  if(start == NONE)
1644  start = root_id();
1645  lookup_result r(path, start);
1646  _lookup_path(&r);
1647  if(r.target != NONE)
1648  {
1649  C4_ASSERT(r.unresolved().empty());
1650  return r.target;
1651  }
1652  _lookup_path_modify(&r);
1653  return r.target;
1654 }
1655 
1656 void Tree::_lookup_path(lookup_result *r) const
1657 {
1658  C4_ASSERT( ! r->unresolved().empty());
1659  _lookup_path_token parent{"", type(r->closest)};
1660  id_type node;
1661  do
1662  {
1663  node = _next_node(r, &parent);
1664  if(node != NONE)
1665  r->closest = node;
1666  if(r->unresolved().empty())
1667  {
1668  r->target = node;
1669  return;
1670  }
1671  } while(node != NONE);
1672 }
1673 
1674 void Tree::_lookup_path_modify(lookup_result *r)
1675 {
1676  C4_ASSERT( ! r->unresolved().empty());
1677  _lookup_path_token parent{"", type(r->closest)};
1678  id_type node;
1679  do
1680  {
1681  node = _next_node_modify(r, &parent);
1682  if(node != NONE)
1683  r->closest = node;
1684  if(r->unresolved().empty())
1685  {
1686  r->target = node;
1687  return;
1688  }
1689  } while(node != NONE);
1690 }
1691 
1692 id_type Tree::_next_node(lookup_result * r, _lookup_path_token *parent) const
1693 {
1694  _lookup_path_token token = _next_token(r, *parent);
1695  if( ! token)
1696  return NONE;
1697 
1698  id_type node = NONE;
1699  csubstr prev = token.value;
1700  if(token.type == MAP || token.type == SEQ)
1701  {
1702  _RYML_ASSERT_VISIT_(m_callbacks, !token.value.begins_with('['), this, r->closest);
1703  //_RYML_ASSERT_VISIT_(m_callbacks, is_container(r->closest) || r->closest == NONE);
1704  _RYML_ASSERT_VISIT_(m_callbacks, is_map(r->closest), this, r->closest);
1705  node = find_child(r->closest, token.value);
1706  }
1707  else if(token.type == KEYVAL)
1708  {
1709  _RYML_ASSERT_VISIT_(m_callbacks, r->unresolved().empty(), this, r->closest);
1710  if(is_map(r->closest))
1711  node = find_child(r->closest, token.value);
1712  }
1713  else if(token.type == KEY)
1714  {
1715  _RYML_ASSERT_VISIT_(m_callbacks, token.value.begins_with('[') && token.value.ends_with(']'), this, r->closest);
1716  token.value = token.value.offs(1, 1).trim(' ');
1717  id_type idx = 0;
1718  _RYML_CHECK_BASIC_(m_callbacks, from_chars(token.value, &idx));
1719  node = child(r->closest, idx);
1720  }
1721  else
1722  {
1723  C4_NEVER_REACH();
1724  }
1725 
1726  if(node != NONE)
1727  {
1728  *parent = token;
1729  }
1730  else
1731  {
1732  csubstr p = r->path.sub(r->path_pos > 0 ? r->path_pos - 1 : r->path_pos);
1733  r->path_pos -= prev.len;
1734  if(p.begins_with('.'))
1735  r->path_pos -= 1u;
1736  }
1737 
1738  return node;
1739 }
1740 
1741 id_type Tree::_next_node_modify(lookup_result * r, _lookup_path_token *parent)
1742 {
1743  _lookup_path_token token = _next_token(r, *parent);
1744  if( ! token)
1745  return NONE;
1746 
1747  id_type node = NONE;
1748  if(token.type == MAP || token.type == SEQ)
1749  {
1750  _RYML_ASSERT_VISIT_(m_callbacks, !token.value.begins_with('['), this, r->closest);
1751  //_RYML_ASSERT_VISIT_(m_callbacks, is_container(r->closest) || r->closest == NONE);
1752  if( ! is_container(r->closest))
1753  {
1754  if(has_key(r->closest))
1755  to_map(r->closest, key(r->closest));
1756  else
1757  to_map(r->closest);
1758  }
1759  else
1760  {
1761  if(is_map(r->closest))
1762  {
1763  node = find_child(r->closest, token.value);
1764  }
1765  else
1766  {
1767  id_type pos = NONE;
1768  _RYML_CHECK_BASIC_(m_callbacks, c4::atox(token.value, &pos));
1769  _RYML_ASSERT_VISIT_(m_callbacks, pos != NONE, this, r->closest);
1770  node = child(r->closest, pos);
1771  }
1772  }
1773  if(node == NONE)
1774  {
1775  _RYML_ASSERT_VISIT_(m_callbacks, is_map(r->closest), this, r->closest);
1776  node = append_child(r->closest);
1777  NodeData *n = _p(node);
1778  n->m_key.scalar = token.value;
1779  n->m_type.add(KEY);
1780  }
1781  }
1782  else if(token.type == KEYVAL)
1783  {
1784  _RYML_ASSERT_VISIT_(m_callbacks, r->unresolved().empty(), this, r->closest);
1785  if(is_map(r->closest))
1786  {
1787  node = find_child(r->closest, token.value);
1788  if(node == NONE)
1789  node = append_child(r->closest);
1790  }
1791  else
1792  {
1793  _RYML_ASSERT_VISIT_(m_callbacks, !is_seq(r->closest), this, r->closest);
1794  _add_flags(r->closest, MAP);
1795  node = append_child(r->closest);
1796  }
1797  NodeData *n = _p(node);
1798  n->m_key.scalar = token.value;
1799  n->m_val.scalar = "";
1800  n->m_type.add(KEYVAL);
1801  }
1802  else if(token.type == KEY)
1803  {
1804  _RYML_ASSERT_VISIT_(m_callbacks, token.value.begins_with('[') && token.value.ends_with(']'), this, r->closest);
1805  token.value = token.value.offs(1, 1).trim(' ');
1806  id_type idx;
1807  if( ! from_chars(token.value, &idx))
1808  return NONE;
1809  if( ! is_container(r->closest))
1810  {
1811  if(has_key(r->closest))
1812  {
1813  csubstr k = key(r->closest);
1814  _clear_type(r->closest);
1815  to_seq(r->closest, k);
1816  }
1817  else
1818  {
1819  _clear_type(r->closest);
1820  to_seq(r->closest);
1821  }
1822  }
1823  _RYML_ASSERT_VISIT_(m_callbacks, is_container(r->closest), this, r->closest);
1824  node = child(r->closest, idx);
1825  if(node == NONE)
1826  {
1827  _RYML_ASSERT_VISIT_(m_callbacks, num_children(r->closest) <= idx, this, r->closest);
1828  for(id_type i = num_children(r->closest); i <= idx; ++i)
1829  {
1830  node = append_child(r->closest);
1831  if(i < idx)
1832  {
1833  if(is_map(r->closest))
1834  to_keyval(node, /*"~"*/{}, /*"~"*/{});
1835  else if(is_seq(r->closest))
1836  to_val(node, /*"~"*/{});
1837  }
1838  }
1839  }
1840  }
1841  else
1842  {
1843  C4_NEVER_REACH();
1844  }
1845 
1846  _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, r->closest);
1847  *parent = token;
1848  return node;
1849 }
1850 
1851 /* types of tokens:
1852  * - seeing "map." ---> "map"/MAP
1853  * - finishing "scalar" ---> "scalar"/KEYVAL
1854  * - seeing "seq[n]" ---> "seq"/SEQ (--> "[n]"/KEY)
1855  * - seeing "[n]" ---> "[n]"/KEY
1856  */
1857 Tree::_lookup_path_token Tree::_next_token(lookup_result *r, _lookup_path_token const& parent) const
1858 {
1859  csubstr unres = r->unresolved();
1860  if(unres.empty())
1861  return {};
1862 
1863  // is it an indexation like [0], [1], etc?
1864  if(unres.begins_with('['))
1865  {
1866  size_t pos = unres.find(']');
1867  if(pos == csubstr::npos)
1868  return {};
1869  csubstr idx = unres.first(pos + 1);
1870  _advance(r, pos + 1);
1871  return {idx, KEY};
1872  }
1873 
1874  // no. so it must be a name
1875  size_t pos = unres.first_of(".[");
1876  if(pos == csubstr::npos)
1877  {
1878  _advance(r, unres.len);
1879  NodeType t;
1880  if(( ! parent) || parent.type.is_seq())
1881  return {unres, VAL};
1882  return {unres, KEYVAL};
1883  }
1884 
1885  // it's either a map or a seq
1886  _RYML_ASSERT_VISIT_(m_callbacks, unres[pos] == '.' || unres[pos] == '[', this, r->closest);
1887  if(unres[pos] == '.')
1888  {
1889  _RYML_ASSERT_VISIT_(m_callbacks, pos != 0, this, r->closest);
1890  _advance(r, pos + 1);
1891  return {unres.first(pos), MAP};
1892  }
1893 
1894  _RYML_ASSERT_VISIT_(m_callbacks, unres[pos] == '[', this, r->closest);
1895  _advance(r, pos);
1896  return {unres.first(pos), SEQ};
1897 }
1898 
1899 
1900 } // namespace yml
1901 } // namespace c4
1902 
1903 
1904 //-----------------------------------------------------------------------------
1905 //-----------------------------------------------------------------------------
1906 //-----------------------------------------------------------------------------
1907 
1909 #include "c4/yml/parse_engine.def.hpp"
1910 #include "c4/yml/parse.hpp"
1911 
1912 namespace c4 {
1913 namespace yml {
1914 
1915 Location Tree::location(Parser const& parser, id_type node) const
1916 {
1917  // try hard to avoid getting the location from a null string.
1918  Location loc;
1919  if(_location_from_node(parser, node, &loc, 0))
1920  return loc;
1921  return parser.val_location(parser.source().str);
1922 }
1923 
1924 bool Tree::_location_from_node(Parser const& parser, id_type node, Location *C4_RESTRICT loc, id_type level) const
1925 {
1926  if(has_key(node))
1927  {
1928  csubstr k = key(node);
1929  if(C4_LIKELY(k.str != nullptr))
1930  {
1931  _RYML_ASSERT_BASIC_(m_callbacks, k.is_sub(parser.source()));
1932  _RYML_ASSERT_BASIC_(m_callbacks, parser.source().is_super(k));
1933  *loc = parser.val_location(k.str);
1934  return true;
1935  }
1936  }
1937 
1938  if(has_val(node))
1939  {
1940  csubstr v = val(node);
1941  if(C4_LIKELY(v.str != nullptr))
1942  {
1943  _RYML_ASSERT_BASIC_(m_callbacks, v.is_sub(parser.source()));
1944  _RYML_ASSERT_BASIC_(m_callbacks, parser.source().is_super(v));
1945  *loc = parser.val_location(v.str);
1946  return true;
1947  }
1948  }
1949 
1950  if(is_container(node))
1951  {
1952  if(_location_from_cont(parser, node, loc))
1953  return true;
1954  }
1955 
1956  if(type(node) != NOTYPE && level == 0)
1957  {
1958  // try the prev sibling
1959  {
1960  const id_type prev = prev_sibling(node);
1961  if(prev != NONE)
1962  {
1963  if(_location_from_node(parser, prev, loc, level+1))
1964  return true;
1965  }
1966  }
1967  // try the next sibling
1968  {
1969  const id_type next = next_sibling(node);
1970  if(next != NONE)
1971  {
1972  if(_location_from_node(parser, next, loc, level+1))
1973  return true;
1974  }
1975  }
1976  // try the parent
1977  {
1978  const id_type parent = this->parent(node);
1979  if(parent != NONE)
1980  {
1981  if(_location_from_node(parser, parent, loc, level+1))
1982  return true;
1983  }
1984  }
1985  }
1986  return false;
1987 }
1988 
1989 bool Tree::_location_from_cont(Parser const& parser, id_type node, Location *C4_RESTRICT loc) const
1990 {
1991  _RYML_ASSERT_BASIC_(m_callbacks, is_container(node));
1992  if(!is_stream(node))
1993  {
1994  const char *node_start = _p(node)->m_val.scalar.str; // this was stored in the container
1995  if(has_children(node))
1996  {
1997  id_type child = first_child(node);
1998  if(has_key(child))
1999  {
2000  // when a map starts, the container was set after the key
2001  csubstr k = key(child);
2002  if(k.str && node_start > k.str)
2003  node_start = k.str;
2004  }
2005  }
2006  *loc = parser.val_location(node_start);
2007  return true;
2008  }
2009  else // it's a stream
2010  {
2011  *loc = parser.val_location(parser.source().str); // just return the front of the buffer
2012  }
2013  return true;
2014 }
2015 
2016 } // namespace yml
2017 } // namespace c4
2018 
2019 
2020 // NOLINTEND(modernize-avoid-c-style-cast)
2021 C4_SUPPRESS_WARNING_GCC_CLANG_POP
2022 C4_SUPPRESS_WARNING_MSVC_POP
Holds a pointer to an existing tree, and a node id.
Definition: node.hpp:855
A reference to a node in an existing yaml tree, offering a more convenient API than the index-based A...
Definition: node.hpp:995
This is the main driver of parsing logic: it scans the YAML or JSON source for tokens,...
Location val_location(const char *val) const
Given a pointer to a buffer position, get the location.
csubstr source() const
Get the latest YAML buffer parsed by this object.
NodeData * m_buf
Definition: tree.hpp:1326
void move(id_type node, id_type after)
change the node's position in the parent
Definition: tree.cpp:819
id_type duplicate(id_type node, id_type new_parent, id_type after)
recursively duplicate a node from this tree into a new parent, placing it after one of its children
Definition: tree.cpp:959
void clear()
clear the tree and zero every node
Definition: tree.cpp:330
id_type m_free_head
Definition: tree.hpp:1330
lookup_result lookup_path(csubstr path, id_type start=NONE) const
for example foo.bar[0].baz
Definition: tree.cpp:1611
id_type lookup_path_or_modify(csubstr default_value, csubstr path, id_type start=NONE)
defaulted lookup: lookup path; if the lookup fails, recursively modify the tree so that the correspon...
Definition: tree.cpp:1624
id_type first_child(id_type node) const
Definition: tree.hpp:510
bool is_stream(id_type node) const
Definition: tree.hpp:408
NodeType type(id_type node) const
Definition: tree.hpp:382
void set_root_as_stream()
ensure the first node is a stream.
Definition: tree.cpp:857
id_type root_id() const
Get the id of the root node. The tree must not be empty.
Definition: tree.hpp:335
void resolve_tags(TagCache &cache, bool all=true)
Resolve tags in the tree such as !!str -> <tag:yaml.org,2002:str>, !foo -> <!foo> and custom tags as ...
Definition: tree.cpp:1556
id_type prev_sibling(id_type node) const
Definition: tree.hpp:504
NodeData * get(id_type node)
get a pointer to a node's NodeData. i can be NONE, in which case a nullptr is returned
Definition: tree.hpp:310
void reserve_arena(size_t arena_cap=RYML_DEFAULT_TREE_ARENA_CAPACITY)
ensure the tree's internal string arena is at least the given capacity
Definition: tree.hpp:968
size_t m_arena_pos
Definition: tree.hpp:1334
bool is_map(id_type node) const
Definition: tree.hpp:411
void clear_tag_directives()
Definition: tree.cpp:1442
void reserve(id_type node_capacity=RYML_DEFAULT_TREE_CAPACITY)
Definition: tree.cpp:292
Tree & operator=(Tree const &that)
Definition: tree.cpp:159
void to_keyval(id_type node, csubstr key, csubstr val, type_bits more_flags=0)
Definition: tree.cpp:1343
TagDirectives m_tag_directives
Definition: tree.hpp:1338
bool is_root(id_type node) const
Definition: tree.hpp:460
bool is_keyval(id_type node) const
Definition: tree.hpp:416
id_type m_size
Definition: tree.hpp:1328
void to_doc(id_type node, type_bits more_flags=0)
Definition: tree.cpp:1388
bool has_key(id_type node) const
Definition: tree.hpp:413
id_type depth_asc(id_type node) const
O(log(num_tree_nodes)) get the ascending depth of the node: number of levels between root and node.
Definition: tree.cpp:1306
bool in_arena(csubstr s) const
return true if the given substring is part of the tree's string arena
Definition: tree.hpp:884
id_type parent(id_type node) const
Definition: tree.hpp:502
Callbacks const & callbacks() const
Definition: tree.hpp:288
size_t resolve_tag(substr output, csubstr tag, id_type node_id) const
resolve the given tag, appearing at node_id.
Definition: tree.cpp:1459
bool is_val(id_type node) const
Definition: tree.hpp:415
bool empty() const
Definition: tree.hpp:282
id_type child_pos(id_type node, id_type ch) const
Definition: tree.cpp:1233
id_type append_child(id_type parent)
create and insert a node as the last child of parent
Definition: tree.hpp:716
void clear_style(id_type node, bool recurse=false)
Definition: tree.cpp:1407
void to_stream(id_type node, type_bits more_flags=0)
Definition: tree.cpp:1396
bool has_sibling(id_type node, id_type sib) const
true if node has a sibling with id sib
Definition: tree.hpp:478
id_type next_sibling(id_type node) const
Definition: tree.hpp:505
void to_seq(id_type node, csubstr key, type_bits more_flags=0)
Definition: tree.cpp:1379
id_type depth_desc(id_type node) const
O(num_tree_nodes) get the descending depth of the node: number of levels between node and deepest chi...
Definition: tree.cpp:1300
id_type num_tag_directives() const
Definition: tree.cpp:1437
bool parent_is_seq(id_type node) const
Definition: tree.hpp:426
csubstr const & key(id_type node) const
Definition: tree.hpp:385
id_type duplicate_children_no_rep(id_type node, id_type parent, id_type after)
duplicate the node's children (but not the node) in a new parent, but omit repetitions where a duplic...
Definition: tree.cpp:1018
id_type m_cap
Definition: tree.hpp:1327
id_type last_child(id_type node) const
Definition: tree.hpp:511
id_type id(NodeData const *n) const
get the index of a node belonging to this tree. n can be nullptr, in which case NONE is returned
Definition: tree.hpp:300
void set_style_conditionally(id_type node, NodeType type_mask, NodeType rem_style_flags, NodeType add_style_flags, bool recurse=false)
Definition: tree.cpp:1417
substr m_arena
Definition: tree.hpp:1333
void normalize_tags()
Definition: tree.cpp:1574
void reorder()
reorder the tree in memory so that all the nodes are stored in a linear sequence when visited in dept...
Definition: tree.cpp:576
void remove_children(id_type node)
remove all the node's children, but keep the node itself
Definition: tree.cpp:918
bool is_ancestor(id_type node, id_type ancestor) const
true when ancestor is parent or parent of a parent of node
Definition: tree.cpp:1318
bool has_val(id_type node) const
Definition: tree.hpp:414
void to_map(id_type node, csubstr key, type_bits more_flags=0)
Definition: tree.cpp:1361
size_t arena_capacity() const
get the current capacity of the tree's internal arena
Definition: tree.hpp:873
bool change_type(id_type node, NodeType type)
change the type of the node to one of MAP, SEQ or VAL.
Definition: tree.cpp:940
id_type m_free_tail
Definition: tree.hpp:1331
void normalize_tags_long()
Definition: tree.cpp:1581
csubstr const & val(id_type node) const
Definition: tree.hpp:391
void resolve(ReferenceResolver *rr, bool clear_anchors=true)
Resolve references (aliases <- anchors), by forwarding to ReferenceResolver::resolve(); refer to Refe...
Definition: tree.cpp:1203
bool is_seq(id_type node) const
Definition: tree.hpp:412
bool parent_is_map(id_type node) const
Definition: tree.hpp:427
void remove(id_type node)
remove an entire branch at once: ie remove the children and the node itself
Definition: tree.hpp:748
id_type find_child(id_type node, csubstr const &key) const
Definition: tree.cpp:1258
Location location(Parser const &p, id_type node) const
Get the location of a node from the parse used to parse this tree.
Definition: tree.cpp:1915
void duplicate_contents(id_type node, id_type where)
Definition: tree.cpp:1003
void add_tag_directive(csubstr handle, csubstr prefix, id_type id)
Definition: tree.cpp:1447
id_type duplicate_children(id_type node, id_type parent, id_type after)
recursively duplicate the node's children (but not the node)
Definition: tree.cpp:981
id_type num_children(id_type node) const
O(num_children)
Definition: tree.cpp:1213
csubstr arena() const
get the current arena
Definition: tree.hpp:879
void merge_with(Tree const *src, id_type src_node=NONE, id_type dst_root=NONE)
Definition: tree.cpp:1118
id_type _claim()
Definition: tree.cpp:414
bool is_container(id_type node) const
Definition: tree.hpp:410
id_type child(id_type node, id_type pos) const
Definition: tree.cpp:1221
bool has_child(id_type node, id_type ch) const
true if node has a child with id ch
Definition: tree.hpp:471
Callbacks m_callbacks
Definition: tree.hpp:1336
NodeData * _p(id_type node)
An if-less form of get() that demands a valid node index. This function is implementation only; use a...
Definition: tree.hpp:329
void to_val(id_type node, csubstr val, type_bits more_flags=0)
Definition: tree.cpp:1334
bool has_children(id_type node) const
true if node has any children key
Definition: tree.hpp:475
#define RYML_DEFAULT_TREE_CAPACITY
default capacity for the tree when not set explicitly
Definition: common.hpp:16
#define RYML_DEFAULT_TREE_ARENA_CAPACITY
default capacity for the tree's arena when not set explicitly
Definition: common.hpp:21
bool atox(csubstr s, uint8_t *v) noexcept
Definition: charconv.hpp:2291
bool from_chars(csubstr buf, uint8_t *v) noexcept
Definition: charconv.hpp:2366
uint32_t type_bits
the integral type necessary to cover all the bits for NodeType_e
Definition: node_type.hpp:30
@ NOTYPE
no node type or style is set
Definition: node_type.hpp:36
@ MAP
a map: a parent of KEYVAL/KEYSEQ/KEYMAP nodes
Definition: node_type.hpp:39
@ STREAM
a stream: a seq of docs
Definition: node_type.hpp:42
@ KEY
is member of a map
Definition: node_type.hpp:37
@ VAL_STYLE
mask of all the scalar styles for val (not container styles!)
Definition: node_type.hpp:93
@ KEYTAG
the key has a tag
Definition: node_type.hpp:47
@ VAL
a scalar: has a scalar (ie string) value, possibly empty. must be a leaf node, and cannot be MAP or S...
Definition: node_type.hpp:38
@ VALTAG
the val has a tag
Definition: node_type.hpp:48
@ SEQ
a seq: a parent of VAL/SEQ/MAP nodes
Definition: node_type.hpp:40
@ KEY_STYLE
mask of all the scalar styles for key (not container styles!)
Definition: node_type.hpp:92
@ CONTAINER_STYLE
Definition: node_type.hpp:97
@ DOC
a document
Definition: node_type.hpp:41
ParseEngine< EventHandlerTree > Parser
This is the main ryml parser, where the parser events are handled to create a ryml tree.
Definition: fwd.hpp:19
Key< K > key(K &k)
Definition: node.hpp:45
bool is_valid_tag_handle(csubstr handle)
Definition: tag.cpp:210
bool is_custom_tag(csubstr tag)
is a tag of the form !handle!tag?
Definition: tag.cpp:9
csubstr normalize_tag_long(csubstr tag)
Definition: tag.cpp:31
csubstr normalize_tag(csubstr tag)
Definition: tag.cpp:19
RYML_ID_TYPE id_type
The type of a node id in the YAML tree; to override the default type, define the macro RYML_ID_TYPE t...
Definition: common.hpp:244
@ npos
a null string position
Definition: common.hpp:258
csubstr serialize_to_arena(Tree *tree, csubstr a)
Definition: tree.cpp:19
size_t to_chars(substr buf, escaped_scalar e)
formatting implementation to escape a scalar with escape_scalar()
@ NONE
an index to none
Definition: common.hpp:251
(Undefined by default) Use shorter error message from checks/asserts: do not show the check condition...
Definition: common.cpp:14
Node classes.
A c-style callbacks class to customize behavior on errors or allocation.
Definition: common.hpp:538
holds a source or yaml file position, for example when an error is detected; See also location_format...
Definition: common.hpp:283
contains the data for each YAML node.
Definition: tree.hpp:228
NodeType m_type
Definition: tree.hpp:229
id_type m_next_sibling
Definition: tree.hpp:237
id_type m_parent
Definition: tree.hpp:234
NodeScalar m_key
Definition: tree.hpp:231
id_type m_prev_sibling
Definition: tree.hpp:238
id_type m_first_child
Definition: tree.hpp:235
NodeScalar m_val
Definition: tree.hpp:232
csubstr scalar
Definition: tree.hpp:113
void clear() noexcept
Definition: tree.hpp:143
wraps a NodeType_e element with some syntactic sugar and predicates
Definition: node_type.hpp:121
bool has_key() const noexcept
Definition: node_type.hpp:174
bool is_seq() const noexcept
Definition: node_type.hpp:173
void rem(NodeType_e t) noexcept
Definition: node_type.hpp:138
bool is_map() const noexcept
Definition: node_type.hpp:172
void add(NodeType_e t) noexcept
Definition: node_type.hpp:137
bool is_val() const noexcept
Definition: node_type.hpp:176
Reusable object to resolve references/aliases in a Tree.
Accelerator structure to reduce memory requirements by enabling reuse of resolved tags.
Definition: tag.hpp:69
LookupResult find(csubstr tag, id_type doc_id, id_type linear_threshold=Entries::sso_size) const noexcept
Definition: tag.cpp:537
void add(csubstr tag, csubstr resolved, id_type doc_id, const_iterator pos) RYML_NOEXCEPT
Definition: tag.cpp:594
id_type doc_id
ID of the target document.
Definition: tag.hpp:111
void clear() noexcept
Definition: tag.cpp:373
TagDirective m_directives[RYML_MAX_TAG_DIRECTIVES]
Definition: tag.hpp:125
id_type size() const noexcept
Definition: tag.cpp:348
csubstr resolve(substr buf, size_t *bufsz, csubstr tag, id_type doc_id, Location const &ymlloc, Callbacks const &callbacks, bool with_brackets=true) const
Definition: tag.cpp:449
TagDirective const * add(csubstr handle, csubstr prefix, id_type doc_id) noexcept
Definition: tag.cpp:358
csubstr unresolved() const
get the part ot the input path that was unresolved
Definition: tree.cpp:1599
csubstr resolved() const
get the part ot the input path that was resolved
Definition: tree.cpp:1591