Path: blob/master/dep/rapidyaml/src/c4/yml/tree.cpp
4262 views
#include "c4/yml/tree.hpp"1#include "c4/yml/detail/parser_dbg.hpp"2#include "c4/yml/node.hpp"3#include "c4/yml/detail/stack.hpp"456C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(4296/*expression is always 'boolean_value'*/)7C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")8C4_SUPPRESS_WARNING_GCC("-Wtype-limits")910namespace c4 {11namespace yml {121314csubstr normalize_tag(csubstr tag)15{16YamlTag_e t = to_tag(tag);17if(t != TAG_NONE)18return from_tag(t);19if(tag.begins_with("!<"))20tag = tag.sub(1);21if(tag.begins_with("<!"))22return tag;23return tag;24}2526csubstr normalize_tag_long(csubstr tag)27{28YamlTag_e t = to_tag(tag);29if(t != TAG_NONE)30return from_tag_long(t);31if(tag.begins_with("!<"))32tag = tag.sub(1);33if(tag.begins_with("<!"))34return tag;35return tag;36}3738YamlTag_e to_tag(csubstr tag)39{40if(tag.begins_with("!<"))41tag = tag.sub(1);42if(tag.begins_with("!!"))43tag = tag.sub(2);44else if(tag.begins_with('!'))45return TAG_NONE;46else if(tag.begins_with("tag:yaml.org,2002:"))47{48RYML_ASSERT(csubstr("tag:yaml.org,2002:").len == 18);49tag = tag.sub(18);50}51else if(tag.begins_with("<tag:yaml.org,2002:"))52{53RYML_ASSERT(csubstr("<tag:yaml.org,2002:").len == 19);54tag = tag.sub(19);55if(!tag.len)56return TAG_NONE;57tag = tag.offs(0, 1);58}5960if(tag == "map")61return TAG_MAP;62else if(tag == "omap")63return TAG_OMAP;64else if(tag == "pairs")65return TAG_PAIRS;66else if(tag == "set")67return TAG_SET;68else if(tag == "seq")69return TAG_SEQ;70else if(tag == "binary")71return TAG_BINARY;72else if(tag == "bool")73return TAG_BOOL;74else if(tag == "float")75return TAG_FLOAT;76else if(tag == "int")77return TAG_INT;78else if(tag == "merge")79return TAG_MERGE;80else if(tag == "null")81return TAG_NULL;82else if(tag == "str")83return TAG_STR;84else if(tag == "timestamp")85return TAG_TIMESTAMP;86else if(tag == "value")87return TAG_VALUE;8889return TAG_NONE;90}9192csubstr from_tag_long(YamlTag_e tag)93{94switch(tag)95{96case TAG_MAP:97return {"<tag:yaml.org,2002:map>"};98case TAG_OMAP:99return {"<tag:yaml.org,2002:omap>"};100case TAG_PAIRS:101return {"<tag:yaml.org,2002:pairs>"};102case TAG_SET:103return {"<tag:yaml.org,2002:set>"};104case TAG_SEQ:105return {"<tag:yaml.org,2002:seq>"};106case TAG_BINARY:107return {"<tag:yaml.org,2002:binary>"};108case TAG_BOOL:109return {"<tag:yaml.org,2002:bool>"};110case TAG_FLOAT:111return {"<tag:yaml.org,2002:float>"};112case TAG_INT:113return {"<tag:yaml.org,2002:int>"};114case TAG_MERGE:115return {"<tag:yaml.org,2002:merge>"};116case TAG_NULL:117return {"<tag:yaml.org,2002:null>"};118case TAG_STR:119return {"<tag:yaml.org,2002:str>"};120case TAG_TIMESTAMP:121return {"<tag:yaml.org,2002:timestamp>"};122case TAG_VALUE:123return {"<tag:yaml.org,2002:value>"};124case TAG_YAML:125return {"<tag:yaml.org,2002:yaml>"};126case TAG_NONE:127return {""};128}129return {""};130}131132csubstr from_tag(YamlTag_e tag)133{134switch(tag)135{136case TAG_MAP:137return {"!!map"};138case TAG_OMAP:139return {"!!omap"};140case TAG_PAIRS:141return {"!!pairs"};142case TAG_SET:143return {"!!set"};144case TAG_SEQ:145return {"!!seq"};146case TAG_BINARY:147return {"!!binary"};148case TAG_BOOL:149return {"!!bool"};150case TAG_FLOAT:151return {"!!float"};152case TAG_INT:153return {"!!int"};154case TAG_MERGE:155return {"!!merge"};156case TAG_NULL:157return {"!!null"};158case TAG_STR:159return {"!!str"};160case TAG_TIMESTAMP:161return {"!!timestamp"};162case TAG_VALUE:163return {"!!value"};164case TAG_YAML:165return {"!!yaml"};166case TAG_NONE:167return {""};168}169return {""};170}171172173//-----------------------------------------------------------------------------174//-----------------------------------------------------------------------------175//-----------------------------------------------------------------------------176177const char* NodeType::type_str(NodeType_e ty)178{179switch(ty & _TYMASK)180{181case KEYVAL:182return "KEYVAL";183case KEY:184return "KEY";185case VAL:186return "VAL";187case MAP:188return "MAP";189case SEQ:190return "SEQ";191case KEYMAP:192return "KEYMAP";193case KEYSEQ:194return "KEYSEQ";195case DOCSEQ:196return "DOCSEQ";197case DOCMAP:198return "DOCMAP";199case DOCVAL:200return "DOCVAL";201case DOC:202return "DOC";203case STREAM:204return "STREAM";205case NOTYPE:206return "NOTYPE";207default:208if((ty & KEYVAL) == KEYVAL)209return "KEYVAL***";210if((ty & KEYMAP) == KEYMAP)211return "KEYMAP***";212if((ty & KEYSEQ) == KEYSEQ)213return "KEYSEQ***";214if((ty & DOCSEQ) == DOCSEQ)215return "DOCSEQ***";216if((ty & DOCMAP) == DOCMAP)217return "DOCMAP***";218if((ty & DOCVAL) == DOCVAL)219return "DOCVAL***";220if(ty & KEY)221return "KEY***";222if(ty & VAL)223return "VAL***";224if(ty & MAP)225return "MAP***";226if(ty & SEQ)227return "SEQ***";228if(ty & DOC)229return "DOC***";230return "(unk)";231}232}233234235//-----------------------------------------------------------------------------236//-----------------------------------------------------------------------------237//-----------------------------------------------------------------------------238239NodeRef Tree::rootref()240{241return NodeRef(this, root_id());242}243ConstNodeRef Tree::rootref() const244{245return ConstNodeRef(this, root_id());246}247248ConstNodeRef Tree::crootref()249{250return ConstNodeRef(this, root_id());251}252ConstNodeRef Tree::crootref() const253{254return ConstNodeRef(this, root_id());255}256257NodeRef Tree::ref(size_t id)258{259_RYML_CB_ASSERT(m_callbacks, id != NONE && id >= 0 && id < m_size);260return NodeRef(this, id);261}262ConstNodeRef Tree::ref(size_t id) const263{264_RYML_CB_ASSERT(m_callbacks, id != NONE && id >= 0 && id < m_size);265return ConstNodeRef(this, id);266}267268ConstNodeRef Tree::cref(size_t id)269{270_RYML_CB_ASSERT(m_callbacks, id != NONE && id >= 0 && id < m_size);271return ConstNodeRef(this, id);272}273ConstNodeRef Tree::cref(size_t id) const274{275_RYML_CB_ASSERT(m_callbacks, id != NONE && id >= 0 && id < m_size);276return ConstNodeRef(this, id);277}278279NodeRef Tree::operator[] (csubstr key)280{281return rootref()[key];282}283ConstNodeRef Tree::operator[] (csubstr key) const284{285return rootref()[key];286}287288NodeRef Tree::operator[] (size_t i)289{290return rootref()[i];291}292ConstNodeRef Tree::operator[] (size_t i) const293{294return rootref()[i];295}296297NodeRef Tree::docref(size_t i)298{299return ref(doc(i));300}301ConstNodeRef Tree::docref(size_t i) const302{303return cref(doc(i));304}305306307//-----------------------------------------------------------------------------308Tree::Tree(Callbacks const& cb)309: m_buf(nullptr)310, m_cap(0)311, m_size(0)312, m_free_head(NONE)313, m_free_tail(NONE)314, m_arena()315, m_arena_pos(0)316, m_callbacks(cb)317{318}319320Tree::Tree(size_t node_capacity, size_t arena_capacity, Callbacks const& cb)321: Tree(cb)322{323reserve(node_capacity);324reserve_arena(arena_capacity);325}326327Tree::~Tree()328{329_free();330}331332333Tree::Tree(Tree const& that) noexcept : Tree(that.m_callbacks)334{335_copy(that);336}337338Tree& Tree::operator= (Tree const& that) noexcept339{340_free();341m_callbacks = that.m_callbacks;342_copy(that);343return *this;344}345346Tree::Tree(Tree && that) noexcept : Tree(that.m_callbacks)347{348_move(that);349}350351Tree& Tree::operator= (Tree && that) noexcept352{353_free();354m_callbacks = that.m_callbacks;355_move(that);356return *this;357}358359void Tree::_free()360{361if(m_buf)362{363_RYML_CB_ASSERT(m_callbacks, m_cap > 0);364_RYML_CB_FREE(m_callbacks, m_buf, NodeData, m_cap);365}366if(m_arena.str)367{368_RYML_CB_ASSERT(m_callbacks, m_arena.len > 0);369_RYML_CB_FREE(m_callbacks, m_arena.str, char, m_arena.len);370}371_clear();372}373374375C4_SUPPRESS_WARNING_GCC_PUSH376#if defined(__GNUC__) && __GNUC__>= 8377C4_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 instead378#endif379380void Tree::_clear()381{382m_buf = nullptr;383m_cap = 0;384m_size = 0;385m_free_head = 0;386m_free_tail = 0;387m_arena = {};388m_arena_pos = 0;389for(size_t i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i)390m_tag_directives[i] = {};391}392393void Tree::_copy(Tree const& that)394{395_RYML_CB_ASSERT(m_callbacks, m_buf == nullptr);396_RYML_CB_ASSERT(m_callbacks, m_arena.str == nullptr);397_RYML_CB_ASSERT(m_callbacks, m_arena.len == 0);398m_buf = _RYML_CB_ALLOC_HINT(m_callbacks, NodeData, that.m_cap, that.m_buf);399memcpy(m_buf, that.m_buf, that.m_cap * sizeof(NodeData));400m_cap = that.m_cap;401m_size = that.m_size;402m_free_head = that.m_free_head;403m_free_tail = that.m_free_tail;404m_arena_pos = that.m_arena_pos;405m_arena = that.m_arena;406if(that.m_arena.str)407{408_RYML_CB_ASSERT(m_callbacks, that.m_arena.len > 0);409substr arena;410arena.str = _RYML_CB_ALLOC_HINT(m_callbacks, char, that.m_arena.len, that.m_arena.str);411arena.len = that.m_arena.len;412_relocate(arena); // does a memcpy of the arena and updates nodes using the old arena413m_arena = arena;414}415for(size_t i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i)416m_tag_directives[i] = that.m_tag_directives[i];417}418419void Tree::_move(Tree & that)420{421_RYML_CB_ASSERT(m_callbacks, m_buf == nullptr);422_RYML_CB_ASSERT(m_callbacks, m_arena.str == nullptr);423_RYML_CB_ASSERT(m_callbacks, m_arena.len == 0);424m_buf = that.m_buf;425m_cap = that.m_cap;426m_size = that.m_size;427m_free_head = that.m_free_head;428m_free_tail = that.m_free_tail;429m_arena = that.m_arena;430m_arena_pos = that.m_arena_pos;431for(size_t i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i)432m_tag_directives[i] = that.m_tag_directives[i];433that._clear();434}435436void Tree::_relocate(substr next_arena)437{438_RYML_CB_ASSERT(m_callbacks, next_arena.not_empty());439_RYML_CB_ASSERT(m_callbacks, next_arena.len >= m_arena.len);440memcpy(next_arena.str, m_arena.str, m_arena_pos);441for(NodeData *C4_RESTRICT n = m_buf, *e = m_buf + m_cap; n != e; ++n)442{443if(in_arena(n->m_key.scalar))444n->m_key.scalar = _relocated(n->m_key.scalar, next_arena);445if(in_arena(n->m_key.tag))446n->m_key.tag = _relocated(n->m_key.tag, next_arena);447if(in_arena(n->m_key.anchor))448n->m_key.anchor = _relocated(n->m_key.anchor, next_arena);449if(in_arena(n->m_val.scalar))450n->m_val.scalar = _relocated(n->m_val.scalar, next_arena);451if(in_arena(n->m_val.tag))452n->m_val.tag = _relocated(n->m_val.tag, next_arena);453if(in_arena(n->m_val.anchor))454n->m_val.anchor = _relocated(n->m_val.anchor, next_arena);455}456for(TagDirective &C4_RESTRICT td : m_tag_directives)457{458if(in_arena(td.prefix))459td.prefix = _relocated(td.prefix, next_arena);460if(in_arena(td.handle))461td.handle = _relocated(td.handle, next_arena);462}463}464465466//-----------------------------------------------------------------------------467void Tree::reserve(size_t cap)468{469if(cap > m_cap)470{471NodeData *buf = _RYML_CB_ALLOC_HINT(m_callbacks, NodeData, cap, m_buf);472if(m_buf)473{474memcpy(buf, m_buf, m_cap * sizeof(NodeData));475_RYML_CB_FREE(m_callbacks, m_buf, NodeData, m_cap);476}477size_t first = m_cap, del = cap - m_cap;478m_cap = cap;479m_buf = buf;480_clear_range(first, del);481if(m_free_head != NONE)482{483_RYML_CB_ASSERT(m_callbacks, m_buf != nullptr);484_RYML_CB_ASSERT(m_callbacks, m_free_tail != NONE);485m_buf[m_free_tail].m_next_sibling = first;486m_buf[first].m_prev_sibling = m_free_tail;487m_free_tail = cap-1;488}489else490{491_RYML_CB_ASSERT(m_callbacks, m_free_tail == NONE);492m_free_head = first;493m_free_tail = cap-1;494}495_RYML_CB_ASSERT(m_callbacks, m_free_head == NONE || (m_free_head >= 0 && m_free_head < cap));496_RYML_CB_ASSERT(m_callbacks, m_free_tail == NONE || (m_free_tail >= 0 && m_free_tail < cap));497498if( ! m_size)499_claim_root();500}501}502503504//-----------------------------------------------------------------------------505void Tree::clear()506{507_clear_range(0, m_cap);508m_size = 0;509if(m_buf)510{511_RYML_CB_ASSERT(m_callbacks, m_cap >= 0);512m_free_head = 0;513m_free_tail = m_cap-1;514_claim_root();515}516else517{518m_free_head = NONE;519m_free_tail = NONE;520}521for(size_t i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i)522m_tag_directives[i] = {};523}524525void Tree::_claim_root()526{527size_t r = _claim();528_RYML_CB_ASSERT(m_callbacks, r == 0);529_set_hierarchy(r, NONE, NONE);530}531532533//-----------------------------------------------------------------------------534void Tree::_clear_range(size_t first, size_t num)535{536if(num == 0)537return; // prevent overflow when subtracting538_RYML_CB_ASSERT(m_callbacks, first >= 0 && first + num <= m_cap);539memset(m_buf + first, 0, num * sizeof(NodeData)); // TODO we should not need this540for(size_t i = first, e = first + num; i < e; ++i)541{542_clear(i);543NodeData *n = m_buf + i;544n->m_prev_sibling = i - 1;545n->m_next_sibling = i + 1;546}547m_buf[first + num - 1].m_next_sibling = NONE;548}549550C4_SUPPRESS_WARNING_GCC_POP551552553//-----------------------------------------------------------------------------554void Tree::_release(size_t i)555{556_RYML_CB_ASSERT(m_callbacks, i >= 0 && i < m_cap);557558_rem_hierarchy(i);559_free_list_add(i);560_clear(i);561562--m_size;563}564565//-----------------------------------------------------------------------------566// add to the front of the free list567void Tree::_free_list_add(size_t i)568{569_RYML_CB_ASSERT(m_callbacks, i >= 0 && i < m_cap);570NodeData &C4_RESTRICT w = m_buf[i];571572w.m_parent = NONE;573w.m_next_sibling = m_free_head;574w.m_prev_sibling = NONE;575if(m_free_head != NONE)576m_buf[m_free_head].m_prev_sibling = i;577m_free_head = i;578if(m_free_tail == NONE)579m_free_tail = m_free_head;580}581582void Tree::_free_list_rem(size_t i)583{584if(m_free_head == i)585m_free_head = _p(i)->m_next_sibling;586_rem_hierarchy(i);587}588589//-----------------------------------------------------------------------------590size_t Tree::_claim()591{592if(m_free_head == NONE || m_buf == nullptr)593{594size_t sz = 2 * m_cap;595sz = sz ? sz : 16;596reserve(sz);597_RYML_CB_ASSERT(m_callbacks, m_free_head != NONE);598}599600_RYML_CB_ASSERT(m_callbacks, m_size < m_cap);601_RYML_CB_ASSERT(m_callbacks, m_free_head >= 0 && m_free_head < m_cap);602603size_t ichild = m_free_head;604NodeData *child = m_buf + ichild;605606++m_size;607m_free_head = child->m_next_sibling;608if(m_free_head == NONE)609{610m_free_tail = NONE;611_RYML_CB_ASSERT(m_callbacks, m_size == m_cap);612}613614_clear(ichild);615616return ichild;617}618619//-----------------------------------------------------------------------------620621C4_SUPPRESS_WARNING_GCC_PUSH622C4_SUPPRESS_WARNING_CLANG_PUSH623C4_SUPPRESS_WARNING_CLANG("-Wnull-dereference")624#if defined(__GNUC__) && (__GNUC__ >= 6)625C4_SUPPRESS_WARNING_GCC("-Wnull-dereference")626#endif627628void Tree::_set_hierarchy(size_t ichild, size_t iparent, size_t iprev_sibling)629{630_RYML_CB_ASSERT(m_callbacks, iparent == NONE || (iparent >= 0 && iparent < m_cap));631_RYML_CB_ASSERT(m_callbacks, iprev_sibling == NONE || (iprev_sibling >= 0 && iprev_sibling < m_cap));632633NodeData *C4_RESTRICT child = get(ichild);634635child->m_parent = iparent;636child->m_prev_sibling = NONE;637child->m_next_sibling = NONE;638639if(iparent == NONE)640{641_RYML_CB_ASSERT(m_callbacks, ichild == 0);642_RYML_CB_ASSERT(m_callbacks, iprev_sibling == NONE);643}644645if(iparent == NONE)646return;647648size_t inext_sibling = iprev_sibling != NONE ? next_sibling(iprev_sibling) : first_child(iparent);649NodeData *C4_RESTRICT parent = get(iparent);650NodeData *C4_RESTRICT psib = get(iprev_sibling);651NodeData *C4_RESTRICT nsib = get(inext_sibling);652653if(psib)654{655_RYML_CB_ASSERT(m_callbacks, next_sibling(iprev_sibling) == id(nsib));656child->m_prev_sibling = id(psib);657psib->m_next_sibling = id(child);658_RYML_CB_ASSERT(m_callbacks, psib->m_prev_sibling != psib->m_next_sibling || psib->m_prev_sibling == NONE);659}660661if(nsib)662{663_RYML_CB_ASSERT(m_callbacks, prev_sibling(inext_sibling) == id(psib));664child->m_next_sibling = id(nsib);665nsib->m_prev_sibling = id(child);666_RYML_CB_ASSERT(m_callbacks, nsib->m_prev_sibling != nsib->m_next_sibling || nsib->m_prev_sibling == NONE);667}668669if(parent->m_first_child == NONE)670{671_RYML_CB_ASSERT(m_callbacks, parent->m_last_child == NONE);672parent->m_first_child = id(child);673parent->m_last_child = id(child);674}675else676{677if(child->m_next_sibling == parent->m_first_child)678parent->m_first_child = id(child);679680if(child->m_prev_sibling == parent->m_last_child)681parent->m_last_child = id(child);682}683}684685C4_SUPPRESS_WARNING_GCC_POP686C4_SUPPRESS_WARNING_CLANG_POP687688689//-----------------------------------------------------------------------------690void Tree::_rem_hierarchy(size_t i)691{692_RYML_CB_ASSERT(m_callbacks, i >= 0 && i < m_cap);693694NodeData &C4_RESTRICT w = m_buf[i];695696// remove from the parent697if(w.m_parent != NONE)698{699NodeData &C4_RESTRICT p = m_buf[w.m_parent];700if(p.m_first_child == i)701{702p.m_first_child = w.m_next_sibling;703}704if(p.m_last_child == i)705{706p.m_last_child = w.m_prev_sibling;707}708}709710// remove from the used list711if(w.m_prev_sibling != NONE)712{713NodeData *C4_RESTRICT prev = get(w.m_prev_sibling);714prev->m_next_sibling = w.m_next_sibling;715}716if(w.m_next_sibling != NONE)717{718NodeData *C4_RESTRICT next = get(w.m_next_sibling);719next->m_prev_sibling = w.m_prev_sibling;720}721}722723//-----------------------------------------------------------------------------724void Tree::reorder()725{726size_t r = root_id();727_do_reorder(&r, 0);728}729730//-----------------------------------------------------------------------------731size_t Tree::_do_reorder(size_t *node, size_t count)732{733// swap this node if it's not in place734if(*node != count)735{736_swap(*node, count);737*node = count;738}739++count; // bump the count from this node740741// now descend in the hierarchy742for(size_t i = first_child(*node); i != NONE; i = next_sibling(i))743{744// this child may have been relocated to a different index,745// so get an updated version746count = _do_reorder(&i, count);747}748return count;749}750751//-----------------------------------------------------------------------------752void Tree::_swap(size_t n_, size_t m_)753{754_RYML_CB_ASSERT(m_callbacks, (parent(n_) != NONE) || type(n_) == NOTYPE);755_RYML_CB_ASSERT(m_callbacks, (parent(m_) != NONE) || type(m_) == NOTYPE);756NodeType tn = type(n_);757NodeType tm = type(m_);758if(tn != NOTYPE && tm != NOTYPE)759{760_swap_props(n_, m_);761_swap_hierarchy(n_, m_);762}763else if(tn == NOTYPE && tm != NOTYPE)764{765_copy_props(n_, m_);766_free_list_rem(n_);767_copy_hierarchy(n_, m_);768_clear(m_);769_free_list_add(m_);770}771else if(tn != NOTYPE && tm == NOTYPE)772{773_copy_props(m_, n_);774_free_list_rem(m_);775_copy_hierarchy(m_, n_);776_clear(n_);777_free_list_add(n_);778}779else780{781C4_NEVER_REACH();782}783}784785//-----------------------------------------------------------------------------786void Tree::_swap_hierarchy(size_t ia, size_t ib)787{788if(ia == ib) return;789790for(size_t i = first_child(ia); i != NONE; i = next_sibling(i))791{792if(i == ib || i == ia)793continue;794_p(i)->m_parent = ib;795}796797for(size_t i = first_child(ib); i != NONE; i = next_sibling(i))798{799if(i == ib || i == ia)800continue;801_p(i)->m_parent = ia;802}803804auto & C4_RESTRICT a = *_p(ia);805auto & C4_RESTRICT b = *_p(ib);806auto & C4_RESTRICT pa = *_p(a.m_parent);807auto & C4_RESTRICT pb = *_p(b.m_parent);808809if(&pa == &pb)810{811if((pa.m_first_child == ib && pa.m_last_child == ia)812||813(pa.m_first_child == ia && pa.m_last_child == ib))814{815std::swap(pa.m_first_child, pa.m_last_child);816}817else818{819bool changed = false;820if(pa.m_first_child == ia)821{822pa.m_first_child = ib;823changed = true;824}825if(pa.m_last_child == ia)826{827pa.m_last_child = ib;828changed = true;829}830if(pb.m_first_child == ib && !changed)831{832pb.m_first_child = ia;833}834if(pb.m_last_child == ib && !changed)835{836pb.m_last_child = ia;837}838}839}840else841{842if(pa.m_first_child == ia)843pa.m_first_child = ib;844if(pa.m_last_child == ia)845pa.m_last_child = ib;846if(pb.m_first_child == ib)847pb.m_first_child = ia;848if(pb.m_last_child == ib)849pb.m_last_child = ia;850}851std::swap(a.m_first_child , b.m_first_child);852std::swap(a.m_last_child , b.m_last_child);853854if(a.m_prev_sibling != ib && b.m_prev_sibling != ia &&855a.m_next_sibling != ib && b.m_next_sibling != ia)856{857if(a.m_prev_sibling != NONE && a.m_prev_sibling != ib)858_p(a.m_prev_sibling)->m_next_sibling = ib;859if(a.m_next_sibling != NONE && a.m_next_sibling != ib)860_p(a.m_next_sibling)->m_prev_sibling = ib;861if(b.m_prev_sibling != NONE && b.m_prev_sibling != ia)862_p(b.m_prev_sibling)->m_next_sibling = ia;863if(b.m_next_sibling != NONE && b.m_next_sibling != ia)864_p(b.m_next_sibling)->m_prev_sibling = ia;865std::swap(a.m_prev_sibling, b.m_prev_sibling);866std::swap(a.m_next_sibling, b.m_next_sibling);867}868else869{870if(a.m_next_sibling == ib) // n will go after m871{872_RYML_CB_ASSERT(m_callbacks, b.m_prev_sibling == ia);873if(a.m_prev_sibling != NONE)874{875_RYML_CB_ASSERT(m_callbacks, a.m_prev_sibling != ib);876_p(a.m_prev_sibling)->m_next_sibling = ib;877}878if(b.m_next_sibling != NONE)879{880_RYML_CB_ASSERT(m_callbacks, b.m_next_sibling != ia);881_p(b.m_next_sibling)->m_prev_sibling = ia;882}883size_t ns = b.m_next_sibling;884b.m_prev_sibling = a.m_prev_sibling;885b.m_next_sibling = ia;886a.m_prev_sibling = ib;887a.m_next_sibling = ns;888}889else if(a.m_prev_sibling == ib) // m will go after n890{891_RYML_CB_ASSERT(m_callbacks, b.m_next_sibling == ia);892if(b.m_prev_sibling != NONE)893{894_RYML_CB_ASSERT(m_callbacks, b.m_prev_sibling != ia);895_p(b.m_prev_sibling)->m_next_sibling = ia;896}897if(a.m_next_sibling != NONE)898{899_RYML_CB_ASSERT(m_callbacks, a.m_next_sibling != ib);900_p(a.m_next_sibling)->m_prev_sibling = ib;901}902size_t ns = b.m_prev_sibling;903a.m_prev_sibling = b.m_prev_sibling;904a.m_next_sibling = ib;905b.m_prev_sibling = ia;906b.m_next_sibling = ns;907}908else909{910C4_NEVER_REACH();911}912}913_RYML_CB_ASSERT(m_callbacks, a.m_next_sibling != ia);914_RYML_CB_ASSERT(m_callbacks, a.m_prev_sibling != ia);915_RYML_CB_ASSERT(m_callbacks, b.m_next_sibling != ib);916_RYML_CB_ASSERT(m_callbacks, b.m_prev_sibling != ib);917918if(a.m_parent != ib && b.m_parent != ia)919{920std::swap(a.m_parent, b.m_parent);921}922else923{924if(a.m_parent == ib && b.m_parent != ia)925{926a.m_parent = b.m_parent;927b.m_parent = ia;928}929else if(a.m_parent != ib && b.m_parent == ia)930{931b.m_parent = a.m_parent;932a.m_parent = ib;933}934else935{936C4_NEVER_REACH();937}938}939}940941//-----------------------------------------------------------------------------942void Tree::_copy_hierarchy(size_t dst_, size_t src_)943{944auto const& C4_RESTRICT src = *_p(src_);945auto & C4_RESTRICT dst = *_p(dst_);946auto & C4_RESTRICT prt = *_p(src.m_parent);947for(size_t i = src.m_first_child; i != NONE; i = next_sibling(i))948{949_p(i)->m_parent = dst_;950}951if(src.m_prev_sibling != NONE)952{953_p(src.m_prev_sibling)->m_next_sibling = dst_;954}955if(src.m_next_sibling != NONE)956{957_p(src.m_next_sibling)->m_prev_sibling = dst_;958}959if(prt.m_first_child == src_)960{961prt.m_first_child = dst_;962}963if(prt.m_last_child == src_)964{965prt.m_last_child = dst_;966}967dst.m_parent = src.m_parent;968dst.m_first_child = src.m_first_child;969dst.m_last_child = src.m_last_child;970dst.m_prev_sibling = src.m_prev_sibling;971dst.m_next_sibling = src.m_next_sibling;972}973974//-----------------------------------------------------------------------------975void Tree::_swap_props(size_t n_, size_t m_)976{977NodeData &C4_RESTRICT n = *_p(n_);978NodeData &C4_RESTRICT m = *_p(m_);979std::swap(n.m_type, m.m_type);980std::swap(n.m_key, m.m_key);981std::swap(n.m_val, m.m_val);982}983984//-----------------------------------------------------------------------------985void Tree::move(size_t node, size_t after)986{987_RYML_CB_ASSERT(m_callbacks, node != NONE);988_RYML_CB_ASSERT(m_callbacks, node != after);989_RYML_CB_ASSERT(m_callbacks, ! is_root(node));990_RYML_CB_ASSERT(m_callbacks, (after == NONE) || (has_sibling(node, after) && has_sibling(after, node)));991992_rem_hierarchy(node);993_set_hierarchy(node, parent(node), after);994}995996//-----------------------------------------------------------------------------997998void Tree::move(size_t node, size_t new_parent, size_t after)999{1000_RYML_CB_ASSERT(m_callbacks, node != NONE);1001_RYML_CB_ASSERT(m_callbacks, node != after);1002_RYML_CB_ASSERT(m_callbacks, new_parent != NONE);1003_RYML_CB_ASSERT(m_callbacks, new_parent != node);1004_RYML_CB_ASSERT(m_callbacks, new_parent != after);1005_RYML_CB_ASSERT(m_callbacks, ! is_root(node));10061007_rem_hierarchy(node);1008_set_hierarchy(node, new_parent, after);1009}10101011size_t Tree::move(Tree *src, size_t node, size_t new_parent, size_t after)1012{1013_RYML_CB_ASSERT(m_callbacks, src != nullptr);1014_RYML_CB_ASSERT(m_callbacks, node != NONE);1015_RYML_CB_ASSERT(m_callbacks, new_parent != NONE);1016_RYML_CB_ASSERT(m_callbacks, new_parent != after);10171018size_t dup = duplicate(src, node, new_parent, after);1019src->remove(node);1020return dup;1021}10221023void Tree::set_root_as_stream()1024{1025size_t root = root_id();1026if(is_stream(root))1027return;1028// don't use _add_flags() because it's checked and will fail1029if(!has_children(root))1030{1031if(is_val(root))1032{1033_p(root)->m_type.add(SEQ);1034size_t next_doc = append_child(root);1035_copy_props_wo_key(next_doc, root);1036_p(next_doc)->m_type.add(DOC);1037_p(next_doc)->m_type.rem(SEQ);1038}1039_p(root)->m_type = STREAM;1040return;1041}1042_RYML_CB_ASSERT(m_callbacks, !has_key(root));1043size_t next_doc = append_child(root);1044_copy_props_wo_key(next_doc, root);1045_add_flags(next_doc, DOC);1046for(size_t prev = NONE, ch = first_child(root), next = next_sibling(ch); ch != NONE; )1047{1048if(ch == next_doc)1049break;1050move(ch, next_doc, prev);1051prev = ch;1052ch = next;1053next = next_sibling(next);1054}1055_p(root)->m_type = STREAM;1056}105710581059//-----------------------------------------------------------------------------1060void Tree::remove_children(size_t node)1061{1062_RYML_CB_ASSERT(m_callbacks, get(node) != nullptr);1063size_t ich = get(node)->m_first_child;1064while(ich != NONE)1065{1066remove_children(ich);1067_RYML_CB_ASSERT(m_callbacks, get(ich) != nullptr);1068size_t next = get(ich)->m_next_sibling;1069_release(ich);1070if(ich == get(node)->m_last_child)1071break;1072ich = next;1073}1074}10751076bool Tree::change_type(size_t node, NodeType type)1077{1078_RYML_CB_ASSERT(m_callbacks, type.is_val() || type.is_map() || type.is_seq());1079_RYML_CB_ASSERT(m_callbacks, type.is_val() + type.is_map() + type.is_seq() == 1);1080_RYML_CB_ASSERT(m_callbacks, type.has_key() == has_key(node) || (has_key(node) && !type.has_key()));1081NodeData *d = _p(node);1082if(type.is_map() && is_map(node))1083return false;1084else if(type.is_seq() && is_seq(node))1085return false;1086else if(type.is_val() && is_val(node))1087return false;1088d->m_type = (d->m_type & (~(MAP|SEQ|VAL))) | type;1089remove_children(node);1090return true;1091}109210931094//-----------------------------------------------------------------------------1095size_t Tree::duplicate(size_t node, size_t parent, size_t after)1096{1097return duplicate(this, node, parent, after);1098}10991100size_t Tree::duplicate(Tree const* src, size_t node, size_t parent, size_t after)1101{1102_RYML_CB_ASSERT(m_callbacks, src != nullptr);1103_RYML_CB_ASSERT(m_callbacks, node != NONE);1104_RYML_CB_ASSERT(m_callbacks, parent != NONE);1105_RYML_CB_ASSERT(m_callbacks, ! src->is_root(node));11061107size_t copy = _claim();11081109_copy_props(copy, src, node);1110_set_hierarchy(copy, parent, after);1111duplicate_children(src, node, copy, NONE);11121113return copy;1114}11151116//-----------------------------------------------------------------------------1117size_t Tree::duplicate_children(size_t node, size_t parent, size_t after)1118{1119return duplicate_children(this, node, parent, after);1120}11211122size_t Tree::duplicate_children(Tree const* src, size_t node, size_t parent, size_t after)1123{1124_RYML_CB_ASSERT(m_callbacks, src != nullptr);1125_RYML_CB_ASSERT(m_callbacks, node != NONE);1126_RYML_CB_ASSERT(m_callbacks, parent != NONE);1127_RYML_CB_ASSERT(m_callbacks, after == NONE || has_child(parent, after));11281129size_t prev = after;1130for(size_t i = src->first_child(node); i != NONE; i = src->next_sibling(i))1131{1132prev = duplicate(src, i, parent, prev);1133}11341135return prev;1136}11371138//-----------------------------------------------------------------------------1139void Tree::duplicate_contents(size_t node, size_t where)1140{1141duplicate_contents(this, node, where);1142}11431144void Tree::duplicate_contents(Tree const *src, size_t node, size_t where)1145{1146_RYML_CB_ASSERT(m_callbacks, src != nullptr);1147_RYML_CB_ASSERT(m_callbacks, node != NONE);1148_RYML_CB_ASSERT(m_callbacks, where != NONE);1149_copy_props_wo_key(where, src, node);1150duplicate_children(src, node, where, last_child(where));1151}11521153//-----------------------------------------------------------------------------1154size_t Tree::duplicate_children_no_rep(size_t node, size_t parent, size_t after)1155{1156return duplicate_children_no_rep(this, node, parent, after);1157}11581159size_t Tree::duplicate_children_no_rep(Tree const *src, size_t node, size_t parent, size_t after)1160{1161_RYML_CB_ASSERT(m_callbacks, node != NONE);1162_RYML_CB_ASSERT(m_callbacks, parent != NONE);1163_RYML_CB_ASSERT(m_callbacks, after == NONE || has_child(parent, after));11641165// don't loop using pointers as there may be a relocation11661167// find the position where "after" is1168size_t after_pos = NONE;1169if(after != NONE)1170{1171for(size_t i = first_child(parent), icount = 0; i != NONE; ++icount, i = next_sibling(i))1172{1173if(i == after)1174{1175after_pos = icount;1176break;1177}1178}1179_RYML_CB_ASSERT(m_callbacks, after_pos != NONE);1180}11811182// for each child to be duplicated...1183size_t prev = after;1184for(size_t i = src->first_child(node); i != NONE; i = src->next_sibling(i))1185{1186if(is_seq(parent))1187{1188prev = duplicate(i, parent, prev);1189}1190else1191{1192_RYML_CB_ASSERT(m_callbacks, is_map(parent));1193// does the parent already have a node with key equal to that of the current duplicate?1194size_t rep = NONE, rep_pos = NONE;1195for(size_t j = first_child(parent), jcount = 0; j != NONE; ++jcount, j = next_sibling(j))1196{1197if(key(j) == key(i))1198{1199rep = j;1200rep_pos = jcount;1201break;1202}1203}1204if(rep == NONE) // there is no repetition; just duplicate1205{1206prev = duplicate(src, i, parent, prev);1207}1208else // yes, there is a repetition1209{1210if(after_pos != NONE && rep_pos < after_pos)1211{1212// rep is located before the node which will be inserted,1213// and will be overridden by the duplicate. So replace it.1214remove(rep);1215prev = duplicate(src, i, parent, prev);1216}1217else if(prev == NONE)1218{1219// first iteration with prev = after = NONE and repetition1220prev = rep;1221}1222else if(rep != prev)1223{1224// rep is located after the node which will be inserted1225// and overrides it. So move the rep into this node's place.1226move(rep, prev);1227prev = rep;1228}1229} // there's a repetition1230}1231}12321233return prev;1234}123512361237//-----------------------------------------------------------------------------12381239void Tree::merge_with(Tree const *src, size_t src_node, size_t dst_node)1240{1241_RYML_CB_ASSERT(m_callbacks, src != nullptr);1242if(src_node == NONE)1243src_node = src->root_id();1244if(dst_node == NONE)1245dst_node = root_id();1246_RYML_CB_ASSERT(m_callbacks, src->has_val(src_node) || src->is_seq(src_node) || src->is_map(src_node));12471248if(src->has_val(src_node))1249{1250if( ! has_val(dst_node))1251{1252if(has_children(dst_node))1253remove_children(dst_node);1254}1255if(src->is_keyval(src_node))1256_copy_props(dst_node, src, src_node);1257else if(src->is_val(src_node))1258_copy_props_wo_key(dst_node, src, src_node);1259else1260C4_NEVER_REACH();1261}1262else if(src->is_seq(src_node))1263{1264if( ! is_seq(dst_node))1265{1266if(has_children(dst_node))1267remove_children(dst_node);1268_clear_type(dst_node);1269if(src->has_key(src_node))1270to_seq(dst_node, src->key(src_node));1271else1272to_seq(dst_node);1273}1274for(size_t sch = src->first_child(src_node); sch != NONE; sch = src->next_sibling(sch))1275{1276size_t dch = append_child(dst_node);1277_copy_props_wo_key(dch, src, sch);1278merge_with(src, sch, dch);1279}1280}1281else if(src->is_map(src_node))1282{1283if( ! is_map(dst_node))1284{1285if(has_children(dst_node))1286remove_children(dst_node);1287_clear_type(dst_node);1288if(src->has_key(src_node))1289to_map(dst_node, src->key(src_node));1290else1291to_map(dst_node);1292}1293for(size_t sch = src->first_child(src_node); sch != NONE; sch = src->next_sibling(sch))1294{1295size_t dch = find_child(dst_node, src->key(sch));1296if(dch == NONE)1297{1298dch = append_child(dst_node);1299_copy_props(dch, src, sch);1300}1301merge_with(src, sch, dch);1302}1303}1304else1305{1306C4_NEVER_REACH();1307}1308}130913101311//-----------------------------------------------------------------------------13121313namespace detail {1314/** @todo make this part of the public API, refactoring as appropriate1315* to be able to use the same resolver to handle multiple trees (one1316* at a time) */1317struct ReferenceResolver1318{1319struct refdata1320{1321NodeType type;1322size_t node;1323size_t prev_anchor;1324size_t target;1325size_t parent_ref;1326size_t parent_ref_sibling;1327};13281329Tree *t;1330/** from the specs: "an alias node refers to the most recent1331* node in the serialization having the specified anchor". So1332* we need to start looking upward from ref nodes.1333*1334* @see http://yaml.org/spec/1.2/spec.html#id2765878 */1335stack<refdata> refs;13361337ReferenceResolver(Tree *t_) : t(t_), refs(t_->callbacks())1338{1339resolve();1340}13411342void store_anchors_and_refs()1343{1344// minimize (re-)allocations by counting first1345size_t num_anchors_and_refs = count_anchors_and_refs(t->root_id());1346if(!num_anchors_and_refs)1347return;1348refs.reserve(num_anchors_and_refs);13491350// now descend through the hierarchy1351_store_anchors_and_refs(t->root_id());13521353// finally connect the reference list1354size_t prev_anchor = npos;1355size_t count = 0;1356for(auto &rd : refs)1357{1358rd.prev_anchor = prev_anchor;1359if(rd.type.is_anchor())1360prev_anchor = count;1361++count;1362}1363}13641365size_t count_anchors_and_refs(size_t n)1366{1367size_t c = 0;1368c += t->has_key_anchor(n);1369c += t->has_val_anchor(n);1370c += t->is_key_ref(n);1371c += t->is_val_ref(n);1372for(size_t ch = t->first_child(n); ch != NONE; ch = t->next_sibling(ch))1373c += count_anchors_and_refs(ch);1374return c;1375}13761377void _store_anchors_and_refs(size_t n)1378{1379if(t->is_key_ref(n) || t->is_val_ref(n) || (t->has_key(n) && t->key(n) == "<<"))1380{1381if(t->is_seq(n))1382{1383// for merging multiple inheritance targets1384// <<: [ *CENTER, *BIG ]1385for(size_t ich = t->first_child(n); ich != NONE; ich = t->next_sibling(ich))1386{1387RYML_ASSERT(t->num_children(ich) == 0);1388refs.push({VALREF, ich, npos, npos, n, t->next_sibling(n)});1389}1390return;1391}1392if(t->is_key_ref(n) && t->key(n) != "<<") // insert key refs BEFORE inserting val refs1393{1394RYML_CHECK((!t->has_key(n)) || t->key(n).ends_with(t->key_ref(n)));1395refs.push({KEYREF, n, npos, npos, NONE, NONE});1396}1397if(t->is_val_ref(n))1398{1399RYML_CHECK((!t->has_val(n)) || t->val(n).ends_with(t->val_ref(n)));1400refs.push({VALREF, n, npos, npos, NONE, NONE});1401}1402}1403if(t->has_key_anchor(n))1404{1405RYML_CHECK(t->has_key(n));1406refs.push({KEYANCH, n, npos, npos, NONE, NONE});1407}1408if(t->has_val_anchor(n))1409{1410RYML_CHECK(t->has_val(n) || t->is_container(n));1411refs.push({VALANCH, n, npos, npos, NONE, NONE});1412}1413for(size_t ch = t->first_child(n); ch != NONE; ch = t->next_sibling(ch))1414{1415_store_anchors_and_refs(ch);1416}1417}14181419size_t lookup_(refdata *C4_RESTRICT ra)1420{1421RYML_ASSERT(ra->type.is_key_ref() || ra->type.is_val_ref());1422RYML_ASSERT(ra->type.is_key_ref() != ra->type.is_val_ref());1423csubstr refname;1424if(ra->type.is_val_ref())1425{1426refname = t->val_ref(ra->node);1427}1428else1429{1430RYML_ASSERT(ra->type.is_key_ref());1431refname = t->key_ref(ra->node);1432}1433while(ra->prev_anchor != npos)1434{1435ra = &refs[ra->prev_anchor];1436if(t->has_anchor(ra->node, refname))1437return ra->node;1438}14391440#ifndef RYML_ERRMSG_SIZE1441#define RYML_ERRMSG_SIZE 10241442#endif14431444char errmsg[RYML_ERRMSG_SIZE];1445snprintf(errmsg, RYML_ERRMSG_SIZE, "anchor does not exist: '%.*s'",1446static_cast<int>(refname.size()), refname.data());1447c4::yml::error(errmsg);1448return NONE;1449}14501451void resolve()1452{1453store_anchors_and_refs();1454if(refs.empty())1455return;14561457/* from the specs: "an alias node refers to the most recent1458* node in the serialization having the specified anchor". So1459* we need to start looking upward from ref nodes.1460*1461* @see http://yaml.org/spec/1.2/spec.html#id2765878 */1462for(size_t i = 0, e = refs.size(); i < e; ++i)1463{1464auto &C4_RESTRICT rd = refs.top(i);1465if( ! rd.type.is_ref())1466continue;1467rd.target = lookup_(&rd);1468}1469}14701471}; // ReferenceResolver1472} // namespace detail14731474void Tree::resolve()1475{1476if(m_size == 0)1477return;14781479detail::ReferenceResolver rr(this);14801481// insert the resolved references1482size_t prev_parent_ref = NONE;1483size_t prev_parent_ref_after = NONE;1484for(auto const& C4_RESTRICT rd : rr.refs)1485{1486if( ! rd.type.is_ref())1487continue;1488if(rd.parent_ref != NONE)1489{1490_RYML_CB_ASSERT(m_callbacks, is_seq(rd.parent_ref));1491size_t after, p = parent(rd.parent_ref);1492if(prev_parent_ref != rd.parent_ref)1493{1494after = rd.parent_ref;//prev_sibling(rd.parent_ref_sibling);1495prev_parent_ref_after = after;1496}1497else1498{1499after = prev_parent_ref_after;1500}1501prev_parent_ref = rd.parent_ref;1502prev_parent_ref_after = duplicate_children_no_rep(rd.target, p, after);1503remove(rd.node);1504}1505else1506{1507if(has_key(rd.node) && is_key_ref(rd.node) && key(rd.node) == "<<")1508{1509_RYML_CB_ASSERT(m_callbacks, is_keyval(rd.node));1510size_t p = parent(rd.node);1511size_t after = prev_sibling(rd.node);1512duplicate_children_no_rep(rd.target, p, after);1513remove(rd.node);1514}1515else if(rd.type.is_key_ref())1516{1517_RYML_CB_ASSERT(m_callbacks, is_key_ref(rd.node));1518_RYML_CB_ASSERT(m_callbacks, has_key_anchor(rd.target) || has_val_anchor(rd.target));1519if(has_val_anchor(rd.target) && val_anchor(rd.target) == key_ref(rd.node))1520{1521_RYML_CB_CHECK(m_callbacks, !is_container(rd.target));1522_RYML_CB_CHECK(m_callbacks, has_val(rd.target));1523_p(rd.node)->m_key.scalar = val(rd.target);1524_add_flags(rd.node, KEY);1525}1526else1527{1528_RYML_CB_CHECK(m_callbacks, key_anchor(rd.target) == key_ref(rd.node));1529_p(rd.node)->m_key.scalar = key(rd.target);1530_add_flags(rd.node, VAL);1531}1532}1533else1534{1535_RYML_CB_ASSERT(m_callbacks, rd.type.is_val_ref());1536if(has_key_anchor(rd.target) && key_anchor(rd.target) == val_ref(rd.node))1537{1538_RYML_CB_CHECK(m_callbacks, !is_container(rd.target));1539_RYML_CB_CHECK(m_callbacks, has_val(rd.target));1540_p(rd.node)->m_val.scalar = key(rd.target);1541_add_flags(rd.node, VAL);1542}1543else1544{1545duplicate_contents(rd.target, rd.node);1546}1547}1548}1549}15501551// clear anchors and refs1552for(auto const& C4_RESTRICT ar : rr.refs)1553{1554rem_anchor_ref(ar.node);1555if(ar.parent_ref != NONE)1556if(type(ar.parent_ref) != NOTYPE)1557remove(ar.parent_ref);1558}15591560}15611562//-----------------------------------------------------------------------------15631564size_t Tree::num_children(size_t node) const1565{1566size_t count = 0;1567for(size_t i = first_child(node); i != NONE; i = next_sibling(i))1568++count;1569return count;1570}15711572size_t Tree::child(size_t node, size_t pos) const1573{1574_RYML_CB_ASSERT(m_callbacks, node != NONE);1575size_t count = 0;1576for(size_t i = first_child(node); i != NONE; i = next_sibling(i))1577{1578if(count++ == pos)1579return i;1580}1581return NONE;1582}15831584size_t Tree::child_pos(size_t node, size_t ch) const1585{1586size_t count = 0;1587for(size_t i = first_child(node); i != NONE; i = next_sibling(i))1588{1589if(i == ch)1590return count;1591++count;1592}1593return npos;1594}15951596#if defined(__clang__)1597# pragma clang diagnostic push1598# pragma GCC diagnostic ignored "-Wnull-dereference"1599#elif defined(__GNUC__)1600# pragma GCC diagnostic push1601# if __GNUC__ >= 61602# pragma GCC diagnostic ignored "-Wnull-dereference"1603# endif1604#endif16051606size_t Tree::find_child(size_t node, csubstr const& name) const1607{1608_RYML_CB_ASSERT(m_callbacks, node != NONE);1609_RYML_CB_ASSERT(m_callbacks, is_map(node));1610if(get(node)->m_first_child == NONE)1611{1612_RYML_CB_ASSERT(m_callbacks, _p(node)->m_last_child == NONE);1613return NONE;1614}1615else1616{1617_RYML_CB_ASSERT(m_callbacks, _p(node)->m_last_child != NONE);1618}1619for(size_t i = first_child(node); i != NONE; i = next_sibling(i))1620{1621if(_p(i)->m_key.scalar == name)1622{1623return i;1624}1625}1626return NONE;1627}16281629#if defined(__clang__)1630# pragma clang diagnostic pop1631#elif defined(__GNUC__)1632# pragma GCC diagnostic pop1633#endif163416351636//-----------------------------------------------------------------------------16371638void Tree::to_val(size_t node, csubstr val, type_bits more_flags)1639{1640_RYML_CB_ASSERT(m_callbacks, ! has_children(node));1641_RYML_CB_ASSERT(m_callbacks, parent(node) == NONE || ! parent_is_map(node));1642_set_flags(node, VAL|more_flags);1643_p(node)->m_key.clear();1644_p(node)->m_val = val;1645}16461647void Tree::to_keyval(size_t node, csubstr key, csubstr val, type_bits more_flags)1648{1649_RYML_CB_ASSERT(m_callbacks, ! has_children(node));1650_RYML_CB_ASSERT(m_callbacks, parent(node) == NONE || parent_is_map(node));1651_set_flags(node, KEYVAL|more_flags);1652_p(node)->m_key = key;1653_p(node)->m_val = val;1654}16551656void Tree::to_map(size_t node, type_bits more_flags)1657{1658_RYML_CB_ASSERT(m_callbacks, ! has_children(node));1659_RYML_CB_ASSERT(m_callbacks, parent(node) == NONE || ! parent_is_map(node)); // parent must not have children with keys1660_set_flags(node, MAP|more_flags);1661_p(node)->m_key.clear();1662_p(node)->m_val.clear();1663}16641665void Tree::to_map(size_t node, csubstr key, type_bits more_flags)1666{1667_RYML_CB_ASSERT(m_callbacks, ! has_children(node));1668_RYML_CB_ASSERT(m_callbacks, parent(node) == NONE || parent_is_map(node));1669_set_flags(node, KEY|MAP|more_flags);1670_p(node)->m_key = key;1671_p(node)->m_val.clear();1672}16731674void Tree::to_seq(size_t node, type_bits more_flags)1675{1676_RYML_CB_ASSERT(m_callbacks, ! has_children(node));1677_RYML_CB_ASSERT(m_callbacks, parent(node) == NONE || parent_is_seq(node));1678_set_flags(node, SEQ|more_flags);1679_p(node)->m_key.clear();1680_p(node)->m_val.clear();1681}16821683void Tree::to_seq(size_t node, csubstr key, type_bits more_flags)1684{1685_RYML_CB_ASSERT(m_callbacks, ! has_children(node));1686_RYML_CB_ASSERT(m_callbacks, parent(node) == NONE || parent_is_map(node));1687_set_flags(node, KEY|SEQ|more_flags);1688_p(node)->m_key = key;1689_p(node)->m_val.clear();1690}16911692void Tree::to_doc(size_t node, type_bits more_flags)1693{1694_RYML_CB_ASSERT(m_callbacks, ! has_children(node));1695_set_flags(node, DOC|more_flags);1696_p(node)->m_key.clear();1697_p(node)->m_val.clear();1698}16991700void Tree::to_stream(size_t node, type_bits more_flags)1701{1702_RYML_CB_ASSERT(m_callbacks, ! has_children(node));1703_set_flags(node, STREAM|more_flags);1704_p(node)->m_key.clear();1705_p(node)->m_val.clear();1706}170717081709//-----------------------------------------------------------------------------1710size_t Tree::num_tag_directives() const1711{1712// this assumes we have a very small number of tag directives1713for(size_t i = 0; i < RYML_MAX_TAG_DIRECTIVES; ++i)1714if(m_tag_directives[i].handle.empty())1715return i;1716return RYML_MAX_TAG_DIRECTIVES;1717}17181719void Tree::clear_tag_directives()1720{1721for(TagDirective &td : m_tag_directives)1722td = {};1723}17241725size_t Tree::add_tag_directive(TagDirective const& td)1726{1727_RYML_CB_CHECK(m_callbacks, !td.handle.empty());1728_RYML_CB_CHECK(m_callbacks, !td.prefix.empty());1729_RYML_CB_ASSERT(m_callbacks, td.handle.begins_with('!'));1730_RYML_CB_ASSERT(m_callbacks, td.handle.ends_with('!'));1731// https://yaml.org/spec/1.2.2/#rule-ns-word-char1732_RYML_CB_ASSERT(m_callbacks, td.handle == '!' || td.handle == "!!" || td.handle.trim('!').first_not_of("01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-") == npos);1733size_t pos = num_tag_directives();1734_RYML_CB_CHECK(m_callbacks, pos < RYML_MAX_TAG_DIRECTIVES);1735m_tag_directives[pos] = td;1736return pos;1737}17381739size_t Tree::resolve_tag(substr output, csubstr tag, size_t node_id) const1740{1741// lookup from the end. We want to find the first directive that1742// matches the tag and has a target node id leq than the given1743// node_id.1744for(size_t i = RYML_MAX_TAG_DIRECTIVES-1; i != (size_t)-1; --i)1745{1746auto const& td = m_tag_directives[i];1747if(td.handle.empty())1748continue;1749if(tag.begins_with(td.handle) && td.next_node_id <= node_id)1750{1751_RYML_CB_ASSERT(m_callbacks, tag.len >= td.handle.len);1752csubstr rest = tag.sub(td.handle.len);1753size_t len = 1u + td.prefix.len + rest.len + 1u;1754size_t numpc = rest.count('%');1755if(numpc == 0)1756{1757if(len <= output.len)1758{1759output.str[0] = '<';1760memcpy(1u + output.str, td.prefix.str, td.prefix.len);1761memcpy(1u + output.str + td.prefix.len, rest.str, rest.len);1762output.str[1u + td.prefix.len + rest.len] = '>';1763}1764}1765else1766{1767// need to decode URI % sequences1768size_t pos = rest.find('%');1769_RYML_CB_ASSERT(m_callbacks, pos != npos);1770do {1771size_t next = rest.first_not_of("0123456789abcdefABCDEF", pos+1);1772if(next == npos)1773next = rest.len;1774_RYML_CB_CHECK(m_callbacks, pos+1 < next);1775_RYML_CB_CHECK(m_callbacks, pos+1 + 2 <= next);1776size_t delta = next - (pos+1);1777len -= delta;1778pos = rest.find('%', pos+1);1779} while(pos != npos);1780if(len <= output.len)1781{1782size_t prev = 0, wpos = 0;1783auto appendstr = [&](csubstr s) { memcpy(output.str + wpos, s.str, s.len); wpos += s.len; };1784auto appendchar = [&](char c) { output.str[wpos++] = c; };1785appendchar('<');1786appendstr(td.prefix);1787pos = rest.find('%');1788_RYML_CB_ASSERT(m_callbacks, pos != npos);1789do {1790size_t next = rest.first_not_of("0123456789abcdefABCDEF", pos+1);1791if(next == npos)1792next = rest.len;1793_RYML_CB_CHECK(m_callbacks, pos+1 < next);1794_RYML_CB_CHECK(m_callbacks, pos+1 + 2 <= next);1795uint8_t val;1796if(C4_UNLIKELY(!read_hex(rest.range(pos+1, next), &val) || val > 127))1797_RYML_CB_ERR(m_callbacks, "invalid URI character");1798appendstr(rest.range(prev, pos));1799appendchar((char)val);1800prev = next;1801pos = rest.find('%', pos+1);1802} while(pos != npos);1803_RYML_CB_ASSERT(m_callbacks, pos == npos);1804_RYML_CB_ASSERT(m_callbacks, prev > 0);1805_RYML_CB_ASSERT(m_callbacks, rest.len >= prev);1806appendstr(rest.sub(prev));1807appendchar('>');1808_RYML_CB_ASSERT(m_callbacks, wpos == len);1809}1810}1811return len;1812}1813}1814return 0; // return 0 to signal that the tag is local and cannot be resolved1815}18161817namespace {1818csubstr _transform_tag(Tree *t, csubstr tag, size_t node)1819{1820size_t required_size = t->resolve_tag(substr{}, tag, node);1821if(!required_size)1822return tag;1823const char *prev_arena = t->arena().str;1824substr buf = t->alloc_arena(required_size);1825_RYML_CB_ASSERT(t->m_callbacks, t->arena().str == prev_arena);1826size_t actual_size = t->resolve_tag(buf, tag, node);1827_RYML_CB_ASSERT(t->m_callbacks, actual_size <= required_size);1828return buf.first(actual_size);1829}1830void _resolve_tags(Tree *t, size_t node)1831{1832for(size_t child = t->first_child(node); child != NONE; child = t->next_sibling(child))1833{1834if(t->has_key(child) && t->has_key_tag(child))1835t->set_key_tag(child, _transform_tag(t, t->key_tag(child), child));1836if(t->has_val(child) && t->has_val_tag(child))1837t->set_val_tag(child, _transform_tag(t, t->val_tag(child), child));1838_resolve_tags(t, child);1839}1840}1841size_t _count_resolved_tags_size(Tree const* t, size_t node)1842{1843size_t sz = 0;1844for(size_t child = t->first_child(node); child != NONE; child = t->next_sibling(child))1845{1846if(t->has_key(child) && t->has_key_tag(child))1847sz += t->resolve_tag(substr{}, t->key_tag(child), child);1848if(t->has_val(child) && t->has_val_tag(child))1849sz += t->resolve_tag(substr{}, t->val_tag(child), child);1850sz += _count_resolved_tags_size(t, child);1851}1852return sz;1853}1854} // namespace18551856void Tree::resolve_tags()1857{1858if(empty())1859return;1860if(num_tag_directives() == 0)1861return;1862size_t needed_size = _count_resolved_tags_size(this, root_id());1863if(needed_size)1864reserve_arena(arena_size() + needed_size);1865_resolve_tags(this, root_id());1866}186718681869//-----------------------------------------------------------------------------18701871csubstr Tree::lookup_result::resolved() const1872{1873csubstr p = path.first(path_pos);1874if(p.ends_with('.'))1875p = p.first(p.len-1);1876return p;1877}18781879csubstr Tree::lookup_result::unresolved() const1880{1881return path.sub(path_pos);1882}18831884void Tree::_advance(lookup_result *r, size_t more) const1885{1886r->path_pos += more;1887if(r->path.sub(r->path_pos).begins_with('.'))1888++r->path_pos;1889}18901891Tree::lookup_result Tree::lookup_path(csubstr path, size_t start) const1892{1893if(start == NONE)1894start = root_id();1895lookup_result r(path, start);1896if(path.empty())1897return r;1898_lookup_path(&r);1899if(r.target == NONE && r.closest == start)1900r.closest = NONE;1901return r;1902}19031904size_t Tree::lookup_path_or_modify(csubstr default_value, csubstr path, size_t start)1905{1906size_t target = _lookup_path_or_create(path, start);1907if(parent_is_map(target))1908to_keyval(target, key(target), default_value);1909else1910to_val(target, default_value);1911return target;1912}19131914size_t Tree::lookup_path_or_modify(Tree const *src, size_t src_node, csubstr path, size_t start)1915{1916size_t target = _lookup_path_or_create(path, start);1917merge_with(src, src_node, target);1918return target;1919}19201921size_t Tree::_lookup_path_or_create(csubstr path, size_t start)1922{1923if(start == NONE)1924start = root_id();1925lookup_result r(path, start);1926_lookup_path(&r);1927if(r.target != NONE)1928{1929C4_ASSERT(r.unresolved().empty());1930return r.target;1931}1932_lookup_path_modify(&r);1933return r.target;1934}19351936void Tree::_lookup_path(lookup_result *r) const1937{1938C4_ASSERT( ! r->unresolved().empty());1939_lookup_path_token parent{"", type(r->closest)};1940size_t node;1941do1942{1943node = _next_node(r, &parent);1944if(node != NONE)1945r->closest = node;1946if(r->unresolved().empty())1947{1948r->target = node;1949return;1950}1951} while(node != NONE);1952}19531954void Tree::_lookup_path_modify(lookup_result *r)1955{1956C4_ASSERT( ! r->unresolved().empty());1957_lookup_path_token parent{"", type(r->closest)};1958size_t node;1959do1960{1961node = _next_node_modify(r, &parent);1962if(node != NONE)1963r->closest = node;1964if(r->unresolved().empty())1965{1966r->target = node;1967return;1968}1969} while(node != NONE);1970}19711972size_t Tree::_next_node(lookup_result * r, _lookup_path_token *parent) const1973{1974_lookup_path_token token = _next_token(r, *parent);1975if( ! token)1976return NONE;19771978size_t node = NONE;1979csubstr prev = token.value;1980if(token.type == MAP || token.type == SEQ)1981{1982_RYML_CB_ASSERT(m_callbacks, !token.value.begins_with('['));1983//_RYML_CB_ASSERT(m_callbacks, is_container(r->closest) || r->closest == NONE);1984_RYML_CB_ASSERT(m_callbacks, is_map(r->closest));1985node = find_child(r->closest, token.value);1986}1987else if(token.type == KEYVAL)1988{1989_RYML_CB_ASSERT(m_callbacks, r->unresolved().empty());1990if(is_map(r->closest))1991node = find_child(r->closest, token.value);1992}1993else if(token.type == KEY)1994{1995_RYML_CB_ASSERT(m_callbacks, token.value.begins_with('[') && token.value.ends_with(']'));1996token.value = token.value.offs(1, 1).trim(' ');1997size_t idx = 0;1998_RYML_CB_CHECK(m_callbacks, from_chars(token.value, &idx));1999node = child(r->closest, idx);2000}2001else2002{2003C4_NEVER_REACH();2004}20052006if(node != NONE)2007{2008*parent = token;2009}2010else2011{2012csubstr p = r->path.sub(r->path_pos > 0 ? r->path_pos - 1 : r->path_pos);2013r->path_pos -= prev.len;2014if(p.begins_with('.'))2015r->path_pos -= 1u;2016}20172018return node;2019}20202021size_t Tree::_next_node_modify(lookup_result * r, _lookup_path_token *parent)2022{2023_lookup_path_token token = _next_token(r, *parent);2024if( ! token)2025return NONE;20262027size_t node = NONE;2028if(token.type == MAP || token.type == SEQ)2029{2030_RYML_CB_ASSERT(m_callbacks, !token.value.begins_with('['));2031//_RYML_CB_ASSERT(m_callbacks, is_container(r->closest) || r->closest == NONE);2032if( ! is_container(r->closest))2033{2034if(has_key(r->closest))2035to_map(r->closest, key(r->closest));2036else2037to_map(r->closest);2038}2039else2040{2041if(is_map(r->closest))2042node = find_child(r->closest, token.value);2043else2044{2045size_t pos = NONE;2046_RYML_CB_CHECK(m_callbacks, c4::atox(token.value, &pos));2047_RYML_CB_ASSERT(m_callbacks, pos != NONE);2048node = child(r->closest, pos);2049}2050}2051if(node == NONE)2052{2053_RYML_CB_ASSERT(m_callbacks, is_map(r->closest));2054node = append_child(r->closest);2055NodeData *n = _p(node);2056n->m_key.scalar = token.value;2057n->m_type.add(KEY);2058}2059}2060else if(token.type == KEYVAL)2061{2062_RYML_CB_ASSERT(m_callbacks, r->unresolved().empty());2063if(is_map(r->closest))2064{2065node = find_child(r->closest, token.value);2066if(node == NONE)2067node = append_child(r->closest);2068}2069else2070{2071_RYML_CB_ASSERT(m_callbacks, !is_seq(r->closest));2072_add_flags(r->closest, MAP);2073node = append_child(r->closest);2074}2075NodeData *n = _p(node);2076n->m_key.scalar = token.value;2077n->m_val.scalar = "";2078n->m_type.add(KEYVAL);2079}2080else if(token.type == KEY)2081{2082_RYML_CB_ASSERT(m_callbacks, token.value.begins_with('[') && token.value.ends_with(']'));2083token.value = token.value.offs(1, 1).trim(' ');2084size_t idx;2085if( ! from_chars(token.value, &idx))2086return NONE;2087if( ! is_container(r->closest))2088{2089if(has_key(r->closest))2090{2091csubstr k = key(r->closest);2092_clear_type(r->closest);2093to_seq(r->closest, k);2094}2095else2096{2097_clear_type(r->closest);2098to_seq(r->closest);2099}2100}2101_RYML_CB_ASSERT(m_callbacks, is_container(r->closest));2102node = child(r->closest, idx);2103if(node == NONE)2104{2105_RYML_CB_ASSERT(m_callbacks, num_children(r->closest) <= idx);2106for(size_t i = num_children(r->closest); i <= idx; ++i)2107{2108node = append_child(r->closest);2109if(i < idx)2110{2111if(is_map(r->closest))2112to_keyval(node, /*"~"*/{}, /*"~"*/{});2113else if(is_seq(r->closest))2114to_val(node, /*"~"*/{});2115}2116}2117}2118}2119else2120{2121C4_NEVER_REACH();2122}21232124_RYML_CB_ASSERT(m_callbacks, node != NONE);2125*parent = token;2126return node;2127}21282129/** types of tokens:2130* - seeing "map." ---> "map"/MAP2131* - finishing "scalar" ---> "scalar"/KEYVAL2132* - seeing "seq[n]" ---> "seq"/SEQ (--> "[n]"/KEY)2133* - seeing "[n]" ---> "[n]"/KEY2134*/2135Tree::_lookup_path_token Tree::_next_token(lookup_result *r, _lookup_path_token const& parent) const2136{2137csubstr unres = r->unresolved();2138if(unres.empty())2139return {};21402141// is it an indexation like [0], [1], etc?2142if(unres.begins_with('['))2143{2144size_t pos = unres.find(']');2145if(pos == csubstr::npos)2146return {};2147csubstr idx = unres.first(pos + 1);2148_advance(r, pos + 1);2149return {idx, KEY};2150}21512152// no. so it must be a name2153size_t pos = unres.first_of(".[");2154if(pos == csubstr::npos)2155{2156_advance(r, unres.len);2157NodeType t;2158if(( ! parent) || parent.type.is_seq())2159return {unres, VAL};2160return {unres, KEYVAL};2161}21622163// it's either a map or a seq2164_RYML_CB_ASSERT(m_callbacks, unres[pos] == '.' || unres[pos] == '[');2165if(unres[pos] == '.')2166{2167_RYML_CB_ASSERT(m_callbacks, pos != 0);2168_advance(r, pos + 1);2169return {unres.first(pos), MAP};2170}21712172_RYML_CB_ASSERT(m_callbacks, unres[pos] == '[');2173_advance(r, pos);2174return {unres.first(pos), SEQ};2175}217621772178} // namespace ryml2179} // namespace c4218021812182C4_SUPPRESS_WARNING_GCC_CLANG_POP2183C4_SUPPRESS_WARNING_MSVC_POP218421852186