rapidyaml  0.7.2
parse and emit YAML, and do it fast
c4::yml::ReferenceResolver Struct Reference

Reusable object to resolve references/aliases in the tree. More...

#include <reference_resolver.hpp>

Public Member Functions

 ReferenceResolver ()=default
 
void resolve (Tree *t_)
 Resolve references: for each reference, look for a matching anchor, and copy its contents to the ref node. More...
 

Detailed Description

Reusable object to resolve references/aliases in the tree.

Definition at line 16 of file reference_resolver.hpp.

Constructor & Destructor Documentation

◆ ReferenceResolver()

c4::yml::ReferenceResolver::ReferenceResolver ( )
default

Member Function Documentation

◆ resolve()

void c4::yml::ReferenceResolver::resolve ( Tree t_)

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).

Definition at line 168 of file reference_resolver.cpp.

169 {
170  _c4dbgp("resolving references...");
171 
172  reset_(t_);
173 
174  _c4dbg_tree("unresolved tree", *m_tree);
175 
176  gather_anchors_and_refs_();
177  if(m_refs.empty())
178  return;
179 
180  /* from the specs: "an alias node refers to the most recent
181  * node in the serialization having the specified anchor". So
182  * we need to start looking upward from ref nodes.
183  *
184  * @see http://yaml.org/spec/1.2/spec.html#id2765878 */
185  _c4dbgp("matching anchors/refs...");
186  for(id_type i = 0, e = m_refs.size(); i < e; ++i)
187  {
188  RefData &C4_RESTRICT refdata = m_refs.top(i);
189  if( ! refdata.type.is_ref())
190  continue;
191  refdata.target = lookup_(&refdata);
192  }
193  _c4dbgp("matching anchors/refs: finished");
194 
195  // insert the resolved references
196  _c4dbgp("modifying tree...");
197  id_type prev_parent_ref = NONE;
198  id_type prev_parent_ref_after = NONE;
199  for(id_type i = 0, e = m_refs.size(); i < e; ++i)
200  {
201  RefData const& C4_RESTRICT refdata = m_refs[i];
202  _c4dbgpf("instance {}/{}...", i, e);
203  if( ! refdata.type.is_ref())
204  continue;
205  _c4dbgpf("instance {} is reference!", i);
206  if(refdata.parent_ref != NONE)
207  {
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) ?
212  refdata.parent_ref//prev_sibling(rd.parent_ref_sibling)
213  :
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);
218  }
219  else
220  {
221  _c4dbgpf("ref {} has no parent", i, refdata.parent_ref);
222  if(m_tree->has_key(refdata.node) && m_tree->key(refdata.node) == "<<")
223  {
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);
230  }
231  else if(refdata.type.is_key_ref())
232  {
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))
237  {
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;
241  static_assert((VAL_STYLE >> 1u) == (KEY_STYLE), "bad flags");
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));
244  }
245  else
246  {
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);
249  // keys cannot be containers, so don't inherit container flags
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);
252  }
253  }
254  else // val ref
255  {
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))
259  {
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));
262  // keys cannot be containers, so don't inherit container flags
263  const type_bits existing_style_flags = (KEY_STYLE) & m_tree->_p(refdata.target)->m_type.type;
264  static_assert((KEY_STYLE << 1u) == (VAL_STYLE), "bad flags");
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));
267  }
268  else
269  {
270  m_tree->duplicate_contents(refdata.target, refdata.node);
271  }
272  }
273  }
274  }
275  _c4dbgp("modifying tree: finished");
276 
277  // clear anchors and refs
278  _c4dbgp("clearing anchors/refs");
279  for(auto const& C4_RESTRICT ar : m_refs)
280  {
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);
285  }
286  _c4dbgp("clearing anchors/refs: finished");
287 
288  _c4dbg_tree("resolved tree", *m_tree);
289 
290  m_tree = nullptr;
291  _c4dbgp("resolving references: finished");
292 }
uint32_t type_bits
the integral type necessary to cover all the bits for NodeType_e
Definition: node_type.hpp:26
@ NOTYPE
no node type or style is set
Definition: node_type.hpp:32
@ KEY
is member of a map, must have non-empty key
Definition: node_type.hpp:33
@ VAL_STYLE
mask of all the scalar styles for val (not container styles!)
Definition: node_type.hpp:87
@ VAL
a scalar: has a scalar (ie string) value, possibly empty. must be a leaf node, and cannot be MAP or S...
Definition: node_type.hpp:34
@ KEY_STYLE
mask of all the scalar styles for key (not container styles!)
Definition: node_type.hpp:86
RYML_ID_TYPE id_type
The type of a node id in the YAML tree; to override the default type, define the macro RYML_ID_TYPE t...
Definition: common.hpp:252
@ NONE
an index to none
Definition: common.hpp:259
#define _c4dbg_tree(...)

References _c4dbg_tree, c4::yml::KEY, c4::yml::KEY_STYLE, c4::yml::NONE, c4::yml::NOTYPE, c4::yml::VAL, and c4::yml::VAL_STYLE.


The documentation for this struct was generated from the following files: