1 #include <assert.h>
2 #include <iterator>
3 #include <sstream>
4 
5 #include "yaml-cpp/exceptions.h"
6 #include "yaml-cpp/node/detail/memory.h"
7 #include "yaml-cpp/node/detail/node.h"  // IWYU pragma: keep
8 #include "yaml-cpp/node/detail/node_data.h"
9 #include "yaml-cpp/node/detail/node_iterator.h"
10 #include "yaml-cpp/node/ptr.h"
11 #include "yaml-cpp/node/type.h"
12 
13 namespace YAML {
14 namespace detail {
15 
16 std::string node_data::empty_scalar;
17 
node_data()18 node_data::node_data()
19     : m_isDefined(false),
20       m_mark(Mark::null_mark()),
21       m_type(NodeType::Null),
22       m_style(EmitterStyle::Default),
23       m_seqSize(0) {}
24 
mark_defined()25 void node_data::mark_defined() {
26   if (m_type == NodeType::Undefined)
27     m_type = NodeType::Null;
28   m_isDefined = true;
29 }
30 
set_mark(const Mark & mark)31 void node_data::set_mark(const Mark& mark) { m_mark = mark; }
32 
set_type(NodeType::value type)33 void node_data::set_type(NodeType::value type) {
34   if (type == NodeType::Undefined) {
35     m_type = type;
36     m_isDefined = false;
37     return;
38   }
39 
40   m_isDefined = true;
41   if (type == m_type)
42     return;
43 
44   m_type = type;
45 
46   switch (m_type) {
47     case NodeType::Null:
48       break;
49     case NodeType::Scalar:
50       m_scalar.clear();
51       break;
52     case NodeType::Sequence:
53       reset_sequence();
54       break;
55     case NodeType::Map:
56       reset_map();
57       break;
58     case NodeType::Undefined:
59       assert(false);
60       break;
61   }
62 }
63 
set_tag(const std::string & tag)64 void node_data::set_tag(const std::string& tag) { m_tag = tag; }
65 
set_style(EmitterStyle::value style)66 void node_data::set_style(EmitterStyle::value style) { m_style = style; }
67 
set_null()68 void node_data::set_null() {
69   m_isDefined = true;
70   m_type = NodeType::Null;
71 }
72 
set_scalar(const std::string & scalar)73 void node_data::set_scalar(const std::string& scalar) {
74   m_isDefined = true;
75   m_type = NodeType::Scalar;
76   m_scalar = scalar;
77 }
78 
79 // size/iterator
size() const80 std::size_t node_data::size() const {
81   if (!m_isDefined)
82     return 0;
83 
84   switch (m_type) {
85     case NodeType::Sequence:
86       compute_seq_size();
87       return m_seqSize;
88     case NodeType::Map:
89       compute_map_size();
90       return m_map.size() - m_undefinedPairs.size();
91     default:
92       return 0;
93   }
94   return 0;
95 }
96 
compute_seq_size() const97 void node_data::compute_seq_size() const {
98   while (m_seqSize < m_sequence.size() && m_sequence[m_seqSize]->is_defined())
99     m_seqSize++;
100 }
101 
compute_map_size() const102 void node_data::compute_map_size() const {
103   kv_pairs::iterator it = m_undefinedPairs.begin();
104   while (it != m_undefinedPairs.end()) {
105     kv_pairs::iterator jt = std::next(it);
106     if (it->first->is_defined() && it->second->is_defined())
107       m_undefinedPairs.erase(it);
108     it = jt;
109   }
110 }
111 
begin() const112 const_node_iterator node_data::begin() const {
113   if (!m_isDefined)
114     return const_node_iterator();
115 
116   switch (m_type) {
117     case NodeType::Sequence:
118       return const_node_iterator(m_sequence.begin());
119     case NodeType::Map:
120       return const_node_iterator(m_map.begin(), m_map.end());
121     default:
122       return const_node_iterator();
123   }
124 }
125 
begin()126 node_iterator node_data::begin() {
127   if (!m_isDefined)
128     return node_iterator();
129 
130   switch (m_type) {
131     case NodeType::Sequence:
132       return node_iterator(m_sequence.begin());
133     case NodeType::Map:
134       return node_iterator(m_map.begin(), m_map.end());
135     default:
136       return node_iterator();
137   }
138 }
139 
end() const140 const_node_iterator node_data::end() const {
141   if (!m_isDefined)
142     return const_node_iterator();
143 
144   switch (m_type) {
145     case NodeType::Sequence:
146       return const_node_iterator(m_sequence.end());
147     case NodeType::Map:
148       return const_node_iterator(m_map.end(), m_map.end());
149     default:
150       return const_node_iterator();
151   }
152 }
153 
end()154 node_iterator node_data::end() {
155   if (!m_isDefined)
156     return node_iterator();
157 
158   switch (m_type) {
159     case NodeType::Sequence:
160       return node_iterator(m_sequence.end());
161     case NodeType::Map:
162       return node_iterator(m_map.end(), m_map.end());
163     default:
164       return node_iterator();
165   }
166 }
167 
168 // sequence
push_back(node & node,shared_memory_holder)169 void node_data::push_back(node& node, shared_memory_holder /* pMemory */) {
170   if (m_type == NodeType::Undefined || m_type == NodeType::Null) {
171     m_type = NodeType::Sequence;
172     reset_sequence();
173   }
174 
175   if (m_type != NodeType::Sequence)
176     throw BadPushback();
177 
178   m_sequence.push_back(&node);
179 }
180 
insert(node & key,node & value,shared_memory_holder pMemory)181 void node_data::insert(node& key, node& value, shared_memory_holder pMemory) {
182   switch (m_type) {
183     case NodeType::Map:
184       break;
185     case NodeType::Undefined:
186     case NodeType::Null:
187     case NodeType::Sequence:
188       convert_to_map(pMemory);
189       break;
190     case NodeType::Scalar:
191       throw BadSubscript();
192   }
193 
194   insert_map_pair(key, value);
195 }
196 
197 // indexing
get(node & key,shared_memory_holder) const198 node* node_data::get(node& key, shared_memory_holder /* pMemory */) const {
199   if (m_type != NodeType::Map) {
200     return NULL;
201   }
202 
203   for (node_map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) {
204     if (it->first->is(key))
205       return it->second;
206   }
207 
208   return NULL;
209 }
210 
get(node & key,shared_memory_holder pMemory)211 node& node_data::get(node& key, shared_memory_holder pMemory) {
212   switch (m_type) {
213     case NodeType::Map:
214       break;
215     case NodeType::Undefined:
216     case NodeType::Null:
217     case NodeType::Sequence:
218       convert_to_map(pMemory);
219       break;
220     case NodeType::Scalar:
221       throw BadSubscript();
222   }
223 
224   for (node_map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) {
225     if (it->first->is(key))
226       return *it->second;
227   }
228 
229   node& value = pMemory->create_node();
230   insert_map_pair(key, value);
231   return value;
232 }
233 
remove(node & key,shared_memory_holder)234 bool node_data::remove(node& key, shared_memory_holder /* pMemory */) {
235   if (m_type != NodeType::Map)
236     return false;
237 
238   for (node_map::iterator it = m_map.begin(); it != m_map.end(); ++it) {
239     if (it->first->is(key)) {
240       m_map.erase(it);
241       return true;
242     }
243   }
244 
245   return false;
246 }
247 
reset_sequence()248 void node_data::reset_sequence() {
249   m_sequence.clear();
250   m_seqSize = 0;
251 }
252 
reset_map()253 void node_data::reset_map() {
254   m_map.clear();
255   m_undefinedPairs.clear();
256 }
257 
insert_map_pair(node & key,node & value)258 void node_data::insert_map_pair(node& key, node& value) {
259   m_map.emplace_back(&key, &value);
260 
261   if (!key.is_defined() || !value.is_defined())
262     m_undefinedPairs.emplace_back(&key, &value);
263 }
264 
convert_to_map(shared_memory_holder pMemory)265 void node_data::convert_to_map(shared_memory_holder pMemory) {
266   switch (m_type) {
267     case NodeType::Undefined:
268     case NodeType::Null:
269       reset_map();
270       m_type = NodeType::Map;
271       break;
272     case NodeType::Sequence:
273       convert_sequence_to_map(pMemory);
274       break;
275     case NodeType::Map:
276       break;
277     case NodeType::Scalar:
278       assert(false);
279       break;
280   }
281 }
282 
convert_sequence_to_map(shared_memory_holder pMemory)283 void node_data::convert_sequence_to_map(shared_memory_holder pMemory) {
284   assert(m_type == NodeType::Sequence);
285 
286   reset_map();
287   for (std::size_t i = 0; i < m_sequence.size(); i++) {
288     std::stringstream stream;
289     stream << i;
290 
291     node& key = pMemory->create_node();
292     key.set_scalar(stream.str());
293     insert_map_pair(key, *m_sequence[i]);
294   }
295 
296   reset_sequence();
297   m_type = NodeType::Map;
298 }
299 }
300 }
301