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