rapidyaml  0.7.0
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  id_type after;
212  if(prev_parent_ref != refdata.parent_ref)
213  {
214  after = refdata.parent_ref;//prev_sibling(rd.parent_ref_sibling);
215  prev_parent_ref_after = after;
216  }
217  else
218  {
219  after = prev_parent_ref_after;
220  }
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);
224  }
225  else
226  {
227  _c4dbgpf("ref {} has no parent", i, refdata.parent_ref);
228  if(m_tree->has_key(refdata.node) && m_tree->key(refdata.node) == "<<")
229  {
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);
236  }
237  else if(refdata.type.is_key_ref())
238  {
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))
243  {
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;
247  static_assert((VAL_STYLE >> 1u) == (KEY_STYLE), "bad flags");
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));
250  }
251  else
252  {
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);
255  // keys cannot be containers, so don't inherit container flags
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);
258  }
259  }
260  else // val ref
261  {
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))
265  {
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));
268  // keys cannot be containers, so don't inherit container flags
269  const type_bits existing_style_flags = (KEY_STYLE) & m_tree->_p(refdata.target)->m_type.type;
270  static_assert((KEY_STYLE << 1u) == (VAL_STYLE), "bad flags");
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));
273  }
274  else
275  {
276  m_tree->duplicate_contents(refdata.target, refdata.node);
277  }
278  }
279  }
280  }
281  _c4dbgp("modifying tree: finished");
282 
283  // clear anchors and refs
284  _c4dbgp("clearing anchors/refs");
285  for(auto const& C4_RESTRICT ar : m_refs)
286  {
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);
291  }
292  _c4dbgp("clearing anchors/refs: finished");
293 
294  _c4dbg_tree("resolved tree", *m_tree);
295 
296  m_tree = nullptr;
297  _c4dbgp("resolving references: finished");
298 }
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: