/src/tomlplusplus/include/toml++/impl/path.inl
Line | Count | Source (jump to first uncovered line) |
1 | | //# This file is a part of toml++ and is subject to the the terms of the MIT license. |
2 | | //# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au> |
3 | | //# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text. |
4 | | // SPDX-License-Identifier: MIT |
5 | | #pragma once |
6 | | |
7 | | //# {{ |
8 | | #include "preprocessor.hpp" |
9 | | #if !TOML_IMPLEMENTATION |
10 | | #error This is an implementation-only header. |
11 | | #endif |
12 | | //# }} |
13 | | |
14 | | #include "path.hpp" |
15 | | #include "at_path.hpp" |
16 | | #include "print_to_stream.hpp" |
17 | | TOML_DISABLE_WARNINGS; |
18 | | #if TOML_INT_CHARCONV |
19 | | #include <charconv> |
20 | | #endif |
21 | | #include <sstream> |
22 | | TOML_ENABLE_WARNINGS; |
23 | | #include "header_start.hpp" |
24 | | |
25 | | //#===================================================================================================================== |
26 | | //# toml::path_component |
27 | | //#===================================================================================================================== |
28 | | |
29 | | TOML_NAMESPACE_START |
30 | | { |
31 | | TOML_EXTERNAL_LINKAGE |
32 | | path_component::path_component() // |
33 | | : type_{ path_component_type::key } |
34 | | { |
35 | | store_key("", value_storage_); |
36 | | } |
37 | | |
38 | | TOML_EXTERNAL_LINKAGE |
39 | | path_component::path_component(size_t index) noexcept // |
40 | | : type_(path_component_type::array_index) |
41 | | { |
42 | | store_index(index, value_storage_); |
43 | | } |
44 | | |
45 | | TOML_EXTERNAL_LINKAGE |
46 | | path_component::path_component(std::string_view key) // |
47 | | : type_(path_component_type::key) |
48 | | { |
49 | | store_key(key, value_storage_); |
50 | | } |
51 | | |
52 | | #if TOML_ENABLE_WINDOWS_COMPAT |
53 | | |
54 | | TOML_EXTERNAL_LINKAGE |
55 | | path_component::path_component(std::wstring_view key) // |
56 | | : path_component(impl::narrow(key)) |
57 | | {} |
58 | | |
59 | | #endif |
60 | | |
61 | | TOML_EXTERNAL_LINKAGE |
62 | | path_component::path_component(const path_component& pc) // |
63 | | : type_{ pc.type_ } |
64 | | { |
65 | | if (type_ == path_component_type::array_index) |
66 | | store_index(pc.index(), value_storage_); |
67 | | else |
68 | | store_key(pc.key(), value_storage_); |
69 | | } |
70 | | |
71 | | TOML_EXTERNAL_LINKAGE |
72 | | path_component::path_component(path_component && pc) noexcept // |
73 | | : type_{ pc.type_ } |
74 | | { |
75 | | if (type_ == path_component_type::array_index) |
76 | | store_index(pc.index_ref(), value_storage_); |
77 | | else |
78 | | store_key(std::move(pc.key_ref()), value_storage_); |
79 | | } |
80 | | |
81 | | TOML_EXTERNAL_LINKAGE |
82 | | path_component& path_component::operator=(const path_component& rhs) |
83 | 0 | { |
84 | 0 | if (type_ != rhs.type_) |
85 | 0 | { |
86 | 0 | destroy(); |
87 | 0 |
|
88 | 0 | type_ = rhs.type_; |
89 | 0 | if (type_ == path_component_type::array_index) |
90 | 0 | store_index(rhs.index(), value_storage_); |
91 | 0 | else |
92 | 0 | store_key(rhs.key(), value_storage_); |
93 | 0 | } |
94 | 0 | else |
95 | 0 | { |
96 | 0 | if (type_ == path_component_type::array_index) |
97 | 0 | index_ref() = rhs.index(); |
98 | 0 | else |
99 | 0 | key_ref() = rhs.key(); |
100 | 0 | } |
101 | 0 | return *this; |
102 | 0 | } |
103 | | |
104 | | TOML_EXTERNAL_LINKAGE |
105 | | path_component& path_component::operator=(path_component&& rhs) noexcept |
106 | 0 | { |
107 | 0 | if (type_ != rhs.type_) |
108 | 0 | { |
109 | 0 | destroy(); |
110 | 0 |
|
111 | 0 | type_ = rhs.type_; |
112 | 0 | if (type_ == path_component_type::array_index) |
113 | 0 | store_index(rhs.index(), value_storage_); |
114 | 0 | else |
115 | 0 | store_key(std::move(rhs.key_ref()), value_storage_); |
116 | 0 | } |
117 | 0 | else |
118 | 0 | { |
119 | 0 | if (type_ == path_component_type::array_index) |
120 | 0 | index_ref() = rhs.index(); |
121 | 0 | else |
122 | 0 | key_ref() = std::move(rhs.key_ref()); |
123 | 0 | } |
124 | 0 | return *this; |
125 | 0 | } |
126 | | |
127 | | TOML_PURE_GETTER |
128 | | TOML_EXTERNAL_LINKAGE |
129 | | bool TOML_CALLCONV path_component::equal(const path_component& lhs, const path_component& rhs) noexcept |
130 | 0 | { |
131 | 0 | // Different comparison depending on contents |
132 | 0 | if (lhs.type_ != rhs.type_) |
133 | 0 | return false; |
134 | 0 |
|
135 | 0 | if (lhs.type_ == path_component_type::array_index) |
136 | 0 | return lhs.index() == rhs.index(); |
137 | 0 | else // path_component_type::key |
138 | 0 | return lhs.key() == rhs.key(); |
139 | 0 | } |
140 | | |
141 | | TOML_EXTERNAL_LINKAGE |
142 | | path_component& path_component::operator=(size_t new_index) noexcept |
143 | 0 | { |
144 | 0 | // If currently a key, string will need to be destroyed regardless |
145 | 0 | destroy(); |
146 | 0 |
|
147 | 0 | type_ = path_component_type::array_index; |
148 | 0 | store_index(new_index, value_storage_); |
149 | 0 |
|
150 | 0 | return *this; |
151 | 0 | } |
152 | | |
153 | | TOML_EXTERNAL_LINKAGE |
154 | | path_component& path_component::operator=(std::string_view new_key) |
155 | 0 | { |
156 | 0 | if (type_ == path_component_type::key) |
157 | 0 | key_ref() = new_key; |
158 | 0 | else |
159 | 0 | { |
160 | 0 | type_ = path_component_type::key; |
161 | 0 | store_key(new_key, value_storage_); |
162 | 0 | } |
163 | 0 |
|
164 | 0 | return *this; |
165 | 0 | } |
166 | | |
167 | | #if TOML_ENABLE_WINDOWS_COMPAT |
168 | | |
169 | | TOML_EXTERNAL_LINKAGE |
170 | | path_component& path_component::operator=(std::wstring_view new_key) |
171 | | { |
172 | | if (type_ == path_component_type::key) |
173 | | key_ref() = impl::narrow(new_key); |
174 | | else |
175 | | { |
176 | | type_ = path_component_type::key; |
177 | | store_key(impl::narrow(new_key), value_storage_); |
178 | | } |
179 | | |
180 | | return *this; |
181 | | } |
182 | | |
183 | | #endif |
184 | | } |
185 | | TOML_NAMESPACE_END; |
186 | | |
187 | | //#===================================================================================================================== |
188 | | //# toml::path |
189 | | //#===================================================================================================================== |
190 | | |
191 | | TOML_ANON_NAMESPACE_START |
192 | | { |
193 | | TOML_INTERNAL_LINKAGE |
194 | | bool parse_path_into(std::string_view path_str, std::vector<path_component> & components) |
195 | 0 | { |
196 | 0 | using components_type = std::remove_reference_t<decltype(components)>; |
197 | 0 |
|
198 | 0 | const auto original_size = components.size(); |
199 | 0 |
|
200 | 0 | static constexpr auto on_key = [](void* data, std::string_view key) -> bool |
201 | 0 | { |
202 | 0 | auto& comps = *static_cast<components_type*>(data); |
203 | 0 | comps.emplace_back(key); |
204 | 0 | return true; |
205 | 0 | }; |
206 | 0 |
|
207 | 0 | static constexpr auto on_index = [](void* data, size_t index) -> bool |
208 | 0 | { |
209 | 0 | auto& comps = *static_cast<components_type*>(data); |
210 | 0 | comps.emplace_back(index); |
211 | 0 | return true; |
212 | 0 | }; |
213 | 0 |
|
214 | 0 | if (!impl::parse_path(path_str, &components, on_key, on_index)) |
215 | 0 | { |
216 | 0 | components.resize(original_size); |
217 | 0 | return false; |
218 | 0 | } |
219 | 0 |
|
220 | 0 | return true; |
221 | 0 | } |
222 | | } |
223 | | TOML_ANON_NAMESPACE_END; |
224 | | |
225 | | TOML_NAMESPACE_START |
226 | | { |
227 | | TOML_EXTERNAL_LINKAGE |
228 | | void path::print_to(std::ostream & os) const |
229 | 0 | { |
230 | 0 | bool root = true; |
231 | 0 | for (const auto& component : components_) |
232 | 0 | { |
233 | 0 | if (component.type() == path_component_type::key) // key |
234 | 0 | { |
235 | 0 | if (!root) |
236 | 0 | impl::print_to_stream(os, '.'); |
237 | 0 | impl::print_to_stream(os, component.key()); |
238 | 0 | } |
239 | 0 | else if (component.type() == path_component_type::array_index) // array |
240 | 0 | { |
241 | 0 | impl::print_to_stream(os, '['); |
242 | 0 | impl::print_to_stream(os, component.index()); |
243 | 0 | impl::print_to_stream(os, ']'); |
244 | 0 | } |
245 | 0 | root = false; |
246 | 0 | } |
247 | 0 | } |
248 | | |
249 | | TOML_PURE_GETTER |
250 | | TOML_EXTERNAL_LINKAGE |
251 | | bool TOML_CALLCONV path::equal(const path& lhs, const path& rhs) noexcept |
252 | 0 | { |
253 | 0 | return lhs.components_ == rhs.components_; |
254 | 0 | } |
255 | | |
256 | | //#=== constructors ================================================= |
257 | | |
258 | | TOML_EXTERNAL_LINKAGE |
259 | | path::path(std::string_view str) // |
260 | | { |
261 | | TOML_ANON_NAMESPACE::parse_path_into(str, components_); |
262 | | } |
263 | | |
264 | | #if TOML_ENABLE_WINDOWS_COMPAT |
265 | | |
266 | | TOML_EXTERNAL_LINKAGE |
267 | | path::path(std::wstring_view str) // |
268 | | : path(impl::narrow(str)) |
269 | | {} |
270 | | |
271 | | #endif |
272 | | |
273 | | //#=== assignment ================================================= |
274 | | |
275 | | TOML_EXTERNAL_LINKAGE |
276 | | path& path::operator=(std::string_view rhs) |
277 | 0 | { |
278 | 0 | components_.clear(); |
279 | 0 | TOML_ANON_NAMESPACE::parse_path_into(rhs, components_); |
280 | 0 | return *this; |
281 | 0 | } |
282 | | |
283 | | #if TOML_ENABLE_WINDOWS_COMPAT |
284 | | |
285 | | TOML_EXTERNAL_LINKAGE |
286 | | path& path::operator=(std::wstring_view rhs) |
287 | | { |
288 | | return assign(impl::narrow(rhs)); |
289 | | } |
290 | | |
291 | | #endif |
292 | | |
293 | | //#=== appending ================================================= |
294 | | |
295 | | TOML_EXTERNAL_LINKAGE |
296 | | path& path::operator+=(const path& rhs) |
297 | 0 | { |
298 | 0 | components_.insert(components_.cend(), rhs.begin(), rhs.end()); |
299 | 0 | return *this; |
300 | 0 | } |
301 | | |
302 | | TOML_EXTERNAL_LINKAGE |
303 | | path& path::operator+=(path&& rhs) |
304 | 0 | { |
305 | 0 | components_.insert(components_.end(), |
306 | 0 | std::make_move_iterator(rhs.components_.begin()), |
307 | 0 | std::make_move_iterator(rhs.components_.end())); |
308 | 0 | return *this; |
309 | 0 | } |
310 | | |
311 | | TOML_EXTERNAL_LINKAGE |
312 | | path& path::operator+=(std::string_view str) |
313 | 0 | { |
314 | 0 | TOML_ANON_NAMESPACE::parse_path_into(str, components_); |
315 | 0 | return *this; |
316 | 0 | } |
317 | | |
318 | | #if TOML_ENABLE_WINDOWS_COMPAT |
319 | | |
320 | | TOML_EXTERNAL_LINKAGE |
321 | | path& path::operator+=(std::wstring_view str) |
322 | | { |
323 | | return *this += impl::narrow(str); |
324 | | } |
325 | | |
326 | | #endif |
327 | | |
328 | | //#=== prepending ================================================= |
329 | | |
330 | | TOML_EXTERNAL_LINKAGE |
331 | | path& path::prepend(const path& source) |
332 | 0 | { |
333 | 0 | components_.insert(components_.begin(), source.components_.begin(), source.components_.end()); |
334 | 0 | return *this; |
335 | 0 | } |
336 | | |
337 | | TOML_EXTERNAL_LINKAGE |
338 | | path& path::prepend(path && source) |
339 | 0 | { |
340 | 0 | components_.insert(components_.begin(), |
341 | 0 | std::make_move_iterator(source.components_.begin()), |
342 | 0 | std::make_move_iterator(source.components_.end())); |
343 | 0 | return *this; |
344 | 0 | } |
345 | | |
346 | | TOML_EXTERNAL_LINKAGE |
347 | | path& path::prepend(std::string_view source) |
348 | 0 | { |
349 | 0 | return prepend(path{ source }); |
350 | 0 | } |
351 | | |
352 | | #if TOML_ENABLE_WINDOWS_COMPAT |
353 | | |
354 | | TOML_EXTERNAL_LINKAGE |
355 | | path& path::prepend(std::wstring_view source) |
356 | | { |
357 | | return prepend(impl::narrow(source)); |
358 | | } |
359 | | |
360 | | #endif |
361 | | |
362 | | //#=== string conversion ================================================= |
363 | | |
364 | | TOML_EXTERNAL_LINKAGE |
365 | | std::string path::str() const |
366 | 0 | { |
367 | 0 | if (empty()) |
368 | 0 | return ""; |
369 | 0 |
|
370 | 0 | std::ostringstream ss; |
371 | 0 | print_to(ss); |
372 | 0 | return std::move(ss).str(); |
373 | 0 | } |
374 | | |
375 | | #if TOML_ENABLE_WINDOWS_COMPAT |
376 | | |
377 | | TOML_EXTERNAL_LINKAGE |
378 | | std::wstring path::wide_str() const |
379 | | { |
380 | | return impl::widen(str()); |
381 | | } |
382 | | |
383 | | #endif |
384 | | |
385 | | //#=== equality and comparison ================================================= |
386 | | |
387 | | TOML_EXTERNAL_LINKAGE |
388 | | void path::clear() noexcept |
389 | 0 | { |
390 | 0 | components_.clear(); |
391 | 0 | } |
392 | | |
393 | | TOML_EXTERNAL_LINKAGE |
394 | | path& path::truncate(size_t n) |
395 | 0 | { |
396 | 0 | n = n > components_.size() ? components_.size() : n; |
397 | 0 |
|
398 | 0 | auto it_end = components_.end(); |
399 | 0 | components_.erase(it_end - static_cast<int>(n), it_end); |
400 | 0 |
|
401 | 0 | return *this; |
402 | 0 | } |
403 | | |
404 | | TOML_EXTERNAL_LINKAGE |
405 | | path path::truncated(size_t n) const |
406 | 0 | { |
407 | 0 | path truncated_path{}; |
408 | 0 |
|
409 | 0 | n = n > components_.size() ? components_.size() : n; |
410 | 0 |
|
411 | 0 | // Copy all components except one |
412 | 0 | // Need at least two path components to have a parent, since if there is |
413 | 0 | // only one path component, the parent is the root/null path "" |
414 | 0 | truncated_path.components_.insert(truncated_path.components_.begin(), |
415 | 0 | components_.begin(), |
416 | 0 | components_.end() - static_cast<int>(n)); |
417 | 0 |
|
418 | 0 | return truncated_path; |
419 | 0 | } |
420 | | |
421 | | TOML_EXTERNAL_LINKAGE |
422 | | path path::parent() const |
423 | 0 | { |
424 | 0 | return truncated(1); |
425 | 0 | } |
426 | | |
427 | | TOML_EXTERNAL_LINKAGE |
428 | | path path::leaf(size_t n) const |
429 | 0 | { |
430 | 0 | path leaf_path{}; |
431 | 0 |
|
432 | 0 | n = n > components_.size() ? components_.size() : n; |
433 | 0 |
|
434 | 0 | if (n > 0) |
435 | 0 | { |
436 | 0 | leaf_path.components_.insert(leaf_path.components_.begin(), |
437 | 0 | components_.end() - static_cast<int>(n), |
438 | 0 | components_.end()); |
439 | 0 | } |
440 | 0 |
|
441 | 0 | return leaf_path; |
442 | 0 | } |
443 | | |
444 | | TOML_EXTERNAL_LINKAGE |
445 | | path path::subpath(std::vector<path_component>::const_iterator start, |
446 | | std::vector<path_component>::const_iterator end) const |
447 | 0 | { |
448 | 0 | if (start >= end) |
449 | 0 | return {}; |
450 | 0 |
|
451 | 0 | path subpath; |
452 | 0 | subpath.components_.insert(subpath.components_.begin(), start, end); |
453 | 0 | return subpath; |
454 | 0 | } |
455 | | |
456 | | TOML_EXTERNAL_LINKAGE |
457 | | path path::subpath(size_t start, size_t length) const |
458 | 0 | { |
459 | 0 | return subpath(begin() + static_cast<int>(start), begin() + static_cast<int>(start + length)); |
460 | 0 | } |
461 | | } |
462 | | TOML_NAMESPACE_END; |
463 | | |
464 | | //#===================================================================================================================== |
465 | | //# at_path() overloads for toml::path |
466 | | //#===================================================================================================================== |
467 | | |
468 | | TOML_NAMESPACE_START |
469 | | { |
470 | | TOML_EXTERNAL_LINKAGE |
471 | | node_view<node> TOML_CALLCONV at_path(node & root, const toml::path& path) noexcept |
472 | 0 | { |
473 | 0 | // early-exit sanity-checks |
474 | 0 | if (root.is_value()) |
475 | 0 | return {}; |
476 | 0 | if (auto tbl = root.as_table(); tbl && tbl->empty()) |
477 | 0 | return {}; |
478 | 0 | if (auto arr = root.as_array(); arr && arr->empty()) |
479 | 0 | return {}; |
480 | 0 |
|
481 | 0 | node* current = &root; |
482 | 0 |
|
483 | 0 | for (const auto& component : path) |
484 | 0 | { |
485 | 0 | auto type = component.type(); |
486 | 0 | if (type == path_component_type::array_index) |
487 | 0 | { |
488 | 0 | const auto current_array = current->as<array>(); |
489 | 0 | if (!current_array) |
490 | 0 | return {}; // not an array, using array index doesn't work |
491 | 0 |
|
492 | 0 | current = current_array->get(component.index()); |
493 | 0 | } |
494 | 0 | else if (type == path_component_type::key) |
495 | 0 | { |
496 | 0 | const auto current_table = current->as<table>(); |
497 | 0 | if (!current_table) |
498 | 0 | return {}; |
499 | 0 |
|
500 | 0 | current = current_table->get(component.key()); |
501 | 0 | } |
502 | 0 | else |
503 | 0 | { |
504 | 0 | // Error: invalid component |
505 | 0 | return {}; |
506 | 0 | } |
507 | 0 |
|
508 | 0 | if (!current) |
509 | 0 | return {}; // not found |
510 | 0 | } |
511 | 0 |
|
512 | 0 | return node_view{ current }; |
513 | 0 | } |
514 | | |
515 | | TOML_EXTERNAL_LINKAGE |
516 | | node_view<const node> TOML_CALLCONV at_path(const node& root, const toml::path& path) noexcept |
517 | 0 | { |
518 | 0 | return node_view<const node>{ at_path(const_cast<node&>(root), path).node() }; |
519 | 0 | } |
520 | | } |
521 | | TOML_NAMESPACE_END; |
522 | | |
523 | | #include "header_end.hpp" |