rapidyaml  0.13.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  C4_SUPPRESS_WARNING_GCC_PUSH
922  #if defined(__GNUC__) && __GNUC__ >= 6
923  C4_SUPPRESS_WARNING_GCC("-Wnull-dereference")
924  #endif
925  id_type ich = get(node)->m_first_child;
926  while(ich != NONE)
927  {
928  remove_children(ich);
929  _RYML_ASSERT_VISIT_(m_callbacks, get(ich) != nullptr, this, node);
930  id_type next = get(ich)->m_next_sibling;
931  _release(ich);
932  if(ich == get(node)->m_last_child)
933  break;
934  ich = next;
935  }
936  C4_SUPPRESS_WARNING_GCC_POP
937 }
938 
940 {
941  _RYML_ASSERT_VISIT_(m_callbacks, type.is_val() || type.is_map() || type.is_seq(), this, node);
942  _RYML_ASSERT_VISIT_(m_callbacks, type.is_val() + type.is_map() + type.is_seq() == 1, this, node);
943  _RYML_ASSERT_VISIT_(m_callbacks, type.has_key() == has_key(node) || (has_key(node) && !type.has_key()), this, node);
944  NodeData *d = _p(node);
945  if(type.is_map() && is_map(node))
946  return false;
947  else if(type.is_seq() && is_seq(node))
948  return false;
949  else if(type.is_val() && is_val(node))
950  return false;
952  remove_children(node);
953  return true;
954 }
955 
956 
957 //-----------------------------------------------------------------------------
959 {
960  return duplicate(this, node, parent, after);
961 }
962 
963 id_type Tree::duplicate(Tree const* src, id_type node, id_type parent, id_type after)
964 {
965  _RYML_ASSERT_VISIT_(m_callbacks, src != nullptr, src, node);
966  _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, src, node);
967  _RYML_ASSERT_VISIT_(m_callbacks, parent != NONE, this, parent);
968  _RYML_ASSERT_VISIT_(m_callbacks, ! src->is_root(node), src, node);
969 
970  id_type copy = _claim();
971 
972  _copy_props(copy, src, node);
973  _set_hierarchy(copy, parent, after);
974  duplicate_children(src, node, copy, NONE);
975 
976  return copy;
977 }
978 
979 //-----------------------------------------------------------------------------
981 {
982  return duplicate_children(this, node, parent, after);
983 }
984 
985 id_type Tree::duplicate_children(Tree const* src, id_type node, id_type parent, id_type after)
986 {
987  _RYML_ASSERT_VISIT_(m_callbacks, src != nullptr, src, node);
988  _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, src, node);
989  _RYML_ASSERT_VISIT_(m_callbacks, parent != NONE, this, parent);
990  _RYML_ASSERT_VISIT_(m_callbacks, after == NONE || has_child(parent, after), this, parent);
991 
992  id_type prev = after;
993  for(id_type i = src->first_child(node); i != NONE; i = src->next_sibling(i))
994  {
995  prev = duplicate(src, i, parent, prev);
996  }
997 
998  return prev;
999 }
1000 
1001 //-----------------------------------------------------------------------------
1003 {
1004  duplicate_contents(this, node, where);
1005 }
1006 
1007 void Tree::duplicate_contents(Tree const *src, id_type node, id_type where)
1008 {
1009  _RYML_ASSERT_VISIT_(m_callbacks, src != nullptr, src, node);
1010  _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, src, node);
1011  _RYML_ASSERT_VISIT_(m_callbacks, where != NONE, this, where);
1012  _copy_props_wo_key(where, src, node);
1013  duplicate_children(src, node, where, last_child(where));
1014 }
1015 
1016 //-----------------------------------------------------------------------------
1018 {
1019  return duplicate_children_no_rep(this, node, parent, after);
1020 }
1021 
1023 {
1024  _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, src, node);
1025  _RYML_ASSERT_VISIT_(m_callbacks, parent != NONE, this, parent);
1026  _RYML_ASSERT_VISIT_(m_callbacks, after == NONE || has_child(parent, after), this, parent);
1027 
1028  // don't loop using pointers as there may be a relocation
1029 
1030  // find the position where "after" is
1031  id_type after_pos = NONE;
1032  if(after != NONE)
1033  {
1034  for(id_type i = first_child(parent), icount = 0; i != NONE; ++icount, i = next_sibling(i))
1035  {
1036  if(i == after)
1037  {
1038  after_pos = icount;
1039  break;
1040  }
1041  }
1042  _RYML_ASSERT_VISIT_(m_callbacks, after_pos != NONE, this, node);
1043  }
1044 
1045  // for each child to be duplicated...
1046  id_type prev = after;
1047  for(id_type i = src->first_child(node); i != NONE; i = src->next_sibling(i))
1048  {
1049  _c4dbgpf("duplicate_no_rep: {} -> {}/{}", i, parent, prev);
1050  _RYML_CHECK_VISIT_(m_callbacks, this != src || (parent != i && !is_ancestor(parent, i)), this, parent);
1051  if(is_seq(parent))
1052  {
1053  _c4dbgpf("duplicate_no_rep: {} is seq", parent);
1054  prev = duplicate(src, i, parent, prev);
1055  }
1056  else
1057  {
1058  _c4dbgpf("duplicate_no_rep: {} is map", parent);
1059  _RYML_ASSERT_VISIT_(m_callbacks, is_map(parent), this, parent);
1060  // does the parent already have a node with key equal to that of the current duplicate?
1061  id_type dstnode_dup = NONE, dstnode_dup_pos = NONE;
1062  {
1063  csubstr srckey = src->key(i);
1064  for(id_type j = first_child(parent), jcount = 0; j != NONE; ++jcount, j = next_sibling(j))
1065  {
1066  if(key(j) == srckey)
1067  {
1068  _c4dbgpf("duplicate_no_rep: found matching key '{}' src={}/{} dst={}/{}", srckey, node, i, parent, j);
1069  dstnode_dup = j;
1070  dstnode_dup_pos = jcount;
1071  break;
1072  }
1073  }
1074  }
1075  _c4dbgpf("duplicate_no_rep: dstnode_dup={} dstnode_dup_pos={} after_pos={}", dstnode_dup, dstnode_dup_pos, after_pos);
1076  if(dstnode_dup == NONE) // there is no repetition; just duplicate
1077  {
1078  _c4dbgpf("duplicate_no_rep: no repetition, just duplicate i={} parent={} prev={}", i, parent, prev);
1079  prev = duplicate(src, i, parent, prev);
1080  }
1081  else // yes, there is a repetition
1082  {
1083  if(after_pos != NONE && dstnode_dup_pos <= after_pos)
1084  {
1085  // the dst duplicate is located before the node which will be inserted,
1086  // and will be overridden by the duplicate. So replace it.
1087  _c4dbgpf("duplicate_no_dstnode_dup: replace {}/{} with {}/{}", parent, dstnode_dup, node, i);
1088  if(prev == dstnode_dup)
1089  prev = prev_sibling(dstnode_dup);
1090  remove(dstnode_dup);
1091  prev = duplicate(src, i, parent, prev);
1092  }
1093  else if(prev == NONE)
1094  {
1095  _c4dbgpf("duplicate_no_dstnode_dup: {}=prev <- {}", prev, dstnode_dup);
1096  // first iteration with prev = after = NONE and dstnode_dupetition
1097  prev = dstnode_dup;
1098  }
1099  else if(dstnode_dup != prev)
1100  {
1101  // dstnode_dup is located after the node which will be inserted
1102  // and overrides it. So move the dstnode_dup into this node's place.
1103  _c4dbgpf("duplicate_no_dstnode_dup: move({}, {})", dstnode_dup, prev);
1104  move(dstnode_dup, prev);
1105  prev = dstnode_dup;
1106  }
1107  } // there's a dstnode_dupetition
1108  }
1109  }
1110 
1111  return prev;
1112 }
1113 
1114 
1115 //-----------------------------------------------------------------------------
1116 
1117 void Tree::merge_with(Tree const *src, id_type src_node, id_type dst_node)
1118 {
1119  _RYML_ASSERT_VISIT_(m_callbacks, src != nullptr, src, src_node);
1120  if(src_node == NONE)
1121  src_node = src->root_id();
1122  if(dst_node == NONE)
1123  dst_node = root_id();
1124  _RYML_ASSERT_VISIT_(m_callbacks, src->has_val(src_node) || src->is_seq(src_node) || src->is_map(src_node), src, src_node);
1125  if(src->has_val(src_node))
1126  {
1127  type_bits mask_src = ~STYLE; // keep the existing style if it is already a val
1128  if( ! has_val(dst_node))
1129  {
1130  if(has_children(dst_node))
1131  remove_children(dst_node);
1132  mask_src |= VAL_STYLE; // copy the src style
1133  }
1134  if(src->is_keyval(src_node))
1135  {
1136  _copy_props(dst_node, src, src_node, mask_src);
1137  }
1138  else
1139  {
1140  _RYML_ASSERT_VISIT_(m_callbacks, src->is_val(src_node), src, src_node);
1141  _copy_props_wo_key(dst_node, src, src_node, mask_src);
1142  }
1143  }
1144  else if(src->is_seq(src_node))
1145  {
1146  if( ! is_seq(dst_node))
1147  {
1148  if(has_children(dst_node))
1149  remove_children(dst_node);
1150  _clear_type(dst_node);
1151  if(src->has_key(src_node))
1152  to_seq(dst_node, src->key(src_node));
1153  else
1154  to_seq(dst_node);
1155  _p(dst_node)->m_type = src->_p(src_node)->m_type;
1156  }
1157  for(id_type sch = src->first_child(src_node); sch != NONE; sch = src->next_sibling(sch))
1158  {
1159  id_type dch = append_child(dst_node);
1160  _copy_props_wo_key(dch, src, sch);
1161  merge_with(src, sch, dch);
1162  }
1163  }
1164  else
1165  {
1166  _RYML_ASSERT_VISIT_(m_callbacks, src->is_map(src_node), src, src_node);
1167  if( ! is_map(dst_node))
1168  {
1169  if(has_children(dst_node))
1170  remove_children(dst_node);
1171  _clear_type(dst_node);
1172  if(src->has_key(src_node))
1173  to_map(dst_node, src->key(src_node));
1174  else
1175  to_map(dst_node);
1176  _p(dst_node)->m_type = src->_p(src_node)->m_type;
1177  }
1178  for(id_type sch = src->first_child(src_node); sch != NONE; sch = src->next_sibling(sch))
1179  {
1180  id_type dch = find_child(dst_node, src->key(sch));
1181  if(dch == NONE)
1182  {
1183  dch = append_child(dst_node);
1184  _copy_props(dch, src, sch);
1185  }
1186  merge_with(src, sch, dch);
1187  }
1188  }
1189 }
1190 
1191 
1192 //-----------------------------------------------------------------------------
1193 
1194 void Tree::resolve(bool clear_anchors)
1195 {
1196  if(m_size == 0)
1197  return;
1198  ReferenceResolver rr;
1199  resolve(&rr, clear_anchors);
1200 }
1201 
1202 void Tree::resolve(ReferenceResolver *C4_RESTRICT rr, bool clear_anchors)
1203 {
1204  if(m_size == 0)
1205  return;
1206  rr->resolve(this, clear_anchors);
1207 }
1208 
1209 
1210 //-----------------------------------------------------------------------------
1211 
1213 {
1214  id_type count = 0;
1215  for(id_type i = first_child(node); i != NONE; i = next_sibling(i))
1216  ++count;
1217  return count;
1218 }
1219 
1221 {
1222  _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
1223  id_type count = 0;
1224  for(id_type i = first_child(node); i != NONE; i = next_sibling(i))
1225  {
1226  if(count++ == pos)
1227  return i;
1228  }
1229  return NONE;
1230 }
1231 
1233 {
1234  _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
1235  id_type count = 0;
1236  for(id_type i = first_child(node); i != NONE; i = next_sibling(i))
1237  {
1238  if(i == ch)
1239  return count;
1240  ++count;
1241  }
1242  return NONE;
1243 }
1244 
1245 #if defined(__clang__)
1246 # pragma clang diagnostic push
1247 #elif defined(__GNUC__)
1248 # pragma GCC diagnostic push
1249 # if __GNUC__ >= 6
1250 # pragma GCC diagnostic ignored "-Wnull-dereference"
1251 # endif
1252 # if __GNUC__ > 9
1253 # pragma GCC diagnostic ignored "-Wanalyzer-null-dereference"
1254 # endif
1255 #endif
1256 
1257 id_type Tree::find_child(id_type node, csubstr const& name) const
1258 {
1259  _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
1260  _RYML_ASSERT_VISIT_(m_callbacks, is_map(node), this, node);
1261  if(get(node)->m_first_child == NONE)
1262  {
1263  _RYML_ASSERT_VISIT_(m_callbacks, _p(node)->m_last_child == NONE, this, node);
1264  return NONE;
1265  }
1266  else
1267  {
1268  _RYML_ASSERT_VISIT_(m_callbacks, _p(node)->m_last_child != NONE, this, node);
1269  }
1270  for(id_type i = first_child(node); i != NONE; i = next_sibling(i))
1271  {
1272  if(_p(i)->m_key.scalar == name)
1273  {
1274  return i;
1275  }
1276  }
1277  return NONE;
1278 }
1279 
1280 #if defined(__clang__)
1281 # pragma clang diagnostic pop
1282 #elif defined(__GNUC__)
1283 # pragma GCC diagnostic pop
1284 #endif
1285 
1286 namespace {
1287 id_type depth_desc_(Tree const& C4_RESTRICT t, id_type id, id_type currdepth=0, id_type maxdepth=0)
1288 {
1289  maxdepth = currdepth > maxdepth ? currdepth : maxdepth;
1290  for(id_type child = t.first_child(id); child != NONE; child = t.next_sibling(child))
1291  {
1292  const id_type d = depth_desc_(t, child, currdepth+1, maxdepth);
1293  maxdepth = d > maxdepth ? d : maxdepth;
1294  }
1295  return maxdepth;
1296 }
1297 }
1298 
1300 {
1301  _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
1302  return depth_desc_(*this, node);
1303 }
1304 
1306 {
1307  _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
1308  id_type depth = 0;
1309  while(!is_root(node))
1310  {
1311  ++depth;
1312  node = parent(node);
1313  }
1314  return depth;
1315 }
1316 
1317 bool Tree::is_ancestor(id_type node, id_type ancestor) const
1318 {
1319  _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, node);
1320  id_type p = parent(node);
1321  while(p != NONE)
1322  {
1323  if(p == ancestor)
1324  return true;
1325  p = parent(p);
1326  }
1327  return false;
1328 }
1329 
1330 
1331 //-----------------------------------------------------------------------------
1332 
1333 void Tree::to_val(id_type node, csubstr val, type_bits more_flags)
1334 {
1335  _RYML_ASSERT_VISIT_(m_callbacks, ! has_children(node), this, node);
1336  _RYML_ASSERT_VISIT_(m_callbacks, parent(node) == NONE || ! parent_is_map(node), this, node);
1337  _set_flags(node, VAL|more_flags);
1338  _p(node)->m_key.clear();
1339  _p(node)->m_val = val;
1340 }
1341 
1342 void Tree::to_keyval(id_type node, csubstr key, csubstr val, type_bits more_flags)
1343 {
1344  _RYML_ASSERT_VISIT_(m_callbacks, ! has_children(node), this, node);
1345  _RYML_ASSERT_VISIT_(m_callbacks, parent(node) == NONE || parent_is_map(node), this, node);
1346  _set_flags(node, KEYVAL|more_flags);
1347  _p(node)->m_key = key;
1348  _p(node)->m_val = val;
1349 }
1350 
1351 void Tree::to_map(id_type node, type_bits more_flags)
1352 {
1353  _RYML_ASSERT_VISIT_(m_callbacks, ! has_children(node), this, node);
1354  _RYML_ASSERT_VISIT_(m_callbacks, parent(node) == NONE || ! parent_is_map(node), this, node); // parent must not have children with keys
1355  _set_flags(node, MAP|more_flags);
1356  _p(node)->m_key.clear();
1357  _p(node)->m_val.clear();
1358 }
1359 
1360 void Tree::to_map(id_type node, csubstr key, type_bits more_flags)
1361 {
1362  _RYML_ASSERT_VISIT_(m_callbacks, ! has_children(node), this, node);
1363  _RYML_ASSERT_VISIT_(m_callbacks, parent(node) == NONE || parent_is_map(node), this, node);
1364  _set_flags(node, KEY|MAP|more_flags);
1365  _p(node)->m_key = key;
1366  _p(node)->m_val.clear();
1367 }
1368 
1369 void Tree::to_seq(id_type node, type_bits more_flags)
1370 {
1371  _RYML_ASSERT_VISIT_(m_callbacks, ! has_children(node), this, node);
1372  _RYML_ASSERT_VISIT_(m_callbacks, parent(node) == NONE || parent_is_seq(node), this, node);
1373  _set_flags(node, SEQ|more_flags);
1374  _p(node)->m_key.clear();
1375  _p(node)->m_val.clear();
1376 }
1377 
1378 void Tree::to_seq(id_type node, csubstr key, type_bits more_flags)
1379 {
1380  _RYML_ASSERT_VISIT_(m_callbacks, ! has_children(node), this, node);
1381  _RYML_ASSERT_VISIT_(m_callbacks, parent(node) == NONE || parent_is_map(node), this, node);
1382  _set_flags(node, KEY|SEQ|more_flags);
1383  _p(node)->m_key = key;
1384  _p(node)->m_val.clear();
1385 }
1386 
1387 void Tree::to_doc(id_type node, type_bits more_flags)
1388 {
1389  _RYML_ASSERT_VISIT_(m_callbacks, ! has_children(node), this, node);
1390  _set_flags(node, DOC|more_flags);
1391  _p(node)->m_key.clear();
1392  _p(node)->m_val.clear();
1393 }
1394 
1395 void Tree::to_stream(id_type node, type_bits more_flags)
1396 {
1397  _RYML_ASSERT_VISIT_(m_callbacks, ! has_children(node), this, node);
1398  _set_flags(node, STREAM|more_flags);
1399  _p(node)->m_key.clear();
1400  _p(node)->m_val.clear();
1401 }
1402 
1403 
1404 //-----------------------------------------------------------------------------
1405 
1406 void Tree::clear_style(id_type node, bool recurse)
1407 {
1408  NodeData *C4_RESTRICT d = _p(node);
1409  d->m_type.clear_style();
1410  if(!recurse)
1411  return;
1412  for(id_type child = d->m_first_child; child != NONE; child = next_sibling(child))
1413  clear_style(child, recurse);
1414 }
1415 
1417  NodeType type_mask,
1418  NodeType rem_style_flags,
1419  NodeType add_style_flags,
1420  bool recurse)
1421 {
1422  NodeData *C4_RESTRICT d = _p(node);
1423  if((d->m_type & type_mask) == type_mask)
1424  {
1425  d->m_type &= ~(NodeType)rem_style_flags;
1426  d->m_type |= (NodeType)add_style_flags;
1427  }
1428  if(!recurse)
1429  return;
1430  for(id_type child = d->m_first_child; child != NONE; child = next_sibling(child))
1431  set_style_conditionally(child, type_mask, rem_style_flags, add_style_flags, recurse);
1432 }
1433 
1434 
1435 //-----------------------------------------------------------------------------
1437 {
1438  return m_tag_directives.size();
1439 }
1440 
1442 {
1444 }
1445 
1446 void Tree::add_tag_directive(csubstr handle, csubstr prefix, id_type id)
1447 {
1448  _RYML_CHECK_BASIC_(m_callbacks,
1449  !handle.empty()
1450  &&
1451  !prefix.empty()
1452  &&
1453  is_valid_tag_handle(handle)
1454  &&
1455  m_tag_directives.add(handle, prefix, id));
1456 }
1457 
1458 size_t Tree::resolve_tag(substr output, csubstr tag, id_type node_id) const
1459 {
1460  size_t reqsz = 0;
1461  m_tag_directives.resolve(output, &reqsz, tag, node_id, Location{}, callbacks());
1462  return reqsz;
1463 }
1464 
1465 namespace {
1466 // return the extra size needed for the arena to accomodate the resolved tag
1467 size_t _transform_tag(Tree *t, id_type node_id, id_type doc_id, TagCache &cache, csubstr tag, csubstr *resolved)
1468 {
1469  _c4dbgpf("tag: doc={} node={} resolving tag ~~~{}~~~", doc_id, node_id, tag);
1470  (void)node_id;
1471  size_t reqsize = 0;
1472  if(tag.begins_with('<'))
1473  {
1474  *resolved = tag;
1475  }
1476  else
1477  {
1478  _RYML_ASSERT_VISIT_(t->callbacks(), !tag.begins_with("!<"), t, node_id); // this should have been handled elsewhere
1479  TagCache::LookupResult ret = cache.find(tag, doc_id);
1480  if(ret)
1481  {
1482  _c4dbgpf("tag: doc={} node={} resolving tag: found in cache[{}]: {}", doc_id, node_id, ret.pos, _prs(ret.resolved));
1483  *resolved = ret.resolved;
1484  }
1485  else
1486  {
1487  _c4dbgpf("tag: doc={} node={} tag not in cache ~~~{}~~~", doc_id, node_id, tag);
1488  substr buf = t->m_arena.sub(t->m_arena_pos);
1489  reqsize = t->resolve_tag(buf, tag, doc_id);
1490  if(!reqsize)
1491  {
1492  *resolved = tag;
1493  }
1494  else if(reqsize <= buf.len)
1495  {
1496  t->m_arena_pos += reqsize;
1497  *resolved = buf.first(reqsize);
1498  cache.add(tag, *resolved, doc_id, ret.pos);
1499  reqsize = 0;
1500  }
1501  else
1502  {
1503  _c4dbgpf("tag: doc={} node={} extra size needed: {}", doc_id, node_id, reqsize);
1504  }
1505  _c4dbgpf("tag: doc={} node={} resolved tag: ~~~{}~~~", doc_id, node_id, *resolved);
1506  }
1507  }
1508  return reqsize;
1509 }
1510 size_t _resolve_tags(Tree *t, id_type node, id_type doc_id, TagCache &cache, bool all=true)
1511 {
1512  NodeData *C4_RESTRICT d = t->_p(node);
1513  size_t extra_size = 0;
1514  if((d->m_type & KEYTAG) && (all || is_custom_tag(d->m_key.tag)))
1515  extra_size += _transform_tag(t, node, doc_id, cache, d->m_key.tag, &d->m_key.tag);
1516  if((d->m_type & VALTAG) && (all || is_custom_tag(d->m_val.tag)))
1517  extra_size += _transform_tag(t, node, doc_id, cache, d->m_val.tag, &d->m_val.tag);
1518  for(id_type child = t->first_child(node); child != NONE; child = t->next_sibling(child))
1519  extra_size += _resolve_tags(t, child, doc_id, cache);
1520  return extra_size;
1521 }
1522 size_t _resolve_tags(Tree *t, TagCache &cache, bool all)
1523 {
1524  id_type r = t->root_id();
1525  size_t extra_size = 0;
1526  if(!t->is_stream(r))
1527  extra_size += _resolve_tags(t, r, r, cache, all);
1528  else
1529  for(id_type doc_id = t->first_child(r); doc_id != NONE; doc_id = t->next_sibling(doc_id))
1530  extra_size += _resolve_tags(t, doc_id, doc_id, cache, all);
1531  return extra_size;
1532 }
1533 void _normalize_tags(Tree *t, id_type node)
1534 {
1535  NodeData *C4_RESTRICT d = t->_p(node);
1536  if(d->m_type & KEYTAG)
1537  d->m_key.tag = normalize_tag(d->m_key.tag);
1538  if(d->m_type & VALTAG)
1539  d->m_val.tag = normalize_tag(d->m_val.tag);
1540  for(id_type child = t->first_child(node); child != NONE; child = t->next_sibling(child))
1541  _normalize_tags(t, child);
1542 }
1543 void _normalize_tags_long(Tree *t, id_type node)
1544 {
1545  NodeData *C4_RESTRICT d = t->_p(node);
1546  if(d->m_type & KEYTAG)
1547  d->m_key.tag = normalize_tag_long(d->m_key.tag);
1548  if(d->m_type & VALTAG)
1549  d->m_val.tag = normalize_tag_long(d->m_val.tag);
1550  for(id_type child = t->first_child(node); child != NONE; child = t->next_sibling(child))
1551  _normalize_tags_long(t, child);
1552 }
1553 } // namespace
1554 
1555 void Tree::resolve_tags(TagCache &cache, bool all)
1556 {
1557  if(empty())
1558  return;
1559  // try to resolve. While doing so, get the extra size needed for
1560  // the arena, if the arena is currently too small.
1561  size_t extra_size = _resolve_tags(this, cache, all);
1562  // if the arena requires extra size, grow it and then resolve the
1563  // missing entries
1564  if(extra_size)
1565  {
1566  _c4dbgpf("tag: extrasize={} -- retry! {}->{}", extra_size, m_arena.len, m_arena.len + extra_size);
1567  _grow_arena(extra_size);
1568  extra_size = _resolve_tags(this, cache, all);
1569  _RYML_ASSERT_BASIC_(callbacks(), extra_size == 0);
1570  }
1571 }
1572 
1574 {
1575  if(empty())
1576  return;
1577  _normalize_tags(this, root_id());
1578 }
1579 
1581 {
1582  if(empty())
1583  return;
1584  _normalize_tags_long(this, root_id());
1585 }
1586 
1587 
1588 //-----------------------------------------------------------------------------
1589 
1591 {
1592  csubstr p = path.first(path_pos);
1593  if(p.ends_with('.'))
1594  p = p.first(p.len-1);
1595  return p;
1596 }
1597 
1599 {
1600  return path.sub(path_pos);
1601 }
1602 
1603 void Tree::_advance(lookup_result *r, size_t more)
1604 {
1605  r->path_pos += more;
1606  if(r->path.sub(r->path_pos).begins_with('.'))
1607  ++r->path_pos;
1608 }
1609 
1611 {
1612  if(start == NONE)
1613  start = root_id();
1614  lookup_result r(path, start);
1615  if(path.empty())
1616  return r;
1617  _lookup_path(&r);
1618  if(r.target == NONE && r.closest == start)
1619  r.closest = NONE;
1620  return r;
1621 }
1622 
1623 id_type Tree::lookup_path_or_modify(csubstr default_value, csubstr path, id_type start)
1624 {
1625  id_type target = _lookup_path_or_create(path, start);
1626  if(parent_is_map(target))
1627  to_keyval(target, key(target), default_value);
1628  else
1629  to_val(target, default_value);
1630  return target;
1631 }
1632 
1633 id_type Tree::lookup_path_or_modify(Tree const *src, id_type src_node, csubstr path, id_type start)
1634 {
1635  id_type target = _lookup_path_or_create(path, start);
1636  merge_with(src, src_node, target);
1637  return target;
1638 }
1639 
1640 id_type Tree::_lookup_path_or_create(csubstr path, id_type start)
1641 {
1642  if(start == NONE)
1643  start = root_id();
1644  lookup_result r(path, start);
1645  _lookup_path(&r);
1646  if(r.target != NONE)
1647  {
1648  C4_ASSERT(r.unresolved().empty());
1649  return r.target;
1650  }
1651  _lookup_path_modify(&r);
1652  return r.target;
1653 }
1654 
1655 void Tree::_lookup_path(lookup_result *r) const
1656 {
1657  C4_ASSERT( ! r->unresolved().empty());
1658  _lookup_path_token parent{"", type(r->closest)};
1659  id_type node;
1660  do
1661  {
1662  node = _next_node(r, &parent);
1663  if(node != NONE)
1664  r->closest = node;
1665  if(r->unresolved().empty())
1666  {
1667  r->target = node;
1668  return;
1669  }
1670  } while(node != NONE);
1671 }
1672 
1673 void Tree::_lookup_path_modify(lookup_result *r)
1674 {
1675  C4_ASSERT( ! r->unresolved().empty());
1676  _lookup_path_token parent{"", type(r->closest)};
1677  id_type node;
1678  do
1679  {
1680  node = _next_node_modify(r, &parent);
1681  if(node != NONE)
1682  r->closest = node;
1683  if(r->unresolved().empty())
1684  {
1685  r->target = node;
1686  return;
1687  }
1688  } while(node != NONE);
1689 }
1690 
1691 id_type Tree::_next_node(lookup_result * r, _lookup_path_token *parent) const
1692 {
1693  _lookup_path_token token = _next_token(r, *parent);
1694  if( ! token)
1695  return NONE;
1696 
1697  id_type node = NONE;
1698  csubstr prev = token.value;
1699  if(token.type == MAP || token.type == SEQ)
1700  {
1701  _RYML_ASSERT_VISIT_(m_callbacks, !token.value.begins_with('['), this, r->closest);
1702  //_RYML_ASSERT_VISIT_(m_callbacks, is_container(r->closest) || r->closest == NONE);
1703  _RYML_ASSERT_VISIT_(m_callbacks, is_map(r->closest), this, r->closest);
1704  node = find_child(r->closest, token.value);
1705  }
1706  else if(token.type == KEYVAL)
1707  {
1708  _RYML_ASSERT_VISIT_(m_callbacks, r->unresolved().empty(), this, r->closest);
1709  if(is_map(r->closest))
1710  node = find_child(r->closest, token.value);
1711  }
1712  else if(token.type == KEY)
1713  {
1714  _RYML_ASSERT_VISIT_(m_callbacks, token.value.begins_with('[') && token.value.ends_with(']'), this, r->closest);
1715  token.value = token.value.offs(1, 1).trim(' ');
1716  id_type idx = 0;
1717  _RYML_CHECK_BASIC_(m_callbacks, from_chars(token.value, &idx));
1718  node = child(r->closest, idx);
1719  }
1720  else
1721  {
1722  C4_NEVER_REACH();
1723  }
1724 
1725  if(node != NONE)
1726  {
1727  *parent = token;
1728  }
1729  else
1730  {
1731  csubstr p = r->path.sub(r->path_pos > 0 ? r->path_pos - 1 : r->path_pos);
1732  r->path_pos -= prev.len;
1733  if(p.begins_with('.'))
1734  r->path_pos -= 1u;
1735  }
1736 
1737  return node;
1738 }
1739 
1740 id_type Tree::_next_node_modify(lookup_result * r, _lookup_path_token *parent)
1741 {
1742  _lookup_path_token token = _next_token(r, *parent);
1743  if( ! token)
1744  return NONE;
1745 
1746  id_type node = NONE;
1747  if(token.type == MAP || token.type == SEQ)
1748  {
1749  _RYML_ASSERT_VISIT_(m_callbacks, !token.value.begins_with('['), this, r->closest);
1750  //_RYML_ASSERT_VISIT_(m_callbacks, is_container(r->closest) || r->closest == NONE);
1751  if( ! is_container(r->closest))
1752  {
1753  if(has_key(r->closest))
1754  to_map(r->closest, key(r->closest));
1755  else
1756  to_map(r->closest);
1757  }
1758  else
1759  {
1760  if(is_map(r->closest))
1761  {
1762  node = find_child(r->closest, token.value);
1763  }
1764  else
1765  {
1766  id_type pos = NONE;
1767  _RYML_CHECK_BASIC_(m_callbacks, c4::atox(token.value, &pos));
1768  _RYML_ASSERT_VISIT_(m_callbacks, pos != NONE, this, r->closest);
1769  node = child(r->closest, pos);
1770  }
1771  }
1772  if(node == NONE)
1773  {
1774  _RYML_ASSERT_VISIT_(m_callbacks, is_map(r->closest), this, r->closest);
1775  node = append_child(r->closest);
1776  NodeData *n = _p(node);
1777  n->m_key.scalar = token.value;
1778  n->m_type.add(KEY);
1779  }
1780  }
1781  else if(token.type == KEYVAL)
1782  {
1783  _RYML_ASSERT_VISIT_(m_callbacks, r->unresolved().empty(), this, r->closest);
1784  if(is_map(r->closest))
1785  {
1786  node = find_child(r->closest, token.value);
1787  if(node == NONE)
1788  node = append_child(r->closest);
1789  }
1790  else
1791  {
1792  _RYML_ASSERT_VISIT_(m_callbacks, !is_seq(r->closest), this, r->closest);
1793  _add_flags(r->closest, MAP);
1794  node = append_child(r->closest);
1795  }
1796  NodeData *n = _p(node);
1797  n->m_key.scalar = token.value;
1798  n->m_val.scalar = "";
1799  n->m_type.add(KEYVAL);
1800  }
1801  else if(token.type == KEY)
1802  {
1803  _RYML_ASSERT_VISIT_(m_callbacks, token.value.begins_with('[') && token.value.ends_with(']'), this, r->closest);
1804  token.value = token.value.offs(1, 1).trim(' ');
1805  id_type idx;
1806  if( ! from_chars(token.value, &idx))
1807  return NONE;
1808  if( ! is_container(r->closest))
1809  {
1810  if(has_key(r->closest))
1811  {
1812  csubstr k = key(r->closest);
1813  _clear_type(r->closest);
1814  to_seq(r->closest, k);
1815  }
1816  else
1817  {
1818  _clear_type(r->closest);
1819  to_seq(r->closest);
1820  }
1821  }
1822  _RYML_ASSERT_VISIT_(m_callbacks, is_container(r->closest), this, r->closest);
1823  node = child(r->closest, idx);
1824  if(node == NONE)
1825  {
1826  _RYML_ASSERT_VISIT_(m_callbacks, num_children(r->closest) <= idx, this, r->closest);
1827  for(id_type i = num_children(r->closest); i <= idx; ++i)
1828  {
1829  node = append_child(r->closest);
1830  if(i < idx)
1831  {
1832  if(is_map(r->closest))
1833  to_keyval(node, /*"~"*/{}, /*"~"*/{});
1834  else if(is_seq(r->closest))
1835  to_val(node, /*"~"*/{});
1836  }
1837  }
1838  }
1839  }
1840  else
1841  {
1842  C4_NEVER_REACH();
1843  }
1844 
1845  _RYML_ASSERT_VISIT_(m_callbacks, node != NONE, this, r->closest);
1846  *parent = token;
1847  return node;
1848 }
1849 
1850 /* types of tokens:
1851  * - seeing "map." ---> "map"/MAP
1852  * - finishing "scalar" ---> "scalar"/KEYVAL
1853  * - seeing "seq[n]" ---> "seq"/SEQ (--> "[n]"/KEY)
1854  * - seeing "[n]" ---> "[n]"/KEY
1855  */
1856 Tree::_lookup_path_token Tree::_next_token(lookup_result *r, _lookup_path_token const& parent) const
1857 {
1858  csubstr unres = r->unresolved();
1859  if(unres.empty())
1860  return {};
1861 
1862  // is it an indexation like [0], [1], etc?
1863  if(unres.begins_with('['))
1864  {
1865  size_t pos = unres.find(']');
1866  if(pos == csubstr::npos)
1867  return {};
1868  csubstr idx = unres.first(pos + 1);
1869  _advance(r, pos + 1);
1870  return {idx, KEY};
1871  }
1872 
1873  // no. so it must be a name
1874  size_t pos = unres.first_of(".[");
1875  if(pos == csubstr::npos)
1876  {
1877  _advance(r, unres.len);
1878  NodeType t;
1879  if(( ! parent) || parent.type.is_seq())
1880  return {unres, VAL};
1881  return {unres, KEYVAL};
1882  }
1883 
1884  // it's either a map or a seq
1885  _RYML_ASSERT_VISIT_(m_callbacks, unres[pos] == '.' || unres[pos] == '[', this, r->closest);
1886  if(unres[pos] == '.')
1887  {
1888  _RYML_ASSERT_VISIT_(m_callbacks, pos != 0, this, r->closest);
1889  _advance(r, pos + 1);
1890  return {unres.first(pos), MAP};
1891  }
1892 
1893  _RYML_ASSERT_VISIT_(m_callbacks, unres[pos] == '[', this, r->closest);
1894  _advance(r, pos);
1895  return {unres.first(pos), SEQ};
1896 }
1897 
1898 
1899 } // namespace yml
1900 } // namespace c4
1901 
1902 
1903 //-----------------------------------------------------------------------------
1904 //-----------------------------------------------------------------------------
1905 //-----------------------------------------------------------------------------
1906 
1908 #include "c4/yml/parse_engine.def.hpp"
1909 #include "c4/yml/parse.hpp"
1910 
1911 namespace c4 {
1912 namespace yml {
1913 
1914 Location Tree::location(Parser const& parser, id_type node) const
1915 {
1916  // try hard to avoid getting the location from a null string.
1917  Location loc;
1918  if(_location_from_node(parser, node, &loc, 0))
1919  return loc;
1920  return parser.val_location(parser.source().str);
1921 }
1922 
1923 bool Tree::_location_from_node(Parser const& parser, id_type node, Location *C4_RESTRICT loc, id_type level) const
1924 {
1925  if(has_key(node))
1926  {
1927  csubstr k = key(node);
1928  if(C4_LIKELY(k.str != nullptr))
1929  {
1930  _RYML_ASSERT_BASIC_(m_callbacks, k.is_sub(parser.source()));
1931  _RYML_ASSERT_BASIC_(m_callbacks, parser.source().is_super(k));
1932  *loc = parser.val_location(k.str);
1933  return true;
1934  }
1935  }
1936 
1937  if(has_val(node))
1938  {
1939  csubstr v = val(node);
1940  if(C4_LIKELY(v.str != nullptr))
1941  {
1942  _RYML_ASSERT_BASIC_(m_callbacks, v.is_sub(parser.source()));
1943  _RYML_ASSERT_BASIC_(m_callbacks, parser.source().is_super(v));
1944  *loc = parser.val_location(v.str);
1945  return true;
1946  }
1947  }
1948 
1949  if(is_container(node))
1950  {
1951  if(_location_from_cont(parser, node, loc))
1952  return true;
1953  }
1954 
1955  if(type(node) != NOTYPE && level == 0)
1956  {
1957  // try the prev sibling
1958  {
1959  const id_type prev = prev_sibling(node);
1960  if(prev != NONE)
1961  {
1962  if(_location_from_node(parser, prev, loc, level+1))
1963  return true;
1964  }
1965  }
1966  // try the next sibling
1967  {
1968  const id_type next = next_sibling(node);
1969  if(next != NONE)
1970  {
1971  if(_location_from_node(parser, next, loc, level+1))
1972  return true;
1973  }
1974  }
1975  // try the parent
1976  {
1977  const id_type parent = this->parent(node);
1978  if(parent != NONE)
1979  {
1980  if(_location_from_node(parser, parent, loc, level+1))
1981  return true;
1982  }
1983  }
1984  }
1985  return false;
1986 }
1987 
1988 bool Tree::_location_from_cont(Parser const& parser, id_type node, Location *C4_RESTRICT loc) const
1989 {
1990  _RYML_ASSERT_BASIC_(m_callbacks, is_container(node));
1991  if(!is_stream(node))
1992  {
1993  const char *node_start = _p(node)->m_val.scalar.str; // this was stored in the container
1994  if(has_children(node))
1995  {
1996  id_type child = first_child(node);
1997  if(has_key(child))
1998  {
1999  // when a map starts, the container was set after the key
2000  csubstr k = key(child);
2001  if(k.str && node_start > k.str)
2002  node_start = k.str;
2003  }
2004  }
2005  *loc = parser.val_location(node_start);
2006  return true;
2007  }
2008  else // it's a stream
2009  {
2010  *loc = parser.val_location(parser.source().str); // just return the front of the buffer
2011  }
2012  return true;
2013 }
2014 
2015 } // namespace yml
2016 } // namespace c4
2017 
2018 
2019 // NOLINTEND(modernize-avoid-c-style-cast)
2020 C4_SUPPRESS_WARNING_GCC_CLANG_POP
2021 C4_SUPPRESS_WARNING_MSVC_POP
Holds a pointer to an existing tree, and a node id.
Definition: node.hpp:856
A reference to a node in an existing yaml tree, offering a more convenient API than the index-based A...
Definition: node.hpp:996
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:1329
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:958
void clear()
clear the tree and zero every node
Definition: tree.cpp:330
id_type m_free_head
Definition: tree.hpp:1333
lookup_result lookup_path(csubstr path, id_type start=NONE) const
for example foo.bar[0].baz
Definition: tree.cpp:1610
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:1623
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" -> "<!...
Definition: tree.cpp:1555
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:971
size_t m_arena_pos
Definition: tree.hpp:1337
bool is_map(id_type node) const
Definition: tree.hpp:411
void clear_tag_directives()
Definition: tree.cpp:1441
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:1342
TagDirectives m_tag_directives
Definition: tree.hpp:1341
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:1331
void to_doc(id_type node, type_bits more_flags=0)
Definition: tree.cpp:1387
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:1305
bool in_arena(csubstr s) const
return true if the given substring is part of the tree's string arena
Definition: tree.hpp:887
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:1458
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:1232
id_type append_child(id_type parent)
create and insert a node as the last child of parent
Definition: tree.hpp:719
void clear_style(id_type node, bool recurse=false)
Definition: tree.cpp:1406
void to_stream(id_type node, type_bits more_flags=0)
Definition: tree.cpp:1395
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:1378
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:1299
id_type num_tag_directives() const
Definition: tree.cpp:1436
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:1017
id_type m_cap
Definition: tree.hpp:1330
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:1416
substr m_arena
Definition: tree.hpp:1336
void normalize_tags()
Definition: tree.cpp:1573
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:1317
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:1360
size_t arena_capacity() const
get the current capacity of the tree's internal arena
Definition: tree.hpp:876
bool change_type(id_type node, NodeType type)
change the type of the node to one of MAP, SEQ or VAL.
Definition: tree.cpp:939
id_type m_free_tail
Definition: tree.hpp:1334
void normalize_tags_long()
Definition: tree.cpp:1580
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:1202
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:751
id_type find_child(id_type node, csubstr const &key) const
Definition: tree.cpp:1257
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:1914
void duplicate_contents(id_type node, id_type where)
Definition: tree.cpp:1002
void add_tag_directive(csubstr handle, csubstr prefix, id_type id)
Definition: tree.cpp:1446
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:980
id_type num_children(id_type node) const
O(num_children)
Definition: tree.cpp:1212
csubstr arena() const
get the current arena
Definition: tree.hpp:882
void merge_with(Tree const *src, id_type src_node=NONE, id_type dst_root=NONE)
Definition: tree.cpp:1117
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:1220
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:1339
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:1333
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:2287
bool from_chars(csubstr buf, uint8_t *v) noexcept
Definition: charconv.hpp:2368
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:46
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:541
holds a source or yaml file position, for example when an error is detected; See also location_format...
Definition: common.hpp:284
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:185
bool is_seq() const noexcept
Definition: node_type.hpp:184
void rem(NodeType_e t) noexcept
Definition: node_type.hpp:138
bool is_map() const noexcept
Definition: node_type.hpp:183
void add(NodeType_e t) noexcept
Definition: node_type.hpp:137
bool is_val() const noexcept
Definition: node_type.hpp:187
Reusable object to resolve references/aliases in a Tree.
Accelerator structure to reduce memory requirements by enabling reuse of resolved tags.
Definition: tag.hpp:71
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:113
void clear() noexcept
Definition: tag.cpp:373
TagDirective m_directives[RYML_MAX_TAG_DIRECTIVES]
Definition: tag.hpp:127
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:1598
csubstr resolved() const
get the part ot the input path that was resolved
Definition: tree.cpp:1590