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