Coverage Report

Created: 2025-10-10 06:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tomlplusplus/include/toml++/impl/array.inl
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
//# {{
8
#include "preprocessor.hpp"
9
#if !TOML_IMPLEMENTATION
10
#error This is an implementation-only header.
11
#endif
12
//# }}
13
14
#include "array.hpp"
15
#include "header_start.hpp"
16
17
TOML_NAMESPACE_START
18
{
19
  TOML_EXTERNAL_LINKAGE
20
  array::array() noexcept
21
86.1k
  {
22
#if TOML_LIFETIME_HOOKS
23
    TOML_ARRAY_CREATED;
24
#endif
25
86.1k
  }
26
27
  TOML_EXTERNAL_LINKAGE
28
  array::~array() noexcept
29
86.1k
  {
30
#if TOML_LIFETIME_HOOKS
31
    TOML_ARRAY_DESTROYED;
32
#endif
33
86.1k
  }
34
35
  TOML_EXTERNAL_LINKAGE
36
  array::array(const impl::array_init_elem* b, const impl::array_init_elem* e)
37
  {
38
#if TOML_LIFETIME_HOOKS
39
    TOML_ARRAY_CREATED;
40
#endif
41
42
    TOML_ASSERT_ASSUME(b);
43
    TOML_ASSERT_ASSUME(e);
44
    TOML_ASSERT_ASSUME(b <= e);
45
46
    if TOML_UNLIKELY(b == e)
47
      return;
48
49
    size_t cap{};
50
    for (auto it = b; it != e; it++)
51
    {
52
      if (it->value)
53
        cap++;
54
    }
55
    if TOML_UNLIKELY(!cap)
56
      return;
57
58
    elems_.reserve(cap);
59
    for (; b != e; b++)
60
    {
61
      if (b->value)
62
        elems_.push_back(std::move(b->value));
63
    }
64
  }
65
66
  TOML_EXTERNAL_LINKAGE
67
  array::array(const array& other) //
68
    : node(other)
69
  {
70
    elems_.reserve(other.elems_.size());
71
    for (const auto& elem : other)
72
      elems_.emplace_back(impl::make_node(elem));
73
74
#if TOML_LIFETIME_HOOKS
75
    TOML_ARRAY_CREATED;
76
#endif
77
  }
78
79
  TOML_EXTERNAL_LINKAGE
80
  array::array(array && other) noexcept //
81
    : node(std::move(other)),
82
      elems_(std::move(other.elems_))
83
  {
84
#if TOML_LIFETIME_HOOKS
85
    TOML_ARRAY_CREATED;
86
#endif
87
  }
88
89
  TOML_EXTERNAL_LINKAGE
90
  array& array::operator=(const array& rhs)
91
0
  {
92
0
    if (&rhs != this)
93
0
    {
94
0
      node::operator=(rhs);
95
0
      elems_.clear();
96
0
      elems_.reserve(rhs.elems_.size());
97
0
      for (const auto& elem : rhs)
98
0
        elems_.emplace_back(impl::make_node(elem));
99
0
    }
100
0
    return *this;
101
0
  }
102
103
  TOML_EXTERNAL_LINKAGE
104
  array& array::operator=(array&& rhs) noexcept
105
0
  {
106
0
    if (&rhs != this)
107
0
    {
108
0
      node::operator=(std::move(rhs));
109
0
      elems_ = std::move(rhs.elems_);
110
0
    }
111
0
    return *this;
112
0
  }
113
114
  TOML_EXTERNAL_LINKAGE
115
  void array::preinsertion_resize(size_t idx, size_t count)
116
0
  {
117
0
    TOML_ASSERT(idx <= elems_.size());
118
0
    TOML_ASSERT_ASSUME(count >= 1u);
119
0
    const auto old_size     = elems_.size();
120
0
    const auto new_size     = old_size + count;
121
0
    const auto inserting_at_end = idx == old_size;
122
0
    elems_.resize(new_size);
123
0
    if (!inserting_at_end)
124
0
    {
125
0
      for (size_t left = old_size, right = new_size - 1u; left-- > idx; right--)
126
0
        elems_[right] = std::move(elems_[left]);
127
0
    }
128
0
  }
129
130
  TOML_EXTERNAL_LINKAGE
131
  void array::insert_at_back(impl::node_ptr && elem)
132
773k
  {
133
773k
    TOML_ASSERT(elem);
134
773k
    elems_.push_back(std::move(elem));
135
773k
  }
136
137
  TOML_EXTERNAL_LINKAGE
138
  array::vector_iterator array::insert_at(const_vector_iterator pos, impl::node_ptr && elem)
139
0
  {
140
0
    return elems_.insert(pos, std::move(elem));
141
0
  }
142
143
  TOML_PURE_GETTER
144
  TOML_EXTERNAL_LINKAGE
145
  bool array::is_homogeneous(node_type ntype) const noexcept
146
356
  {
147
356
    if (elems_.empty())
148
1
      return false;
149
150
355
    if (ntype == node_type::none)
151
0
      ntype = elems_[0]->type();
152
153
355
    for (const auto& val : elems_)
154
552
      if (val->type() != ntype)
155
4
        return false;
156
157
351
    return true;
158
355
  }
159
160
  TOML_NODISCARD
161
  TOML_EXTERNAL_LINKAGE
162
  bool array::is_homogeneous(node_type ntype, node * &first_nonmatch) noexcept
163
0
  {
164
0
    if (elems_.empty())
165
0
    {
166
0
      first_nonmatch = {};
167
0
      return false;
168
0
    }
169
0
    if (ntype == node_type::none)
170
0
      ntype = elems_[0]->type();
171
0
    for (const auto& val : elems_)
172
0
    {
173
0
      if (val->type() != ntype)
174
0
      {
175
0
        first_nonmatch = val.get();
176
0
        return false;
177
0
      }
178
0
    }
179
0
    return true;
180
0
  }
181
182
  TOML_NODISCARD
183
  TOML_EXTERNAL_LINKAGE
184
  bool array::is_homogeneous(node_type ntype, const node*& first_nonmatch) const noexcept
185
0
  {
186
0
    node* fnm     = nullptr;
187
0
    const auto result = const_cast<array&>(*this).is_homogeneous(ntype, fnm);
188
0
    first_nonmatch    = fnm;
189
0
    return result;
190
0
  }
191
192
  TOML_EXTERNAL_LINKAGE
193
  node& array::at(size_t index)
194
0
  {
195
0
#if TOML_COMPILER_HAS_EXCEPTIONS
196
0
197
0
    return *elems_.at(index);
198
0
199
0
#else
200
0
201
0
    auto n = get(index);
202
0
    TOML_ASSERT_ASSUME(n && "element index not found in array!");
203
0
    return *n;
204
0
205
0
#endif
206
0
  }
207
208
  TOML_EXTERNAL_LINKAGE
209
  void array::reserve(size_t new_capacity)
210
2.35k
  {
211
2.35k
    elems_.reserve(new_capacity);
212
2.35k
  }
213
214
  TOML_EXTERNAL_LINKAGE
215
  void array::shrink_to_fit()
216
0
  {
217
0
    elems_.shrink_to_fit();
218
0
  }
219
220
  TOML_EXTERNAL_LINKAGE
221
  void array::truncate(size_t new_size)
222
0
  {
223
0
    if (new_size < elems_.size())
224
0
      elems_.resize(new_size);
225
0
  }
226
227
  TOML_EXTERNAL_LINKAGE
228
  array::iterator array::erase(const_iterator pos) noexcept
229
0
  {
230
0
    return iterator{ elems_.erase(const_vector_iterator{ pos }) };
231
0
  }
232
233
  TOML_EXTERNAL_LINKAGE
234
  array::iterator array::erase(const_iterator first, const_iterator last) noexcept
235
0
  {
236
0
    return iterator{ elems_.erase(const_vector_iterator{ first }, const_vector_iterator{ last }) };
237
0
  }
238
239
  TOML_EXTERNAL_LINKAGE
240
  size_t array::total_leaf_count() const noexcept
241
0
  {
242
0
    size_t leaves{};
243
0
    for (size_t i = 0, e = elems_.size(); i < e; i++)
244
0
    {
245
0
      auto arr = elems_[i]->as_array();
246
0
      leaves += arr ? arr->total_leaf_count() : size_t{ 1 };
247
0
    }
248
0
    return leaves;
249
0
  }
250
251
  TOML_EXTERNAL_LINKAGE
252
  void array::flatten_child(array && child, size_t & dest_index) noexcept
253
0
  {
254
0
    for (size_t i = 0, e = child.size(); i < e; i++)
255
0
    {
256
0
      auto type = child.elems_[i]->type();
257
0
      if (type == node_type::array)
258
0
      {
259
0
        array& arr = *reinterpret_cast<array*>(child.elems_[i].get());
260
0
        if (!arr.empty())
261
0
          flatten_child(std::move(arr), dest_index);
262
0
      }
263
0
      else
264
0
        elems_[dest_index++] = std::move(child.elems_[i]);
265
0
    }
266
0
  }
267
268
  TOML_EXTERNAL_LINKAGE
269
  array& array::flatten()&
270
0
  {
271
0
    if (elems_.empty())
272
0
      return *this;
273
0
274
0
    bool requires_flattening   = false;
275
0
    size_t size_after_flattening = elems_.size();
276
0
    for (size_t i = elems_.size(); i-- > 0u;)
277
0
    {
278
0
      auto arr = elems_[i]->as_array();
279
0
      if (!arr)
280
0
        continue;
281
0
      size_after_flattening--; // discount the array itself
282
0
      const auto leaf_count = arr->total_leaf_count();
283
0
      if (leaf_count > 0u)
284
0
      {
285
0
        requires_flattening = true;
286
0
        size_after_flattening += leaf_count;
287
0
      }
288
0
      else
289
0
        elems_.erase(elems_.cbegin() + static_cast<ptrdiff_t>(i));
290
0
    }
291
0
292
0
    if (!requires_flattening)
293
0
      return *this;
294
0
295
0
    elems_.reserve(size_after_flattening);
296
0
297
0
    size_t i = 0;
298
0
    while (i < elems_.size())
299
0
    {
300
0
      auto arr = elems_[i]->as_array();
301
0
      if (!arr)
302
0
      {
303
0
        i++;
304
0
        continue;
305
0
      }
306
0
307
0
      impl::node_ptr arr_storage = std::move(elems_[i]);
308
0
      const auto leaf_count    = arr->total_leaf_count();
309
0
      if (leaf_count > 1u)
310
0
        preinsertion_resize(i + 1u, leaf_count - 1u);
311
0
      flatten_child(std::move(*arr), i); // increments i
312
0
    }
313
0
314
0
    return *this;
315
0
  }
316
317
  TOML_EXTERNAL_LINKAGE
318
  array& array::prune(bool recursive)& noexcept
319
0
  {
320
0
    if (elems_.empty())
321
0
      return *this;
322
0
323
0
    for (size_t i = elems_.size(); i-- > 0u;)
324
0
    {
325
0
      if (auto arr = elems_[i]->as_array())
326
0
      {
327
0
        if (recursive)
328
0
          arr->prune(true);
329
0
        if (arr->empty())
330
0
          elems_.erase(elems_.cbegin() + static_cast<ptrdiff_t>(i));
331
0
      }
332
0
      else if (auto tbl = elems_[i]->as_table())
333
0
      {
334
0
        if (recursive)
335
0
          tbl->prune(true);
336
0
        if (tbl->empty())
337
0
          elems_.erase(elems_.cbegin() + static_cast<ptrdiff_t>(i));
338
0
      }
339
0
    }
340
0
341
0
    return *this;
342
0
  }
343
344
  TOML_EXTERNAL_LINKAGE
345
  void array::pop_back() noexcept
346
0
  {
347
0
    elems_.pop_back();
348
0
  }
349
350
  TOML_EXTERNAL_LINKAGE
351
  void array::clear() noexcept
352
0
  {
353
0
    elems_.clear();
354
0
  }
355
356
  TOML_EXTERNAL_LINKAGE
357
  bool TOML_CALLCONV array::equal(const array& lhs, const array& rhs) noexcept
358
0
  {
359
0
    if (&lhs == &rhs)
360
0
      return true;
361
0
    if (lhs.elems_.size() != rhs.elems_.size())
362
0
      return false;
363
0
    for (size_t i = 0, e = lhs.elems_.size(); i < e; i++)
364
0
    {
365
0
      const auto lhs_type = lhs.elems_[i]->type();
366
0
      const node& rhs_  = *rhs.elems_[i];
367
0
      const auto rhs_type = rhs_.type();
368
0
      if (lhs_type != rhs_type)
369
0
        return false;
370
0
371
0
      const bool equal = lhs.elems_[i]->visit(
372
0
        [&](const auto& lhs_) noexcept
373
0
        { return lhs_ == *reinterpret_cast<std::remove_reference_t<decltype(lhs_)>*>(&rhs_); });
374
0
      if (!equal)
375
0
        return false;
376
0
    }
377
0
    return true;
378
0
  }
379
}
380
TOML_NAMESPACE_END;
381
382
#include "header_end.hpp"