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