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