tetl 0.1.0
Embedded Template Library
Loading...
Searching...
No Matches
static_vector.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: BSL-1.0
2// SPDX-FileCopyrightText: Copyright (C) 2020 Tobias Hienzsch
3
4#ifndef TETL_VECTOR_STATIC_VECTOR_HPP
5#define TETL_VECTOR_STATIC_VECTOR_HPP
6
7#include <etl/_algorithm/equal_range.hpp>
8#include <etl/_algorithm/find.hpp>
9#include <etl/_algorithm/generate_n.hpp>
10#include <etl/_algorithm/move.hpp>
11#include <etl/_algorithm/remove_if.hpp>
12#include <etl/_algorithm/rotate.hpp>
13#include <etl/_algorithm/transform.hpp>
14#include <etl/_array/array.hpp>
15#include <etl/_array/c_array.hpp>
16#include <etl/_concepts/same_as.hpp>
17#include <etl/_container/index.hpp>
18#include <etl/_contracts/check.hpp>
19#include <etl/_cstdint/uint_t.hpp>
20#include <etl/_functional/is_transparent.hpp>
21#include <etl/_iterator/begin.hpp>
22#include <etl/_iterator/data.hpp>
23#include <etl/_iterator/end.hpp>
24#include <etl/_iterator/rbegin.hpp>
25#include <etl/_iterator/rend.hpp>
26#include <etl/_iterator/size.hpp>
27#include <etl/_new/operator.hpp>
28#include <etl/_type_traits/aligned_storage.hpp>
29#include <etl/_type_traits/conditional.hpp>
30#include <etl/_type_traits/is_assignable.hpp>
31#include <etl/_type_traits/is_const.hpp>
32#include <etl/_type_traits/is_constructible.hpp>
33#include <etl/_type_traits/is_copy_constructible.hpp>
34#include <etl/_type_traits/is_move_constructible.hpp>
35#include <etl/_type_traits/is_nothrow_copy_constructible.hpp>
36#include <etl/_type_traits/is_nothrow_destructible.hpp>
37#include <etl/_type_traits/is_nothrow_move_constructible.hpp>
38#include <etl/_type_traits/is_pointer.hpp>
39#include <etl/_type_traits/is_trivial.hpp>
40#include <etl/_type_traits/smallest_size_t.hpp>
41
42namespace etl {
43namespace detail {
44/// \brief Storage for zero elements.
45template <typename T>
46struct static_vector_zero_storage {
47 using size_type = uint8_t;
48 using value_type = T;
49 using difference_type = ptrdiff_t;
50 using pointer = T*;
51 using const_pointer = T const*;
52
53 /// \brief Defaulted constructor.
54 constexpr static_vector_zero_storage() = default;
55
56 /// \brief Defaulted copy constructor.
57 constexpr static_vector_zero_storage(static_vector_zero_storage const&) = default;
58
59 /// \brief Defaulted copy assignment .
60 constexpr auto operator=(static_vector_zero_storage const&) noexcept -> static_vector_zero_storage& = default;
61
62 /// \brief Defaulted move constructor.
63 constexpr static_vector_zero_storage(static_vector_zero_storage&&) noexcept = default;
64
65 /// \brief Defaulted move assignment.
66 constexpr auto operator=(static_vector_zero_storage&&) noexcept -> static_vector_zero_storage& = default;
67
68 /// \brief Defaulted destructor.
69 ~static_vector_zero_storage() = default;
70
71 /// \brief Pointer to the data in the storage.
72 [[nodiscard]] static constexpr auto data() noexcept -> pointer
73 {
74 return nullptr;
75 }
76
77 /// \brief Number of elements currently stored.
78 [[nodiscard]] static constexpr auto size() noexcept -> size_type
79 {
80 return 0;
81 }
82
83 /// \brief Capacity of the storage.
84 [[nodiscard]] static constexpr auto capacity() noexcept -> size_type
85 {
86 return 0;
87 }
88
89 /// \brief Is the storage empty?
90 [[nodiscard]] static constexpr auto empty() noexcept -> bool
91 {
92 return true;
93 }
94
95 /// \brief Is the storage full?
96 [[nodiscard]] static constexpr auto full() noexcept -> bool
97 {
98 return true;
99 }
100
101 /// \brief Constructs a new element at the end of the storagein-place.
102 /// Increases size of the storage by one. Always fails for empty
103 /// storage.
104 template <typename... Args>
105 requires(is_constructible_v<T, Args...>)
106 static constexpr auto emplace_back(Args&&... /*unused*/) noexcept -> void
107 {
108 TETL_PRECONDITION(false);
109 }
110
111 /// \brief Removes the last element of the storage. Always fails for
112 /// empty storage.
113 static constexpr void pop_back() noexcept
114 {
115 TETL_PRECONDITION(false);
116 }
117
118protected:
119 /// \brief Changes the size of the storage without adding or removing
120 /// elements (unsafe). The size of an empty storage can only be changed
121 /// to 0.
122 static constexpr void unsafe_set_size([[maybe_unused]] size_t newSize) noexcept
123 {
124 TETL_PRECONDITION(newSize == 0);
125 }
126
127 /// \brief Destroys all elements of the storage in range [begin, end)
128 /// without changings its size (unsafe). Nothing to destroy since the
129 /// storage is empty.
130 template <typename InputIt>
131 static constexpr auto unsafe_destroy(InputIt /* begin */, InputIt /* end */) noexcept -> void
132 {
133 }
134
135 /// \brief Destroys all elements of the storage without changing its
136 /// size (unsafe). Nothing to destroy since the storage is empty.
137 static constexpr void unsafe_destroy_all() noexcept { }
138};
139
140/// \brief Storage for trivial types.
141template <typename T, size_t Capacity>
142struct static_vector_trivial_storage {
143 static_assert(etl::is_trivial_v<T>);
144 static_assert(Capacity != size_t{0});
145
146 using size_type = etl::smallest_size_t<Capacity>;
147 using value_type = T;
148 using difference_type = ptrdiff_t;
149 using pointer = T*;
150 using const_pointer = T const*;
151
152 constexpr static_vector_trivial_storage() noexcept = default;
153
154 constexpr static_vector_trivial_storage(static_vector_trivial_storage const&) noexcept = default;
155 constexpr auto operator=(static_vector_trivial_storage const&) noexcept -> static_vector_trivial_storage& = default;
156
157 constexpr static_vector_trivial_storage(static_vector_trivial_storage&&) noexcept = default;
158 constexpr auto operator=(static_vector_trivial_storage&&) noexcept -> static_vector_trivial_storage& = default;
159
160 ~static_vector_trivial_storage() = default;
161
162 /// \brief Direct access to the underlying storage.
163 [[nodiscard]] constexpr auto data() const noexcept -> const_pointer
164 {
165 return _data.data();
166 }
167
168 /// \brief Direct access to the underlying storage.
169 [[nodiscard]] constexpr auto data() noexcept -> pointer
170 {
171 return _data.data();
172 }
173
174 /// \brief Number of elements in the storage.
175 [[nodiscard]] constexpr auto size() const noexcept -> size_type
176 {
177 return _size;
178 }
179
180 /// \brief Maximum number of elements that can be allocated in the
181 /// storage.
182 [[nodiscard]] constexpr auto capacity() const noexcept -> size_type
183 {
184 return Capacity;
185 }
186
187 /// \brief Is the storage empty?
188 [[nodiscard]] constexpr auto empty() const noexcept -> bool
189 {
190 return size() == size_type{0};
191 }
192
193 /// \brief Is the storage full?
194 [[nodiscard]] constexpr auto full() const noexcept -> bool
195 {
196 return size() == Capacity;
197 }
198
199 /// \brief Constructs an element in-place at the end of the storage.
200 template <typename... Args>
201 requires(is_constructible_v<T, Args...> and is_assignable_v<value_type&, T>)
202 constexpr auto emplace_back(Args&&... args) noexcept -> void
203 {
204 TETL_PRECONDITION(!full());
205 index(_data, size()) = T(etl::forward<Args>(args)...);
206 unsafe_set_size(static_cast<size_type>(size()) + 1U);
207 }
208
209 /// \brief Remove the last element from the container.
210 constexpr auto pop_back() noexcept -> void
211 {
212 TETL_PRECONDITION(!empty());
213 unsafe_set_size(static_cast<size_type>(size() - 1));
214 }
215
216protected:
217 /// \brief (unsafe) Changes the container size to new_size.
218 ///
219 /// \warning No elements are constructed or destroyed.
220 constexpr auto unsafe_set_size(size_t newSize) noexcept -> void
221 {
222 TETL_PRECONDITION(newSize <= Capacity);
223 _size = size_type(newSize);
224 }
225
226 /// \brief (unsafe) Destroy elements in the range [begin, end).
227 ///
228 /// \warning The size of the storage is not changed.
229 template <typename InputIt>
230 constexpr auto unsafe_destroy(InputIt /*unused*/, InputIt /*unused*/) noexcept -> void
231 {
232 }
233
234 /// \brief (unsafe) Destroys all elements of the storage.
235 ///
236 /// \warning The size of the storage is not changed.
237 constexpr auto unsafe_destroy_all() noexcept -> void { }
238
239private:
240 // If the value_type is const, make a const array of
241 // non-const elements:
242 using data_t = conditional_t<!is_const_v<T>, array<T, Capacity>, array<remove_const_t<T>, Capacity> const>;
243 alignas(alignof(T)) data_t _data{};
244
245 size_type _size = 0;
246};
247
248/// \brief Storage for non-trivial elements.
249template <typename T, size_t Capacity>
250struct static_vector_non_trivial_storage {
251 static_assert(!is_trivial_v<T>);
252 static_assert(Capacity != size_t{0});
253
254 using size_type = etl::smallest_size_t<Capacity>;
255 using value_type = T;
256 using difference_type = ptrdiff_t;
257 using pointer = T*;
258 using const_pointer = T const*;
259
260 static_vector_non_trivial_storage() = default;
261
262 static_vector_non_trivial_storage(static_vector_non_trivial_storage const&) = default;
263 auto operator=(static_vector_non_trivial_storage const&) -> static_vector_non_trivial_storage& = default;
264
265 static_vector_non_trivial_storage(static_vector_non_trivial_storage&&) noexcept = default;
266 auto operator=(static_vector_non_trivial_storage&&) noexcept -> static_vector_non_trivial_storage& = default;
267
268 ~static_vector_non_trivial_storage() noexcept(is_nothrow_destructible_v<T>)
269 {
270 unsafe_destroy_all();
271 }
272
273 /// \brief Direct access to the underlying storage.
274 [[nodiscard]] auto data() const noexcept -> const_pointer
275 {
276 return reinterpret_cast<const_pointer>(_data);
277 }
278
279 /// \brief Direct access to the underlying storage.
280 [[nodiscard]] auto data() noexcept -> pointer
281 {
282 return reinterpret_cast<pointer>(_data);
283 }
284
285 /// \brief Pointer to one-past-the-end.
286 [[nodiscard]] auto end() const noexcept -> const_pointer
287 {
288 return data() + size();
289 }
290
291 /// \brief Pointer to one-past-the-end.
292 [[nodiscard]] auto end() noexcept -> pointer
293 {
294 return data() + size();
295 }
296
297 /// \brief Number of elements in the storage.
298 [[nodiscard]] auto size() const noexcept -> size_type
299 {
300 return _size;
301 }
302
303 /// \brief Maximum number of elements that can be allocated in the
304 /// storage.
305 [[nodiscard]] auto capacity() const noexcept -> size_type
306 {
307 return Capacity;
308 }
309
310 /// \brief Is the storage empty?
311 [[nodiscard]] auto empty() const noexcept -> bool
312 {
313 return size() == size_type{0};
314 }
315
316 /// \brief Is the storage full?
317 [[nodiscard]] auto full() const noexcept -> bool
318 {
319 return size() == Capacity;
320 }
321
322 /// \brief Constructs an element in-place at the end of the embedded
323 /// storage.
324 template <typename... Args>
325 auto emplace_back(Args&&... args) noexcept(noexcept(new (end()) T(etl::forward<Args>(args)...))) -> void
326 {
327 TETL_PRECONDITION(!full());
328 new (end()) T(etl::forward<Args>(args)...);
329 unsafe_set_size(static_cast<size_type>(size() + 1));
330 }
331
332 /// \brief Remove the last element from the container.
333 auto pop_back() noexcept(is_nothrow_destructible_v<T>) -> void
334 {
335 TETL_PRECONDITION(!empty());
336 auto* ptr = end() - 1;
337 ptr->~T();
338 unsafe_set_size(static_cast<size_type>(size() - 1));
339 }
340
341protected:
342 /// \brief (unsafe) Changes the container size to new_size.
343 ///
344 /// \warning No elements are constructed or destroyed.
345 auto unsafe_set_size(size_t newSize) noexcept -> void
346 {
347 TETL_PRECONDITION(newSize <= Capacity);
348 _size = size_type(newSize);
349 }
350
351 /// \brief (unsafe) Destroy elements in the range [begin, end).
352 ///
353 /// \warning The size of the storage is not changed.
354 template <typename InputIt>
355 auto unsafe_destroy(InputIt first, InputIt last) noexcept(is_nothrow_destructible_v<T>) -> void
356 {
357 TETL_PRECONDITION(first >= data() and first <= end());
358 TETL_PRECONDITION(last >= data() and last <= end());
359 for (; first != last; ++first) {
360 first->~T();
361 }
362 }
363
364 /// \brief (unsafe) Destroys all elements of the storage.
365 ///
366 /// \warning The size of the storage is not changed.
367 auto unsafe_destroy_all() noexcept(is_nothrow_destructible_v<T>) -> void
368 {
369 unsafe_destroy(data(), end());
370 }
371
372private:
373 using raw_type = remove_const_t<T>;
374 using aligned = aligned_storage_t<sizeof(raw_type), alignof(raw_type)>;
375 using storage_type = conditional_t<!is_const_v<T>, aligned, aligned const>;
376
377 alignas(alignof(T)) storage_type _data[Capacity];
378 size_type _size = 0;
379};
380
381/// \brief Selects the vector storage.
382template <typename T, size_t Capacity>
383using static_vector_storage_type = conditional_t<
384 Capacity == 0,
385 static_vector_zero_storage<T>,
386 conditional_t<
387 is_trivial_v<T>,
388 static_vector_trivial_storage<T, Capacity>,
389 static_vector_non_trivial_storage<T, Capacity>
390 >
391>;
392
393} // namespace detail
394
395/// Dynamically-resizable fixed-capacity vector.
396/// \headerfile etl/vector.hpp
397/// \ingroup vector
398///
399/// \include vector.cpp
400template <typename T, size_t Capacity>
401struct static_vector : detail::static_vector_storage_type<T, Capacity> {
402private:
403 static_assert(is_nothrow_destructible_v<T>);
404 using base_type = detail::static_vector_storage_type<T, Capacity>;
405 using self = static_vector<T, Capacity>;
406
407 using base_type::unsafe_destroy;
408 using base_type::unsafe_destroy_all;
409 using base_type::unsafe_set_size;
410
411public:
412 /// The type being used
413 using value_type = typename base_type::value_type;
414 /// The type being used
415 using difference_type = ptrdiff_t;
416 /// The type being used
417 using reference = value_type&;
418 /// The type being used
419 using const_reference = value_type const&;
420 /// The type being used
421 using pointer = typename base_type::pointer;
422 /// The type being used
423 using const_pointer = typename base_type::const_pointer;
424 /// The type being used
425 using iterator = typename base_type::pointer;
426 /// The type being used
427 using const_iterator = typename base_type::const_pointer;
428 /// The type being used
429 using size_type = size_t;
430 /// The type being used
431 using reverse_iterator = etl::reverse_iterator<iterator>;
432 /// The type being used
433 using const_reverse_iterator = etl::reverse_iterator<const_iterator>;
434
435private:
436 constexpr auto emplace_n(size_type n) noexcept(
437 (is_move_constructible_v<T> and is_nothrow_move_constructible_v<T>)
438 || (is_copy_constructible_v<T> and is_nothrow_copy_constructible_v<T>)
439 ) -> void
440 {
441 TETL_PRECONDITION(n <= capacity());
442 while (n != size()) {
443 emplace_back(T{});
444 }
445 }
446
447public:
448 [[nodiscard]] constexpr auto begin() noexcept -> iterator
449 {
450 return data();
451 }
452
453 [[nodiscard]] constexpr auto begin() const noexcept -> const_iterator
454 {
455 return data();
456 }
457
458 [[nodiscard]] constexpr auto end() noexcept -> iterator
459 {
460 return data() + size();
461 }
462
463 [[nodiscard]] constexpr auto end() const noexcept -> const_iterator
464 {
465 return data() + size();
466 }
467
468 [[nodiscard]] constexpr auto rbegin() noexcept -> reverse_iterator
469 {
470 return reverse_iterator(end());
471 }
472
473 [[nodiscard]] constexpr auto rbegin() const noexcept -> const_reverse_iterator
474 {
475 return const_reverse_iterator(end());
476 }
477
478 [[nodiscard]] constexpr auto rend() noexcept -> reverse_iterator
479 {
480 return reverse_iterator(begin());
481 }
482
483 [[nodiscard]] constexpr auto rend() const noexcept -> const_reverse_iterator
484 {
485 return const_reverse_iterator(begin());
486 }
487
488 [[nodiscard]] constexpr auto cbegin() noexcept -> const_iterator
489 {
490 return begin();
491 }
492
493 [[nodiscard]] constexpr auto cbegin() const noexcept -> const_iterator
494 {
495 return begin();
496 }
497
498 [[nodiscard]] constexpr auto cend() noexcept -> const_iterator
499 {
500 return end();
501 }
502
503 [[nodiscard]] constexpr auto cend() const noexcept -> const_iterator
504 {
505 return end();
506 }
507
508 [[nodiscard]] constexpr auto crbegin() const noexcept -> const_reverse_iterator
509 {
510 return const_reverse_iterator(end());
511 }
512
513 [[nodiscard]] constexpr auto crend() const noexcept -> const_reverse_iterator
514 {
515 return const_reverse_iterator(begin());
516 }
517
518 using base_type::emplace_back;
519
520 using base_type::pop_back;
521
522 /// \brief Appends value at the end of the vector.
523 template <typename U>
524 requires(is_constructible_v<T, U> and is_assignable_v<reference, U &&>)
525 constexpr auto push_back(U&& value) noexcept(noexcept(emplace_back(etl::forward<U>(value)))) -> void
526 {
527 TETL_PRECONDITION(!full());
528 emplace_back(etl::forward<U>(value));
529 }
530
531 template <typename InIt>
532 requires(detail::InputIterator<InIt>)
533 constexpr auto
534 move_insert(const_iterator position, InIt first, InIt last) noexcept(noexcept(emplace_back(etl::move(*first))))
535 -> iterator
536 {
537 assert_iterator_in_range(position);
538 assert_valid_iterator_pair(first, last);
539 if constexpr (detail::RandomAccessIterator<InIt>) {
540 TETL_PRECONDITION(size() + static_cast<size_type>(last - first) <= capacity());
541 }
542 iterator b = end();
543
544 // we insert at the end and then just rotate:
545 for (; first != last; ++first) {
546 emplace_back(etl::move(*first));
547 }
548 auto* writablePosition = begin() + (position - begin());
549 rotate<iterator>(writablePosition, b, end());
550 return writablePosition;
551 }
552
553 template <typename... Args>
554 requires(is_constructible_v<T, Args...>)
555 constexpr auto emplace(const_iterator position, Args&&... args) noexcept(
557 ) -> iterator
558 {
559 TETL_PRECONDITION(!full());
560 assert_iterator_in_range(position);
561 value_type a(etl::forward<Args>(args)...);
562 return move_insert(position, &a, &a + 1);
563 }
564
565 /// \brief Data access
566 using base_type::data;
567
568 constexpr auto insert(const_iterator position, value_type&& x) noexcept(noexcept(move_insert(position, &x, &x + 1)))
569 -> iterator
570 requires(is_move_constructible_v<T>)
571 {
572 TETL_PRECONDITION(!full());
573 assert_iterator_in_range(position);
574 return move_insert(position, &x, &x + 1);
575 }
576
577 constexpr auto insert(const_iterator position, size_type n, T const& x) noexcept(noexcept(push_back(x))) -> iterator
578 requires(is_copy_constructible_v<T>)
579 {
580 assert_iterator_in_range(position);
581 TETL_PRECONDITION(size() + n <= capacity());
582 auto* b = end();
583 while (n != 0) {
584 push_back(x);
585 --n;
586 }
587
588 auto* writablePosition = begin() + (position - begin());
589 rotate(writablePosition, b, end());
590 return writablePosition;
591 }
592
593 constexpr auto
594 insert(const_iterator position, const_reference x) noexcept(noexcept(insert(position, size_type(1), x))) -> iterator
595 requires(is_copy_constructible_v<T>)
596 {
597 TETL_PRECONDITION(!full());
598 assert_iterator_in_range(position);
599 return insert(position, size_type(1), x);
600 }
601
602 template <typename InputIt>
603 constexpr auto insert(const_iterator position, InputIt first, InputIt last) noexcept(noexcept(emplace_back(*first)))
604 -> iterator
605 requires(
606 detail::InputIterator<InputIt> && is_constructible_v<value_type, detail::iterator_reference_t<InputIt>>
607 )
608 {
609 assert_iterator_in_range(position);
610 assert_valid_iterator_pair(first, last);
611 if constexpr (detail::RandomAccessIterator<InputIt>) {
612 TETL_PRECONDITION(size() + static_cast<size_type>(last - first) <= capacity());
613 }
614 auto* b = end();
615
616 // insert at the end and then just rotate:
617 for (; first != last; ++first) {
618 emplace_back(*first);
619 }
620
621 auto* writablePosition = begin() + (position - begin());
622 rotate(writablePosition, b, end());
623 return writablePosition;
624 }
625
626 /// \brief Clears the vector.
627 constexpr void clear() noexcept
628 {
629 unsafe_destroy_all();
630 unsafe_set_size(0);
631 }
632
633 constexpr static_vector() = default;
634
635 template <etl::same_as<empty_c_array> Source = empty_c_array>
636 constexpr static_vector(Source /*unused*/) noexcept
637 {
638 }
639
640 template <etl::size_t Size>
641 requires(Size <= Capacity)
642 constexpr static_vector(c_array<T, Size>&& source)
643 {
644 move_insert(begin(), etl::begin(source), etl::end(source));
645 }
646
647 /// \brief Copy constructor.
648 constexpr static_vector(static_vector const& other) noexcept(noexcept(insert(begin(), other.begin(), other.end())))
649 {
650 // Nothing to assert: size of other cannot exceed capacity because both
651 // vectors have the same type
652 insert(begin(), other.begin(), other.end());
653 }
654
655 /// \brief Move constructor.
656 constexpr static_vector(static_vector&& other) noexcept(noexcept(move_insert(begin(), other.begin(), other.end())))
657 {
658 // Nothing to assert: size of other cannot exceed capacity because both
659 // vectors have the same type
660 move_insert(begin(), other.begin(), other.end());
661 }
662
663 /// \brief Copy assignment.
664 constexpr auto operator=(static_vector const& other) noexcept(
665 noexcept(clear()) && noexcept(insert(begin(), other.begin(), other.end()))
666 ) -> static_vector&
667 requires(is_assignable_v<reference, const_reference>)
668 {
669 // Nothing to assert: size of other cannot exceed capacity because both
670 // vectors have the same type
671 clear();
672 insert(begin(), other.begin(), other.end());
673 return *this;
674 }
675
676 /// \brief Move assignment.
677 constexpr auto operator=(static_vector&& other) noexcept(
678 noexcept(clear()) and noexcept(move_insert(begin(), other.begin(), other.end()))
679 ) -> static_vector&
680 requires(is_assignable_v<reference, reference>)
681 {
682 // Nothing to assert: size of other cannot exceed capacity because both
683 // vectors have the same type
684 clear();
685 move_insert(begin(), other.begin(), other.end());
686 return *this;
687 }
688
689 /// \brief Initializes vector with n default-constructed elements.
690 explicit constexpr static_vector(size_type n) noexcept(noexcept(emplace_n(n)))
691 requires(is_copy_constructible_v<T> || is_move_constructible_v<T>)
692 {
693 TETL_PRECONDITION(n <= capacity());
694 emplace_n(n);
695 }
696
697 /// \brief Initializes vector with n with value.
698 constexpr static_vector(size_type n, T const& value) noexcept(noexcept(insert(begin(), n, value)))
699 requires(is_copy_constructible_v<T>)
700 {
701 TETL_PRECONDITION(n <= capacity());
702 insert(begin(), n, value);
703 }
704
705 /// \brief Initialize vector from range [first, last).
706 template <typename InputIter>
707 requires(detail::InputIterator<InputIter>)
708 constexpr static_vector(InputIter first, InputIter last)
709 {
710 if constexpr (detail::RandomAccessIterator<InputIter>) {
711 TETL_PRECONDITION(last - first >= 0);
712 TETL_PRECONDITION(static_cast<size_type>(last - first) <= capacity());
713 }
714 insert(begin(), first, last);
715 }
716
717 /// \brief Is the storage empty/full?
718 using base_type::empty;
719
720 using base_type::full;
721
722 /// \brief Number of elements in the vector
723 [[nodiscard]] constexpr auto size() const noexcept -> size_type
724 {
725 return base_type::size();
726 }
727
728 /// \brief Maximum number of elements that can be allocated in the vector
729 [[nodiscard]] constexpr auto capacity() const noexcept -> size_type
730 {
731 return base_type::capacity();
732 }
733
734 [[nodiscard]] constexpr auto max_size() const noexcept -> size_type
735 {
736 return capacity();
737 }
738
739 /// \brief assign
740 template <typename InputIter>
741 requires(detail::InputIterator<InputIter>)
742 constexpr auto
743 assign(InputIter first, InputIter last) noexcept(noexcept(clear()) and noexcept(insert(begin(), first, last)))
744 -> void
745 {
746 if constexpr (detail::RandomAccessIterator<InputIter>) {
747 TETL_PRECONDITION(last - first >= 0);
748 TETL_PRECONDITION(static_cast<size_type>(last - first) <= capacity());
749 }
750 clear();
751 insert(begin(), first, last);
752 }
753
754 constexpr auto assign(size_type n, T const& u) -> void
755 requires(is_copy_constructible_v<T>)
756 {
757 TETL_PRECONDITION(n <= capacity());
758 clear();
759 insert(begin(), n, u);
760 }
761
762 /// \brief Unchecked access to element at index pos (UB if index not in
763 [[nodiscard]] constexpr auto operator[](size_type pos) noexcept -> reference
764 {
765 return detail::index(*this, pos);
766 }
767
768 /// \brief Unchecked access to element at index pos (UB if index not in
769 [[nodiscard]] constexpr auto operator[](size_type pos) const noexcept -> const_reference
770 {
771 return detail::index(*this, pos);
772 }
773
774 /// \brief front
775 [[nodiscard]] constexpr auto front() noexcept -> reference
776 {
777 return detail::index(*this, 0);
778 }
779
780 [[nodiscard]] constexpr auto front() const noexcept -> const_reference
781 {
782 return detail::index(*this, 0);
783 }
784
785 /// \brief back
786 [[nodiscard]] constexpr auto back() noexcept -> reference
787 {
788 TETL_PRECONDITION(!empty());
789 return detail::index(*this, static_cast<size_type>(size() - 1));
790 }
791
792 [[nodiscard]] constexpr auto back() const noexcept -> const_reference
793 {
794 TETL_PRECONDITION(!empty());
795 return detail::index(*this, static_cast<size_type>(size() - 1));
796 }
797
798 /// \brief erase
799 constexpr auto erase(const_iterator position) noexcept -> iterator
800 requires(detail::is_movable_v<value_type>)
801 {
802 assert_iterator_in_range(position);
803 return erase(position, position + 1);
804 }
805
806 constexpr auto erase(const_iterator first, const_iterator last) noexcept -> iterator
807 requires(detail::is_movable_v<value_type>)
808 {
809 assert_iterator_pair_in_range(first, last);
810 iterator p = begin() + (first - begin());
811 if (first != last) {
812 unsafe_destroy(etl::move(p + (last - first), end(), p), end());
813 unsafe_set_size(size() - static_cast<size_type>(last - first));
814 }
815
816 return p;
817 }
818
819 /// \brief Exchanges the contents of the container with those of other.
820 constexpr auto swap(static_vector& other) noexcept(is_nothrow_swappable_v<T>) -> void
821 requires(is_assignable_v<T&, T &&>)
822 {
823 static_vector tmp = etl::move(other);
824 other = etl::move(*this);
825 (*this) = etl::move(tmp);
826 }
827
828 /// \brief Resizes the container to contain sz elements. If elements need to
829 /// be appended, these are move-constructed from `T{}` (or copy-constructed
830 constexpr auto resize(size_type sz) noexcept(
831 (is_move_constructible_v<T> && is_nothrow_move_constructible_v<T>)
832 || (is_copy_constructible_v<T> && is_nothrow_copy_constructible_v<T>)
833 ) -> void
834 requires(detail::is_movable_v<value_type>)
835 {
836 if (sz == size()) {
837 return;
838 }
839
840 if (sz > size()) {
841 emplace_n(sz);
842 return;
843 }
844
845 erase(end() - (size() - sz), end());
846 }
847
848 constexpr auto resize(size_type sz, T const& value) noexcept(is_nothrow_copy_constructible_v<T>) -> void
849 requires(is_copy_constructible_v<T>)
850 {
851 if (sz == size()) {
852 return;
853 }
854 if (sz > size()) {
855 TETL_PRECONDITION(sz <= capacity());
856 insert(end(), sz - size(), value);
857 } else {
858 erase(end() - (size() - sz), end());
859 }
860 }
861
862private:
863 template <typename It>
864 constexpr void assert_iterator_in_range([[maybe_unused]] It it) noexcept
865 {
866 static_assert(is_pointer_v<It>);
867 TETL_PRECONDITION(begin() <= it);
868 TETL_PRECONDITION(it <= end());
869 }
870
871 template <typename It0, typename It1>
872 constexpr void assert_valid_iterator_pair([[maybe_unused]] It0 first, [[maybe_unused]] It1 last) noexcept
873 {
874 static_assert(is_pointer_v<It0>);
875 static_assert(is_pointer_v<It1>);
876 TETL_PRECONDITION(first <= last);
877 }
878
879 template <typename It0, typename It1>
880 constexpr void assert_iterator_pair_in_range([[maybe_unused]] It0 first, [[maybe_unused]] It1 last) noexcept
881 {
882 assert_iterator_in_range(first);
883 assert_iterator_in_range(last);
884 assert_valid_iterator_pair(first, last);
885 }
886};
887
888/// \brief Specializes the swap algorithm for static_vector. Swaps the
889/// contents of lhs and rhs.
890template <typename T, size_t Capacity>
891constexpr auto swap(static_vector<T, Capacity>& lhs, static_vector<T, Capacity>& rhs) noexcept -> void
892{
893 lhs.swap(rhs);
894}
895
896/// \brief Compares the contents of two vectors.
897///
898/// \details Checks if the contents of lhs and rhs are equal, that is, they have
899/// the same number of elements and each element in lhs compares equal with the
900/// element in rhs at the same position.
901template <typename T, size_t Capacity>
902constexpr auto operator==(static_vector<T, Capacity> const& lhs, static_vector<T, Capacity> const& rhs) noexcept -> bool
903{
904 if (size(lhs) == size(rhs)) {
905 return equal(begin(lhs), end(lhs), begin(rhs), end(rhs), equal_to{});
906 }
907
908 return false;
909}
910
911template <typename T, size_t Capacity>
912constexpr auto operator!=(static_vector<T, Capacity> const& lhs, static_vector<T, Capacity> const& rhs) noexcept -> bool
913{
914 return !(lhs == rhs);
915}
916
917/// \brief Compares the contents of two vectors.
918///
919/// \details Compares the contents of lhs and rhs lexicographically. The
920/// comparison is performed by a function equivalent to
921/// lexicographical_compare.
922template <typename T, size_t Capacity>
923constexpr auto operator<(static_vector<T, Capacity> const& lhs, static_vector<T, Capacity> const& rhs) noexcept -> bool
924{
925 return lexicographical_compare(begin(lhs), end(lhs), begin(rhs), end(rhs));
926}
927
928template <typename T, size_t Capacity>
929constexpr auto operator<=(static_vector<T, Capacity> const& lhs, static_vector<T, Capacity> const& rhs) noexcept -> bool
930{
931 return !(rhs < lhs);
932}
933
934template <typename T, size_t Capacity>
935constexpr auto operator>(static_vector<T, Capacity> const& lhs, static_vector<T, Capacity> const& rhs) noexcept -> bool
936{
937 return rhs < lhs;
938}
939
940template <typename T, size_t Capacity>
941constexpr auto operator>=(static_vector<T, Capacity> const& lhs, static_vector<T, Capacity> const& rhs) noexcept -> bool
942{
943 return !(lhs < rhs);
944}
945
946/// \brief Erases all elements that satisfy the predicate pred from the
947/// container.
948/// \returns The number of erased elements.
949///
950/// https://en.cppreference.com/w/cpp/container/vector/erase2
951template <typename T, size_t Capacity, typename Predicate>
952constexpr auto erase_if(static_vector<T, Capacity>& c, Predicate pred) -> typename static_vector<T, Capacity>::size_type
953{
954 auto* it = remove_if(c.begin(), c.end(), pred);
955 auto r = distance(it, c.end());
956 c.erase(it, c.end());
957 return static_cast<typename static_vector<T, Capacity>::size_type>(r);
958}
959
960template <typename T, size_t Capacity, typename U>
961constexpr auto erase(static_vector<T, Capacity>& c, U const& value) -> typename static_vector<T, Capacity>::size_type
962{
963 return erase_if(c, [&value](auto const& item) { return item == value; });
964}
965
966} // namespace etl
967
968#endif // TETL_VECTOR_STATIC_VECTOR_HPP
Definition adjacent_find.hpp:9
constexpr auto swap(static_vector< T, Capacity > &lhs, static_vector< T, Capacity > &rhs) noexcept -> void
Specializes the swap algorithm for static_vector. Swaps the contents of lhs and rhs.
Definition static_vector.hpp:891
constexpr auto operator==(static_vector< T, Capacity > const &lhs, static_vector< T, Capacity > const &rhs) noexcept -> bool
Compares the contents of two vectors.
Definition static_vector.hpp:902
constexpr auto operator!=(static_vector< T, Capacity > const &lhs, static_vector< T, Capacity > const &rhs) noexcept -> bool
Definition static_vector.hpp:912
constexpr auto operator>=(static_vector< T, Capacity > const &lhs, static_vector< T, Capacity > const &rhs) noexcept -> bool
Definition static_vector.hpp:941
constexpr auto operator<=(static_vector< T, Capacity > const &lhs, static_vector< T, Capacity > const &rhs) noexcept -> bool
Definition static_vector.hpp:929
constexpr auto erase_if(static_vector< T, Capacity > &c, Predicate pred) -> typename static_vector< T, Capacity >::size_type
Erases all elements that satisfy the predicate pred from the container.
Definition static_vector.hpp:952
constexpr auto erase(static_vector< T, Capacity > &c, U const &value) -> typename static_vector< T, Capacity >::size_type
Definition static_vector.hpp:961
constexpr auto operator<(static_vector< T, Capacity > const &lhs, static_vector< T, Capacity > const &rhs) noexcept -> bool
Compares the contents of two vectors.
Definition static_vector.hpp:923
constexpr auto operator>(static_vector< T, Capacity > const &lhs, static_vector< T, Capacity > const &rhs) noexcept -> bool
Definition static_vector.hpp:935
A container that encapsulates fixed size arrays.
Definition array.hpp:49
Definition c_array.hpp:16
Function object for performing comparisons. Unless specialised, invokes operator== on type T....
Definition equal_to.hpp:15
Dynamically-resizable fixed-capacity vector.
Definition static_vector.hpp:401
constexpr auto assign(InputIter first, InputIter last) noexcept(noexcept(clear()) and noexcept(insert(begin(), first, last))) -> void
assign
Definition static_vector.hpp:743
constexpr auto insert(const_iterator position, const_reference x) noexcept(noexcept(insert(position, size_type(1), x))) -> iterator requires(is_copy_constructible_v< T >)
Definition static_vector.hpp:594
constexpr auto operator[](size_type pos) const noexcept -> const_reference
Unchecked access to element at index pos (UB if index not in.
Definition static_vector.hpp:769
constexpr static_vector(InputIter first, InputIter last)
Initialize vector from range [first, last).
Definition static_vector.hpp:708
constexpr auto emplace(const_iterator position, Args &&... args) noexcept(noexcept(move_insert(position, declval< value_type * >(), declval< value_type * >()))) -> iterator
Definition static_vector.hpp:555
constexpr auto front() const noexcept -> const_reference
Definition static_vector.hpp:780
constexpr auto operator=(static_vector const &other) noexcept(noexcept(clear()) &&noexcept(insert(begin(), other.begin(), other.end()))) -> static_vector &requires(is_assignable_v< reference, const_reference >)
Copy assignment.
Definition static_vector.hpp:664
constexpr static_vector()=default
constexpr auto operator=(static_vector &&other) noexcept(noexcept(clear()) and noexcept(move_insert(begin(), other.begin(), other.end()))) -> static_vector &requires(is_assignable_v< reference, reference >)
Move assignment.
Definition static_vector.hpp:677
constexpr static_vector(static_vector &&other) noexcept(noexcept(move_insert(begin(), other.begin(), other.end())))
Move constructor.
Definition static_vector.hpp:656
constexpr auto crbegin() const noexcept -> const_reverse_iterator
Definition static_vector.hpp:508
constexpr auto move_insert(const_iterator position, InIt first, InIt last) noexcept(noexcept(emplace_back(etl::move(*first)))) -> iterator
Definition static_vector.hpp:534
constexpr auto insert(const_iterator position, size_type n, T const &x) noexcept(noexcept(push_back(x))) -> iterator requires(is_copy_constructible_v< T >)
Definition static_vector.hpp:577
constexpr auto rbegin() const noexcept -> const_reverse_iterator
Definition static_vector.hpp:473
constexpr auto swap(static_vector &other) noexcept(is_nothrow_swappable_v< T >) -> void requires(is_assignable_v< T &, T && >)
Exchanges the contents of the container with those of other.
Definition static_vector.hpp:820
constexpr auto cend() noexcept -> const_iterator
Definition static_vector.hpp:498
constexpr auto back() noexcept -> reference
back
Definition static_vector.hpp:786
constexpr auto insert(const_iterator position, InputIt first, InputIt last) noexcept(noexcept(emplace_back(*first))) -> iterator requires(detail::InputIterator< InputIt > &&is_constructible_v< value_type, detail::iterator_reference_t< InputIt > >)
Definition static_vector.hpp:603
constexpr auto push_back(U &&value) noexcept(noexcept(emplace_back(etl::forward< U >(value)))) -> void
Appends value at the end of the vector.
Definition static_vector.hpp:525
constexpr auto rend() noexcept -> reverse_iterator
Definition static_vector.hpp:478
constexpr auto begin() noexcept -> iterator
Definition static_vector.hpp:448
constexpr static_vector(Source) noexcept
Definition static_vector.hpp:636
constexpr auto end() noexcept -> iterator
Definition static_vector.hpp:458
constexpr auto begin() const noexcept -> const_iterator
Definition static_vector.hpp:453
constexpr auto cbegin() const noexcept -> const_iterator
Definition static_vector.hpp:493
constexpr auto resize(size_type sz, T const &value) noexcept(is_nothrow_copy_constructible_v< T >) -> void requires(is_copy_constructible_v< T >)
Definition static_vector.hpp:848
constexpr auto assign(size_type n, T const &u) -> void requires(is_copy_constructible_v< T >)
Definition static_vector.hpp:754
constexpr auto erase(const_iterator first, const_iterator last) noexcept -> iterator requires(detail::is_movable_v< value_type >)
Definition static_vector.hpp:806
constexpr auto operator[](size_type pos) noexcept -> reference
Unchecked access to element at index pos (UB if index not in.
Definition static_vector.hpp:763
constexpr void clear() noexcept
Clears the vector.
Definition static_vector.hpp:627
constexpr auto back() const noexcept -> const_reference
Definition static_vector.hpp:792
constexpr auto front() noexcept -> reference
front
Definition static_vector.hpp:775
constexpr auto erase(const_iterator position) noexcept -> iterator requires(detail::is_movable_v< value_type >)
erase
Definition static_vector.hpp:799
constexpr auto max_size() const noexcept -> size_type
Definition static_vector.hpp:734
constexpr static_vector(size_type n, T const &value) noexcept(noexcept(insert(begin(), n, value)))
Initializes vector with n with value.
Definition static_vector.hpp:698
constexpr auto resize(size_type sz) noexcept((is_move_constructible_v< T > &&is_nothrow_move_constructible_v< T >)||(is_copy_constructible_v< T > &&is_nothrow_copy_constructible_v< T >)) -> void requires(detail::is_movable_v< value_type >)
Resizes the container to contain sz elements. If elements need to be appended, these are move-constru...
Definition static_vector.hpp:830
constexpr auto end() const noexcept -> const_iterator
Definition static_vector.hpp:463
constexpr auto crend() const noexcept -> const_reverse_iterator
Definition static_vector.hpp:513
constexpr auto insert(const_iterator position, value_type &&x) noexcept(noexcept(move_insert(position, &x, &x+1))) -> iterator requires(is_move_constructible_v< T >)
Definition static_vector.hpp:568
constexpr static_vector(c_array< T, Size > &&source)
Definition static_vector.hpp:642
constexpr static_vector(static_vector const &other) noexcept(noexcept(insert(begin(), other.begin(), other.end())))
Copy constructor.
Definition static_vector.hpp:648
constexpr auto rend() const noexcept -> const_reverse_iterator
Definition static_vector.hpp:483
constexpr auto size() const noexcept -> size_type
Number of elements in the vector.
Definition static_vector.hpp:723
constexpr auto cend() const noexcept -> const_iterator
Definition static_vector.hpp:503
constexpr auto capacity() const noexcept -> size_type
Maximum number of elements that can be allocated in the vector.
Definition static_vector.hpp:729
constexpr static_vector(size_type n) noexcept(noexcept(emplace_n(n)))
Initializes vector with n default-constructed elements.
Definition static_vector.hpp:690
constexpr auto rbegin() noexcept -> reverse_iterator
Definition static_vector.hpp:468
constexpr auto cbegin() noexcept -> const_iterator
Definition static_vector.hpp:488