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