Coverage Report

Created: 2025-11-09 06:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tomlplusplus/include/toml++/impl/array.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 "std_utility.hpp"
8
#include "std_vector.hpp"
9
#include "std_initializer_list.hpp"
10
#include "value.hpp"
11
#include "make_node.hpp"
12
#include "header_start.hpp"
13
14
#ifndef TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN
15
#if TOML_GCC && TOML_GCC <= 7
16
#define TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN 1
17
#else
18
#define TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN 0
19
#endif
20
#endif
21
22
#if TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN && !defined(TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_ACKNOWLEDGED)
23
#define TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_MESSAGE                                                                  \
24
  "If you're seeing this error it's because you're using one of toml++'s for_each() functions on a compiler with "   \
25
  "known bugs in that area (e.g. GCC 7). On these compilers returning a bool (or bool-convertible) value from the "  \
26
  "for_each() callable causes spurious compilation failures, while returning nothing (void) works fine. "            \
27
  "If you believe this message is incorrect for your compiler, you can try your luck by #defining "                  \
28
  "TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN as 0 and recompiling - if it works, great! Let me know at "                 \
29
  "https://github.com/marzer/tomlplusplus/issues. Alternatively, if you don't have any need for early-exiting from " \
30
  "for_each(), you can suppress this error by #defining TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_ACKNOWLEDGED "         \
31
  "and moving on with your life."
32
#endif
33
34
/// \cond
35
TOML_IMPL_NAMESPACE_START
36
{
37
  template <bool IsConst>
38
  class TOML_TRIVIAL_ABI array_iterator
39
  {
40
    private:
41
    template <bool>
42
    friend class array_iterator;
43
44
    using mutable_vector_iterator = std::vector<node_ptr>::iterator;
45
    using const_vector_iterator   = std::vector<node_ptr>::const_iterator;
46
    using vector_iterator     = std::conditional_t<IsConst, const_vector_iterator, mutable_vector_iterator>;
47
48
    mutable vector_iterator iter_;
49
50
    public:
51
    using value_type    = std::conditional_t<IsConst, const node, node>;
52
    using reference     = value_type&;
53
    using pointer     = value_type*;
54
    using difference_type = ptrdiff_t;
55
    using iterator_category = typename std::iterator_traits<vector_iterator>::iterator_category;
56
57
    TOML_NODISCARD_CTOR
58
    array_iterator() noexcept = default;
59
60
    TOML_NODISCARD_CTOR
61
    explicit array_iterator(mutable_vector_iterator iter) noexcept //
62
13.4k
      : iter_{ iter }
63
13.4k
    {}
64
65
    TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst)
66
    TOML_NODISCARD_CTOR
67
    explicit array_iterator(const_vector_iterator iter) noexcept //
68
      : iter_{ iter }
69
    {}
70
71
    TOML_CONSTRAINED_TEMPLATE(C, bool C = IsConst)
72
    TOML_NODISCARD_CTOR
73
    array_iterator(const array_iterator<false>& other) noexcept //
74
      : iter_{ other.iter_ }
75
    {}
76
77
    TOML_NODISCARD_CTOR
78
    array_iterator(const array_iterator&) noexcept = default;
79
80
    array_iterator& operator=(const array_iterator&) noexcept = default;
81
82
    array_iterator& operator++() noexcept // ++pre
83
327k
    {
84
327k
      ++iter_;
85
327k
      return *this;
86
327k
    }
toml::v3::impl::array_iterator<false>::operator++()
Line
Count
Source
83
327k
    {
84
327k
      ++iter_;
85
327k
      return *this;
86
327k
    }
Unexecuted instantiation: toml::v3::impl::array_iterator<true>::operator++()
87
88
    array_iterator operator++(int) noexcept // post++
89
    {
90
      array_iterator out{ iter_ };
91
      ++iter_;
92
      return out;
93
    }
94
95
    array_iterator& operator--() noexcept // --pre
96
    {
97
      --iter_;
98
      return *this;
99
    }
100
101
    array_iterator operator--(int) noexcept // post--
102
    {
103
      array_iterator out{ iter_ };
104
      --iter_;
105
      return out;
106
    }
107
108
    TOML_PURE_INLINE_GETTER
109
    reference operator*() const noexcept
110
327k
    {
111
327k
      return *iter_->get();
112
327k
    }
toml::v3::impl::array_iterator<false>::operator*() const
Line
Count
Source
110
327k
    {
111
327k
      return *iter_->get();
112
327k
    }
Unexecuted instantiation: toml::v3::impl::array_iterator<true>::operator*() const
113
114
    TOML_PURE_INLINE_GETTER
115
    pointer operator->() const noexcept
116
    {
117
      return iter_->get();
118
    }
119
120
    TOML_PURE_INLINE_GETTER
121
    explicit operator const vector_iterator&() const noexcept
122
0
    {
123
0
      return iter_;
124
0
    }
125
126
    TOML_CONSTRAINED_TEMPLATE(!C, bool C = IsConst)
127
    TOML_PURE_INLINE_GETTER
128
    explicit operator const const_vector_iterator() const noexcept
129
    {
130
      return iter_;
131
    }
132
133
    array_iterator& operator+=(ptrdiff_t rhs) noexcept
134
    {
135
      iter_ += rhs;
136
      return *this;
137
    }
138
139
    array_iterator& operator-=(ptrdiff_t rhs) noexcept
140
    {
141
      iter_ -= rhs;
142
      return *this;
143
    }
144
145
    TOML_NODISCARD
146
    friend array_iterator operator+(const array_iterator& lhs, ptrdiff_t rhs) noexcept
147
    {
148
      return array_iterator{ lhs.iter_ + rhs };
149
    }
150
151
    TOML_NODISCARD
152
    friend array_iterator operator+(ptrdiff_t lhs, const array_iterator& rhs) noexcept
153
    {
154
      return array_iterator{ rhs.iter_ + lhs };
155
    }
156
157
    TOML_NODISCARD
158
    friend array_iterator operator-(const array_iterator& lhs, ptrdiff_t rhs) noexcept
159
    {
160
      return array_iterator{ lhs.iter_ - rhs };
161
    }
162
163
    TOML_PURE_INLINE_GETTER
164
    friend ptrdiff_t operator-(const array_iterator& lhs, const array_iterator& rhs) noexcept
165
    {
166
      return lhs.iter_ - rhs.iter_;
167
    }
168
169
    TOML_PURE_INLINE_GETTER
170
    friend bool operator==(const array_iterator& lhs, const array_iterator& rhs) noexcept
171
    {
172
      return lhs.iter_ == rhs.iter_;
173
    }
174
175
    TOML_PURE_INLINE_GETTER
176
    friend bool operator!=(const array_iterator& lhs, const array_iterator& rhs) noexcept
177
334k
    {
178
334k
      return lhs.iter_ != rhs.iter_;
179
334k
    }
toml::v3::impl::operator!=(toml::v3::impl::array_iterator<false> const&, toml::v3::impl::array_iterator<false> const&)
Line
Count
Source
177
334k
    {
178
334k
      return lhs.iter_ != rhs.iter_;
179
334k
    }
Unexecuted instantiation: toml::v3::impl::operator!=(toml::v3::impl::array_iterator<true> const&, toml::v3::impl::array_iterator<true> const&)
180
181
    TOML_PURE_INLINE_GETTER
182
    friend bool operator<(const array_iterator& lhs, const array_iterator& rhs) noexcept
183
    {
184
      return lhs.iter_ < rhs.iter_;
185
    }
186
187
    TOML_PURE_INLINE_GETTER
188
    friend bool operator<=(const array_iterator& lhs, const array_iterator& rhs) noexcept
189
    {
190
      return lhs.iter_ <= rhs.iter_;
191
    }
192
193
    TOML_PURE_INLINE_GETTER
194
    friend bool operator>(const array_iterator& lhs, const array_iterator& rhs) noexcept
195
    {
196
      return lhs.iter_ > rhs.iter_;
197
    }
198
199
    TOML_PURE_INLINE_GETTER
200
    friend bool operator>=(const array_iterator& lhs, const array_iterator& rhs) noexcept
201
    {
202
      return lhs.iter_ >= rhs.iter_;
203
    }
204
205
    TOML_PURE_INLINE_GETTER
206
    reference operator[](ptrdiff_t idx) const noexcept
207
    {
208
      return *(iter_ + idx)->get();
209
    }
210
  };
211
212
  struct array_init_elem
213
  {
214
    mutable node_ptr value;
215
216
    template <typename T>
217
    TOML_NODISCARD_CTOR
218
    array_init_elem(T&& val, value_flags flags = preserve_source_value_flags) //
219
      : value{ make_node(static_cast<T&&>(val), flags) }
220
    {}
221
  };
222
}
223
TOML_IMPL_NAMESPACE_END;
224
/// \endcond
225
226
TOML_NAMESPACE_START
227
{
228
  /// \brief A RandomAccessIterator for iterating over elements in a toml::array.
229
  using array_iterator = POXY_IMPLEMENTATION_DETAIL(impl::array_iterator<false>);
230
231
  /// \brief A RandomAccessIterator for iterating over const elements in a toml::array.
232
  using const_array_iterator = POXY_IMPLEMENTATION_DETAIL(impl::array_iterator<true>);
233
234
  /// \brief  A TOML array.
235
  ///
236
  /// \detail The interface of this type is modeled after std::vector, with some
237
  ///     additional considerations made for the heterogeneous nature of a
238
  ///     TOML array.
239
  ///
240
  /// \godbolt{sjK4da}
241
  ///
242
  /// \cpp
243
  ///
244
  /// toml::table tbl = toml::parse(R"(
245
  ///     arr = [1, 2, 3, 4, 'five']
246
  /// )"sv);
247
  ///
248
  /// // get the element as an array
249
  /// toml::array& arr = *tbl.get_as<toml::array>("arr");
250
  /// std::cout << arr << "\n";
251
  ///
252
  /// // increment each element with visit()
253
  /// for (auto&& elem : arr)
254
  /// {
255
  ///   elem.visit([](auto&& el) noexcept
256
  ///   {
257
  ///     if constexpr (toml::is_number<decltype(el)>)
258
  ///       (*el)++;
259
  ///     else if constexpr (toml::is_string<decltype(el)>)
260
  ///       el = "six"sv;
261
  ///   });
262
  /// }
263
  /// std::cout << arr << "\n";
264
  ///
265
  /// // add and remove elements
266
  /// arr.push_back(7);
267
  /// arr.push_back(8.0f);
268
  /// arr.push_back("nine"sv);
269
  /// arr.erase(arr.cbegin());
270
  /// std::cout << arr << "\n";
271
  ///
272
  /// // emplace elements
273
  /// arr.emplace_back("ten");
274
  /// arr.emplace_back<toml::array>(11, 12.0);
275
  /// std::cout << arr << "\n";
276
  /// \ecpp
277
  ///
278
  /// \out
279
  /// [ 1, 2, 3, 4, 'five' ]
280
  /// [ 2, 3, 4, 5, 'six' ]
281
  /// [ 3, 4, 5, 'six', 7, 8.0, 'nine' ]
282
  /// [ 3, 4, 5, 'six', 7, 8.0, 'nine', 'ten', [ 11, 12.0 ] ]
283
  /// \eout
284
  class TOML_EXPORTED_CLASS array : public node
285
  {
286
    private:
287
    /// \cond
288
289
    using vector_type     = std::vector<impl::node_ptr>;
290
    using vector_iterator   = typename vector_type::iterator;
291
    using const_vector_iterator = typename vector_type::const_iterator;
292
    vector_type elems_;
293
294
    TOML_NODISCARD_CTOR
295
    TOML_EXPORTED_MEMBER_FUNCTION
296
    array(const impl::array_init_elem*, const impl::array_init_elem*);
297
298
    TOML_NODISCARD_CTOR
299
    array(std::false_type, std::initializer_list<impl::array_init_elem> elems) //
300
      : array{ elems.begin(), elems.end() }
301
0
    {}
302
303
    TOML_EXPORTED_MEMBER_FUNCTION
304
    void preinsertion_resize(size_t idx, size_t count);
305
306
    TOML_EXPORTED_MEMBER_FUNCTION
307
    void insert_at_back(impl::node_ptr&&);
308
309
    TOML_EXPORTED_MEMBER_FUNCTION
310
    vector_iterator insert_at(const_vector_iterator, impl::node_ptr&&);
311
312
    template <typename T>
313
    void emplace_back_if_not_empty_view(T&& val, value_flags flags)
314
    {
315
      if constexpr (is_node_view<T>)
316
      {
317
        if (!val)
318
          return;
319
      }
320
      insert_at_back(impl::make_node(static_cast<T&&>(val), flags));
321
    }
322
323
    TOML_NODISCARD
324
    TOML_EXPORTED_MEMBER_FUNCTION
325
    size_t total_leaf_count() const noexcept;
326
327
    TOML_EXPORTED_MEMBER_FUNCTION
328
    void flatten_child(array&& child, size_t& dest_index) noexcept;
329
330
    /// \endcond
331
332
    public:
333
    using value_type    = node;
334
    using size_type     = size_t;
335
    using difference_type = ptrdiff_t;
336
    using reference     = node&;
337
    using const_reference = const node&;
338
339
    /// \brief  Default constructor.
340
    TOML_NODISCARD_CTOR
341
    TOML_EXPORTED_MEMBER_FUNCTION
342
    array() noexcept;
343
344
    TOML_EXPORTED_MEMBER_FUNCTION
345
    ~array() noexcept;
346
347
    /// \brief  Copy constructor.
348
    TOML_NODISCARD_CTOR
349
    TOML_EXPORTED_MEMBER_FUNCTION
350
    array(const array&);
351
352
    /// \brief  Move constructor.
353
    TOML_NODISCARD_CTOR
354
    TOML_EXPORTED_MEMBER_FUNCTION
355
    array(array&& other) noexcept;
356
357
    /// \brief  Constructs an array with one or more initial elements.
358
    ///
359
    /// \detail \cpp
360
    /// auto arr = toml::array{ 1, 2.0, "three"sv, toml::array{ 4, 5 } };
361
    /// std::cout << arr << "\n";
362
    /// \ecpp
363
    ///
364
    /// \out
365
    /// [ 1, 2.0, 'three', [ 4, 5 ] ]
366
    /// \eout
367
    ///
368
    /// \remark \parblock If you need to construct an array with one child array element, the array's move constructor
369
    ///     will take precedence and perform a move-construction instead. You can use toml::inserter to
370
    ///     suppress this behaviour: \cpp
371
    /// // desired result: [ [ 42 ] ]
372
    /// auto bad = toml::array{ toml::array{ 42 } }
373
    /// auto good = toml::array{ toml::inserter{ toml::array{ 42 } } }
374
    /// std::cout << "bad: " << bad << "\n";
375
    /// std::cout << "good:" << good << "\n";
376
    /// \ecpp
377
    ///
378
    /// \out
379
    /// bad:  [ 42 ]
380
    /// good: [ [ 42 ] ]
381
    /// \eout
382
    ///
383
    /// \endparblock
384
    ///
385
    /// \tparam ElemType  One of the TOML node or value types (or a type promotable to one).
386
    /// \tparam ElemTypes One of the TOML node or value types (or a type promotable to one).
387
    /// \param  val   The node or value used to initialize element 0.
388
    /// \param  vals  The nodes or values used to initialize elements 1...N.
389
    TOML_CONSTRAINED_TEMPLATE((sizeof...(ElemTypes) > 0 || !std::is_same_v<impl::remove_cvref<ElemType>, array>),
390
                  typename ElemType,
391
                  typename... ElemTypes)
392
    TOML_NODISCARD_CTOR
393
    explicit array(ElemType&& val, ElemTypes&&... vals)
394
      : array{ std::false_type{},
395
           std::initializer_list<impl::array_init_elem>{ static_cast<ElemType&&>(val),
396
                                   static_cast<ElemTypes&&>(vals)... } }
397
    {}
398
399
    /// \brief  Copy-assignment operator.
400
    TOML_EXPORTED_MEMBER_FUNCTION
401
    array& operator=(const array&);
402
403
    /// \brief  Move-assignment operator.
404
    TOML_EXPORTED_MEMBER_FUNCTION
405
    array& operator=(array&& rhs) noexcept;
406
407
    /// \name Type checks
408
    /// @{
409
410
    /// \brief Returns #toml::node_type::array.
411
    TOML_CONST_INLINE_GETTER
412
    node_type type() const noexcept final
413
6.75k
    {
414
6.75k
      return node_type::array;
415
6.75k
    }
416
417
    TOML_PURE_GETTER
418
    TOML_EXPORTED_MEMBER_FUNCTION
419
    bool is_homogeneous(node_type ntype) const noexcept final;
420
421
    TOML_NODISCARD
422
    TOML_EXPORTED_MEMBER_FUNCTION
423
    bool is_homogeneous(node_type ntype, node*& first_nonmatch) noexcept final;
424
425
    TOML_NODISCARD
426
    TOML_EXPORTED_MEMBER_FUNCTION
427
    bool is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept final;
428
429
    /// \cond
430
    template <typename ElemType = void>
431
    TOML_PURE_GETTER
432
    bool is_homogeneous() const noexcept
433
    {
434
      using type = impl::remove_cvref<impl::unwrap_node<ElemType>>;
435
      static_assert(std::is_void_v<type> || toml::is_value<type> || toml::is_container<type>,
436
              "The template type argument of array::is_homogeneous() must be void or one "
437
              "of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
438
439
      return is_homogeneous(impl::node_type_of<type>);
440
    }
441
    /// \endcond
442
443
    /// \brief Returns `false`.
444
    TOML_CONST_INLINE_GETTER
445
    bool is_table() const noexcept final
446
1.12k
    {
447
1.12k
      return false;
448
1.12k
    }
449
450
    /// \brief Returns `true`.
451
    TOML_CONST_INLINE_GETTER
452
    bool is_array() const noexcept final
453
0
    {
454
0
      return true;
455
0
    }
456
457
    /// \brief Returns `true` if the array contains only tables.
458
    TOML_PURE_GETTER
459
    bool is_array_of_tables() const noexcept final
460
1.12k
    {
461
1.12k
      return is_homogeneous(node_type::table);
462
1.12k
    }
463
464
    /// \brief Returns `false`.
465
    TOML_CONST_INLINE_GETTER
466
    bool is_value() const noexcept final
467
0
    {
468
0
      return false;
469
0
    }
470
471
    /// \brief Returns `false`.
472
    TOML_CONST_INLINE_GETTER
473
    bool is_string() const noexcept final
474
0
    {
475
0
      return false;
476
0
    }
477
478
    /// \brief Returns `false`.
479
    TOML_CONST_INLINE_GETTER
480
    bool is_integer() const noexcept final
481
0
    {
482
0
      return false;
483
0
    }
484
485
    /// \brief Returns `false`.
486
    TOML_CONST_INLINE_GETTER
487
    bool is_floating_point() const noexcept final
488
0
    {
489
0
      return false;
490
0
    }
491
492
    /// \brief Returns `false`.
493
    TOML_CONST_INLINE_GETTER
494
    bool is_number() const noexcept final
495
0
    {
496
0
      return false;
497
0
    }
498
499
    /// \brief Returns `false`.
500
    TOML_CONST_INLINE_GETTER
501
    bool is_boolean() const noexcept final
502
0
    {
503
0
      return false;
504
0
    }
505
506
    /// \brief Returns `false`.
507
    TOML_CONST_INLINE_GETTER
508
    bool is_date() const noexcept final
509
0
    {
510
0
      return false;
511
0
    }
512
513
    /// \brief Returns `false`.
514
    TOML_CONST_INLINE_GETTER
515
    bool is_time() const noexcept final
516
0
    {
517
0
      return false;
518
0
    }
519
520
    /// \brief Returns `false`.
521
    TOML_CONST_INLINE_GETTER
522
    bool is_date_time() const noexcept final
523
0
    {
524
0
      return false;
525
0
    }
526
527
    /// @}
528
529
    /// \name Type casts
530
    /// @{
531
532
    /// \brief Returns `nullptr`.
533
    TOML_CONST_INLINE_GETTER
534
    table* as_table() noexcept final
535
25.7k
    {
536
25.7k
      return nullptr;
537
25.7k
    }
538
539
    /// \brief Returns a pointer to the array.
540
    TOML_CONST_INLINE_GETTER
541
    array* as_array() noexcept final
542
39.7k
    {
543
39.7k
      return this;
544
39.7k
    }
545
546
    /// \brief Returns `nullptr`.
547
    TOML_CONST_INLINE_GETTER
548
    toml::value<std::string>* as_string() noexcept final
549
0
    {
550
0
      return nullptr;
551
0
    }
552
553
    /// \brief Returns `nullptr`.
554
    TOML_CONST_INLINE_GETTER
555
    toml::value<int64_t>* as_integer() noexcept final
556
0
    {
557
0
      return nullptr;
558
0
    }
559
560
    /// \brief Returns `nullptr`.
561
    TOML_CONST_INLINE_GETTER
562
    toml::value<double>* as_floating_point() noexcept final
563
0
    {
564
0
      return nullptr;
565
0
    }
566
567
    /// \brief Returns `nullptr`.
568
    TOML_CONST_INLINE_GETTER
569
    toml::value<bool>* as_boolean() noexcept final
570
0
    {
571
0
      return nullptr;
572
0
    }
573
574
    /// \brief Returns `nullptr`.
575
    TOML_CONST_INLINE_GETTER
576
    toml::value<date>* as_date() noexcept final
577
0
    {
578
0
      return nullptr;
579
0
    }
580
581
    /// \brief Returns `nullptr`.
582
    TOML_CONST_INLINE_GETTER
583
    toml::value<time>* as_time() noexcept final
584
0
    {
585
0
      return nullptr;
586
0
    }
587
588
    /// \brief Returns `nullptr`.
589
    TOML_CONST_INLINE_GETTER
590
    toml::value<date_time>* as_date_time() noexcept final
591
0
    {
592
0
      return nullptr;
593
0
    }
594
595
    /// \brief Returns `nullptr`.
596
    TOML_CONST_INLINE_GETTER
597
    const table* as_table() const noexcept final
598
0
    {
599
0
      return nullptr;
600
0
    }
601
602
    /// \brief Returns a const-qualified pointer to the array.
603
    TOML_CONST_INLINE_GETTER
604
    const array* as_array() const noexcept final
605
0
    {
606
0
      return this;
607
0
    }
608
609
    /// \brief Returns `nullptr`.
610
    TOML_CONST_INLINE_GETTER
611
    const toml::value<std::string>* as_string() const noexcept final
612
0
    {
613
0
      return nullptr;
614
0
    }
615
616
    /// \brief Returns `nullptr`.
617
    TOML_CONST_INLINE_GETTER
618
    const toml::value<int64_t>* as_integer() const noexcept final
619
0
    {
620
0
      return nullptr;
621
0
    }
622
623
    /// \brief Returns `nullptr`.
624
    TOML_CONST_INLINE_GETTER
625
    const toml::value<double>* as_floating_point() const noexcept final
626
0
    {
627
0
      return nullptr;
628
0
    }
629
630
    /// \brief Returns `nullptr`.
631
    TOML_CONST_INLINE_GETTER
632
    const toml::value<bool>* as_boolean() const noexcept final
633
0
    {
634
0
      return nullptr;
635
0
    }
636
637
    /// \brief Returns `nullptr`.
638
    TOML_CONST_INLINE_GETTER
639
    const toml::value<date>* as_date() const noexcept final
640
0
    {
641
0
      return nullptr;
642
0
    }
643
644
    /// \brief Returns `nullptr`.
645
    TOML_CONST_INLINE_GETTER
646
    const toml::value<time>* as_time() const noexcept final
647
0
    {
648
0
      return nullptr;
649
0
    }
650
651
    /// \brief Returns `nullptr`.
652
    TOML_CONST_INLINE_GETTER
653
    const toml::value<date_time>* as_date_time() const noexcept final
654
0
    {
655
0
      return nullptr;
656
0
    }
657
658
    /// @}
659
660
    /// \name Value retrieval
661
    /// @{
662
663
    /// \brief  Gets a pointer to the element at a specific index.
664
    ///
665
    /// \detail \cpp
666
    /// auto arr = toml::array{ 99, "bottles of beer on the wall" };
667
    /// std::cout << "element [0] exists: "sv << !!arr.get(0) << "\n";
668
    /// std::cout << "element [1] exists: "sv << !!arr.get(1) << "\n";
669
    /// std::cout << "element [2] exists: "sv << !!arr.get(2) << "\n";
670
    /// if (toml::node* val = arr.get(0))
671
    ///   std::cout << "element [0] is an "sv << val->type() << "\n";
672
    /// \ecpp
673
    ///
674
    /// \out
675
    /// element [0] exists: true
676
    /// element [1] exists: true
677
    /// element [2] exists: false
678
    /// element [0] is an integer
679
    /// \eout
680
    ///
681
    /// \param  index The element's index.
682
    ///
683
    /// \returns  A pointer to the element at the specified index if one existed, or nullptr.
684
    TOML_PURE_INLINE_GETTER
685
    node* get(size_t index) noexcept
686
0
    {
687
0
      return index < elems_.size() ? elems_[index].get() : nullptr;
688
0
    }
689
690
    /// \brief  Gets a pointer to the element at a specific index (const overload).
691
    ///
692
    /// \param  index The element's index.
693
    ///
694
    /// \returns  A pointer to the element at the specified index if one existed, or nullptr.
695
    TOML_PURE_INLINE_GETTER
696
    const node* get(size_t index) const noexcept
697
0
    {
698
0
      return const_cast<array&>(*this).get(index);
699
0
    }
700
701
    /// \brief  Gets a pointer to the element at a specific index if it is a particular type.
702
    ///
703
    /// \detail \cpp
704
    /// auto arr = toml::array{ 42, "is the meaning of life, apparently."sv };
705
    /// if (toml::value<int64_t>* val = arr.get_as<int64_t>(0))
706
    ///   std::cout << "element [0] is an integer with value "sv << *val << "\n";
707
    /// \ecpp
708
    ///
709
    /// \out
710
    /// element [0] is an integer with value 42
711
    /// \eout
712
    ///
713
    /// \tparam ElemType  toml::table, toml::array, or a native TOML value type
714
    /// \param  index   The element's index.
715
    ///
716
    /// \returns  A pointer to the selected element if it existed and was of the specified type, or nullptr.
717
    template <typename ElemType>
718
    TOML_NODISCARD
719
    impl::wrap_node<ElemType>* get_as(size_t index) noexcept
720
    {
721
      if (auto val = get(index))
722
        return val->template as<ElemType>();
723
      return nullptr;
724
    }
725
726
    /// \brief  Gets a pointer to the element at a specific index if it is a particular type (const overload).
727
    ///
728
    /// \tparam ElemType  toml::table, toml::array, or a native TOML value type
729
    /// \param  index   The element's index.
730
    ///
731
    /// \returns  A pointer to the selected element if it existed and was of the specified type, or nullptr.
732
    template <typename ElemType>
733
    TOML_NODISCARD
734
    const impl::wrap_node<ElemType>* get_as(size_t index) const noexcept
735
    {
736
      return const_cast<array&>(*this).template get_as<ElemType>(index);
737
    }
738
739
    /// \cond
740
    using node::operator[]; // inherit operator[toml::path]
741
    /// \endcond
742
743
    /// \brief  Gets a reference to the element at a specific index.
744
    TOML_NODISCARD
745
    node& operator[](size_t index) noexcept
746
0
    {
747
0
      return *elems_[index];
748
0
    }
749
750
    /// \brief  Gets a reference to the element at a specific index.
751
    TOML_NODISCARD
752
    const node& operator[](size_t index) const noexcept
753
0
    {
754
0
      return *elems_[index];
755
0
    }
756
757
    /// \brief  Gets a reference to the element at a specific index, throwing `std::out_of_range` if none existed.
758
    TOML_NODISCARD
759
    TOML_EXPORTED_MEMBER_FUNCTION
760
    node& at(size_t index);
761
762
    /// \brief  Gets a reference to the element at a specific index, throwing `std::out_of_range` if none existed.
763
    TOML_NODISCARD
764
    const node& at(size_t index) const
765
0
    {
766
0
      return const_cast<array&>(*this).at(index);
767
0
    }
768
769
    /// \brief  Returns a reference to the first element in the array.
770
    TOML_NODISCARD
771
    node& front() noexcept
772
0
    {
773
0
      return *elems_.front();
774
0
    }
775
776
    /// \brief  Returns a reference to the first element in the array.
777
    TOML_NODISCARD
778
    const node& front() const noexcept
779
0
    {
780
0
      return *elems_.front();
781
0
    }
782
783
    /// \brief  Returns a reference to the last element in the array.
784
    TOML_NODISCARD
785
    node& back() noexcept
786
25.7k
    {
787
25.7k
      return *elems_.back();
788
25.7k
    }
789
790
    /// \brief  Returns a reference to the last element in the array.
791
    TOML_NODISCARD
792
    const node& back() const noexcept
793
0
    {
794
0
      return *elems_.back();
795
0
    }
796
797
    /// @}
798
799
    /// \name Iteration
800
    /// @{
801
802
    /// \brief A RandomAccessIterator for iterating over elements in a toml::array.
803
    using iterator = array_iterator;
804
805
    /// \brief A RandomAccessIterator for iterating over const elements in a toml::array.
806
    using const_iterator = const_array_iterator;
807
808
    /// \brief  Returns an iterator to the first element.
809
    TOML_NODISCARD
810
    iterator begin() noexcept
811
6.72k
    {
812
6.72k
      return iterator{ elems_.begin() };
813
6.72k
    }
814
815
    /// \brief  Returns an iterator to the first element.
816
    TOML_NODISCARD
817
    const_iterator begin() const noexcept
818
0
    {
819
0
      return const_iterator{ elems_.cbegin() };
820
0
    }
821
822
    /// \brief  Returns an iterator to the first element.
823
    TOML_NODISCARD
824
    const_iterator cbegin() const noexcept
825
0
    {
826
0
      return const_iterator{ elems_.cbegin() };
827
0
    }
828
829
    /// \brief  Returns an iterator to one-past-the-last element.
830
    TOML_NODISCARD
831
    iterator end() noexcept
832
6.72k
    {
833
6.72k
      return iterator{ elems_.end() };
834
6.72k
    }
835
836
    /// \brief  Returns an iterator to one-past-the-last element.
837
    TOML_NODISCARD
838
    const_iterator end() const noexcept
839
0
    {
840
0
      return const_iterator{ elems_.cend() };
841
0
    }
842
843
    /// \brief  Returns an iterator to one-past-the-last element.
844
    TOML_NODISCARD
845
    const_iterator cend() const noexcept
846
0
    {
847
0
      return const_iterator{ elems_.cend() };
848
0
    }
849
850
    private:
851
    /// \cond
852
853
    template <typename T, typename Array>
854
    using for_each_elem_ref = impl::copy_cvref<impl::wrap_node<impl::remove_cvref<impl::unwrap_node<T>>>, Array>;
855
856
    template <typename Func, typename Array, typename T>
857
    using can_for_each = std::disjunction<std::is_invocable<Func, for_each_elem_ref<T, Array>, size_t>,
858
                        std::is_invocable<Func, size_t, for_each_elem_ref<T, Array>>,
859
                        std::is_invocable<Func, for_each_elem_ref<T, Array>>>;
860
861
    template <typename Func, typename Array, typename T>
862
    using can_for_each_nothrow = std::conditional_t<
863
      // first form
864
      std::is_invocable_v<Func, for_each_elem_ref<T, Array>, size_t>,
865
      std::is_nothrow_invocable<Func, for_each_elem_ref<T, Array>, size_t>,
866
      std::conditional_t<
867
        // second form
868
        std::is_invocable_v<Func, size_t, for_each_elem_ref<T, Array>>,
869
        std::is_nothrow_invocable<Func, size_t, for_each_elem_ref<T, Array>>,
870
        std::conditional_t<
871
          // third form
872
          std::is_invocable_v<Func, for_each_elem_ref<T, Array>>,
873
          std::is_nothrow_invocable<Func, for_each_elem_ref<T, Array>>,
874
          std::false_type>>>;
875
876
    template <typename Func, typename Array>
877
    using can_for_each_any = std::disjunction<can_for_each<Func, Array, table>,
878
                          can_for_each<Func, Array, array>,
879
                          can_for_each<Func, Array, std::string>,
880
                          can_for_each<Func, Array, int64_t>,
881
                          can_for_each<Func, Array, double>,
882
                          can_for_each<Func, Array, bool>,
883
                          can_for_each<Func, Array, date>,
884
                          can_for_each<Func, Array, time>,
885
                          can_for_each<Func, Array, date_time>>;
886
887
    template <typename Func, typename Array, typename T>
888
    using for_each_is_nothrow_one = std::disjunction<std::negation<can_for_each<Func, Array, T>>, //
889
                             can_for_each_nothrow<Func, Array, T>>;
890
891
    template <typename Func, typename Array>
892
    using for_each_is_nothrow = std::conjunction<for_each_is_nothrow_one<Func, Array, table>,
893
                           for_each_is_nothrow_one<Func, Array, array>,
894
                           for_each_is_nothrow_one<Func, Array, std::string>,
895
                           for_each_is_nothrow_one<Func, Array, int64_t>,
896
                           for_each_is_nothrow_one<Func, Array, double>,
897
                           for_each_is_nothrow_one<Func, Array, bool>,
898
                           for_each_is_nothrow_one<Func, Array, date>,
899
                           for_each_is_nothrow_one<Func, Array, time>,
900
                           for_each_is_nothrow_one<Func, Array, date_time>>;
901
902
    template <typename Func, typename Array>
903
    static void do_for_each(Func&& visitor, Array&& arr) //
904
      noexcept(for_each_is_nothrow<Func&&, Array&&>::value)
905
    {
906
      static_assert(can_for_each_any<Func&&, Array&&>::value,
907
              "TOML array for_each visitors must be invocable for at least one of the toml::node "
908
              "specializations:" TOML_SA_NODE_TYPE_LIST);
909
910
      for (size_t i = 0; i < arr.size(); i++)
911
      {
912
        using node_ref = impl::copy_cvref<toml::node, Array&&>;
913
        static_assert(std::is_reference_v<node_ref>);
914
915
#if TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN
916
917
#ifndef TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_ACKNOWLEDGED
918
        static_assert(impl::always_false<Func, Array, node_ref>, //
919
                TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_MESSAGE);
920
#endif
921
922
        static_cast<node_ref>(static_cast<Array&&>(arr)[i])
923
          .visit(
924
            [&]([[maybe_unused]] auto&& elem) //
925
            noexcept(for_each_is_nothrow_one<Func&&, Array&&, decltype(elem)>::value)
926
            {
927
              using elem_ref = for_each_elem_ref<decltype(elem), Array&&>;
928
              static_assert(std::is_reference_v<elem_ref>);
929
930
              // func(elem, i)
931
              if constexpr (std::is_invocable_v<Func&&, elem_ref, size_t>)
932
              {
933
                static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem), i);
934
              }
935
936
              // func(i, elem)
937
              else if constexpr (std::is_invocable_v<Func&&, size_t, elem_ref>)
938
              {
939
                static_cast<Func&&>(visitor)(i, static_cast<elem_ref>(elem));
940
              }
941
942
              // func(elem)
943
              else if constexpr (std::is_invocable_v<Func&&, elem_ref>)
944
              {
945
                static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem));
946
              }
947
            });
948
949
#else
950
        const auto keep_going =
951
          static_cast<node_ref>(static_cast<Array&&>(arr)[i])
952
            .visit(
953
              [&]([[maybe_unused]] auto&& elem) //
954
// Define this macro as a workaround to compile errors caused by a bug in MSVC's "legacy lambda processor".
955
#if !TOML_DISABLE_CONDITIONAL_NOEXCEPT_LAMBDA
956
              noexcept(for_each_is_nothrow_one<Func&&, Array&&, decltype(elem)>::value)
957
#endif
958
              {
959
                using elem_ref = for_each_elem_ref<decltype(elem), Array&&>;
960
                static_assert(std::is_reference_v<elem_ref>);
961
962
                // func(elem, i)
963
                if constexpr (std::is_invocable_v<Func&&, elem_ref, size_t>)
964
                {
965
                  using return_type =
966
                    decltype(static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem), i));
967
968
                  if constexpr (impl::is_constructible_or_convertible<bool, return_type>)
969
                  {
970
                    return static_cast<bool>(
971
                      static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem), i));
972
                  }
973
                  else
974
                  {
975
                    static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem), i);
976
                    return true;
977
                  }
978
                }
979
980
                // func(i, elem)
981
                else if constexpr (std::is_invocable_v<Func&&, size_t, elem_ref>)
982
                {
983
                  using return_type =
984
                    decltype(static_cast<Func&&>(visitor)(i, static_cast<elem_ref>(elem)));
985
986
                  if constexpr (impl::is_constructible_or_convertible<bool, return_type>)
987
                  {
988
                    return static_cast<bool>(
989
                      static_cast<Func&&>(visitor)(i, static_cast<elem_ref>(elem)));
990
                  }
991
                  else
992
                  {
993
                    static_cast<Func&&>(visitor)(i, static_cast<elem_ref>(elem));
994
                    return true;
995
                  }
996
                }
997
998
                // func(elem)
999
                else if constexpr (std::is_invocable_v<Func&&, elem_ref>)
1000
                {
1001
                  using return_type =
1002
                    decltype(static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem)));
1003
1004
                  if constexpr (impl::is_constructible_or_convertible<bool, return_type>)
1005
                  {
1006
                    return static_cast<bool>(
1007
                      static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem)));
1008
                  }
1009
                  else
1010
                  {
1011
                    static_cast<Func&&>(visitor)(static_cast<elem_ref>(elem));
1012
                    return true;
1013
                  }
1014
                }
1015
1016
                // visitor not compatible with this particular type
1017
                else
1018
                  return true;
1019
              });
1020
1021
        if (!keep_going)
1022
          return;
1023
#endif
1024
      }
1025
    }
1026
1027
    /// \endcond
1028
1029
    public:
1030
    /// \brief  Invokes a visitor on each element in the array.
1031
    ///
1032
    /// \tparam Func  A callable type invocable with one of the following signatures:
1033
    ///         <ul>
1034
    ///         <li> `func(elem, index)`
1035
    ///         <li> `func(elem)`
1036
    ///         <li> `func(index, elem)`
1037
    ///         </ul>
1038
    ///         Where:
1039
    ///         <ul>
1040
    ///         <li> `elem` will recieve the element as it's concrete type with cvref-qualifications matching the array
1041
    ///         <li> `index` will recieve a `size_t` indicating the element's index
1042
    ///         </ul>
1043
    ///         Visitors returning `bool` (or something convertible to `bool`) will cause iteration to
1044
    ///         stop if they return `false`.
1045
    ///
1046
    /// \param  visitor The visitor object.
1047
    ///
1048
    /// \returns A reference to the array.
1049
    ///
1050
    /// \details \cpp
1051
    /// toml::array arr{ 0, 1, 2, 3.0, "four", "five", 6 };
1052
    ///
1053
    /// // select only the integers using a strongly-typed visitor
1054
    /// arr.for_each([](toml::value<int64_t>& elem)
1055
    /// {
1056
    ///   std::cout << elem << ", ";
1057
    /// });
1058
    /// std::cout << "\n";
1059
    ///
1060
    /// // select all the numeric values using a generic visitor + is_number<> metafunction
1061
    /// arr.for_each([](auto&& elem)
1062
    /// {
1063
    ///   if constexpr (toml::is_number<decltype(elem)>)
1064
    ///     std::cout << elem << ", ";
1065
    /// });
1066
    /// std::cout << "\n";
1067
    ///
1068
    /// // select all the numeric values until we encounter something non-numeric
1069
    /// arr.for_each([](auto&& elem)
1070
    /// {
1071
    ///   if constexpr (toml::is_number<decltype(elem)>)
1072
    ///   {
1073
    ///     std::cout << elem << ", ";
1074
    ///     return true; // "keep going"
1075
    ///   }
1076
    ///   else
1077
    ///     return false; // "stop!"
1078
    ///
1079
    /// });
1080
    /// std::cout << "\n";
1081
    ///
1082
    /// \ecpp
1083
    /// \out
1084
    /// 0, 1, 2, 6,
1085
    /// 0, 1, 2, 3.0, 6,
1086
    /// 0, 1, 2, 3.0,
1087
    /// \eout
1088
    ///
1089
    /// \see node::visit()
1090
    template <typename Func>
1091
    array& for_each(Func&& visitor) & //
1092
      noexcept(for_each_is_nothrow<Func&&, array&>::value)
1093
    {
1094
      do_for_each(static_cast<Func&&>(visitor), *this);
1095
      return *this;
1096
    }
1097
1098
    /// \brief  Invokes a visitor on each element in the array (rvalue overload).
1099
    template <typename Func>
1100
    array&& for_each(Func&& visitor) && //
1101
      noexcept(for_each_is_nothrow<Func&&, array&&>::value)
1102
    {
1103
      do_for_each(static_cast<Func&&>(visitor), static_cast<array&&>(*this));
1104
      return static_cast<array&&>(*this);
1105
    }
1106
1107
    /// \brief  Invokes a visitor on each element in the array (const lvalue overload).
1108
    template <typename Func>
1109
    const array& for_each(Func&& visitor) const& //
1110
      noexcept(for_each_is_nothrow<Func&&, const array&>::value)
1111
    {
1112
      do_for_each(static_cast<Func&&>(visitor), *this);
1113
      return *this;
1114
    }
1115
1116
    /// \brief  Invokes a visitor on each element in the array (const rvalue overload).
1117
    template <typename Func>
1118
    const array&& for_each(Func&& visitor) const&& //
1119
      noexcept(for_each_is_nothrow<Func&&, const array&&>::value)
1120
    {
1121
      do_for_each(static_cast<Func&&>(visitor), static_cast<const array&&>(*this));
1122
      return static_cast<const array&&>(*this);
1123
    }
1124
1125
    /// @}
1126
1127
    /// \name Size and Capacity
1128
    /// @{
1129
1130
    /// \brief  Returns true if the array is empty.
1131
    TOML_NODISCARD
1132
    bool empty() const noexcept
1133
0
    {
1134
0
      return elems_.empty();
1135
0
    }
1136
1137
    /// \brief  Returns the number of elements in the array.
1138
    TOML_NODISCARD
1139
    size_t size() const noexcept
1140
0
    {
1141
0
      return elems_.size();
1142
0
    }
1143
1144
    /// \brief  Returns the maximum number of elements that can be stored in an array on the current platform.
1145
    TOML_NODISCARD
1146
    size_t max_size() const noexcept
1147
0
    {
1148
0
      return elems_.max_size();
1149
0
    }
1150
1151
    /// \brief  Returns the current max number of elements that may be held in the array's internal storage.
1152
    TOML_NODISCARD
1153
    size_t capacity() const noexcept
1154
325k
    {
1155
325k
      return elems_.capacity();
1156
325k
    }
1157
1158
    /// \brief  Reserves internal storage capacity up to a pre-determined number of elements.
1159
    TOML_EXPORTED_MEMBER_FUNCTION
1160
    void reserve(size_t new_capacity);
1161
1162
    /// \brief  Requests the removal of any unused internal storage capacity.
1163
    TOML_EXPORTED_MEMBER_FUNCTION
1164
    void shrink_to_fit();
1165
1166
    /// \brief  Shrinks the array to the given size.
1167
    ///
1168
    /// \detail \godbolt{rxEzK5}
1169
    ///
1170
    /// \cpp
1171
    /// auto arr = toml::array{ 1, 2, 3 };
1172
    /// std::cout << arr << "\n";
1173
    ///
1174
    /// arr.truncate(5); // no-op
1175
    /// std::cout << arr << "\n";
1176
    ///
1177
    /// arr.truncate(1);
1178
    /// std::cout << arr << "\n";
1179
    /// \ecpp
1180
    ///
1181
    /// \out
1182
    /// [ 1, 2, 3 ]
1183
    /// [ 1, 2, 3 ]
1184
    /// [ 1]
1185
    /// \eout
1186
    ///
1187
    /// \remarks  Does nothing if the requested size is larger than or equal to the current size.
1188
    TOML_EXPORTED_MEMBER_FUNCTION
1189
    void truncate(size_t new_size);
1190
1191
    /// \brief  Resizes the array.
1192
    ///
1193
    /// \detail \godbolt{W5zqx3}
1194
    ///
1195
    /// \cpp
1196
    /// auto arr = toml::array{ 1, 2, 3 };
1197
    /// std::cout << arr << "\n";
1198
    ///
1199
    /// arr.resize(6, 42);
1200
    /// std::cout << arr << "\n";
1201
    ///
1202
    /// arr.resize(2, 0);
1203
    /// std::cout << arr << "\n";
1204
    /// \ecpp
1205
    ///
1206
    /// \out
1207
    /// [ 1, 2, 3 ]
1208
    /// [ 1, 2, 3, 42, 42, 42 ]
1209
    /// [ 1, 2 ]
1210
    /// \eout
1211
    ///
1212
    /// \tparam ElemType  toml::node, toml::table, toml::array, or a native TOML value type
1213
    ///           (or a type promotable to one).
1214
    ///
1215
    /// \param  new_size      The number of elements the array will have after resizing.
1216
    /// \param  default_init_val  The node or value used to initialize new elements if the array needs to grow.
1217
    /// \param  default_init_flags  Value flags to apply to new values created if new elements are created by growing.
1218
    template <typename ElemType>
1219
    void resize(size_t new_size,
1220
          ElemType&& default_init_val,
1221
          value_flags default_init_flags = preserve_source_value_flags)
1222
    {
1223
      static_assert(!is_node_view<ElemType>,
1224
              "The default element type argument to toml::array::resize may not be toml::node_view.");
1225
1226
      if (!new_size)
1227
        clear();
1228
      else if (new_size > elems_.size())
1229
        insert(cend(), new_size - elems_.size(), static_cast<ElemType&&>(default_init_val), default_init_flags);
1230
      else
1231
        truncate(new_size);
1232
    }
1233
1234
    /// @}
1235
1236
    /// \name Erasure
1237
    /// @{
1238
1239
    /// \brief  Removes the specified element from the array.
1240
    ///
1241
    /// \detail \cpp
1242
    /// auto arr = toml::array{ 1, 2, 3 };
1243
    /// std::cout << arr << "\n";
1244
    ///
1245
    /// arr.erase(arr.cbegin() + 1);
1246
    /// std::cout << arr << "\n";
1247
    /// \ecpp
1248
    ///
1249
    /// \out
1250
    /// [ 1, 2, 3 ]
1251
    /// [ 1, 3 ]
1252
    /// \eout
1253
    ///
1254
    /// \param  pos   Iterator to the element being erased.
1255
    ///
1256
    /// \returns Iterator to the first element immediately following the removed element.
1257
    TOML_EXPORTED_MEMBER_FUNCTION
1258
    iterator erase(const_iterator pos) noexcept;
1259
1260
    /// \brief  Removes the elements in the range [first, last) from the array.
1261
    ///
1262
    /// \detail \cpp
1263
    /// auto arr = toml::array{ 1, "bad", "karma" 2 };
1264
    /// std::cout << arr << "\n";
1265
    ///
1266
    /// arr.erase(arr.cbegin() + 1, arr.cbegin() + 3);
1267
    /// std::cout << arr << "\n";
1268
    /// \ecpp
1269
    ///
1270
    /// \out
1271
    /// [ 1, 'bad', 'karma', 3 ]
1272
    /// [ 1, 3 ]
1273
    /// \eout
1274
    ///
1275
    /// \param  first Iterator to the first element being erased.
1276
    /// \param  last  Iterator to the one-past-the-last element being erased.
1277
    ///
1278
    /// \returns Iterator to the first element immediately following the last removed element.
1279
    TOML_EXPORTED_MEMBER_FUNCTION
1280
    iterator erase(const_iterator first, const_iterator last) noexcept;
1281
1282
    /// \brief  Flattens this array, recursively hoisting the contents of child arrays up into itself.
1283
    ///
1284
    /// \detail \cpp
1285
    ///
1286
    /// auto arr = toml::array{ 1, 2, toml::array{ 3, 4, toml::array{ 5 } }, 6, toml::array{} };
1287
    /// std::cout << arr << "\n";
1288
    ///
1289
    /// arr.flatten();
1290
    /// std::cout << arr << "\n";
1291
    /// \ecpp
1292
    ///
1293
    /// \out
1294
    /// [ 1, 2, [ 3, 4, [ 5 ] ], 6, [] ]
1295
    /// [ 1, 2, 3, 4, 5, 6 ]
1296
    /// \eout
1297
    ///
1298
    /// \remarks  Arrays inside child tables are not flattened.
1299
    ///
1300
    /// \returns A reference to the array.
1301
    TOML_EXPORTED_MEMBER_FUNCTION
1302
    array& flatten() &;
1303
1304
    /// \brief   Flattens this array, recursively hoisting the contents of child arrays up into itself (rvalue overload).
1305
    array&& flatten() &&
1306
0
    {
1307
0
      return static_cast<toml::array&&>(this->flatten());
1308
0
    }
1309
1310
    /// \brief  Removes empty child arrays and tables.
1311
    ///
1312
    /// \detail \cpp
1313
    ///
1314
    /// auto arr = toml::array{ 1, 2, toml::array{ }, toml::array{ 3, toml::array{ } }, 4 };
1315
    /// std::cout << arr << "\n";
1316
    ///
1317
    /// arr.prune(true);
1318
    /// std::cout << arr << "\n";
1319
    /// \ecpp
1320
    ///
1321
    /// \out
1322
    /// [ 1, 2, [], [ 3, [] ], 4 ]
1323
    /// [ 1, 2, [ 3 ], 4 ]
1324
    /// \eout
1325
    ///
1326
    /// \param recursive Should child arrays and tables themselves be pruned?
1327
    ///
1328
    /// \returns A reference to the array.
1329
    TOML_EXPORTED_MEMBER_FUNCTION
1330
    array& prune(bool recursive = true) & noexcept;
1331
1332
    /// \brief  Removes empty child arrays and tables (rvalue overload).
1333
    ///
1334
    /// \param recursive Should child arrays and tables themselves be pruned?
1335
    ///
1336
    /// \returns An rvalue reference to the array.
1337
    array&& prune(bool recursive = true) && noexcept
1338
0
    {
1339
0
      return static_cast<toml::array&&>(this->prune(recursive));
1340
0
    }
1341
1342
    /// \brief  Removes the last element from the array.
1343
    TOML_EXPORTED_MEMBER_FUNCTION
1344
    void pop_back() noexcept;
1345
1346
    /// \brief  Removes all elements from the array.
1347
    TOML_EXPORTED_MEMBER_FUNCTION
1348
    void clear() noexcept;
1349
1350
    /// @}
1351
1352
    /// \name Insertion and Emplacement
1353
    /// @{
1354
1355
    /// \brief  Inserts a new element at a specific position in the array.
1356
    ///
1357
    /// \detail \cpp
1358
    /// auto arr = toml::array{ 1, 3 };
1359
    /// arr.insert(arr.cbegin() + 1, "two");
1360
    /// arr.insert(arr.cend(), toml::array{ 4, 5 });
1361
    /// std::cout << arr << "\n";
1362
    /// \ecpp
1363
    ///
1364
    /// \out
1365
    /// [ 1, 'two', 3, [ 4, 5 ] ]
1366
    /// \eout
1367
    ///
1368
    /// \tparam ElemType  toml::node, toml::node_view, toml::table, toml::array, or a native TOML value type
1369
    ///           (or a type promotable to one).
1370
    /// \param  pos     The insertion position.
1371
    /// \param  val     The node or value being inserted.
1372
    /// \param  flags   Value flags to apply to new values.
1373
    ///
1374
    /// \returns \conditional_return{Valid input}
1375
    ///      An iterator to the newly-inserted element.
1376
    ///      \conditional_return{Input is a null toml::node_view}
1377
    ///      end()
1378
    ///
1379
    /// \attention The return value will always be `end()` if the input value was a null toml::node_view,
1380
    ///        because no insertion can take place. This is the only circumstance in which this can occur.
1381
    template <typename ElemType>
1382
    iterator insert(const_iterator pos, ElemType&& val, value_flags flags = preserve_source_value_flags)
1383
    {
1384
      if constexpr (is_node_view<ElemType>)
1385
      {
1386
        if (!val)
1387
          return end();
1388
      }
1389
      return iterator{ insert_at(const_vector_iterator{ pos },
1390
                     impl::make_node(static_cast<ElemType&&>(val), flags)) };
1391
    }
1392
1393
    /// \brief  Repeatedly inserts a new element starting at a specific position in the array.
1394
    ///
1395
    /// \detail \cpp
1396
    /// auto arr = toml::array{
1397
    ///   "with an evil twinkle in its eye the goose said",
1398
    ///   "and immediately we knew peace was never an option."
1399
    /// };
1400
    /// arr.insert(arr.cbegin() + 1, 3, "honk");
1401
    /// std::cout << arr << "\n";
1402
    /// \ecpp
1403
    ///
1404
    /// \out
1405
    /// [
1406
    ///   'with an evil twinkle in its eye the goose said',
1407
    ///   'honk',
1408
    ///   'honk',
1409
    ///   'honk',
1410
    ///   'and immediately we knew peace was never an option.'
1411
    /// ]
1412
    /// \eout
1413
    ///
1414
    /// \tparam ElemType  toml::node, toml::node_view, toml::table, toml::array, or a native TOML value type
1415
    ///           (or a type promotable to one).
1416
    /// \param  pos     The insertion position.
1417
    /// \param  count   The number of times the node or value should be inserted.
1418
    /// \param  val     The node or value being inserted.
1419
    /// \param  flags   Value flags to apply to new values.
1420
    ///
1421
    /// \returns \conditional_return{Valid input}
1422
    ///      An iterator to the newly-inserted element.
1423
    ///      \conditional_return{count == 0}
1424
    ///      A copy of pos
1425
    ///      \conditional_return{Input is a null toml::node_view}
1426
    ///      end()
1427
    ///
1428
    /// \attention The return value will always be `end()` if the input value was a null toml::node_view,
1429
    ///        because no insertion can take place. This is the only circumstance in which this can occur.
1430
    template <typename ElemType>
1431
    iterator insert(const_iterator pos,
1432
            size_t count,
1433
            ElemType&& val,
1434
            value_flags flags = preserve_source_value_flags)
1435
    {
1436
      if constexpr (is_node_view<ElemType>)
1437
      {
1438
        if (!val)
1439
          return end();
1440
      }
1441
      switch (count)
1442
      {
1443
        case 0: return iterator{ elems_.begin() + (const_vector_iterator{ pos } - elems_.cbegin()) };
1444
        case 1: return insert(pos, static_cast<ElemType&&>(val), flags);
1445
        default:
1446
        {
1447
          const auto start_idx = static_cast<size_t>(const_vector_iterator{ pos } - elems_.cbegin());
1448
          preinsertion_resize(start_idx, count);
1449
          size_t i = start_idx;
1450
          for (size_t e = start_idx + count - 1u; i < e; i++)
1451
            elems_[i] = impl::make_node(val, flags);
1452
1453
          //# potentially move the initial value into the last element
1454
          elems_[i] = impl::make_node(static_cast<ElemType&&>(val), flags);
1455
          return iterator{ elems_.begin() + static_cast<ptrdiff_t>(start_idx) };
1456
        }
1457
      }
1458
    }
1459
1460
    /// \brief  Inserts a range of elements into the array at a specific position.
1461
    ///
1462
    /// \tparam Iter  An iterator type. Must satisfy ForwardIterator.
1463
    /// \param  pos   The insertion position.
1464
    /// \param  first Iterator to the first node or value being inserted.
1465
    /// \param  last  Iterator to the one-past-the-last node or value being inserted.
1466
    /// \param  flags   Value flags to apply to new values.
1467
    ///
1468
    /// \returns \conditional_return{Valid input}
1469
    ///      An iterator to the first newly-inserted element.
1470
    ///      \conditional_return{first >= last}
1471
    ///      A copy of pos
1472
    ///      \conditional_return{All objects in the range were null toml::node_views}
1473
    ///      A copy of pos
1474
    template <typename Iter>
1475
    iterator insert(const_iterator pos, Iter first, Iter last, value_flags flags = preserve_source_value_flags)
1476
    {
1477
      const auto distance = std::distance(first, last);
1478
      if (distance <= 0)
1479
        return iterator{ elems_.begin() + (const_vector_iterator{ pos } - elems_.cbegin()) };
1480
      else
1481
      {
1482
        auto count     = distance;
1483
        using deref_type = decltype(*first);
1484
        if constexpr (is_node_view<deref_type>)
1485
        {
1486
          for (auto it = first; it != last; it++)
1487
            if (!(*it))
1488
              count--;
1489
          if (!count)
1490
            return iterator{ elems_.begin() + (const_vector_iterator{ pos } - elems_.cbegin()) };
1491
        }
1492
        const auto start_idx = static_cast<size_t>(const_vector_iterator{ pos } - elems_.cbegin());
1493
        preinsertion_resize(start_idx, static_cast<size_t>(count));
1494
        size_t i = start_idx;
1495
        for (auto it = first; it != last; it++)
1496
        {
1497
          if constexpr (is_node_view<deref_type>)
1498
          {
1499
            if (!(*it))
1500
              continue;
1501
          }
1502
          if constexpr (std::is_rvalue_reference_v<deref_type>)
1503
            elems_[i++] = impl::make_node(std::move(*it), flags);
1504
          else
1505
            elems_[i++] = impl::make_node(*it, flags);
1506
        }
1507
        return iterator{ elems_.begin() + static_cast<ptrdiff_t>(start_idx) };
1508
      }
1509
    }
1510
1511
    /// \brief  Inserts a range of elements into the array at a specific position.
1512
    ///
1513
    /// \tparam ElemType  toml::node_view, toml::table, toml::array, or a native TOML value type
1514
    ///           (or a type promotable to one).
1515
    /// \param  pos     The insertion position.
1516
    /// \param  ilist   An initializer list containing the values to be inserted.
1517
    /// \param  flags   Value flags to apply to new values.
1518
    ///
1519
    /// \returns \conditional_return{Valid input}
1520
    ///      An iterator to the first newly-inserted element.
1521
    ///      \conditional_return{Input list is empty}
1522
    ///      A copy of pos
1523
    ///      \conditional_return{All objects in the list were null toml::node_views}
1524
    ///      A copy of pos
1525
    template <typename ElemType>
1526
    iterator insert(const_iterator pos,
1527
            std::initializer_list<ElemType> ilist,
1528
            value_flags flags = preserve_source_value_flags)
1529
    {
1530
      return insert(pos, ilist.begin(), ilist.end(), flags);
1531
    }
1532
1533
    /// \brief  Emplaces a new element at a specific position in the array.
1534
    ///
1535
    /// \detail \cpp
1536
    /// auto arr = toml::array{ 1, 2 };
1537
    ///
1538
    /// //add a string using std::string's substring constructor
1539
    /// arr.emplace<std::string>(arr.cbegin() + 1, "this is not a drill"sv, 14, 5);
1540
    /// std::cout << arr << "\n";
1541
    /// \ecpp
1542
    ///
1543
    /// \out
1544
    /// [ 1, 'drill', 2 ]
1545
    /// \eout
1546
    ///
1547
    /// \tparam ElemType  toml::table, toml::array, or any native TOML value type.
1548
    /// \tparam Args    Value constructor argument types.
1549
    /// \param  pos     The insertion position.
1550
    /// \param  args    Arguments to forward to the value's constructor.
1551
    ///
1552
    /// \returns  An iterator to the inserted element.
1553
    ///
1554
    /// \remarks There is no difference between insert() and emplace()
1555
    ///      for trivial value types (floats, ints, bools).
1556
    template <typename ElemType = void, typename... Args>
1557
    iterator emplace(const_iterator pos, Args&&... args)
1558
    {
1559
      using raw_elem_type = impl::remove_cvref<ElemType>;
1560
      using elem_type   = std::conditional_t<std::is_void_v<raw_elem_type>, //
1561
                           impl::emplaced_type_of<Args&&...>,
1562
                           raw_elem_type>;
1563
1564
      using type = impl::remove_cvref<impl::unwrap_node<elem_type>>;
1565
      static_assert(impl::is_native<type> || impl::is_one_of<type, table, array>,
1566
              "Emplacement type parameter must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
1567
1568
      return iterator{ insert_at(const_vector_iterator{ pos },
1569
                     impl::node_ptr{ new impl::wrap_node<type>{ static_cast<Args&&>(args)... } }) };
1570
    }
1571
1572
    /// \brief  Replaces the element at a specific position in the array with a different value.
1573
    ///
1574
    /// \detail \cpp
1575
    /// auto arr = toml::array{ 1, 2, 3 };
1576
    /// std::cout << arr << "\n";
1577
    /// arr.replace(arr.cbegin() + 1, "two");
1578
    /// std::cout << arr << "\n";
1579
    /// \ecpp
1580
    ///
1581
    /// \out
1582
    /// [ 1, 2, 3 ]
1583
    /// [ 1, 'two', 3 ]
1584
    /// \eout
1585
    ///
1586
    /// \tparam ElemType  toml::node, toml::node_view, toml::table, toml::array, or a native TOML value type
1587
    ///           (or a type promotable to one).
1588
    /// \param  pos     The insertion position.
1589
    /// \param  val     The node or value being inserted.
1590
    /// \param  flags   Value flags to apply to new values.
1591
    ///
1592
    /// \returns \conditional_return{Valid input}
1593
    ///      An iterator to the replaced element.
1594
    ///      \conditional_return{Input is a null toml::node_view}
1595
    ///      end()
1596
    ///
1597
    /// \attention The return value will always be `end()` if the input value was a null toml::node_view,
1598
    ///        because no replacement can take place. This is the only circumstance in which this can occur.
1599
    template <typename ElemType>
1600
    iterator replace(const_iterator pos, ElemType&& val, value_flags flags = preserve_source_value_flags)
1601
    {
1602
      TOML_ASSERT(pos >= cbegin() && pos < cend());
1603
1604
      if constexpr (is_node_view<ElemType>)
1605
      {
1606
        if (!val)
1607
          return end();
1608
      }
1609
1610
      const auto it = elems_.begin() + (const_vector_iterator{ pos } - elems_.cbegin());
1611
      *it       = impl::make_node(static_cast<ElemType&&>(val), flags);
1612
      return iterator{ it };
1613
    }
1614
1615
    /// \brief  Appends a new element to the end of the array.
1616
    ///
1617
    /// \detail \cpp
1618
    /// auto arr = toml::array{ 1, 2 };
1619
    /// arr.push_back(3);
1620
    /// arr.push_back(4.0);
1621
    /// arr.push_back(toml::array{ 5, "six"sv });
1622
    /// std::cout << arr << "\n";
1623
    /// \ecpp
1624
    ///
1625
    /// \out
1626
    /// [ 1, 2, 3, 4.0, [ 5, 'six' ] ]
1627
    /// \eout
1628
    ///
1629
    /// \tparam ElemType  toml::node, toml::node_view, toml::table, toml::array, or a native TOML value type
1630
    /// \param  val     The node or value being added.
1631
    /// \param  flags   Value flags to apply to new values.
1632
    ///
1633
    /// \attention  No insertion takes place if the input value is a null toml::node_view.
1634
    ///       This is the only circumstance in which this can occur.
1635
    template <typename ElemType>
1636
    void push_back(ElemType&& val, value_flags flags = preserve_source_value_flags)
1637
    {
1638
      emplace_back_if_not_empty_view(static_cast<ElemType&&>(val), flags);
1639
    }
1640
1641
    /// \brief  Emplaces a new element at the end of the array.
1642
    ///
1643
    /// \detail \cpp
1644
    /// auto arr = toml::array{ 1, 2 };
1645
    /// arr.emplace_back<toml::array>(3, "four"sv);
1646
    /// std::cout << arr << "\n";
1647
    /// \ecpp
1648
    ///
1649
    /// \out
1650
    /// [ 1, 2, [ 3, 'four' ] ]
1651
    /// \eout
1652
    ///
1653
    /// \tparam ElemType  toml::table, toml::array, or a native TOML value type
1654
    /// \tparam Args  Element constructor argument types.
1655
    /// \param  args    Arguments to forward to the elements's constructor.
1656
    ///
1657
    /// \returns A reference to the newly-constructed element.
1658
    ///
1659
    /// \remarks There is no difference between push_back() and emplace_back()
1660
    ///      For trivial value types (floats, ints, bools).
1661
    template <typename ElemType = void, typename... Args>
1662
    decltype(auto) emplace_back(Args&&... args)
1663
359k
    {
1664
359k
      using raw_elem_type = impl::remove_cvref<ElemType>;
1665
359k
      using elem_type   = std::conditional_t<std::is_void_v<raw_elem_type>, //
1666
359k
                           impl::emplaced_type_of<Args&&...>,
1667
359k
                           raw_elem_type>;
1668
1669
359k
      static constexpr auto moving_node_ptr = std::is_same_v<elem_type, impl::node_ptr> //
1670
0
                         && sizeof...(Args) == 1u            //
1671
0
                         && impl::first_is_same<impl::node_ptr&&, Args&&...>;
1672
1673
359k
      using unwrapped_type = impl::remove_cvref<impl::unwrap_node<elem_type>>;
1674
1675
359k
      static_assert(
1676
359k
        moving_node_ptr                     //
1677
359k
          || impl::is_native<unwrapped_type>          //
1678
359k
          || impl::is_one_of<unwrapped_type, table, array>, //
1679
359k
        "ElemType argument of array::emplace_back() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
1680
1681
      if constexpr (moving_node_ptr)
1682
325k
      {
1683
325k
        insert_at_back(static_cast<Args&&>(args)...);
1684
325k
        return *elems_.back();
1685
      }
1686
      else
1687
34.1k
      {
1688
34.1k
        auto ptr = new impl::wrap_node<unwrapped_type>{ static_cast<Args&&>(args)... };
1689
34.1k
        insert_at_back(impl::node_ptr{ ptr });
1690
34.1k
        return *ptr;
1691
34.1k
      }
1692
359k
    }
decltype(auto) toml::v3::array::emplace_back<toml::v3::table>()
Line
Count
Source
1663
34.1k
    {
1664
34.1k
      using raw_elem_type = impl::remove_cvref<ElemType>;
1665
34.1k
      using elem_type   = std::conditional_t<std::is_void_v<raw_elem_type>, //
1666
34.1k
                           impl::emplaced_type_of<Args&&...>,
1667
34.1k
                           raw_elem_type>;
1668
1669
34.1k
      static constexpr auto moving_node_ptr = std::is_same_v<elem_type, impl::node_ptr> //
1670
0
                         && sizeof...(Args) == 1u            //
1671
0
                         && impl::first_is_same<impl::node_ptr&&, Args&&...>;
1672
1673
34.1k
      using unwrapped_type = impl::remove_cvref<impl::unwrap_node<elem_type>>;
1674
1675
34.1k
      static_assert(
1676
34.1k
        moving_node_ptr                     //
1677
34.1k
          || impl::is_native<unwrapped_type>          //
1678
34.1k
          || impl::is_one_of<unwrapped_type, table, array>, //
1679
34.1k
        "ElemType argument of array::emplace_back() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
1680
1681
      if constexpr (moving_node_ptr)
1682
      {
1683
        insert_at_back(static_cast<Args&&>(args)...);
1684
        return *elems_.back();
1685
      }
1686
      else
1687
34.1k
      {
1688
34.1k
        auto ptr = new impl::wrap_node<unwrapped_type>{ static_cast<Args&&>(args)... };
1689
34.1k
        insert_at_back(impl::node_ptr{ ptr });
1690
34.1k
        return *ptr;
1691
34.1k
      }
1692
34.1k
    }
decltype(auto) toml::v3::array::emplace_back<std::__1::unique_ptr<toml::v3::node, std::__1::default_delete<toml::v3::node> >, std::__1::unique_ptr<toml::v3::node, std::__1::default_delete<toml::v3::node> > >(std::__1::unique_ptr<toml::v3::node, std::__1::default_delete<toml::v3::node> >&&)
Line
Count
Source
1663
325k
    {
1664
325k
      using raw_elem_type = impl::remove_cvref<ElemType>;
1665
325k
      using elem_type   = std::conditional_t<std::is_void_v<raw_elem_type>, //
1666
325k
                           impl::emplaced_type_of<Args&&...>,
1667
325k
                           raw_elem_type>;
1668
1669
325k
      static constexpr auto moving_node_ptr = std::is_same_v<elem_type, impl::node_ptr> //
1670
0
                         && sizeof...(Args) == 1u            //
1671
0
                         && impl::first_is_same<impl::node_ptr&&, Args&&...>;
1672
1673
325k
      using unwrapped_type = impl::remove_cvref<impl::unwrap_node<elem_type>>;
1674
1675
325k
      static_assert(
1676
325k
        moving_node_ptr                     //
1677
325k
          || impl::is_native<unwrapped_type>          //
1678
325k
          || impl::is_one_of<unwrapped_type, table, array>, //
1679
325k
        "ElemType argument of array::emplace_back() must be one of:" TOML_SA_UNWRAPPED_NODE_TYPE_LIST);
1680
1681
      if constexpr (moving_node_ptr)
1682
325k
      {
1683
325k
        insert_at_back(static_cast<Args&&>(args)...);
1684
325k
        return *elems_.back();
1685
      }
1686
      else
1687
      {
1688
        auto ptr = new impl::wrap_node<unwrapped_type>{ static_cast<Args&&>(args)... };
1689
        insert_at_back(impl::node_ptr{ ptr });
1690
        return *ptr;
1691
      }
1692
325k
    }
1693
1694
    /// @}
1695
1696
    private:
1697
    /// \cond
1698
1699
    TOML_NODISCARD
1700
    TOML_EXPORTED_STATIC_FUNCTION
1701
    static bool TOML_CALLCONV equal(const array&, const array&) noexcept;
1702
1703
    template <typename T>
1704
    TOML_NODISCARD
1705
    static bool equal_to_container(const array& lhs, const T& rhs) noexcept
1706
    {
1707
      using element_type = std::remove_const_t<typename T::value_type>;
1708
      static_assert(impl::is_losslessly_convertible_to_native<element_type>,
1709
              "Container element type must be losslessly convertible one of the native TOML value types");
1710
1711
      if (lhs.size() != rhs.size())
1712
        return false;
1713
      if (rhs.size() == 0u)
1714
        return true;
1715
1716
      size_t i{};
1717
      for (auto& list_elem : rhs)
1718
      {
1719
        const auto elem = lhs.get_as<impl::native_type_of<element_type>>(i++);
1720
        if (!elem || *elem != list_elem)
1721
          return false;
1722
      }
1723
1724
      return true;
1725
    }
1726
1727
    /// \endcond
1728
1729
    public:
1730
    /// \name Equality
1731
    /// @{
1732
1733
    /// \brief  Equality operator.
1734
    ///
1735
    /// \param  lhs The LHS array.
1736
    /// \param  rhs The RHS array.
1737
    ///
1738
    /// \returns  True if the arrays contained the same elements.
1739
    TOML_NODISCARD
1740
    friend bool operator==(const array& lhs, const array& rhs) noexcept
1741
0
    {
1742
0
      return equal(lhs, rhs);
1743
0
    }
1744
1745
    /// \brief  Inequality operator.
1746
    ///
1747
    /// \param  lhs The LHS array.
1748
    /// \param  rhs The RHS array.
1749
    ///
1750
    /// \returns  True if the arrays did not contain the same elements.
1751
    TOML_NODISCARD
1752
    friend bool operator!=(const array& lhs, const array& rhs) noexcept
1753
0
    {
1754
0
      return !equal(lhs, rhs);
1755
0
    }
1756
1757
    /// \brief  Initializer list equality operator.
1758
    template <typename T>
1759
    TOML_NODISCARD
1760
    friend bool operator==(const array& lhs, const std::initializer_list<T>& rhs) noexcept
1761
    {
1762
      return equal_to_container(lhs, rhs);
1763
    }
1764
    TOML_ASYMMETRICAL_EQUALITY_OPS(const array&, const std::initializer_list<T>&, template <typename T>);
1765
1766
    /// \brief  Vector equality operator.
1767
    template <typename T>
1768
    TOML_NODISCARD
1769
    friend bool operator==(const array& lhs, const std::vector<T>& rhs) noexcept
1770
    {
1771
      return equal_to_container(lhs, rhs);
1772
    }
1773
    TOML_ASYMMETRICAL_EQUALITY_OPS(const array&, const std::vector<T>&, template <typename T>);
1774
1775
    /// @}
1776
1777
#if TOML_ENABLE_FORMATTERS
1778
1779
    /// \brief  Prints the array out to a stream as formatted TOML.
1780
    ///
1781
    /// \availability This operator is only available when #TOML_ENABLE_FORMATTERS is enabled.
1782
    friend std::ostream& operator<<(std::ostream& lhs, const array& rhs)
1783
0
    {
1784
0
      impl::print_to_stream(lhs, rhs);
1785
0
      return lhs;
1786
0
    }
1787
1788
#endif
1789
  };
1790
}
1791
TOML_NAMESPACE_END;
1792
1793
#include "header_end.hpp"