NeBuild dev
Loading...
Searching...
No Matches
path.inl
Go to the documentation of this file.
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 "at_path.hpp"
15#include "path.hpp"
16#include "print_to_stream.hpp"
18#if TOML_INT_CHARCONV
19#include <charconv>
20#endif
21#include <sstream>
23#include "header_start.hpp"
24
25// #=====================================================================================================================
26// # toml::path_component
27// #=====================================================================================================================
28
32 : type_{path_component_type::key} {
33 store_key("", value_storage_);
34 }
35
37 path_component::path_component(size_t index) noexcept //
38 : type_(path_component_type::array_index) {
39 store_index(index, value_storage_);
40 }
41
43 path_component::path_component(std::string_view key) //
44 : type_(path_component_type::key) {
45 store_key(key, value_storage_);
46 }
47
48#if TOML_ENABLE_WINDOWS_COMPAT
49
51 path_component::path_component(std::wstring_view key) //
52 : path_component(impl::narrow(key)) {}
53
54#endif
55
58 : type_{pc.type_} {
59 if (type_ == path_component_type::array_index)
60 store_index(pc.index(), value_storage_);
61 else
62 store_key(pc.key(), value_storage_);
63 }
64
67 : type_{pc.type_} {
68 if (type_ == path_component_type::array_index)
69 store_index(pc.index_ref(), value_storage_);
70 else
71 store_key(std::move(pc.key_ref()), value_storage_);
72 }
73
76 if (type_ != rhs.type_) {
77 destroy();
78
79 type_ = rhs.type_;
80 if (type_ == path_component_type::array_index)
81 store_index(rhs.index(), value_storage_);
82 else
83 store_key(rhs.key(), value_storage_);
84 } else {
85 if (type_ == path_component_type::array_index)
86 index_ref() = rhs.index();
87 else
88 key_ref() = rhs.key();
89 }
90 return *this;
91 }
92
95 if (type_ != rhs.type_) {
96 destroy();
97
98 type_ = rhs.type_;
99 if (type_ == path_component_type::array_index)
100 store_index(rhs.index(), value_storage_);
101 else
102 store_key(std::move(rhs.key_ref()), value_storage_);
103 } else {
104 if (type_ == path_component_type::array_index)
105 index_ref() = rhs.index();
106 else
107 key_ref() = std::move(rhs.key_ref());
108 }
109 return *this;
110 }
111
114 bool TOML_CALLCONV path_component::equal(const path_component& lhs,
115 const path_component& rhs) noexcept {
116 // Different comparison depending on contents
117 if (lhs.type_ != rhs.type_) return false;
118
119 if (lhs.type_ == path_component_type::array_index)
120 return lhs.index() == rhs.index();
121 else // path_component_type::key
122 return lhs.key() == rhs.key();
123 }
124
126 path_component& path_component::operator=(size_t new_index) noexcept {
127 // If currently a key, string will need to be destroyed regardless
128 destroy();
129
130 type_ = path_component_type::array_index;
131 store_index(new_index, value_storage_);
132
133 return *this;
134 }
135
137 path_component& path_component::operator=(std::string_view new_key) {
138 if (type_ == path_component_type::key)
139 key_ref() = new_key;
140 else {
141 type_ = path_component_type::key;
142 store_key(new_key, value_storage_);
143 }
144
145 return *this;
146 }
147
148#if TOML_ENABLE_WINDOWS_COMPAT
149
151 path_component& path_component::operator=(std::wstring_view new_key) {
152 if (type_ == path_component_type::key)
153 key_ref() = impl::narrow(new_key);
154 else {
155 type_ = path_component_type::key;
156 store_key(impl::narrow(new_key), value_storage_);
157 }
158
159 return *this;
160 }
161
162#endif
163}
165
166// #=====================================================================================================================
167// # toml::path
168// #=====================================================================================================================
169
172 bool parse_path_into(std::string_view path_str, std::vector<path_component> & components) {
173 using components_type = std::remove_reference_t<decltype(components)>;
174
175 const auto original_size = components.size();
176
177 static constexpr auto on_key = [](void* data, std::string_view key) -> bool {
178 auto& comps = *static_cast<components_type*>(data);
179 comps.emplace_back(key);
180 return true;
181 };
182
183 static constexpr auto on_index = [](void* data, size_t index) -> bool {
184 auto& comps = *static_cast<components_type*>(data);
185 comps.emplace_back(index);
186 return true;
187 };
188
189 if (!impl::parse_path(path_str, &components, on_key, on_index)) {
190 components.resize(original_size);
191 return false;
192 }
193
194 return true;
195 }
196}
198
201 void path::print_to(std::ostream & os) const {
202 bool root = true;
203 for (const auto& component : components_) {
204 if (component.type() == path_component_type::key) // key
205 {
206 if (!root) impl::print_to_stream(os, '.');
207 impl::print_to_stream(os, component.key());
208 } else if (component.type() == path_component_type::array_index) // array
209 {
210 impl::print_to_stream(os, '[');
211 impl::print_to_stream(os, component.index());
212 impl::print_to_stream(os, ']');
213 }
214 root = false;
215 }
216 }
217
220 bool TOML_CALLCONV path::equal(const path& lhs, const path& rhs) noexcept {
221 return lhs.components_ == rhs.components_;
222 }
223
224 // #=== constructors =================================================
225
227 path::path(std::string_view str) //
228 {
229 TOML_ANON_NAMESPACE::parse_path_into(str, components_);
230 }
231
232#if TOML_ENABLE_WINDOWS_COMPAT
233
235 path::path(std::wstring_view str) //
236 : path(impl::narrow(str)) {}
237
238#endif
239
240 // #=== assignment =================================================
241
243 path& path::operator=(std::string_view rhs) {
244 components_.clear();
245 TOML_ANON_NAMESPACE::parse_path_into(rhs, components_);
246 return *this;
247 }
248
249#if TOML_ENABLE_WINDOWS_COMPAT
250
252 path& path::operator=(std::wstring_view rhs) {
253 return assign(impl::narrow(rhs));
254 }
255
256#endif
257
258 // #=== appending =================================================
259
261 path& path::operator+=(const path& rhs) {
262 components_.insert(components_.cend(), rhs.begin(), rhs.end());
263 return *this;
264 }
265
267 path& path::operator+=(path&& rhs) {
268 components_.insert(components_.end(), std::make_move_iterator(rhs.components_.begin()),
269 std::make_move_iterator(rhs.components_.end()));
270 return *this;
271 }
272
274 path& path::operator+=(std::string_view str) {
275 TOML_ANON_NAMESPACE::parse_path_into(str, components_);
276 return *this;
277 }
278
279#if TOML_ENABLE_WINDOWS_COMPAT
280
282 path& path::operator+=(std::wstring_view str) {
283 return *this += impl::narrow(str);
284 }
285
286#endif
287
288 // #=== prepending =================================================
289
291 path& path::prepend(const path& source) {
292 components_.insert(components_.begin(), source.components_.begin(), source.components_.end());
293 return *this;
294 }
295
297 path& path::prepend(path && source) {
298 components_.insert(components_.begin(), std::make_move_iterator(source.components_.begin()),
299 std::make_move_iterator(source.components_.end()));
300 return *this;
301 }
302
304 path& path::prepend(std::string_view source) {
305 return prepend(path{source});
306 }
307
308#if TOML_ENABLE_WINDOWS_COMPAT
309
311 path& path::prepend(std::wstring_view source) {
312 return prepend(impl::narrow(source));
313 }
314
315#endif
316
317 // #=== string conversion =================================================
318
320 std::string path::str() const {
321 if (empty()) return "";
322
323 std::ostringstream ss;
324 print_to(ss);
325 return std::move(ss).str();
326 }
327
328#if TOML_ENABLE_WINDOWS_COMPAT
329
331 std::wstring path::wide_str() const {
332 return impl::widen(str());
333 }
334
335#endif
336
337 // #=== equality and comparison =================================================
338
340 void path::clear() noexcept {
341 components_.clear();
342 }
343
345 path& path::truncate(size_t n) {
346 n = n > components_.size() ? components_.size() : n;
347
348 auto it_end = components_.end();
349 components_.erase(it_end - static_cast<int>(n), it_end);
350
351 return *this;
352 }
353
355 path path::truncated(size_t n) const {
356 path truncated_path{};
357
358 n = n > components_.size() ? components_.size() : n;
359
360 // Copy all components except one
361 // Need at least two path components to have a parent, since if there is
362 // only one path component, the parent is the root/null path ""
363 truncated_path.components_.insert(truncated_path.components_.begin(), components_.begin(),
364 components_.end() - static_cast<int>(n));
365
366 return truncated_path;
367 }
368
370 path path::parent() const {
371 return truncated(1);
372 }
373
375 path path::leaf(size_t n) const {
376 path leaf_path{};
377
378 n = n > components_.size() ? components_.size() : n;
379
380 if (n > 0) {
381 leaf_path.components_.insert(leaf_path.components_.begin(),
382 components_.end() - static_cast<int>(n), components_.end());
383 }
384
385 return leaf_path;
386 }
387
389 path path::subpath(std::vector<path_component>::const_iterator start,
390 std::vector<path_component>::const_iterator end) const {
391 if (start >= end) return {};
392
394 subpath.components_.insert(subpath.components_.begin(), start, end);
395 return subpath;
396 }
397
399 path path::subpath(size_t start, size_t length) const {
400 return subpath(begin() + static_cast<int>(start), begin() + static_cast<int>(start + length));
401 }
402}
404
405// #=====================================================================================================================
406// # at_path() overloads for toml::path
407// #=====================================================================================================================
408
411 node_view<node> TOML_CALLCONV at_path(node & root, const toml::path& path) noexcept {
412 // early-exit sanity-checks
413 if (root.is_value()) return {};
414 if (auto tbl = root.as_table(); tbl && tbl->empty()) return {};
415 if (auto arr = root.as_array(); arr && arr->empty()) return {};
416
417 node* current = &root;
418
419 for (const auto& component : path) {
420 auto type = component.type();
421 if (type == path_component_type::array_index) {
422 const auto current_array = current->as<array>();
423 if (!current_array) return {}; // not an array, using array index doesn't work
424
425 current = current_array->get(component.index());
426 } else if (type == path_component_type::key) {
427 const auto current_table = current->as<table>();
428 if (!current_table) return {};
429
430 current = current_table->get(component.key());
431 } else {
432 // Error: invalid component
433 return {};
434 }
435
436 if (!current) return {}; // not found
437 }
438
439 return node_view{current};
440 }
441
443 node_view<const node> TOML_CALLCONV at_path(const node& root, const toml::path& path) noexcept {
444 return node_view<const node>{at_path(const_cast<node&>(root), path).node()};
445 }
446}
448
449#include "header_end.hpp"
TOML_NODISCARD TOML_EXPORTED_FREE_FUNCTION node_view< const node > TOML_CALLCONV at_path(const node &root, std::string_view path) noexcept
Returns a const view of the node matching a fully-qualified "TOML path".
A TOML array.
Definition array.hpp:285
TOML_PURE_INLINE_GETTER node * get(size_t index) noexcept
Gets a pointer to the element at a specific index.
Definition array.hpp:685
Represents a single component of a complete 'TOML-path': either a key or an array index.
Definition path.hpp:22
TOML_NODISCARD_CTOR TOML_EXPORTED_MEMBER_FUNCTION path_component()
Default constructor (creates an empty key).
TOML_EXPORTED_MEMBER_FUNCTION path_component & operator=(const path_component &rhs)
Copy-assignment operator.
TOML_PURE_GETTER const std::string & key() const noexcept
Returns the key string.
Definition path.hpp:177
TOML_PURE_GETTER size_t index() const noexcept
Returns the array index (const lvalue overload).
Definition path.hpp:155
A TOML path.
Definition path.hpp:239
TOML_NODISCARD TOML_EXPORTED_MEMBER_FUNCTION std::wstring wide_str() const
Returns a string representation of this path.
TOML_EXPORTED_MEMBER_FUNCTION void clear() noexcept
Erases the contents of the path.
TOML_NODISCARD TOML_EXPORTED_MEMBER_FUNCTION path parent() const
Returns a toml::path object representing the path of the parent node.
TOML_EXPORTED_MEMBER_FUNCTION path & truncate(size_t n)
Removes the number of terminal path components specified by n.
TOML_NODISCARD TOML_EXPORTED_MEMBER_FUNCTION path truncated(size_t n) const
Returns a toml::path object which has had n terminal path components removed.
TOML_PURE_INLINE_GETTER iterator end() noexcept
Returns an iterator to one-past-the-last component in the path.
Definition path.hpp:692
TOML_PURE_INLINE_GETTER size_t size() const noexcept
Returns the number of components in the path.
Definition path.hpp:288
TOML_NODISCARD TOML_EXPORTED_MEMBER_FUNCTION std::string str() const
Returns a string representation of this path.
TOML_NODISCARD_CTOR path() noexcept=default
Default constructor.
TOML_PURE_INLINE_GETTER iterator begin() noexcept
Returns an iterator to the first component in the path.
Definition path.hpp:684
TOML_EXPORTED_MEMBER_FUNCTION path & prepend(const path &)
Prepends another path onto the beginning of this one.
TOML_EXPORTED_MEMBER_FUNCTION path & operator+=(const path &)
Appends another path onto the end of this one.
TOML_PURE_INLINE_GETTER bool empty() const noexcept
Whether (true) or not (false) the path is empty.
Definition path.hpp:302
TOML_NODISCARD TOML_EXPORTED_MEMBER_FUNCTION path leaf(size_t n=1) const
Returns a toml::path object representing terminal n-parts of a TOML path.
TOML_ALWAYS_INLINE path & assign(const path &p)
Replaces the contents of the path with that of another.
Definition path.hpp:348
path & operator=(const path &)=default
Copy-assignment operator.
TOML_NODISCARD TOML_EXPORTED_MEMBER_FUNCTION path subpath(const_iterator start, const_iterator end) const
Returns a toml::path object that is a specified subpath of the current path, representing the range o...
A TOML table.
Definition table.hpp:220
TOML_PURE_GETTER TOML_EXPORTED_MEMBER_FUNCTION node * get(std::string_view key) noexcept
Gets the node at a specific key.
#define TOML_CALLCONV
Calling convention to apply to exported free/static functions. \detail Not defined by default (let th...
Definition preprocessor.hpp:1134
TOML_NAMESPACE_START
Definition path.inl:29
TOML_ANON_NAMESPACE_START
Definition path.inl:170
TOML_ENABLE_WARNINGS
Definition path.inl:22
TOML_DISABLE_WARNINGS
Definition path.inl:17
#define TOML_ANON_NAMESPACE_END
Definition preprocessor.hpp:1337
#define TOML_INTERNAL_LINKAGE
Definition preprocessor.hpp:1340
#define TOML_EXTERNAL_LINKAGE
Definition preprocessor.hpp:1339
#define TOML_PURE_GETTER
Definition preprocessor.hpp:474
#define TOML_NAMESPACE_END
Definition preprocessor.hpp:1320