duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

tree.cpp (64502B)


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