rapidyaml  0.11.1
parse and emit YAML, and do it fast
reference_resolver.hpp
Go to the documentation of this file.
1 #ifndef _C4_YML_REFERENCE_RESOLVER_HPP_
2 #define _C4_YML_REFERENCE_RESOLVER_HPP_
3 
4 #include "c4/yml/tree.hpp"
5 #include "c4/yml/detail/stack.hpp"
6 
7 
8 namespace c4 {
9 namespace yml {
10 
11 /** @addtogroup doc_ref_utils
12  * @{
13  */
14 
15 /** Reusable object to resolve references/aliases in a @ref Tree. */
17 {
18  ReferenceResolver() = default;
19 
20  /** Resolve references: for each reference, look for a matching
21  * anchor, and copy its contents to the ref node.
22  *
23  * @p tree the subject tree
24  *
25  * @p clear_anchors whether to clear existing anchors after
26  * resolving
27  *
28  * This method first does a full traversal of the tree to gather
29  * all anchors and references in a separate collection, then it
30  * goes through that collection to locate the names, which it does
31  * by obeying the YAML standard diktat that "an alias node refers
32  * to the most recent node in the serialization having the
33  * specified anchor"
34  *
35  * So, depending on the number of anchor/alias nodes, this is a
36  * potentially expensive operation, with a best-case linear
37  * complexity (from the initial traversal). This potential cost is
38  * one of the reasons for requiring an explicit call.
39  *
40  * The @ref Tree has an `Tree::resolve()` overload set forwarding
41  * here. Previously this operation was done there, using a
42  * discarded object; using this separate class offers opportunity
43  * for reuse of the object.
44  *
45  * @warning resolving references opens an attack vector when the
46  * data is malicious or severely malformed, as the tree can expand
47  * exponentially. See for example the [Billion Laughs
48  * Attack](https://en.wikipedia.org/wiki/Billion_laughs_attack).
49  *
50  */
51  void resolve(Tree *tree, bool clear_anchors=true);
52 
53 public:
54 
55  /** @cond dev */
56 
57  struct RefData
58  {
59  NodeType type;
60  id_type node;
61  id_type prev_anchor;
62  id_type target;
63  id_type parent_ref;
64  id_type parent_ref_sibling;
65  };
66 
67  void reset_(Tree *t_);
68  void resolve_();
69  void gather_anchors_and_refs_();
70  void gather_anchors_and_refs__(id_type n);
71  id_type count_anchors_and_refs_(id_type n);
72 
73  id_type lookup_(RefData const* C4_RESTRICT ra);
74 
75  Tree *C4_RESTRICT m_tree;
76  /** We're using this stack purely as an array. */
77  detail::stack<RefData> m_refs;
78 
79  /** @endcond */
80 };
81 
82 /** @} */
83 
84 } // namespace ryml
85 } // namespace c4
86 
87 
88 #endif // _C4_YML_REFERENCE_RESOLVER_HPP_
#define RYML_EXPORT
Definition: export.hpp:15
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:244
(Undefined by default) Use shorter error message from checks/asserts: do not show the check condition...
Definition: common.cpp:14
wraps a NodeType_e element with some syntactic sugar and predicates
Definition: node_type.hpp:120
Reusable object to resolve references/aliases in a Tree.
void resolve(Tree *tree, bool clear_anchors=true)
Resolve references: for each reference, look for a matching anchor, and copy its contents to the ref ...