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