Coverage Report

Created: 2025-11-16 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tomlplusplus/include/toml++/impl/table.hpp
Line
Count
Source
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
#include "forward_declarations.hpp"
8
#include "std_map.hpp"
9
#include "std_initializer_list.hpp"
10
#include "array.hpp"
11
#include "make_node.hpp"
12
#include "node_view.hpp"
13
#include "key.hpp"
14
#include "header_start.hpp"
15
16
/// \cond
17
TOML_IMPL_NAMESPACE_START
18
{
19
  template <bool IsConst>
20
  struct table_proxy_pair
21
  {
22
    using value_type = std::conditional_t<IsConst, const node, node>;
23
24
    const toml::key& first;
25
    value_type& second;
26
  };
27
28
  template <bool IsConst>
29
  class table_iterator
30
  {
31
    private:
32
    template <bool>
33
    friend class table_iterator;
34
35
    using proxy_type       = table_proxy_pair<IsConst>;
36
    using mutable_map_iterator = std::map<toml::key, node_ptr, std::less<>>::iterator;
37
    using const_map_iterator   = std::map<toml::key, node_ptr, std::less<>>::const_iterator;
38
    using map_iterator       = std::conditional_t<IsConst, const_map_iterator, mutable_map_iterator>;
39
40
    mutable map_iterator iter_;
41
    alignas(proxy_type) mutable unsigned char proxy_[sizeof(proxy_type)];
42
    mutable bool proxy_instantiated_ = false;
43
44
    TOML_NODISCARD
45
    proxy_type* get_proxy() const noexcept
46
1.25M
    {
47
1.25M
      if (!proxy_instantiated_)
48
1.11M
      {
49
1.11M
        auto p = ::new (static_cast<void*>(proxy_)) proxy_type{ iter_->first, *iter_->second.get() };
50
1.11M
        proxy_instantiated_ = true;
51
1.11M
        return p;
52
1.11M
      }
53
141k
      else
54
141k
        return TOML_LAUNDER(reinterpret_cast<proxy_type*>(proxy_));
55
1.25M
    }
toml::v3::impl::table_iterator<false>::get_proxy() const
Line
Count
Source
46
1.25M
    {
47
1.25M
      if (!proxy_instantiated_)
48
1.11M
      {
49
1.11M
        auto p = ::new (static_cast<void*>(proxy_)) proxy_type{ iter_->first, *iter_->second.get() };
50
1.11M
        proxy_instantiated_ = true;
51
1.11M
        return p;
52
1.11M
      }
53
141k
      else
54
141k
        return TOML_LAUNDER(reinterpret_cast<proxy_type*>(proxy_));
55
1.25M
    }
Unexecuted instantiation: toml::v3::impl::table_iterator<true>::get_proxy() const
56
57
    public:
58
    TOML_NODISCARD_CTOR
59
    table_iterator() noexcept = default;
60
61
    TOML_NODISCARD_CTOR
62
    explicit table_iterator(mutable_map_iterator iter) noexcept //
63
2.56M
      : iter_{ iter }
64
2.56M
    {}
65
66
    TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst)
67
    TOML_NODISCARD_CTOR
68
    explicit table_iterator(const_map_iterator iter) noexcept //
69
      : iter_{ iter }
70
    {}
71
72
    TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst)
73
    TOML_NODISCARD_CTOR
74
    table_iterator(const table_iterator<false>& other) noexcept //
75
470k
      : iter_{ other.iter_ }
76
470k
    {}
77
78
    TOML_NODISCARD_CTOR
79
    table_iterator(const table_iterator& other) noexcept //
80
470k
      : iter_{ other.iter_ }
81
470k
    {}
82
83
    table_iterator& operator=(const table_iterator& rhs) noexcept
84
447k
    {
85
447k
      iter_       = rhs.iter_;
86
447k
      proxy_instantiated_ = false;
87
447k
      return *this;
88
447k
    }
89
90
    using value_type    = table_proxy_pair<IsConst>;
91
    using reference     = value_type&;
92
    using pointer     = value_type*;
93
    using difference_type = typename std::iterator_traits<map_iterator>::difference_type;
94
    using iterator_category = typename std::iterator_traits<map_iterator>::iterator_category;
95
96
    table_iterator& operator++() noexcept // ++pre
97
470k
    {
98
470k
      ++iter_;
99
470k
      proxy_instantiated_ = false;
100
470k
      return *this;
101
470k
    }
toml::v3::impl::table_iterator<false>::operator++()
Line
Count
Source
97
470k
    {
98
470k
      ++iter_;
99
470k
      proxy_instantiated_ = false;
100
470k
      return *this;
101
470k
    }
Unexecuted instantiation: toml::v3::impl::table_iterator<true>::operator++()
102
103
    table_iterator operator++(int) noexcept // post++
104
    {
105
      table_iterator out{ iter_ };
106
      ++iter_;
107
      proxy_instantiated_ = false;
108
      return out;
109
    }
110
111
    table_iterator& operator--() noexcept // --pre
112
    {
113
      --iter_;
114
      proxy_instantiated_ = false;
115
      return *this;
116
    }
117
118
    table_iterator operator--(int) noexcept // post--
119
    {
120
      table_iterator out{ iter_ };
121
      --iter_;
122
      proxy_instantiated_ = false;
123
      return out;
124
    }
125
126
    TOML_PURE_INLINE_GETTER
127
    reference operator*() const noexcept
128
470k
    {
129
470k
      return *get_proxy();
130
470k
    }
toml::v3::impl::table_iterator<false>::operator*() const
Line
Count
Source
128
470k
    {
129
470k
      return *get_proxy();
130
470k
    }
Unexecuted instantiation: toml::v3::impl::table_iterator<true>::operator*() const
131
132
    TOML_PURE_INLINE_GETTER
133
    pointer operator->() const noexcept
134
782k
    {
135
782k
      return get_proxy();
136
782k
    }
137
138
    TOML_PURE_INLINE_GETTER
139
    explicit operator const map_iterator&() const noexcept
140
470k
    {
141
470k
      return iter_;
142
470k
    }
143
144
    TOML_CONSTRAINED_TEMPLATE(!C, bool C = IsConst)
145
    TOML_PURE_INLINE_GETTER
146
    explicit operator const const_map_iterator() const noexcept
147
0
    {
148
0
      return iter_;
149
0
    }
150
151
    TOML_PURE_INLINE_GETTER
152
    friend bool operator==(const table_iterator& lhs, const table_iterator& rhs) noexcept
153
    {
154
      return lhs.iter_ == rhs.iter_;
155
    }
156
157
    TOML_PURE_INLINE_GETTER
158
    friend bool operator!=(const table_iterator& lhs, const table_iterator& rhs) noexcept
159
1.51M
    {
160
1.51M
      return lhs.iter_ != rhs.iter_;
161
1.51M
    }
toml::v3::impl::operator!=(toml::v3::impl::table_iterator<false> const&, toml::v3::impl::table_iterator<false> const&)
Line
Count
Source
159
1.51M
    {
160
1.51M
      return lhs.iter_ != rhs.iter_;
161
1.51M
    }
Unexecuted instantiation: toml::v3::impl::operator!=(toml::v3::impl::table_iterator<true> const&, toml::v3::impl::table_iterator<true> const&)
162
  };
163
164
  struct table_init_pair
165
  {
166
    mutable toml::key key;
167
    mutable node_ptr value;
168
169
    template <typename K, typename V>
170
    TOML_NODISCARD_CTOR
171
    table_init_pair(K&& k, V&& v, value_flags flags = preserve_source_value_flags) //
172
      : key{ static_cast<K&&>(k) },
173
        value{ make_node(static_cast<V&&>(v), flags) }
174
    {}
175
  };
176
}
177
TOML_IMPL_NAMESPACE_END;
178
/// \endcond
179
180
TOML_NAMESPACE_START
181
{
182
  /// \brief A BidirectionalIterator for iterating over key-value pairs in a toml::table.
183
  using table_iterator = POXY_IMPLEMENTATION_DETAIL(impl::table_iterator<false>);
184
185
  /// \brief A BidirectionalIterator for iterating over const key-value pairs in a toml::table.
186
  using const_table_iterator = POXY_IMPLEMENTATION_DETAIL(impl::table_iterator<true>);
187
188
  /// \brief  A TOML table.
189
  ///
190
  /// \detail The interface of this type is modeled after std::map, with some
191
  ///     additional considerations made for the heterogeneous nature of a
192
  ///     TOML table.
193
  ///
194
  /// \cpp
195
  /// toml::table tbl = toml::parse(R"(
196
  ///
197
  ///   [animals]
198
  ///   cats = [ "tiger", "lion", "puma" ]
199
  ///   birds = [ "macaw", "pigeon", "canary" ]
200
  ///   fish = [ "salmon", "trout", "carp" ]
201
  ///
202
  /// )"sv);
203
  ///
204
  /// // operator[] retrieves node-views
205
  /// std::cout << "cats: " << tbl["animals"]["cats"] << "\n";
206
  /// std::cout << "fish[1]: " << tbl["animals"]["fish"][1] << "\n";
207
  ///
208
  /// // at_path() does fully-qualified "toml path" lookups
209
  /// std::cout << "cats: " << tbl.at_path("animals.cats") << "\n";
210
  /// std::cout << "fish[1]: " << tbl.at_path("animals.fish[1]") << "\n";
211
  /// \ecpp
212
  ///
213
  /// \out
214
  /// cats: ['tiger', 'lion', 'puma']
215
  /// fish[1] : 'trout'
216
  /// cats : ['tiger', 'lion', 'puma']
217
  /// fish[1] : 'trout'
218
  /// \eout
219
  class TOML_EXPORTED_CLASS table : public node
220
  {
221
    private:
222
    /// \cond
223
224
    using map_type       = std::map<toml::key, impl::node_ptr, std::less<>>;
225
    using map_pair       = std::pair<const toml::key, impl::node_ptr>;
226
    using map_iterator     = typename map_type::iterator;
227
    using const_map_iterator = typename map_type::const_iterator;
228
    map_type map_;
229
230
    bool inline_ = false;
231
232
    TOML_NODISCARD_CTOR
233
    TOML_EXPORTED_MEMBER_FUNCTION
234
    table(const impl::table_init_pair*, const impl::table_init_pair*);
235
236
    /// \endcond
237
238
    public:
239
    /// \brief  Default constructor.
240
    TOML_NODISCARD_CTOR
241
    TOML_EXPORTED_MEMBER_FUNCTION
242
    table() noexcept;
243
244
    TOML_EXPORTED_MEMBER_FUNCTION
245
    ~table() noexcept;
246
247
    /// \brief  Copy constructor.
248
    TOML_NODISCARD_CTOR
249
    TOML_EXPORTED_MEMBER_FUNCTION
250
    table(const table&);
251
252
    /// \brief  Move constructor.
253
    TOML_NODISCARD_CTOR
254
    TOML_EXPORTED_MEMBER_FUNCTION
255
    table(table&& other) noexcept;
256
257
    /// \brief  Constructs a table with one or more initial key-value pairs.
258
    ///
259
    /// \detail \cpp
260
    /// auto tbl = toml::table{
261
    ///   { "foo", 1 },
262
    ///   { "bar", 2.0 },
263
    ///   { "kek", "three" }
264
    /// };
265
    /// std::cout << tbl << "\n";
266
    /// \ecpp
267
    ///
268
    /// \out
269
    /// { foo = 1, bar = 2.0, kek = "three" }
270
    /// \eout
271
    ///
272
    /// \param  kvps  A list of key-value pairs used to initialize the table.
273
    TOML_NODISCARD_CTOR
274
    TOML_EXPORTED_MEMBER_FUNCTION
275
    explicit table(std::initializer_list<impl::table_init_pair> kvps) //
276
      : table(kvps.begin(), kvps.end())
277
0
    {}
278
279
    /// \brief  Copy-assignment operator.
280
    TOML_EXPORTED_MEMBER_FUNCTION
281
    table& operator=(const table&);
282
283
    /// \brief  Move-assignment operator.
284
    TOML_EXPORTED_MEMBER_FUNCTION
285
    table& operator=(table&& rhs) noexcept;
286
287
    /// \name Type checks
288
    /// @{
289
290
    /// \brief Returns #toml::node_type::table.
291
    TOML_CONST_INLINE_GETTER
292
    node_type type() const noexcept final
293
463k
    {
294
463k
      return node_type::table;
295
463k
    }
296
297
    TOML_PURE_GETTER
298
    TOML_EXPORTED_MEMBER_FUNCTION
299
    bool is_homogeneous(node_type ntype) const noexcept final;
300
301
    TOML_NODISCARD
302
    TOML_EXPORTED_MEMBER_FUNCTION
303
    bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept final;
304
305
    TOML_NODISCARD
306
    TOML_EXPORTED_MEMBER_FUNCTION
307
    bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept final;
308
309
    /// \cond
310
    template <typename ElemType = void>
311
    TOML_PURE_GETTER
312
    bool is_homogeneous() const noexcept
313
    {
314
      using type = impl::remove_cvref<impl::unwrap_node<ElemType>>;
315
      static_assert(std::is_void_v<type> || toml::is_value<type> || toml::is_container<type>,
316
              "The template type argument of table::is_homogeneous() must be void or one "
317
              "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
318
319
      return is_homogeneous(impl::node_type_of<type>);
320
    }
321
    /// \endcond
322
323
    /// \brief Returns `true`.
324
    TOML_CONST_INLINE_GETTER
325
    bool is_table() const noexcept final
326
6.61k
    {
327
6.61k
      return true;
328
6.61k
    }
329
330
    /// \brief Returns `false`.
331
    TOML_CONST_INLINE_GETTER
332
    bool is_array() const noexcept final
333
0
    {
334
0
      return false;
335
0
    }
336
337
    /// \brief Returns `false`.
338
    TOML_PURE_GETTER
339
    bool is_array_of_tables() const noexcept final
340
0
    {
341
0
      return false;
342
0
    }
343
344
    /// \brief Returns `false`.
345
    TOML_CONST_INLINE_GETTER
346
    bool is_value() const noexcept final
347
0
    {
348
0
      return false;
349
0
    }
350
351
    /// \brief Returns `false`.
352
    TOML_CONST_INLINE_GETTER
353
    bool is_string() const noexcept final
354
0
    {
355
0
      return false;
356
0
    }
357
358
    /// \brief Returns `false`.
359
    TOML_CONST_INLINE_GETTER
360
    bool is_integer() const noexcept final
361
0
    {
362
0
      return false;
363
0
    }
364
365
    /// \brief Returns `false`.
366
    TOML_CONST_INLINE_GETTER
367
    bool is_floating_point() const noexcept final
368
0
    {
369
0
      return false;
370
0
    }
371
372
    /// \brief Returns `false`.
373
    TOML_CONST_INLINE_GETTER
374
    bool is_number() const noexcept final
375
0
    {
376
0
      return false;
377
0
    }
378
379
    /// \brief Returns `false`.
380
    TOML_CONST_INLINE_GETTER
381
    bool is_boolean() const noexcept final
382
0
    {
383
0
      return false;
384
0
    }
385
386
    /// \brief Returns `false`.
387
    TOML_CONST_INLINE_GETTER
388
    bool is_date() const noexcept final
389
0
    {
390
0
      return false;
391
0
    }
392
393
    /// \brief Returns `false`.
394
    TOML_CONST_INLINE_GETTER
395
    bool is_time() const noexcept final
396
0
    {
397
0
      return false;
398
0
    }
399
400
    /// \brief Returns `false`.
401
    TOML_CONST_INLINE_GETTER
402
    bool is_date_time() const noexcept final
403
0
    {
404
0
      return false;
405
0
    }
406
407
    /// @}
408
409
    /// \name Type casts
410
    /// @{
411
412
    /// \brief Returns a pointer to the table.
413
    TOML_CONST_INLINE_GETTER
414
    table* as_table() noexcept final
415
49.8k
    {
416
49.8k
      return this;
417
49.8k
    }
418
419
    /// \brief Returns `nullptr`.
420
    TOML_CONST_INLINE_GETTER
421
    array* as_array() noexcept final
422
7.28k
    {
423
7.28k
      return nullptr;
424
7.28k
    }
425
426
    /// \brief Returns `nullptr`.
427
    TOML_CONST_INLINE_GETTER
428
    toml::value<std::string>* as_string() noexcept final
429
0
    {
430
0
      return nullptr;
431
0
    }
432
433
    /// \brief Returns `nullptr`.
434
    TOML_CONST_INLINE_GETTER
435
    toml::value<int64_t>* as_integer() noexcept final
436
0
    {
437
0
      return nullptr;
438
0
    }
439
440
    /// \brief Returns `nullptr`.
441
    TOML_CONST_INLINE_GETTER
442
    toml::value<double>* as_floating_point() noexcept final
443
0
    {
444
0
      return nullptr;
445
0
    }
446
447
    /// \brief Returns `nullptr`.
448
    TOML_CONST_INLINE_GETTER
449
    toml::value<bool>* as_boolean() noexcept final
450
0
    {
451
0
      return nullptr;
452
0
    }
453
454
    /// \brief Returns `nullptr`.
455
    TOML_CONST_INLINE_GETTER
456
    toml::value<date>* as_date() noexcept final
457
0
    {
458
0
      return nullptr;
459
0
    }
460
461
    /// \brief Returns `nullptr`.
462
    TOML_CONST_INLINE_GETTER
463
    toml::value<time>* as_time() noexcept final
464
0
    {
465
0
      return nullptr;
466
0
    }
467
468
    /// \brief Returns `nullptr`.
469
    TOML_CONST_INLINE_GETTER
470
    toml::value<date_time>* as_date_time() noexcept final
471
0
    {
472
0
      return nullptr;
473
0
    }
474
475
    /// \brief Returns a const-qualified pointer to the table.
476
    TOML_CONST_INLINE_GETTER
477
    const table* as_table() const noexcept final
478
0
    {
479
0
      return this;
480
0
    }
481
482
    /// \brief Returns `nullptr`.
483
    TOML_CONST_INLINE_GETTER
484
    const array* as_array() const noexcept final
485
0
    {
486
0
      return nullptr;
487
0
    }
488
489
    /// \brief Returns `nullptr`.
490
    TOML_CONST_INLINE_GETTER
491
    const toml::value<std::string>* as_string() const noexcept final
492
0
    {
493
0
      return nullptr;
494
0
    }
495
496
    /// \brief Returns `nullptr`.
497
    TOML_CONST_INLINE_GETTER
498
    const toml::value<int64_t>* as_integer() const noexcept final
499
0
    {
500
0
      return nullptr;
501
0
    }
502
503
    /// \brief Returns `nullptr`.
504
    TOML_CONST_INLINE_GETTER
505
    const toml::value<double>* as_floating_point() const noexcept final
506
0
    {
507
0
      return nullptr;
508
0
    }
509
510
    /// \brief Returns `nullptr`.
511
    TOML_CONST_INLINE_GETTER
512
    const toml::value<bool>* as_boolean() const noexcept final
513
0
    {
514
0
      return nullptr;
515
0
    }
516
517
    /// \brief Returns `nullptr`.
518
    TOML_CONST_INLINE_GETTER
519
    const toml::value<date>* as_date() const noexcept final
520
0
    {
521
0
      return nullptr;
522
0
    }
523
524
    /// \brief Returns `nullptr`.
525
    TOML_CONST_INLINE_GETTER
526
    const toml::value<time>* as_time() const noexcept final
527
0
    {
528
0
      return nullptr;
529
0
    }
530
531
    /// \brief Returns `nullptr`.
532
    TOML_CONST_INLINE_GETTER
533
    const toml::value<date_time>* as_date_time() const noexcept final
534
0
    {
535
0
      return nullptr;
536
0
    }
537
538
    /// @}
539
540
    /// \name Metadata
541
    /// @{
542
543
    /// \brief  Returns true if this table is an inline table.
544
    ///
545
    /// \remarks Runtime-constructed tables (i.e. those not created during
546
    ///      parsing) are not inline by default.
547
    TOML_PURE_INLINE_GETTER
548
    bool is_inline() const noexcept
549
468k
    {
550
468k
      return inline_;
551
468k
    }
552
553
    /// \brief  Sets whether this table is a TOML inline table.
554
    ///
555
    /// \detail \godbolt{an9xdj}
556
    ///
557
    /// \cpp
558
    /// auto tbl = toml::table{
559
    ///   { "a", 1 },
560
    ///   { "b", 2 },
561
    ///   { "c", 3 },
562
    ///   { "d", toml::table{ { "e", 4 } } }
563
    /// };
564
    /// std::cout << "is inline? "sv << tbl.is_inline() << "\n";
565
    /// std::cout << tbl << "\n\n";
566
    ///
567
    /// tbl.is_inline(!tbl.is_inline());
568
    /// std::cout << "is inline? "sv << tbl.is_inline() << "\n";
569
    /// std::cout << tbl << "\n";
570
    /// \ecpp
571
    ///
572
    /// \out
573
    /// is inline? false
574
    /// a = 1
575
    /// b = 2
576
    /// c = 3
577
    ///
578
    /// [d]
579
    /// e = 4
580
    ///
581
    ///
582
    /// is inline? true
583
    /// { a = 1, b = 2, c = 3, d = { e = 4 } }
584
    /// \eout
585
    ///
586
    /// \remarks A table being 'inline' is only relevent during printing;
587
    ///      it has no effect on the general functionality of the table
588
    ///      object.
589
    ///
590
    /// \param  val The new value for 'inline'.
591
    void is_inline(bool val) noexcept
592
3.93k
    {
593
3.93k
      inline_ = val;
594
3.93k
    }
595
596
    /// @}
597
598
    /// \name Value retrieval
599
    /// @{
600
601
    /// \brief  Gets the node at a specific key.
602
    ///
603
    /// \detail \cpp
604
    /// auto tbl = toml::table{
605
    ///   { "a", 42, },
606
    ///   { "b", "is the meaning of life, apparently." }
607
    /// };
608
    /// std::cout << R"(node ["a"] exists: )"sv << !!tbl.get("a") << "\n";
609
    /// std::cout << R"(node ["b"] exists: )"sv << !!tbl.get("b") << "\n";
610
    /// std::cout << R"(node ["c"] exists: )"sv << !!tbl.get("c") << "\n";
611
    /// if (auto val = tbl.get("a"))
612
    ///   std::cout << R"(node ["a"] was an )"sv << val->type() << "\n";
613
    /// \ecpp
614
    ///
615
    /// \out
616
    /// node ["a"] exists: true
617
    /// node ["b"] exists: true
618
    /// node ["c"] exists: false
619
    /// node ["a"] was an integer
620
    /// \eout
621
    ///
622
    /// \param  key The node's key.
623
    ///
624
    /// \returns  A pointer to the node at the specified key, or nullptr.
625
    TOML_PURE_GETTER
626
    TOML_EXPORTED_MEMBER_FUNCTION
627
    node* get(std::string_view key) noexcept;
628
629
    /// \brief  Gets the node at a specific key (const overload).
630
    ///
631
    /// \param  key The node's key.
632
    ///
633
    /// \returns  A pointer to the node at the specified key, or nullptr.
634
    TOML_PURE_INLINE_GETTER
635
    const node* get(std::string_view key) const noexcept
636
0
    {
637
0
      return const_cast<table&>(*this).get(key);
638
0
    }
639
640
#if TOML_ENABLE_WINDOWS_COMPAT
641
642
    /// \brief  Gets the node at a specific key.
643
    ///
644
    /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
645
    ///
646
    /// \param  key The node's key.
647
    ///
648
    /// \returns  A pointer to the node at the specified key, or nullptr.
649
    TOML_NODISCARD
650
    node* get(std::wstring_view key)
651
    {
652
      if (empty())
653
        return nullptr;
654
655
      return get(impl::narrow(key));
656
    }
657
658
    /// \brief  Gets the node at a specific key (const overload).
659
    ///
660
    /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
661
    ///
662
    /// \param  key The node's key.
663
    ///
664
    /// \returns  A pointer to the node at the specified key, or nullptr.
665
    TOML_NODISCARD
666
    const node* get(std::wstring_view key) const
667
    {
668
      return const_cast<table&>(*this).get(key);
669
    }
670
671
#endif // TOML_ENABLE_WINDOWS_COMPAT
672
673
    /// \brief  Gets the node at a specific key if it is a particular type.
674
    ///
675
    /// \detail \cpp
676
    /// auto tbl = toml::table{
677
    ///   { "a", 42, },
678
    ///   { "b", "is the meaning of life, apparently." }
679
    /// };
680
    /// if (auto val = arr.get_as<int64_t>("a"))
681
    ///   std::cout << R"(node ["a"] was an integer with value )"sv << **val << "\n";
682
    /// \ecpp
683
    ///
684
    /// \out
685
    /// node ["a"] was an integer with value 42
686
    /// \eout
687
    ///
688
    /// \tparam T   One of the TOML node or value types.
689
    /// \param  key   The node's key.
690
    ///
691
    /// \returns  A pointer to the node at the specified key if it was of the given type, or nullptr.
692
    template <typename T>
693
    TOML_PURE_GETTER
694
    impl::wrap_node<T>* get_as(std::string_view key) noexcept
695
    {
696
      const auto n = this->get(key);
697
      return n ? n->template as<T>() : nullptr;
698
    }
699
700
    /// \brief  Gets the node at a specific key if it is a particular type (const overload).
701
    ///
702
    /// \tparam T   One of the TOML node or value types.
703
    /// \param  key   The node's key.
704
    ///
705
    /// \returns  A pointer to the node at the specified key if it was of the given type, or nullptr.
706
    template <typename T>
707
    TOML_PURE_GETTER
708
    const impl::wrap_node<T>* get_as(std::string_view key) const noexcept
709
    {
710
      return const_cast<table&>(*this).template get_as<T>(key);
711
    }
712
713
#if TOML_ENABLE_WINDOWS_COMPAT
714
715
    /// \brief  Gets the node at a specific key if it is a particular type.
716
    ///
717
    /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
718
    ///
719
    /// \tparam T   One of the TOML node or value types.
720
    /// \param  key   The node's key.
721
    ///
722
    /// \returns  A pointer to the node at the specified key if it was of the given type, or nullptr.
723
    template <typename T>
724
    TOML_NODISCARD
725
    impl::wrap_node<T>* get_as(std::wstring_view key)
726
    {
727
      if (empty())
728
        return nullptr;
729
730
      return get_as<T>(impl::narrow(key));
731
    }
732
733
    /// \brief  Gets the node at a specific key if it is a particular type (const overload).
734
    ///
735
    /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
736
    ///
737
    /// \tparam T   One of the TOML node or value types.
738
    /// \param  key   The node's key.
739
    ///
740
    /// \returns  A pointer to the node at the specified key if it was of the given type, or nullptr.
741
    template <typename T>
742
    TOML_NODISCARD
743
    const impl::wrap_node<T>* get_as(std::wstring_view key) const
744
    {
745
      return const_cast<table&>(*this).template get_as<T>(key);
746
    }
747
748
#endif // TOML_ENABLE_WINDOWS_COMPAT
749
750
    /// \brief  Gets a reference to the element at a specific key, throwing `std::out_of_range` if none existed.
751
    TOML_NODISCARD
752
    TOML_EXPORTED_MEMBER_FUNCTION
753
    node& at(std::string_view key);
754
755
    /// \brief  Gets a reference to the element at a specific key, throwing `std::out_of_range` if none existed.
756
    TOML_NODISCARD
757
    const node& at(std::string_view key) const
758
0
    {
759
0
      return const_cast<table&>(*this).at(key);
760
0
    }
761
762
#if TOML_ENABLE_WINDOWS_COMPAT
763
764
    /// \brief  Gets a reference to the element at a specific key, throwing `std::out_of_range` if none existed.
765
    ///
766
    /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
767
    TOML_NODISCARD
768
    node& at(std::wstring_view key)
769
    {
770
      return at(impl::narrow(key));
771
    }
772
773
    /// \brief  Gets a reference to the element at a specific key, throwing `std::out_of_range` if none existed.
774
    ///
775
    /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
776
    TOML_NODISCARD
777
    const node& at(std::wstring_view key) const
778
    {
779
      return const_cast<table&>(*this).at(key);
780
    }
781
782
#endif // TOML_ENABLE_WINDOWS_COMPAT
783
784
    /// @}
785
786
    /// \name Iteration
787
    /// @{
788
789
    /// \brief A BidirectionalIterator for iterating over key-value pairs in a toml::table.
790
    using iterator = toml::table_iterator;
791
792
    /// \brief A BidirectionalIterator for iterating over const key-value pairs in a toml::table.
793
    using const_iterator = toml::const_table_iterator;
794
795
    /// \brief  Returns an iterator to the first key-value pair.
796
    TOML_PURE_INLINE_GETTER
797
    iterator begin() noexcept
798
433k
    {
799
433k
      return iterator{ map_.begin() };
800
433k
    }
801
802
    /// \brief  Returns an iterator to the first key-value pair.
803
    TOML_PURE_INLINE_GETTER
804
    const_iterator begin() const noexcept
805
0
    {
806
0
      return const_iterator{ map_.cbegin() };
807
0
    }
808
809
    /// \brief  Returns an iterator to the first key-value pair.
810
    TOML_PURE_INLINE_GETTER
811
    const_iterator cbegin() const noexcept
812
0
    {
813
0
      return const_iterator{ map_.cbegin() };
814
0
    }
815
816
    /// \brief  Returns an iterator to one-past-the-last key-value pair.
817
    TOML_PURE_INLINE_GETTER
818
    iterator end() noexcept
819
1.04M
    {
820
1.04M
      return iterator{ map_.end() };
821
1.04M
    }
822
823
    /// \brief  Returns an iterator to one-past-the-last key-value pair.
824
    TOML_PURE_INLINE_GETTER
825
    const_iterator end() const noexcept
826
0
    {
827
0
      return const_iterator{ map_.cend() };
828
0
    }
829
830
    /// \brief  Returns an iterator to one-past-the-last key-value pair.
831
    TOML_PURE_INLINE_GETTER
832
    const_iterator cend() const noexcept
833
0
    {
834
0
      return const_iterator{ map_.cend() };
835
0
    }
836
837
    private:
838
    /// \cond
839
840
    template <typename T, typename Table>
841
    using for_each_value_ref = impl::copy_cvref<impl::wrap_node<impl::remove_cvref<impl::unwrap_node<T>>>, Table>;
842
843
    template <typename Func, typename Table, typename T>
844
    using can_for_each = std::disjunction<std::is_invocable<Func, const key&, for_each_value_ref<T, Table>>, //
845
                        std::is_invocable<Func, for_each_value_ref<T, Table>>>;
846
847
    template <typename Func, typename Table, typename T>
848
    using can_for_each_nothrow = std::conditional_t<
849
      // first form
850
      std::is_invocable_v<Func, const key&, for_each_value_ref<T, Table>>,
851
      std::is_nothrow_invocable<Func, const key&, for_each_value_ref<T, Table>>,
852
      std::conditional_t<
853
        // second form
854
        std::is_invocable_v<Func, for_each_value_ref<T, Table>>,
855
        std::is_nothrow_invocable<Func, for_each_value_ref<T, Table>>,
856
        std::false_type>>;
857
858
    template <typename Func, typename Table>
859
    using can_for_each_any = std::disjunction<can_for_each<Func, Table, table>,
860
                          can_for_each<Func, Table, array>,
861
                          can_for_each<Func, Table, std::string>,
862
                          can_for_each<Func, Table, int64_t>,
863
                          can_for_each<Func, Table, double>,
864
                          can_for_each<Func, Table, bool>,
865
                          can_for_each<Func, Table, date>,
866
                          can_for_each<Func, Table, time>,
867
                          can_for_each<Func, Table, date_time>>;
868
869
    template <typename Func, typename Table, typename T>
870
    using for_each_is_nothrow_one = std::disjunction<std::negation<can_for_each<Func, Table, T>>, //
871
                             can_for_each_nothrow<Func, Table, T>>;
872
873
    template <typename Func, typename Table>
874
    using for_each_is_nothrow = std::conjunction<for_each_is_nothrow_one<Func, Table, table>,
875
                           for_each_is_nothrow_one<Func, Table, array>,
876
                           for_each_is_nothrow_one<Func, Table, std::string>,
877
                           for_each_is_nothrow_one<Func, Table, int64_t>,
878
                           for_each_is_nothrow_one<Func, Table, double>,
879
                           for_each_is_nothrow_one<Func, Table, bool>,
880
                           for_each_is_nothrow_one<Func, Table, date>,
881
                           for_each_is_nothrow_one<Func, Table, time>,
882
                           for_each_is_nothrow_one<Func, Table, date_time>>;
883
884
    template <typename Func, typename Table>
885
    static void do_for_each(Func&& visitor, Table&& tbl) //
886
      noexcept(for_each_is_nothrow<Func&&, Table&&>::value)
887
    {
888
      static_assert(can_for_each_any<Func&&, Table&&>::value,
889
              "TOML table for_each visitors must be invocable for at least one of the toml::node "
890
              "specializations:" TOML_SA_NODE_TYPE_LIST);
891
892
      using kvp_type = impl::copy_cv<map_pair, std::remove_reference_t<Table>>;
893
894
      for (kvp_type& kvp : tbl.map_)
895
      {
896
        using node_ref = impl::copy_cvref<toml::node, Table&&>;
897
        static_assert(std::is_reference_v<node_ref>);
898
899
#if TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN
900
901
#ifndef TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_ACKNOWLEDGED
902
        static_assert(impl::always_false<Func, Table, kvp_type, node_ref>, //
903
                TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_MESSAGE);
904
#endif
905
906
        static_cast<node_ref>(*kvp.second)
907
          .visit(
908
            [&]([[maybe_unused]] auto&& v) //
909
            noexcept(for_each_is_nothrow_one<Func&&, Table&&, decltype(v)>::value)
910
            {
911
              using value_ref = for_each_value_ref<decltype(v), Table&&>;
912
              static_assert(std::is_reference_v<value_ref>);
913
914
              // func(key, val)
915
              if constexpr (std::is_invocable_v<Func&&, const key&, value_ref>)
916
              {
917
                static_cast<Func&&>(visitor)(static_cast<const key&>(kvp.first),
918
                               static_cast<value_ref>(v));
919
              }
920
921
              // func(val)
922
              else if constexpr (std::is_invocable_v<Func&&, value_ref>)
923
              {
924
                static_cast<Func&&>(visitor)(static_cast<value_ref>(v));
925
              }
926
            });
927
928
#else
929
        const auto keep_going =
930
          static_cast<node_ref>(*kvp.second)
931
            .visit(
932
              [&]([[maybe_unused]] auto&& v) //
933
// Define this macro as a workaround to compile errors caused by a bug in MSVC's "legacy lambda processor".
934
#if !TOML_DISABLE_CONDITIONAL_NOEXCEPT_LAMBDA
935
              noexcept(for_each_is_nothrow_one<Func&&, Table&&, decltype(v)>::value)
936
#endif
937
              {
938
                using value_ref = for_each_value_ref<decltype(v), Table&&>;
939
                static_assert(std::is_reference_v<value_ref>);
940
941
                // func(key, val)
942
                if constexpr (std::is_invocable_v<Func&&, const key&, value_ref>)
943
                {
944
                  using return_type = decltype(static_cast<Func&&>(
945
                    visitor)(static_cast<const key&>(kvp.first), static_cast<value_ref>(v)));
946
947
                  if constexpr (impl::is_constructible_or_convertible<bool, return_type>)
948
                  {
949
                    return static_cast<bool>(static_cast<Func&&>(
950
                      visitor)(static_cast<const key&>(kvp.first), static_cast<value_ref>(v)));
951
                  }
952
                  else
953
                  {
954
                    static_cast<Func&&>(visitor)(static_cast<const key&>(kvp.first),
955
                                   static_cast<value_ref>(v));
956
                    return true;
957
                  }
958
                }
959
960
                // func(val)
961
                else if constexpr (std::is_invocable_v<Func&&, value_ref>)
962
                {
963
                  using return_type =
964
                    decltype(static_cast<Func&&>(visitor)(static_cast<value_ref>(v)));
965
966
                  if constexpr (impl::is_constructible_or_convertible<bool, return_type>)
967
                  {
968
                    return static_cast<bool>(
969
                      static_cast<Func&&>(visitor)(static_cast<value_ref>(v)));
970
                  }
971
                  else
972
                  {
973
                    static_cast<Func&&>(visitor)(static_cast<value_ref>(v));
974
                    return true;
975
                  }
976
                }
977
978
                // visitor not compatible with this particular type
979
                else
980
                  return true;
981
              });
982
983
        if (!keep_going)
984
          return;
985
#endif
986
      }
987
    }
988
989
    /// \endcond
990
991
    public:
992
    /// \brief  Invokes a visitor on each key-value pair in the table.
993
    ///
994
    /// \tparam Func  A callable type invocable with one of the following signatures:
995
    ///         <ul>
996
    ///         <li> `func(key, val)`
997
    ///         <li> `func(val)`
998
    ///         </ul>
999
    ///         Where:
1000
    ///         <ul>
1001
    ///         <li> `key` will recieve a const reference to a toml::key
1002
    ///         <li> `val` will recieve the value as it's concrete type with cvref-qualifications matching the table
1003
    ///         </ul>
1004
    ///         Visitors returning `bool` (or something convertible to `bool`) will cause iteration to
1005
    ///         stop if they return `false`.
1006
    ///
1007
    /// \param  visitor The visitor object.
1008
    ///
1009
    /// \returns A reference to the table.
1010
    ///
1011
    /// \details \cpp
1012
    /// toml::table tbl{
1013
    ///   { "0",  0      },
1014
    ///   { "1",  1      },
1015
    ///   { "2",  2      },
1016
    ///   { "3",  3.0    },
1017
    ///   { "4",  "four" },
1018
    ///   { "5",  "five" },
1019
    ///   { "6",  6      }
1020
    /// };
1021
    ///
1022
    /// // select only the integers using a strongly-typed visitor
1023
    /// tbl.for_each([](toml::value<int64_t>& val)
1024
    /// {
1025
    ///   std::cout << val << ", ";
1026
    /// });
1027
    /// std::cout << "\n";
1028
    ///
1029
    /// // select all the numeric values using a generic visitor + is_number<> metafunction
1030
    /// tbl.for_each([](auto&& val)
1031
    /// {
1032
    ///   if constexpr (toml::is_number<decltype(val)>)
1033
    ///     std::cout << val << ", ";
1034
    /// });
1035
    /// std::cout << "\n";
1036
    ///
1037
    /// // select all the numeric values until we encounter something non-numeric
1038
    /// tbl.for_each([](auto&& val)
1039
    /// {
1040
    ///   if constexpr (toml::is_number<decltype(val)>)
1041
    ///   {
1042
    ///     std::cout << val << ", ";
1043
    ///     return true; // "keep going"
1044
    ///   }
1045
    ///   else
1046
    ///     return false; // "stop!"
1047
    ///
1048
    /// });
1049
    /// std::cout << "\n\n";
1050
    ///
1051
    /// // visitors may also recieve the key
1052
    /// tbl.for_each([](const toml::key& key, auto&& val)
1053
    /// {
1054
    ///   std::cout << key << ": " << val << "\n";
1055
    /// });
1056
    ///
1057
    /// \ecpp
1058
    /// \out
1059
    /// 0, 1, 2, 6,
1060
    /// 0, 1, 2, 3.0, 6,
1061
    /// 0, 1, 2, 3.0,
1062
    ///
1063
    /// 0: 0
1064
    /// 1: 1
1065
    /// 2: 2
1066
    /// 3: 3.0
1067
    /// 4: 'four'
1068
    /// 5: 'five'
1069
    /// 6: 6
1070
    /// \eout
1071
    ///
1072
    /// \see node::visit()
1073
    template <typename Func>
1074
    table& for_each(Func&& visitor) & //
1075
      noexcept(for_each_is_nothrow<Func&&, table&>::value)
1076
    {
1077
      do_for_each(static_cast<Func&&>(visitor), *this);
1078
      return *this;
1079
    }
1080
1081
    /// \brief  Invokes a visitor on each key-value pair in the table (rvalue overload).
1082
    template <typename Func>
1083
    table&& for_each(Func&& visitor) && //
1084
      noexcept(for_each_is_nothrow<Func&&, table&&>::value)
1085
    {
1086
      do_for_each(static_cast<Func&&>(visitor), static_cast<table&&>(*this));
1087
      return static_cast<table&&>(*this);
1088
    }
1089
1090
    /// \brief  Invokes a visitor on each key-value pair in the table (const lvalue overload).
1091
    template <typename Func>
1092
    const table& for_each(Func&& visitor) const& //
1093
      noexcept(for_each_is_nothrow<Func&&, const table&>::value)
1094
    {
1095
      do_for_each(static_cast<Func&&>(visitor), *this);
1096
      return *this;
1097
    }
1098
1099
    /// \brief  Invokes a visitor on each key-value pair in the table (const rvalue overload).
1100
    template <typename Func>
1101
    const table&& for_each(Func&& visitor) const&& //
1102
      noexcept(for_each_is_nothrow<Func&&, const table&&>::value)
1103
    {
1104
      do_for_each(static_cast<Func&&>(visitor), static_cast<const table&&>(*this));
1105
      return static_cast<const table&&>(*this);
1106
    }
1107
1108
    /// @}
1109
1110
    /// \name Size and Capacity
1111
    /// @{
1112
1113
    /// \brief  Returns true if the table is empty.
1114
    TOML_PURE_INLINE_GETTER
1115
    bool empty() const noexcept
1116
7.27k
    {
1117
7.27k
      return map_.empty();
1118
7.27k
    }
1119
1120
    /// \brief  Returns the number of key-value pairs in the table.
1121
    TOML_PURE_INLINE_GETTER
1122
    size_t size() const noexcept
1123
0
    {
1124
0
      return map_.size();
1125
0
    }
1126
1127
    /// @}
1128
1129
    /// \name Searching
1130
    /// @{
1131
1132
    private:
1133
    /// \cond
1134
1135
    TOML_PURE_GETTER
1136
    TOML_EXPORTED_MEMBER_FUNCTION
1137
    map_iterator get_lower_bound(std::string_view) noexcept;
1138
1139
    /// \endcond
1140
1141
    public:
1142
    /// \brief Returns an iterator to the first key-value pair with key that is _not less_ than the given key.
1143
    ///
1144
    /// \returns  An iterator to the first matching key-value pair, or #end().
1145
    TOML_PURE_GETTER
1146
    iterator lower_bound(std::string_view key) noexcept
1147
615k
    {
1148
615k
      return iterator{ get_lower_bound(key) };
1149
615k
    }
1150
1151
    /// \brief Returns a const iterator to the first key-value pair with key that is _not less_ than the given key.
1152
    ///
1153
    /// \returns  An iterator to the first matching key-value pair, or #end().
1154
    TOML_PURE_GETTER
1155
    const_iterator lower_bound(std::string_view key) const noexcept
1156
0
    {
1157
0
      return const_iterator{ const_cast<table&>(*this).get_lower_bound(key) };
1158
0
    }
1159
1160
#if TOML_ENABLE_WINDOWS_COMPAT
1161
1162
    /// \brief Returns an iterator to the first key-value pair with key that is _not less_ than the given key.
1163
    ///
1164
    /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
1165
    ///
1166
    /// \returns  An iterator to the first matching key-value pair, or #end().
1167
    TOML_NODISCARD
1168
    iterator lower_bound(std::wstring_view key)
1169
    {
1170
      if (empty())
1171
        return end();
1172
1173
      return lower_bound(impl::narrow(key));
1174
    }
1175
1176
    /// \brief Returns a const iterator to the first key-value pair with key that is _not less_ than the given key.
1177
    ///
1178
    /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
1179
    ///
1180
    /// \returns  An iterator to the first matching key-value pair, or #end().
1181
    TOML_NODISCARD
1182
    const_iterator lower_bound(std::wstring_view key) const
1183
    {
1184
      if (empty())
1185
        return end();
1186
1187
      return lower_bound(impl::narrow(key));
1188
    }
1189
1190
#endif // TOML_ENABLE_WINDOWS_COMPAT
1191
1192
    /// \brief  Gets an iterator to the node at a specific key.
1193
    ///
1194
    /// \param  key The node's key.
1195
    ///
1196
    /// \returns  An iterator to the node at the specified key, or end().
1197
    TOML_PURE_GETTER
1198
    TOML_EXPORTED_MEMBER_FUNCTION
1199
    iterator find(std::string_view key) noexcept;
1200
1201
    /// \brief  Gets an iterator to the node at a specific key (const overload)
1202
    ///
1203
    /// \param  key The node's key.
1204
    ///
1205
    /// \returns  A const iterator to the node at the specified key, or cend().
1206
    TOML_PURE_GETTER
1207
    TOML_EXPORTED_MEMBER_FUNCTION
1208
    const_iterator find(std::string_view key) const noexcept;
1209
1210
    /// \brief  Returns true if the table contains a node at the given key.
1211
    TOML_PURE_GETTER
1212
    bool contains(std::string_view key) const noexcept
1213
0
    {
1214
0
      return get(key) != nullptr;
1215
0
    }
1216
1217
#if TOML_ENABLE_WINDOWS_COMPAT
1218
1219
    /// \brief  Gets an iterator to the node at a specific key.
1220
    ///
1221
    /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
1222
    ///
1223
    /// \param  key The node's key.
1224
    ///
1225
    /// \returns  An iterator to the node at the specified key, or end().
1226
    TOML_NODISCARD
1227
    iterator find(std::wstring_view key)
1228
    {
1229
      if (empty())
1230
        return end();
1231
1232
      return find(impl::narrow(key));
1233
    }
1234
1235
    /// \brief  Gets an iterator to the node at a specific key (const overload).
1236
    ///
1237
    /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
1238
    ///
1239
    /// \param  key The node's key.
1240
    ///
1241
    /// \returns  A const iterator to the node at the specified key, or cend().
1242
    TOML_NODISCARD
1243
    const_iterator find(std::wstring_view key) const
1244
    {
1245
      return find(impl::narrow(key));
1246
    }
1247
1248
    /// \brief  Returns true if the table contains a node at the given key.
1249
    ///
1250
    /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
1251
    TOML_NODISCARD
1252
    bool contains(std::wstring_view key) const
1253
    {
1254
      return contains(impl::narrow(key));
1255
    }
1256
1257
#endif // TOML_ENABLE_WINDOWS_COMPAT
1258
1259
    /// @}
1260
1261
    /// \name Erasure
1262
    /// @{
1263
1264
    private:
1265
    /// \cond
1266
1267
    TOML_EXPORTED_MEMBER_FUNCTION
1268
    map_iterator erase(const_map_iterator) noexcept;
1269
1270
    TOML_EXPORTED_MEMBER_FUNCTION
1271
    map_iterator erase(const_map_iterator, const_map_iterator) noexcept;
1272
1273
    /// \endcond
1274
1275
    public:
1276
    /// \brief  Removes the specified key-value pair from the table.
1277
    ///
1278
    /// \detail \cpp
1279
    /// auto tbl = toml::table{
1280
    ///   { "a", 1 },
1281
    ///   { "b", 2 },
1282
    ///   { "c", 3 }
1283
    /// };
1284
    /// std::cout << tbl << "\n";
1285
    ///
1286
    /// tbl.erase(tbl.begin() + 1);
1287
    /// std::cout << tbl << "\n";
1288
    /// \ecpp
1289
    ///
1290
    /// \out
1291
    /// { a = 1, b = 2, c = 3 }
1292
    /// { a = 1, c = 3 }
1293
    /// \eout
1294
    ///
1295
    /// \param  pos   Iterator to the key-value pair being erased.
1296
    ///
1297
    /// \returns Iterator to the first key-value pair immediately following the removed key-value pair.
1298
    iterator erase(iterator pos) noexcept
1299
0
    {
1300
0
      return iterator{ erase(const_map_iterator{ pos }) };
1301
0
    }
1302
1303
    /// \brief  Removes the specified key-value pair from the table (const iterator overload).
1304
    ///
1305
    /// \detail \cpp
1306
    /// auto tbl = toml::table{
1307
    ///   { "a", 1 },
1308
    ///   { "b", 2 },
1309
    ///   { "c", 3 }
1310
    /// };
1311
    /// std::cout << tbl << "\n";
1312
    ///
1313
    /// tbl.erase(tbl.cbegin() + 1);
1314
    /// std::cout << tbl << "\n";
1315
    /// \ecpp
1316
    ///
1317
    /// \out
1318
    /// { a = 1, b = 2, c = 3 }
1319
    /// { a = 1, c = 3 }
1320
    /// \eout
1321
    ///
1322
    /// \param  pos   Iterator to the key-value pair being erased.
1323
    ///
1324
    /// \returns Iterator to the first key-value pair immediately following the removed key-value pair.
1325
    iterator erase(const_iterator pos) noexcept
1326
0
    {
1327
0
      return iterator{ erase(const_map_iterator{ pos }) };
1328
0
    }
1329
1330
    /// \brief  Removes the key-value pairs in the range [first, last) from the table.
1331
    ///
1332
    /// \detail \cpp
1333
    /// auto tbl = toml::table{
1334
    ///   { "a", 1 },
1335
    ///   { "b", "bad" },
1336
    ///   { "c", "karma" },
1337
    ///   { "d", 2 }
1338
    /// };
1339
    /// std::cout << tbl << "\n";
1340
    ///
1341
    /// tbl.erase(tbl.cbegin() + 1, tbl.cbegin() + 3);
1342
    /// std::cout << tbl << "\n";
1343
    /// \ecpp
1344
    ///
1345
    /// \out
1346
    /// { a = 1, b = "bad", c = "karma", d = 2 }
1347
    /// { a = 1, d = 2 }
1348
    /// \eout
1349
    ///
1350
    /// \param  begin Iterator to the first key-value pair being erased.
1351
    /// \param  end   Iterator to the one-past-the-last key-value pair being erased.
1352
    ///
1353
    /// \returns Iterator to the first key-value pair immediately following the last removed key-value pair.
1354
    iterator erase(const_iterator begin, const_iterator end) noexcept
1355
0
    {
1356
0
      return iterator{ erase(const_map_iterator{ begin }, const_map_iterator{ end }) };
1357
0
    }
1358
1359
    /// \brief  Removes the value with the given key from the table.
1360
    ///
1361
    /// \detail \cpp
1362
    /// auto tbl = toml::table{
1363
    ///   { "a", 1 },
1364
    ///   { "b", 2 },
1365
    ///   { "c", 3 }
1366
    /// };
1367
    /// std::cout << tbl << "\n";
1368
    ///
1369
    /// std::cout << tbl.erase("b") << "\n";
1370
    /// std::cout << tbl.erase("not an existing key") << "\n";
1371
    /// std::cout << tbl << "\n";
1372
    /// \ecpp
1373
    ///
1374
    /// \out
1375
    /// { a = 1, b = 2, c = 3 }
1376
    /// true
1377
    /// false
1378
    /// { a = 1, c = 3 }
1379
    /// \eout
1380
    ///
1381
    /// \param  key   Key to erase.
1382
    ///
1383
    /// \returns Number of elements removed (0 or 1).
1384
    TOML_EXPORTED_MEMBER_FUNCTION
1385
    size_t erase(std::string_view key) noexcept;
1386
1387
#if TOML_ENABLE_WINDOWS_COMPAT
1388
1389
    /// \brief  Removes the value with the given key from the table.
1390
    ///
1391
    /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
1392
    ///
1393
    /// \param  key   Key to erase.
1394
    ///
1395
    /// \returns Number of elements removed (0 or 1).
1396
    size_t erase(std::wstring_view key)
1397
    {
1398
      if (empty())
1399
        return false;
1400
1401
      return erase(impl::narrow(key));
1402
    }
1403
1404
#endif // TOML_ENABLE_WINDOWS_COMPAT
1405
1406
    /// \brief  Removes empty child arrays and tables.
1407
    ///
1408
    /// \detail \cpp
1409
    ///
1410
    /// auto tbl = toml::table{ { "a", 1 }, { "b", toml::array{ } }, { "c", toml::array{ toml::table{}, toml::array{} } } };
1411
    /// std::cout << arr << "\n";
1412
    ///
1413
    /// arr.prune();
1414
    /// std::cout << arr << "\n";
1415
    /// \ecpp
1416
    ///
1417
    /// \out
1418
    /// { a = 1, b = [], c = [ {}, [] ] }
1419
    /// { a = 1 }
1420
    /// \eout
1421
    ///
1422
    /// \param recursive Should child arrays and tables themselves be pruned?
1423
    ///
1424
    /// \returns A reference to the table.
1425
    TOML_EXPORTED_MEMBER_FUNCTION
1426
    table& prune(bool recursive = true) & noexcept;
1427
1428
    /// \brief  Removes empty child arrays and tables (rvalue overload).
1429
    ///
1430
    /// \param recursive Should child arrays and tables themselves be pruned?
1431
    ///
1432
    /// \returns An rvalue reference to the table.
1433
    table&& prune(bool recursive = true) && noexcept
1434
0
    {
1435
0
      return static_cast<toml::table&&>(this->prune(recursive));
1436
0
    }
1437
1438
    /// \brief  Removes all key-value pairs from the table.
1439
    TOML_EXPORTED_MEMBER_FUNCTION
1440
    void clear() noexcept;
1441
1442
    /// @}
1443
1444
    /// \name Insertion and Emplacement
1445
    /// @{
1446
1447
    private:
1448
    /// \cond
1449
1450
    TOML_EXPORTED_MEMBER_FUNCTION
1451
    map_iterator insert_with_hint(const_iterator, key&&, impl::node_ptr&&);
1452
1453
    /// \endcond
1454
1455
    public:
1456
    /// \brief  Emplaces a new value at a specific key if one did not already exist.
1457
    ///
1458
    /// \tparam ValueType toml::table, toml::array, or any native TOML value type.
1459
    /// \tparam KeyType   A toml::key or any compatible string type.
1460
    /// \tparam ValueArgs Value constructor argument types.
1461
    /// \param  hint    Iterator to the position before which the new element will be emplaced.
1462
    /// \param  key     The key at which to emplace the new value.
1463
    /// \param  args    Arguments to forward to the value's constructor.
1464
    ///
1465
    /// \returns An iterator to the emplacement position (or the position of the value that prevented emplacement)
1466
    ///
1467
    /// \note This function has exactly the same semantics as [std::map::emplace_hint()](https://en.cppreference.com/w/cpp/container/map/emplace_hint).
1468
    TOML_CONSTRAINED_TEMPLATE((is_key_or_convertible<KeyType&&> || impl::is_wide_string<KeyType>),
1469
                  typename ValueType = void,
1470
                  typename KeyType,
1471
                  typename... ValueArgs)
1472
    iterator emplace_hint(const_iterator hint, KeyType&& key, ValueArgs&&... args)
1473
470k
    {
1474
470k
      static_assert(!impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT,
1475
470k
              "Emplacement using wide-character keys is only supported on Windows with "
1476
470k
              "TOML_ENABLE_WINDOWS_COMPAT enabled.");
1477
1478
470k
      using raw_value_type = impl::remove_cvref<ValueType>;
1479
470k
      using value_type   = std::
1480
470k
        conditional_t<std::is_void_v<raw_value_type>, impl::emplaced_type_of<ValueArgs&&...>, raw_value_type>;
1481
1482
      if constexpr (impl::is_wide_string<KeyType>)
1483
      {
1484
#if TOML_ENABLE_WINDOWS_COMPAT
1485
        return emplace_hint<value_type>(hint,
1486
                        impl::narrow(static_cast<KeyType&&>(key)),
1487
                        static_cast<ValueArgs&&>(args)...);
1488
#else
1489
        static_assert(impl::always_false<KeyType>, "Evaluated unreachable branch!");
1490
#endif
1491
      }
1492
      else
1493
470k
      {
1494
470k
        static constexpr auto moving_node_ptr = std::is_same_v<value_type, impl::node_ptr> //
1495
0
                           && sizeof...(ValueArgs) == 1u           //
1496
0
                           && impl::first_is_same<impl::node_ptr&&, ValueArgs&&...>;
1497
470k
        using unwrapped_type = impl::remove_cvref<impl::unwrap_node<value_type>>;
1498
1499
470k
        static_assert(moving_node_ptr                   //
1500
470k
                  || impl::is_native<unwrapped_type>        //
1501
470k
                  || impl::is_one_of<unwrapped_type, table, array>, //
1502
470k
                "ValueType argument of table::emplace_hint() must be one "
1503
470k
                "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
1504
1505
470k
        map_iterator ipos = insert_with_hint(hint, toml::key{ static_cast<KeyType&&>(key) }, nullptr);
1506
1507
        // if second is nullptr then we successully claimed the key and inserted the empty sentinel,
1508
        // so now we have to construct the actual value
1509
470k
        if (!ipos->second)
1510
470k
        {
1511
          if constexpr (moving_node_ptr)
1512
23.4k
            ipos->second = std::move(static_cast<ValueArgs&&>(args)...);
1513
          else
1514
447k
          {
1515
447k
#if TOML_COMPILER_HAS_EXCEPTIONS
1516
447k
            try
1517
447k
            {
1518
447k
#endif
1519
447k
              ipos->second.reset(
1520
447k
                new impl::wrap_node<unwrapped_type>{ static_cast<ValueArgs&&>(args)... });
1521
447k
#if TOML_COMPILER_HAS_EXCEPTIONS
1522
447k
            }
1523
447k
            catch (...)
1524
447k
            {
1525
0
              erase(const_map_iterator{ ipos }); // strong exception guarantee
1526
0
              throw;
1527
0
            }
1528
447k
#endif
1529
447k
          }
1530
470k
        }
1531
0
        return iterator{ ipos };
1532
470k
      }
1533
1534
470k
      TOML_UNREACHABLE;
1535
470k
    }
_ZN4toml2v35table12emplace_hintIS1_NS0_3keyEJETnNSt3__19enable_ifIXoo21is_key_or_convertibleIOT0_Esr4implE14is_wide_stringIS6_EEiE4typeELi0EEENS0_4impl14table_iteratorILb0EEENSB_ILb1EEES7_DpOT1_
Line
Count
Source
1473
388k
    {
1474
388k
      static_assert(!impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT,
1475
388k
              "Emplacement using wide-character keys is only supported on Windows with "
1476
388k
              "TOML_ENABLE_WINDOWS_COMPAT enabled.");
1477
1478
388k
      using raw_value_type = impl::remove_cvref<ValueType>;
1479
388k
      using value_type   = std::
1480
388k
        conditional_t<std::is_void_v<raw_value_type>, impl::emplaced_type_of<ValueArgs&&...>, raw_value_type>;
1481
1482
      if constexpr (impl::is_wide_string<KeyType>)
1483
      {
1484
#if TOML_ENABLE_WINDOWS_COMPAT
1485
        return emplace_hint<value_type>(hint,
1486
                        impl::narrow(static_cast<KeyType&&>(key)),
1487
                        static_cast<ValueArgs&&>(args)...);
1488
#else
1489
        static_assert(impl::always_false<KeyType>, "Evaluated unreachable branch!");
1490
#endif
1491
      }
1492
      else
1493
388k
      {
1494
388k
        static constexpr auto moving_node_ptr = std::is_same_v<value_type, impl::node_ptr> //
1495
0
                           && sizeof...(ValueArgs) == 1u           //
1496
0
                           && impl::first_is_same<impl::node_ptr&&, ValueArgs&&...>;
1497
388k
        using unwrapped_type = impl::remove_cvref<impl::unwrap_node<value_type>>;
1498
1499
388k
        static_assert(moving_node_ptr                   //
1500
388k
                  || impl::is_native<unwrapped_type>        //
1501
388k
                  || impl::is_one_of<unwrapped_type, table, array>, //
1502
388k
                "ValueType argument of table::emplace_hint() must be one "
1503
388k
                "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
1504
1505
388k
        map_iterator ipos = insert_with_hint(hint, toml::key{ static_cast<KeyType&&>(key) }, nullptr);
1506
1507
        // if second is nullptr then we successully claimed the key and inserted the empty sentinel,
1508
        // so now we have to construct the actual value
1509
388k
        if (!ipos->second)
1510
388k
        {
1511
          if constexpr (moving_node_ptr)
1512
            ipos->second = std::move(static_cast<ValueArgs&&>(args)...);
1513
          else
1514
388k
          {
1515
388k
#if TOML_COMPILER_HAS_EXCEPTIONS
1516
388k
            try
1517
388k
            {
1518
388k
#endif
1519
388k
              ipos->second.reset(
1520
388k
                new impl::wrap_node<unwrapped_type>{ static_cast<ValueArgs&&>(args)... });
1521
388k
#if TOML_COMPILER_HAS_EXCEPTIONS
1522
388k
            }
1523
388k
            catch (...)
1524
388k
            {
1525
0
              erase(const_map_iterator{ ipos }); // strong exception guarantee
1526
0
              throw;
1527
0
            }
1528
388k
#endif
1529
388k
          }
1530
388k
        }
1531
0
        return iterator{ ipos };
1532
388k
      }
1533
1534
388k
      TOML_UNREACHABLE;
1535
388k
    }
_ZN4toml2v35table12emplace_hintINS0_5arrayENS0_3keyEJETnNSt3__19enable_ifIXoo21is_key_or_convertibleIOT0_Esr4implE14is_wide_stringIS7_EEiE4typeELi0EEENS0_4impl14table_iteratorILb0EEENSC_ILb1EEES8_DpOT1_
Line
Count
Source
1473
58.4k
    {
1474
58.4k
      static_assert(!impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT,
1475
58.4k
              "Emplacement using wide-character keys is only supported on Windows with "
1476
58.4k
              "TOML_ENABLE_WINDOWS_COMPAT enabled.");
1477
1478
58.4k
      using raw_value_type = impl::remove_cvref<ValueType>;
1479
58.4k
      using value_type   = std::
1480
58.4k
        conditional_t<std::is_void_v<raw_value_type>, impl::emplaced_type_of<ValueArgs&&...>, raw_value_type>;
1481
1482
      if constexpr (impl::is_wide_string<KeyType>)
1483
      {
1484
#if TOML_ENABLE_WINDOWS_COMPAT
1485
        return emplace_hint<value_type>(hint,
1486
                        impl::narrow(static_cast<KeyType&&>(key)),
1487
                        static_cast<ValueArgs&&>(args)...);
1488
#else
1489
        static_assert(impl::always_false<KeyType>, "Evaluated unreachable branch!");
1490
#endif
1491
      }
1492
      else
1493
58.4k
      {
1494
58.4k
        static constexpr auto moving_node_ptr = std::is_same_v<value_type, impl::node_ptr> //
1495
0
                           && sizeof...(ValueArgs) == 1u           //
1496
0
                           && impl::first_is_same<impl::node_ptr&&, ValueArgs&&...>;
1497
58.4k
        using unwrapped_type = impl::remove_cvref<impl::unwrap_node<value_type>>;
1498
1499
58.4k
        static_assert(moving_node_ptr                   //
1500
58.4k
                  || impl::is_native<unwrapped_type>        //
1501
58.4k
                  || impl::is_one_of<unwrapped_type, table, array>, //
1502
58.4k
                "ValueType argument of table::emplace_hint() must be one "
1503
58.4k
                "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
1504
1505
58.4k
        map_iterator ipos = insert_with_hint(hint, toml::key{ static_cast<KeyType&&>(key) }, nullptr);
1506
1507
        // if second is nullptr then we successully claimed the key and inserted the empty sentinel,
1508
        // so now we have to construct the actual value
1509
58.4k
        if (!ipos->second)
1510
58.4k
        {
1511
          if constexpr (moving_node_ptr)
1512
            ipos->second = std::move(static_cast<ValueArgs&&>(args)...);
1513
          else
1514
58.4k
          {
1515
58.4k
#if TOML_COMPILER_HAS_EXCEPTIONS
1516
58.4k
            try
1517
58.4k
            {
1518
58.4k
#endif
1519
58.4k
              ipos->second.reset(
1520
58.4k
                new impl::wrap_node<unwrapped_type>{ static_cast<ValueArgs&&>(args)... });
1521
58.4k
#if TOML_COMPILER_HAS_EXCEPTIONS
1522
58.4k
            }
1523
58.4k
            catch (...)
1524
58.4k
            {
1525
0
              erase(const_map_iterator{ ipos }); // strong exception guarantee
1526
0
              throw;
1527
0
            }
1528
58.4k
#endif
1529
58.4k
          }
1530
58.4k
        }
1531
0
        return iterator{ ipos };
1532
58.4k
      }
1533
1534
58.4k
      TOML_UNREACHABLE;
1535
58.4k
    }
_ZN4toml2v35table12emplace_hintINSt3__110unique_ptrINS0_4nodeENS3_14default_deleteIS5_EEEENS0_3keyEJS8_ETnNS3_9enable_ifIXoo21is_key_or_convertibleIOT0_Esr4implE14is_wide_stringISB_EEiE4typeELi0EEENS0_4impl14table_iteratorILb0EEENSG_ILb1EEESC_DpOT1_
Line
Count
Source
1473
23.4k
    {
1474
23.4k
      static_assert(!impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT,
1475
23.4k
              "Emplacement using wide-character keys is only supported on Windows with "
1476
23.4k
              "TOML_ENABLE_WINDOWS_COMPAT enabled.");
1477
1478
23.4k
      using raw_value_type = impl::remove_cvref<ValueType>;
1479
23.4k
      using value_type   = std::
1480
23.4k
        conditional_t<std::is_void_v<raw_value_type>, impl::emplaced_type_of<ValueArgs&&...>, raw_value_type>;
1481
1482
      if constexpr (impl::is_wide_string<KeyType>)
1483
      {
1484
#if TOML_ENABLE_WINDOWS_COMPAT
1485
        return emplace_hint<value_type>(hint,
1486
                        impl::narrow(static_cast<KeyType&&>(key)),
1487
                        static_cast<ValueArgs&&>(args)...);
1488
#else
1489
        static_assert(impl::always_false<KeyType>, "Evaluated unreachable branch!");
1490
#endif
1491
      }
1492
      else
1493
23.4k
      {
1494
23.4k
        static constexpr auto moving_node_ptr = std::is_same_v<value_type, impl::node_ptr> //
1495
0
                           && sizeof...(ValueArgs) == 1u           //
1496
0
                           && impl::first_is_same<impl::node_ptr&&, ValueArgs&&...>;
1497
23.4k
        using unwrapped_type = impl::remove_cvref<impl::unwrap_node<value_type>>;
1498
1499
23.4k
        static_assert(moving_node_ptr                   //
1500
23.4k
                  || impl::is_native<unwrapped_type>        //
1501
23.4k
                  || impl::is_one_of<unwrapped_type, table, array>, //
1502
23.4k
                "ValueType argument of table::emplace_hint() must be one "
1503
23.4k
                "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
1504
1505
23.4k
        map_iterator ipos = insert_with_hint(hint, toml::key{ static_cast<KeyType&&>(key) }, nullptr);
1506
1507
        // if second is nullptr then we successully claimed the key and inserted the empty sentinel,
1508
        // so now we have to construct the actual value
1509
23.4k
        if (!ipos->second)
1510
23.4k
        {
1511
          if constexpr (moving_node_ptr)
1512
23.4k
            ipos->second = std::move(static_cast<ValueArgs&&>(args)...);
1513
          else
1514
          {
1515
#if TOML_COMPILER_HAS_EXCEPTIONS
1516
            try
1517
            {
1518
#endif
1519
              ipos->second.reset(
1520
                new impl::wrap_node<unwrapped_type>{ static_cast<ValueArgs&&>(args)... });
1521
#if TOML_COMPILER_HAS_EXCEPTIONS
1522
            }
1523
            catch (...)
1524
            {
1525
              erase(const_map_iterator{ ipos }); // strong exception guarantee
1526
              throw;
1527
            }
1528
#endif
1529
          }
1530
23.4k
        }
1531
23.4k
        return iterator{ ipos };
1532
23.4k
      }
1533
1534
23.4k
      TOML_UNREACHABLE;
1535
23.4k
    }
1536
1537
    /// \brief  Inserts a new value at a specific key if one did not already exist.
1538
    ///
1539
    /// \detail \godbolt{bMnW5r}
1540
    ///
1541
    /// \cpp
1542
    /// auto tbl = toml::table{
1543
    ///   { "a", 1 },
1544
    ///   { "b", 2 },
1545
    ///   { "c", 3 }
1546
    /// };
1547
    /// std::cout << tbl << "\n";
1548
    ///
1549
    /// for (auto k : { "a", "d" })
1550
    /// {
1551
    ///   auto result = tbl.insert(k, 42);
1552
    ///   std::cout << "inserted with key '"sv << k << "': "sv << result.second << "\n";
1553
    /// }
1554
    /// std::cout << tbl << "\n";
1555
    /// \ecpp
1556
    ///
1557
    /// \out
1558
    /// a = 1
1559
    /// b = 2
1560
    /// c = 3
1561
    ///
1562
    /// inserted with key 'a': false
1563
    /// inserted with key 'd': true
1564
    /// a = 1
1565
    /// b = 2
1566
    /// c = 3
1567
    /// d = 42
1568
    /// \eout
1569
    ///
1570
    /// \tparam KeyType   A toml::key or any compatible string type.
1571
    /// \tparam ValueType toml::node, toml::node_view, toml::table, toml::array, or a native TOML value type
1572
    ///           (or a type promotable to one).
1573
    /// \param  key     The key at which to insert the new value.
1574
    /// \param  val     The new value to insert.
1575
    /// \param  flags   Value flags to apply to new values.
1576
    ///
1577
    /// \returns  \conditional_return{Valid input}
1578
    ///       <ul>
1579
    ///         <li>An iterator to the insertion position (or the position of the value that prevented insertion)
1580
    ///         <li>A boolean indicating if the insertion was successful.
1581
    ///       </ul>
1582
    ///       \conditional_return{Input is a null toml::node_view}
1583
    ///       `{ end(), false }`
1584
    ///
1585
    /// \attention The return value will always be `{ end(), false }` if the input value was an
1586
    ///        null toml::node_view, because no insertion can take place. This is the only circumstance
1587
    ///        in which this can occur.
1588
    TOML_CONSTRAINED_TEMPLATE((is_key_or_convertible<KeyType&&> || impl::is_wide_string<KeyType>),
1589
                  typename KeyType,
1590
                  typename ValueType)
1591
    std::pair<iterator, bool> insert(KeyType&& key,
1592
                     ValueType&& val,
1593
                     value_flags flags = preserve_source_value_flags)
1594
    {
1595
      static_assert(!impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT,
1596
              "Insertion using wide-character keys is only supported on Windows with "
1597
              "TOML_ENABLE_WINDOWS_COMPAT enabled.");
1598
1599
      if constexpr (is_node_view<ValueType>)
1600
      {
1601
        if (!val)
1602
          return { end(), false };
1603
      }
1604
1605
      if constexpr (impl::is_wide_string<KeyType>)
1606
      {
1607
#if TOML_ENABLE_WINDOWS_COMPAT
1608
        return insert(impl::narrow(static_cast<KeyType&&>(key)), static_cast<ValueType&&>(val), flags);
1609
#else
1610
        static_assert(impl::always_false<KeyType>, "Evaluated unreachable branch!");
1611
#endif
1612
      }
1613
      else
1614
      {
1615
        const auto key_view = std::string_view{ key };
1616
        map_iterator ipos = get_lower_bound(key_view);
1617
        if (ipos == map_.end() || ipos->first != key_view)
1618
        {
1619
          ipos = insert_with_hint(const_iterator{ ipos },
1620
                      toml::key{ static_cast<KeyType&&>(key) },
1621
                      impl::make_node(static_cast<ValueType&&>(val), flags));
1622
          return { iterator{ ipos }, true };
1623
        }
1624
        return { iterator{ ipos }, false };
1625
      }
1626
    }
1627
1628
    /// \brief  Inserts a series of key-value pairs into the table.
1629
    ///
1630
    /// \detail \godbolt{bzYcce}
1631
    ///
1632
    /// \cpp
1633
    /// auto tbl = toml::table{
1634
    ///   { "a", 1 },
1635
    ///   { "b", 2 },
1636
    ///   { "c", 3 }
1637
    /// };
1638
    /// std::cout << tbl << "\n";
1639
    ///
1640
    /// auto kvps = std::array<std::pair<std::string, int>, 2>{{
1641
    ///   { "d", 42 },
1642
    ///   { "a", 43 } // won't be inserted, 'a' already exists
1643
    /// }};
1644
    /// tbl.insert(kvps.begin(), kvps.end());
1645
    /// std::cout << tbl << "\n";
1646
    /// \ecpp
1647
    ///
1648
    /// \out
1649
    /// a = 1
1650
    /// b = 2
1651
    /// c = 3
1652
    ///
1653
    /// a = 1
1654
    /// b = 2
1655
    /// c = 3
1656
    /// d = 42
1657
    /// \eout
1658
    ///
1659
    /// \tparam Iter  An InputIterator to a collection of key-value pairs.
1660
    /// \param  begin An iterator to the first value in the input collection.
1661
    /// \param  end   An iterator to one-past-the-last value in the input collection.
1662
    /// \param  flags   Value flags to apply to new values.
1663
    ///
1664
    /// \remarks This function is morally equivalent to calling `insert(key, value)` for each
1665
    ///      key-value pair covered by the iterator range, so any values with keys already found in the
1666
    ///      table will not be replaced.
1667
    TOML_CONSTRAINED_TEMPLATE((!is_key_or_convertible<Iter> && !impl::is_wide_string<Iter>), typename Iter)
1668
    void insert(Iter begin, Iter end, value_flags flags = preserve_source_value_flags)
1669
    {
1670
      if (begin == end)
1671
        return;
1672
      for (auto it = begin; it != end; it++)
1673
      {
1674
        if constexpr (std::is_rvalue_reference_v<decltype(*it)>)
1675
          insert(std::move((*it).first), std::move((*it).second), flags);
1676
        else
1677
          insert((*it).first, (*it).second, flags);
1678
      }
1679
    }
1680
1681
    /// \brief  Inserts or assigns a value at a specific key.
1682
    ///
1683
    /// \detail \godbolt{ddK563}
1684
    ///
1685
    /// \cpp
1686
    /// auto tbl = toml::table{
1687
    ///   { "a", 1 },
1688
    ///   { "b", 2 },
1689
    ///   { "c", 3 }
1690
    /// };
1691
    /// std::cout << tbl << "\n";
1692
    ///
1693
    /// for (auto k : { "a", "d" })
1694
    /// {
1695
    ///   auto result = tbl.insert_or_assign(k, 42);
1696
    ///   std::cout << "value at key '"sv << k
1697
    ///     << "' was "sv << (result.second ? "inserted"sv : "assigned"sv) << "\n";
1698
    /// }
1699
    /// std::cout << tbl << "\n";
1700
    /// \ecpp
1701
    ///
1702
    /// \out
1703
    /// a = 1
1704
    /// b = 2
1705
    /// c = 3
1706
    ///
1707
    /// value at key 'a' was assigned
1708
    /// value at key 'd' was inserted
1709
    /// a = 42
1710
    /// b = 2
1711
    /// c = 3
1712
    /// d = 42
1713
    /// \eout
1714
    ///
1715
    /// \tparam KeyType   A toml::key or any compatible string type.
1716
    /// \tparam ValueType toml::node, toml::node_view, toml::table, toml::array, or a native TOML value type
1717
    ///           (or a type promotable to one).
1718
    /// \param  key     The key at which to insert or assign the value.
1719
    /// \param  val     The value to insert/assign.
1720
    /// \param  flags   Value flags to apply to new values.
1721
    ///
1722
    /// \returns  \conditional_return{Valid input}
1723
    ///       <ul>
1724
    ///         <li>An iterator to the value's position
1725
    ///         <li>`true` if the value was inserted, `false` if it was assigned.
1726
    ///       </ul>
1727
    ///       \conditional_return{Input is a null toml::node_view}
1728
    ///        `{ end(), false }`
1729
    ///
1730
    /// \attention The return value will always be `{ end(), false }` if the input value was
1731
    ///        a null toml::node_view, because no insertion or assignment can take place.
1732
    ///        This is the only circumstance in which this can occur.
1733
    TOML_CONSTRAINED_TEMPLATE((is_key_or_convertible<KeyType&&> || impl::is_wide_string<KeyType>),
1734
                  typename KeyType,
1735
                  typename ValueType)
1736
    std::pair<iterator, bool> insert_or_assign(KeyType&& key,
1737
                           ValueType&& val,
1738
                           value_flags flags = preserve_source_value_flags)
1739
    {
1740
      static_assert(!impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT,
1741
              "Insertion using wide-character keys is only supported on Windows with "
1742
              "TOML_ENABLE_WINDOWS_COMPAT enabled.");
1743
1744
      if constexpr (is_node_view<ValueType>)
1745
      {
1746
        if (!val)
1747
          return { end(), false };
1748
      }
1749
1750
      if constexpr (impl::is_wide_string<KeyType>)
1751
      {
1752
#if TOML_ENABLE_WINDOWS_COMPAT
1753
        return insert_or_assign(impl::narrow(static_cast<KeyType&&>(key)),
1754
                    static_cast<ValueType&&>(val),
1755
                    flags);
1756
#else
1757
        static_assert(impl::always_false<KeyType>, "Evaluated unreachable branch!");
1758
#endif
1759
      }
1760
      else
1761
      {
1762
        const auto key_view = std::string_view{ key };
1763
        map_iterator ipos = get_lower_bound(key_view);
1764
        if (ipos == map_.end() || ipos->first != key_view)
1765
        {
1766
          ipos = insert_with_hint(const_iterator{ ipos },
1767
                      toml::key{ static_cast<KeyType&&>(key) },
1768
                      impl::make_node(static_cast<ValueType&&>(val), flags));
1769
          return { iterator{ ipos }, true };
1770
        }
1771
        else
1772
        {
1773
          (*ipos).second = impl::make_node(static_cast<ValueType&&>(val), flags);
1774
          return { iterator{ ipos }, false };
1775
        }
1776
      }
1777
    }
1778
1779
    /// \brief  Emplaces a new value at a specific key if one did not already exist.
1780
    ///
1781
    /// \detail \cpp
1782
    /// auto tbl = toml::table{
1783
    ///   { "a", 1 },
1784
    ///   { "b", 2 },
1785
    ///   { "c", 3 }
1786
    /// };
1787
    /// std::cout << tbl << "\n";
1788
    ///
1789
    /// for (auto k : { "a", "d" })
1790
    /// {
1791
    ///   // add a string using std::string's substring constructor
1792
    ///   auto result = tbl.emplace<std::string>(k, "this is not a drill"sv, 14, 5);
1793
    ///   std::cout << "emplaced with key '"sv << k << "': "sv << result.second << "\n";
1794
    /// }
1795
    /// std::cout << tbl << "\n";
1796
    /// \ecpp
1797
    ///
1798
    /// \out
1799
    /// { a = 1, b = 2, c = 3 }
1800
    /// emplaced with key 'a': false
1801
    /// emplaced with key 'd': true
1802
    /// { a = 1, b = 2, c = 3, d = "drill" }
1803
    /// \eout
1804
    ///
1805
    /// \tparam ValueType toml::table, toml::array, or any native TOML value type.
1806
    /// \tparam KeyType   A toml::key or any compatible string type.
1807
    /// \tparam ValueArgs Value constructor argument types.
1808
    /// \param  key     The key at which to emplace the new value.
1809
    /// \param  args    Arguments to forward to the value's constructor.
1810
    ///
1811
    /// \returns A std::pair containing: <br>
1812
    ///     - An iterator to the emplacement position (or the position of the value that prevented emplacement)
1813
    ///     - A boolean indicating if the emplacement was successful.
1814
    ///
1815
    /// \remark There is no difference between insert() and emplace() for trivial value types (floats, ints, bools).
1816
    TOML_CONSTRAINED_TEMPLATE((is_key_or_convertible<KeyType&&> || impl::is_wide_string<KeyType>),
1817
                  typename ValueType = void,
1818
                  typename KeyType,
1819
                  typename... ValueArgs)
1820
    std::pair<iterator, bool> emplace(KeyType&& key, ValueArgs&&... args)
1821
    {
1822
      static_assert(!impl::is_wide_string<KeyType> || TOML_ENABLE_WINDOWS_COMPAT,
1823
              "Emplacement using wide-character keys is only supported on Windows with "
1824
              "TOML_ENABLE_WINDOWS_COMPAT enabled.");
1825
1826
      using raw_value_type = impl::remove_cvref<ValueType>;
1827
      using value_type   = std::
1828
        conditional_t<std::is_void_v<raw_value_type>, impl::emplaced_type_of<ValueArgs&&...>, raw_value_type>;
1829
1830
      if constexpr (impl::is_wide_string<KeyType>)
1831
      {
1832
#if TOML_ENABLE_WINDOWS_COMPAT
1833
        return emplace<value_type>(impl::narrow(static_cast<KeyType&&>(key)),
1834
                       static_cast<ValueArgs&&>(args)...);
1835
#else
1836
        static_assert(impl::always_false<KeyType>, "Evaluated unreachable branch!");
1837
#endif
1838
      }
1839
      else
1840
      {
1841
        using unwrapped_type = impl::remove_cvref<impl::unwrap_node<value_type>>;
1842
        static_assert((impl::is_native<unwrapped_type> || impl::is_one_of<unwrapped_type, table, array>),
1843
                "ValueType argument of table::emplace() must be one "
1844
                "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
1845
1846
        const auto key_view = std::string_view{ key };
1847
        auto ipos     = get_lower_bound(key_view);
1848
        if (ipos == map_.end() || ipos->first != key_view)
1849
        {
1850
          ipos = insert_with_hint(
1851
            const_iterator{ ipos },
1852
            toml::key{ static_cast<KeyType&&>(key) },
1853
            impl::node_ptr{ new impl::wrap_node<unwrapped_type>{ static_cast<ValueArgs&&>(args)... } });
1854
          return { iterator{ ipos }, true };
1855
        }
1856
        return { iterator{ ipos }, false };
1857
      }
1858
    }
1859
1860
    /// @}
1861
1862
    /// \name Node views
1863
    /// @{
1864
1865
    /// \cond
1866
    using node::operator[]; // inherit operator[toml::path]
1867
    /// \endcond
1868
1869
    /// \brief  Gets a node_view for the selected value.
1870
    ///
1871
    /// \param  key The key used for the lookup.
1872
    ///
1873
    /// \returns  A view of the value at the given key if one existed, or an empty node view.
1874
    ///
1875
    /// \remarks std::map::operator[]'s behaviour of default-constructing a value at a key if it
1876
    ///      didn't exist is a crazy bug factory so I've deliberately chosen not to emulate it.
1877
    ///      <strong>This is not an error.</strong>
1878
    ///
1879
    /// \see toml::node_view
1880
    TOML_NODISCARD
1881
    node_view<node> operator[](std::string_view key) noexcept
1882
0
    {
1883
0
      return node_view<node>{ get(key) };
1884
0
    }
1885
1886
    /// \brief  Gets a node_view for the selected value (const overload).
1887
    ///
1888
    /// \param  key The key used for the lookup.
1889
    ///
1890
    /// \returns  A view of the value at the given key if one existed, or an empty node view.
1891
    ///
1892
    /// \remarks std::map::operator[]'s behaviour of default-constructing a value at a key if it
1893
    ///      didn't exist is a crazy bug factory so I've deliberately chosen not to emulate it.
1894
    ///      <strong>This is not an error.</strong>
1895
    ///
1896
    /// \see toml::node_view
1897
    TOML_NODISCARD
1898
    node_view<const node> operator[](std::string_view key) const noexcept
1899
0
    {
1900
0
      return node_view<const node>{ get(key) };
1901
0
    }
1902
1903
#if TOML_ENABLE_WINDOWS_COMPAT
1904
1905
    /// \brief  Gets a node_view for the selected value.
1906
    ///
1907
    /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
1908
    ///
1909
    /// \param  key The key used for the lookup.
1910
    ///
1911
    /// \returns  A view of the value at the given key if one existed, or an empty node view.
1912
    ///
1913
    /// \remarks std::map::operator[]'s behaviour of default-constructing a value at a key if it
1914
    ///      didn't exist is a crazy bug factory so I've deliberately chosen not to emulate it.
1915
    ///      <strong>This is not an error.</strong>
1916
    ///
1917
    /// \see toml::node_view
1918
    TOML_NODISCARD
1919
    node_view<node> operator[](std::wstring_view key)
1920
    {
1921
      return node_view<node>{ get(key) };
1922
    }
1923
1924
    /// \brief  Gets a node_view for the selected value (const overload).
1925
    ///
1926
    /// \availability This overload is only available when #TOML_ENABLE_WINDOWS_COMPAT is enabled.
1927
    ///
1928
    /// \param  key The key used for the lookup.
1929
    ///
1930
    /// \returns  A view of the value at the given key if one existed, or an empty node view.
1931
    ///
1932
    /// \remarks std::map::operator[]'s behaviour of default-constructing a value at a key if it
1933
    ///      didn't exist is a crazy bug factory so I've deliberately chosen not to emulate it.
1934
    ///      <strong>This is not an error.</strong>
1935
    ///
1936
    /// \see toml::node_view
1937
    TOML_NODISCARD
1938
    node_view<const node> operator[](std::wstring_view key) const
1939
    {
1940
      return node_view<const node>{ get(key) };
1941
    }
1942
1943
#endif // TOML_ENABLE_WINDOWS_COMPAT
1944
1945
    /// @}
1946
1947
    /// \name Equality
1948
    /// @{
1949
1950
    private:
1951
    /// \cond
1952
1953
    TOML_PURE_GETTER
1954
    TOML_EXPORTED_STATIC_FUNCTION
1955
    static bool TOML_CALLCONV equal(const table&, const table&) noexcept;
1956
1957
    /// \endcond
1958
    public:
1959
    /// \brief  Equality operator.
1960
    ///
1961
    /// \param  lhs The LHS table.
1962
    /// \param  rhs The RHS table.
1963
    ///
1964
    /// \returns  True if the tables contained the same keys and map.
1965
    TOML_NODISCARD
1966
    friend bool operator==(const table& lhs, const table& rhs) noexcept
1967
0
    {
1968
0
      return equal(lhs, rhs);
1969
0
    }
1970
1971
    /// \brief  Inequality operator.
1972
    ///
1973
    /// \param  lhs The LHS table.
1974
    /// \param  rhs The RHS table.
1975
    ///
1976
    /// \returns  True if the tables did not contain the same keys and map.
1977
    TOML_NODISCARD
1978
    friend bool operator!=(const table& lhs, const table& rhs) noexcept
1979
0
    {
1980
0
      return !equal(lhs, rhs);
1981
0
    }
1982
1983
    /// @}
1984
1985
#if TOML_ENABLE_FORMATTERS
1986
1987
    /// \brief  Prints the table out to a stream as formatted TOML.
1988
    ///
1989
    /// \availability This operator is only available when #TOML_ENABLE_FORMATTERS is enabled.
1990
    friend std::ostream& operator<<(std::ostream& lhs, const table& rhs)
1991
0
    {
1992
0
      impl::print_to_stream(lhs, rhs);
1993
0
      return lhs;
1994
0
    }
1995
1996
#endif
1997
  };
1998
}
1999
TOML_NAMESPACE_END;
2000
2001
#include "header_end.hpp"