Resolve references: for each reference, look for a matching anchor, and copy its contents to the ref node.
This method first does a full traversal of the tree to gather all anchors and references in a separate collection, then it goes through that collection to locate the names, which it does by obeying the YAML standard diktat that "an alias node refers to the most recent node in the serialization having the specified anchor"
So, depending on the number of anchor/alias nodes, this is a potentially expensive operation, with a best-case linear complexity (from the initial traversal).
170 _c4dbgp(
"resolving references...");
176 gather_anchors_and_refs_();
185 _c4dbgp(
"matching anchors/refs...");
186 for(
id_type i = 0, e = m_refs.size(); i < e; ++i)
188 RefData &C4_RESTRICT refdata = m_refs.top(i);
189 if( ! refdata.type.is_ref())
191 refdata.target = lookup_(&refdata);
193 _c4dbgp(
"matching anchors/refs: finished");
196 _c4dbgp(
"modifying tree...");
199 for(
id_type i = 0, e = m_refs.size(); i < e; ++i)
201 RefData
const& C4_RESTRICT refdata = m_refs[i];
202 _c4dbgpf(
"instance {}/{}...", i, e);
203 if( ! refdata.type.is_ref())
205 _c4dbgpf(
"instance {} is reference!", i);
206 if(refdata.parent_ref !=
NONE)
208 _c4dbgpf(
"ref {} has parent: {}", i, refdata.parent_ref);
209 _RYML_CB_ASSERT(m_tree->m_callbacks, m_tree->is_seq(refdata.parent_ref));
210 const id_type p = m_tree->parent(refdata.parent_ref);
211 const id_type after = (prev_parent_ref != refdata.parent_ref) ?
214 prev_parent_ref_after;
215 prev_parent_ref = refdata.parent_ref;
216 prev_parent_ref_after = m_tree->duplicate_children_no_rep(refdata.target, p, after);
217 m_tree->remove(refdata.node);
221 _c4dbgpf(
"ref {} has no parent", i, refdata.parent_ref);
222 if(m_tree->has_key(refdata.node) && m_tree->key(refdata.node) ==
"<<")
224 _c4dbgpf(
"ref {} is inheriting", i);
225 _RYML_CB_ASSERT(m_tree->m_callbacks, m_tree->is_keyval(refdata.node));
226 const id_type p = m_tree->parent(refdata.node);
227 const id_type after = m_tree->prev_sibling(refdata.node);
228 m_tree->duplicate_children_no_rep(refdata.target, p, after);
229 m_tree->remove(refdata.node);
231 else if(refdata.type.is_key_ref())
233 _c4dbgpf(
"ref {} is key ref", i);
234 _RYML_CB_ASSERT(m_tree->m_callbacks, m_tree->is_key_ref(refdata.node));
235 _RYML_CB_ASSERT(m_tree->m_callbacks, m_tree->has_key_anchor(refdata.target) || m_tree->has_val_anchor(refdata.target));
236 if(m_tree->has_val_anchor(refdata.target) && m_tree->val_anchor(refdata.target) == m_tree->key_ref(refdata.node))
238 _RYML_CB_CHECK(m_tree->m_callbacks, !m_tree->is_container(refdata.target));
239 _RYML_CB_CHECK(m_tree->m_callbacks, m_tree->has_val(refdata.target));
240 const type_bits existing_style_flags =
VAL_STYLE & m_tree->_p(refdata.target)->m_type.type;
242 m_tree->_p(refdata.node)->m_key.scalar = m_tree->val(refdata.target);
243 m_tree->_add_flags(refdata.node,
KEY | (existing_style_flags >> 1u));
247 _RYML_CB_CHECK(m_tree->m_callbacks, m_tree->key_anchor(refdata.target) == m_tree->key_ref(refdata.node));
248 m_tree->_p(refdata.node)->m_key.scalar = m_tree->key(refdata.target);
250 const type_bits existing_style_flags =
KEY_STYLE & m_tree->_p(refdata.target)->m_type.type;
251 m_tree->_add_flags(refdata.node,
KEY | existing_style_flags);
256 _c4dbgpf(
"ref {} is val ref", i);
257 _RYML_CB_ASSERT(m_tree->m_callbacks, refdata.type.is_val_ref());
258 if(m_tree->has_key_anchor(refdata.target) && m_tree->key_anchor(refdata.target) == m_tree->val_ref(refdata.node))
260 _RYML_CB_CHECK(m_tree->m_callbacks, !m_tree->is_container(refdata.target));
261 _RYML_CB_CHECK(m_tree->m_callbacks, m_tree->has_val(refdata.target));
263 const type_bits existing_style_flags = (
KEY_STYLE) & m_tree->_p(refdata.target)->m_type.type;
265 m_tree->_p(refdata.node)->m_val.scalar = m_tree->key(refdata.target);
266 m_tree->_add_flags(refdata.node,
VAL | (existing_style_flags << 1u));
270 m_tree->duplicate_contents(refdata.target, refdata.node);
275 _c4dbgp(
"modifying tree: finished");
278 _c4dbgp(
"clearing anchors/refs");
279 for(
auto const& C4_RESTRICT ar : m_refs)
281 m_tree->rem_anchor_ref(ar.node);
282 if(ar.parent_ref !=
NONE)
283 if(m_tree->type(ar.parent_ref) !=
NOTYPE)
284 m_tree->remove(ar.parent_ref);
286 _c4dbgp(
"clearing anchors/refs: finished");
291 _c4dbgp(
"resolving references: finished");
uint32_t type_bits
the integral type necessary to cover all the bits for NodeType_e
@ NOTYPE
no node type or style is set
@ KEY
is member of a map, must have non-empty key
@ VAL_STYLE
mask of all the scalar styles for val (not container styles!)
@ VAL
a scalar: has a scalar (ie string) value, possibly empty. must be a leaf node, and cannot be MAP or S...
@ KEY_STYLE
mask of all the scalar styles for key (not container styles!)
RYML_ID_TYPE id_type
The type of a node id in the YAML tree; to override the default type, define the macro RYML_ID_TYPE t...