Coverage Report

Created: 2025-08-26 06:19

/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"