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