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);
212 if(prev_parent_ref != refdata.parent_ref)
214 after = refdata.parent_ref;
215 prev_parent_ref_after = after;
219 after = prev_parent_ref_after;
221 prev_parent_ref = refdata.parent_ref;
222 prev_parent_ref_after = m_tree->duplicate_children_no_rep(refdata.target, p, after);
223 m_tree->remove(refdata.node);
227 _c4dbgpf(
"ref {} has no parent", i, refdata.parent_ref);
228 if(m_tree->has_key(refdata.node) && m_tree->key(refdata.node) ==
"<<")
230 _c4dbgpf(
"ref {} is inheriting", i);
231 _RYML_CB_ASSERT(m_tree->m_callbacks, m_tree->is_keyval(refdata.node));
232 const id_type p = m_tree->parent(refdata.node);
233 const id_type after = m_tree->prev_sibling(refdata.node);
234 m_tree->duplicate_children_no_rep(refdata.target, p, after);
235 m_tree->remove(refdata.node);
237 else if(refdata.type.is_key_ref())
239 _c4dbgpf(
"ref {} is key ref", i);
240 _RYML_CB_ASSERT(m_tree->m_callbacks, m_tree->is_key_ref(refdata.node));
241 _RYML_CB_ASSERT(m_tree->m_callbacks, m_tree->has_key_anchor(refdata.target) || m_tree->has_val_anchor(refdata.target));
242 if(m_tree->has_val_anchor(refdata.target) && m_tree->val_anchor(refdata.target) == m_tree->key_ref(refdata.node))
244 _RYML_CB_CHECK(m_tree->m_callbacks, !m_tree->is_container(refdata.target));
245 _RYML_CB_CHECK(m_tree->m_callbacks, m_tree->has_val(refdata.target));
246 const type_bits existing_style_flags =
VAL_STYLE & m_tree->_p(refdata.target)->m_type.type;
248 m_tree->_p(refdata.node)->m_key.scalar = m_tree->val(refdata.target);
249 m_tree->_add_flags(refdata.node,
KEY | (existing_style_flags >> 1u));
253 _RYML_CB_CHECK(m_tree->m_callbacks, m_tree->key_anchor(refdata.target) == m_tree->key_ref(refdata.node));
254 m_tree->_p(refdata.node)->m_key.scalar = m_tree->key(refdata.target);
256 const type_bits existing_style_flags =
KEY_STYLE & m_tree->_p(refdata.target)->m_type.type;
257 m_tree->_add_flags(refdata.node,
KEY | existing_style_flags);
262 _c4dbgpf(
"ref {} is val ref", i);
263 _RYML_CB_ASSERT(m_tree->m_callbacks, refdata.type.is_val_ref());
264 if(m_tree->has_key_anchor(refdata.target) && m_tree->key_anchor(refdata.target) == m_tree->val_ref(refdata.node))
266 _RYML_CB_CHECK(m_tree->m_callbacks, !m_tree->is_container(refdata.target));
267 _RYML_CB_CHECK(m_tree->m_callbacks, m_tree->has_val(refdata.target));
269 const type_bits existing_style_flags = (
KEY_STYLE) & m_tree->_p(refdata.target)->m_type.type;
271 m_tree->_p(refdata.node)->m_val.scalar = m_tree->key(refdata.target);
272 m_tree->_add_flags(refdata.node,
VAL | (existing_style_flags << 1u));
276 m_tree->duplicate_contents(refdata.target, refdata.node);
281 _c4dbgp(
"modifying tree: finished");
284 _c4dbgp(
"clearing anchors/refs");
285 for(
auto const& C4_RESTRICT ar : m_refs)
287 m_tree->rem_anchor_ref(ar.node);
288 if(ar.parent_ref !=
NONE)
289 if(m_tree->type(ar.parent_ref) !=
NOTYPE)
290 m_tree->remove(ar.parent_ref);
292 _c4dbgp(
"clearing anchors/refs: finished");
297 _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...