Sen API
Sen Libraries
Loading...
Searching...
No Matches
static_vector.h
Go to the documentation of this file.
1// === static_vector.h =================================================================================================
2// Sen Infrastructure
3// Released under the Apache License v2.0 (SPDX-License-Identifier Apache-2.0).
4// See the LICENSE.txt file for more information.
5// © Airbus SAS, Airbus Helicopters, and Airbus Defence and Space SAU/GmbH/SAS.
6// =====================================================================================================================
7
8#ifndef SEN_CORE_BASE_STATIC_VECTOR_H
9#define SEN_CORE_BASE_STATIC_VECTOR_H
10
13
14// std
15#include <cstddef>
16#include <cstdint>
17#include <iterator>
18#include <memory>
19
20namespace sen
21{
22
23namespace impl
24{
25
27template <typename T, typename Range, typename Index>
28inline T& index(Range&& range, Index&& i) noexcept
29{
30 // check that the index is within the range
31 SEN_EXPECT(static_cast<ptrdiff_t>(i) < (std::end(range) - std::begin(range)));
32
33 // go to the beginning of the range and fetch the element at index i
34 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
35 return std::begin(std::forward<Range>(range))[std::forward<Index>(i)];
36}
37
39template <typename T, typename Range, typename Index>
40inline const T& cindex(Range&& range, Index&& i) noexcept
41{
42 // check that the index is within the range
43 SEN_EXPECT(static_cast<ptrdiff_t>(i) < (std::end(range) - std::begin(range)));
44
45 // go to the beginning of the range and fetch the element at index i
46 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
47 return std::begin(std::forward<Range>(range))[std::forward<Index>(i)];
48}
49
50} // namespace impl
51
54
56enum class StaticVectorError : std::uint8_t
57{
61};
62
77template <typename T>
79{
80public: // checks
81 static constexpr bool nothrowDes = std::is_nothrow_destructible_v<T>;
82 static constexpr bool nothrowDefaultCons = std::is_nothrow_default_constructible_v<T>;
83 static constexpr bool nothrowCopyCons = std::is_nothrow_copy_constructible_v<T>;
84 static constexpr bool nothrowMoveCons = std::is_nothrow_move_constructible_v<T>;
85 static constexpr bool nothrowCopyAndDes = nothrowDes && nothrowCopyCons;
87
88 // the following types allow compatibility with stdlib algorithms
89public:
90 using value_type = T; // NOLINT(readability-identifier-naming)
91 using difference_type = ptrdiff_t; // NOLINT(readability-identifier-naming)
92 using pointer = T*; // NOLINT(readability-identifier-naming)
93 using const_pointer = T const*; // NOLINT(readability-identifier-naming)
94 using reference = T&; // NOLINT(readability-identifier-naming)
95 using const_reference = T const&; // NOLINT(readability-identifier-naming)
96 using rvalue_reference = T&&; // NOLINT(readability-identifier-naming)
97 using iterator = pointer; // NOLINT(readability-identifier-naming)
98 using const_iterator = const_pointer; // NOLINT(readability-identifier-naming)
99 using size_type = std::size_t; // NOLINT(readability-identifier-naming)
100 using reverse_iterator = std::reverse_iterator<iterator>; // NOLINT(readability-identifier-naming)
101 using const_reverse_iterator = std::reverse_iterator<const_iterator>; // NOLINT(readability-identifier-naming)
102
103public:
106
107public: // special members
108 StaticVectorBase(const StaticVectorBase&) noexcept = delete;
109 StaticVectorBase(StaticVectorBase&&) noexcept = delete;
110 StaticVectorBase& operator=(StaticVectorBase&&) noexcept = delete;
111 StaticVectorBase& operator=(const StaticVectorBase&) noexcept = delete;
112
113public: // getters.
116 [[nodiscard]] size_type size() const noexcept { return size_; }
117
120 [[nodiscard]] size_type capacity() const noexcept { return capacity_; }
121
124 [[nodiscard]] size_type maxSize() const noexcept { return capacity(); }
125
128 [[nodiscard]] const_pointer data() const noexcept
129 {
130 return reinterpret_cast<const_pointer>(dataPtr_); // NOLINT NOSONAR
131 }
132
135 [[nodiscard]] pointer data() noexcept
136 {
137 return reinterpret_cast<pointer>(dataPtr_); // NOLINT NOSONAR
138 }
139
142 [[nodiscard]] bool empty() const noexcept { return size() == size_type {0U}; }
143
146 [[nodiscard]] bool full() const noexcept { return size() == capacity(); }
147
148public: // assignment
157 [[nodiscard]] Maybe assign(size_type n, const T& u) noexcept(nothrowCopyCons);
158
166 [[nodiscard]] Maybe assign(const std::initializer_list<T>& list) noexcept(nothrowCopyCons);
167
175 [[nodiscard]] Maybe assign(std::initializer_list<T>&& list) noexcept(nothrowMoveCons);
176
184 template <class InputIt>
185 [[nodiscard]] Maybe assign(InputIt first, InputIt last) noexcept(nothrowCopyCons);
186
187public: // positional iterator accessors
191 [[nodiscard]] iterator begin() noexcept { return data(); }
192
196 [[nodiscard]] const_iterator begin() const noexcept { return data(); }
197
200 [[nodiscard]] iterator end() noexcept
201 {
202 return data() + size(); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
203 }
204
208 [[nodiscard]] const_iterator end() const noexcept { return data() + size(); }
209
212 [[nodiscard]] reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
213
216 [[nodiscard]] const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
217
222 [[nodiscard]] reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
223
228 [[nodiscard]] const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
229
233 [[nodiscard]] const_iterator cbegin() noexcept { return begin(); }
234
238 [[nodiscard]] const_iterator cbegin() const noexcept { return begin(); }
239
242 [[nodiscard]] const_iterator cend() noexcept { return end(); }
243
246 [[nodiscard]] const_iterator cend() const noexcept { return end(); }
247
248public: // index-based value accessors
259 [[nodiscard]] reference operator[](size_type i) noexcept { return impl::index<value_type>(*this, i); }
260
271 [[nodiscard]] const_reference operator[](size_type i) const noexcept { return impl::cindex<value_type>(*this, i); }
272
273public: // position-based value accessors
278 [[nodiscard]] reference front() noexcept
279 {
280 SEN_EXPECT(!empty());
281 return impl::index<value_type>(*this, 0U);
282 }
283
288 [[nodiscard]] const_reference front() const noexcept
289 {
290 SEN_EXPECT(!empty());
291 return impl::cindex<value_type>(*this, 0U);
292 }
293
298 [[nodiscard]] reference back() noexcept
299 {
300 SEN_EXPECT(!empty());
301 return impl::index<value_type>(*this, size() - 1);
302 }
303
308 [[nodiscard]] const_reference back() const noexcept
309 {
310 SEN_EXPECT(!empty());
311 return impl::cindex<value_type>(*this, size() - 1);
312 }
313
314public: // modifiers
320 void clear() noexcept(nothrowDes)
321 {
322 internalDestroyAll();
323 internalSetSize(0U);
324 }
325
332 Maybe push_back(T&& value) noexcept(nothrowMoveCons);
333
340 Maybe push_back(const T& value) noexcept(nothrowCopyCons);
341
349
362 template <typename... Args>
363 MaybeIterator emplace(iterator position, Args&&... args) noexcept(nothrowMoveCons);
364
377 template <typename... Args>
378 Maybe emplace_back(Args&&... args) noexcept( // NOLINT(readability-identifier-naming)
380
386 Maybe pop_back() noexcept(nothrowDes); // NOLINT(readability-identifier-naming)
387
388public: // insert overloads
398
408
418 MaybeIterator insert(iterator position, size_type n, const T& x) noexcept(nothrowCopyCons);
419
429 MaybeIterator insert(iterator position, std::initializer_list<T> list) noexcept(nothrowCopyCons);
430
442 template <class InputIt>
443 MaybeIterator insert(iterator position, InputIt first, InputIt last) noexcept(nothrowCopyCons);
444
456 template <class InputIt>
457 MaybeIterator move_insert(iterator position, // NOLINT(readability-identifier-naming)
458 InputIt first,
459 InputIt last) noexcept(nothrowMoveCons);
460
461public: // resizing
470 Maybe resize(size_type newSize, const T& value) noexcept(nothrowCopyAndDes);
471
480
481public: // erase
497
511
512private: // implementation details
515 [[nodiscard]] Maybe emplaceMultiple(size_type n) noexcept(nothrowDefaultCons);
516
518 template <typename Iterator>
519 [[nodiscard]] Maybe checkIteratorRange(Iterator itr) noexcept;
520
522 template <typename IteratorA, typename IteratorB>
523 [[nodiscard]] Maybe checkIteratorPair(IteratorA first, IteratorB last) noexcept;
524
529 template <class Itr>
530 void internalDestroy(Itr first, Itr last) noexcept(nothrowDes);
531
535 void internalDestroyAll() noexcept(nothrowDes) { internalDestroy(data(), end()); }
536
537protected:
538 StaticVectorBase(std::size_t capacity, void* dataPtr) noexcept: capacity_(capacity), dataPtr_(dataPtr)
539 {
540 SEN_EXPECT(dataPtr != nullptr);
541 }
542 virtual ~StaticVectorBase() noexcept { internalDestroyAll(); }
543
548 void internalSetSize(std::size_t newSize) noexcept;
549
550private:
551 std::size_t capacity_;
552 void* dataPtr_;
553 std::size_t size_ = 0U;
554};
555
569template <typename T, std::size_t s>
571{
572public:
573 static constexpr std::size_t staticCapacity = s;
574 static_assert(staticCapacity != 0U, "Vectors of no capacity are not supported");
575
576public:
578
579public:
581 StaticVector() noexcept: StaticVectorBase<T>(s, &data_) {}
582
585 explicit StaticVector(std::size_t n) noexcept;
586
589 StaticVector(std::size_t n, T const& value) noexcept(Base::nothrowCopyCons);
590
593 StaticVector(std::initializer_list<T> list) noexcept(Base::nothrowCopyCons);
594
597 template <class InputIt>
598 StaticVector(InputIt first, InputIt last) noexcept(Base::nothrowCopyCons);
599
602 StaticVector(const StaticVector& other) noexcept(Base::nothrowCopyCons);
603
607 StaticVector(StaticVector&& other) noexcept;
608
611 ~StaticVector() noexcept override = default;
612
615 StaticVector& operator=(const StaticVector& other) noexcept(Base::nothrowCopyCons);
616
620 StaticVector& operator=(StaticVector&& other) noexcept;
621
624 void swap(StaticVector& other) noexcept;
625
627 [[nodiscard]] Base& base() noexcept { return *this; }
628
630 [[nodiscard]] const Base& base() const noexcept { return *this; }
631
632private:
633 alignas(T) std::byte data_[sizeof(T) * s];
634};
635
636//--------------------------------------------------------------------------------------------------------------
637// Comparison operators
638//--------------------------------------------------------------------------------------------------------------
639
642template <typename T, std::size_t size>
643std::enable_if_t<HasOperator<T>::eq, bool> operator==(StaticVector<T, size> const& lhs,
644 StaticVector<T, size> const& rhs) noexcept
645{
646 if (lhs.size() != rhs.size())
647 {
648 return false;
649 }
650
651 return lhs.size() == 0 || std::equal(lhs.begin(), lhs.end(), rhs.begin(), std::equal_to<T> {});
652}
653
655template <typename T, std::size_t size>
656std::enable_if_t<HasOperator<T>::ne, bool> operator!=(StaticVector<T, size> const& lhs,
657 StaticVector<T, size> const& rhs) noexcept
658{
659 return !(lhs == rhs);
660}
661
663
664} // namespace sen
665
666//----------------------------------------------------------------------------------------------------------------------
667// Inline implementation
668//----------------------------------------------------------------------------------------------------------------------
669
670// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
671#define SEN_VECTOR_TRY(...) \
672 { \
673 auto res = __VA_ARGS__; \
674 if (res.isError()) \
675 { \
676 return Err(res.getError()); \
677 } \
678 }
679
680namespace sen
681{
682
683template <typename T>
685 const T& u) noexcept(nothrowCopyCons)
686{
687 if (n > capacity())
688 {
690 }
691
692 // clear and insert the elements at the beginning
693 clear();
694 return insert(begin(), n, u);
695}
696
697template <typename T>
698inline typename StaticVectorBase<T>::Maybe StaticVectorBase<T>::assign(const std::initializer_list<T>& list) noexcept(
700{
701 if (list.size() > capacity())
702 {
704 }
705
706 clear();
707 return insert(begin(), list.begin(), list.end());
708}
709
710template <typename T>
711inline typename StaticVectorBase<T>::Maybe StaticVectorBase<T>::assign(std::initializer_list<T>&& list) noexcept(
713{
714 if (list.size() > capacity())
715 {
717 }
718
719 // clear and move-insert the elements at the beginning
720 clear();
721 return move_insert(begin(), list.begin(), list.end());
722}
723
724template <typename T>
725template <class InputIt>
727 InputIt last) noexcept(nothrowCopyCons)
728{
729 // check capacity
730 if (last - first < 0)
731 {
733 }
734
735 if (static_cast<size_type>(last - first) > capacity())
736 {
738 }
739
740 // clear and insert the elements at the beginning
741 clear();
742 return insert(begin(), first, last);
743}
744
745template <typename T>
746// NOLINTNEXTLINE(readability-identifier-naming)
748{
749 if (full())
750 {
752 }
753 return emplace_back(std::move(value));
754}
755
756template <typename T>
757// NOLINTNEXTLINE(readability-identifier-naming)
759{
760 if (full())
761 {
763 }
764
765 return emplace_back(value);
766}
767
768template <typename T>
769// NOLINTNEXTLINE(readability-identifier-naming)
771{
772 static_assert(std::is_default_constructible<T>::value,
773 "this version of push_back requires a default constructible type");
774
775 if (full())
776 {
778 }
779 return emplace_back(T {});
780}
781
782template <typename T>
783template <typename... Args>
786 Args&&... args) noexcept(nothrowMoveCons)
787{
788 if (full())
789 {
791 }
792
793 // check that the position is valid
794 SEN_VECTOR_TRY(checkIteratorRange(position))
795
796 if (position == end())
797 {
798 std::ignore = emplace_back(std::forward<Args...>(args...)); // not full
799 return Ok(position);
800 }
801
802 const auto previousEnd = end();
803
804 // move the back to a new extra place
805 std::ignore = emplace_back(std::move(back())); // not full
806
807 if (std::distance(position, previousEnd) != 1)
808 {
809 // move the rest of the elements to make room
810 std::move_backward(position, end() - 2, end() - 1); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
811
812 // destroy the element that was in position
813 std::destroy_at(position);
814 }
815
816 // place the new element in position
817 ::new (std::addressof(*position)) T(std::forward<Args>(args)...);
818
819 return Ok(position);
820}
821
822template <typename T>
823template <typename... Args>
825{
826 if (full())
827 {
829 }
830
831 // placement new at the end of the array
832 new (end()) T(std::forward<Args>(args)...);
833
834 // increase the size
835 internalSetSize(size() + 1);
836 return Ok();
837}
838
839template <typename T>
840// NOLINTNEXTLINE(readability-identifier-naming)
842{
843 if (empty())
844 {
846 }
847
848 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
849 auto ptr = end() - 1; // get the pointer to the last element
850 std::destroy_at(ptr); // do placement delete
851 internalSetSize(size() - 1); // decrease the size
852 return Ok();
853}
854
855template <typename T>
859{
860 if (full())
861 {
863 }
864
865 SEN_VECTOR_TRY(checkIteratorRange(position))
866 return insert(position, static_cast<size_type>(1), x);
867}
868
869template <typename T>
870template <class InputIt>
872 InputIt first,
873 InputIt last) noexcept(nothrowCopyCons)
874{
875 // checks
876 SEN_VECTOR_TRY(checkIteratorRange(position))
877 SEN_VECTOR_TRY(checkIteratorPair(first, last))
878
879 // check if we would be inserting beyond the capacity
880 if (size() + static_cast<size_type>(last - first) > capacity())
881 {
883 }
884
885 const size_t insertN = std::distance(first, last);
886 const size_t insertBegin = std::distance(begin(), position);
887 const size_t insertEnd = insertBegin + insertN;
888
889 // move old data.
890 size_t copyOldN;
891 size_t constructOldN;
892 iterator pConstructOld;
893
894 auto pEnd = end();
895
896 if (insertEnd > size())
897 {
898 copyOldN = 0;
899 constructOldN = size() - insertBegin;
900 pConstructOld = begin() + insertEnd; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
901 }
902 else
903 {
904 copyOldN = size() - insertBegin - insertN;
905 constructOldN = insertN;
906 pConstructOld = pEnd;
907 }
908
909 const size_t copyNewN = constructOldN;
910 const size_t constructNewN = insertN - copyNewN;
911
912 // move-construct old on the new (uninitialized memory area).
913 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
914 std::uninitialized_move(pEnd - constructOldN, pEnd, pConstructOld);
915
916 // move old to the remaining (already initialized) memory area.
917 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
918 std::move_backward(begin() + insertBegin, begin() + insertBegin + copyOldN, begin() + insertEnd + copyOldN);
919
920 // copy-construct new in the (uninitialized) memory area
921 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
922 std::uninitialized_copy(first + copyNewN, first + copyNewN + constructNewN, pEnd);
923
924 // copy new to the final location
925 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
926 std::copy(first, first + copyNewN, begin() + insertBegin);
927
928 internalSetSize(size_ + insertN);
929
930 return Ok(position);
931}
932
933template <typename T>
935 value_type&& x) noexcept(nothrowMoveCons)
936{
937 if (full())
938 {
940 }
941
942 SEN_VECTOR_TRY(checkIteratorRange(position))
943
944 if (position == end())
945 {
946 std::ignore = emplace_back(std::move(x)); // not full, so cannot fail
947 }
948 else
949 {
950 // move the back to a new extra place
951 std::ignore = emplace_back(std::move(back())); // not full, so cannot fail
952
953 // move affected range one position
954 std::move_backward(position, end() - 2, end() - 1); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
955
956 // move our value into the desired position
957 *position = std::move(x);
958 }
959
960 return Ok(position);
961}
962
963template <typename T>
966 const T& x) noexcept(nothrowCopyCons)
967{
968 SEN_VECTOR_TRY(checkIteratorRange(position))
969
970 if (const auto newSize = size() + n; newSize > capacity())
971 {
973 }
974
975 if (n == 0U)
976 {
977 return Ok(position);
978 }
979
980 const size_t insertN = n;
981 const size_t insertBegin = std::distance(begin(), position);
982 const size_t insertEnd = insertBegin + insertN;
983
984 // copy old data.
985 size_t copyOldN;
986 size_t constructOldN;
987 iterator pConstructOld;
988
989 auto pEnd = end();
990
991 if (insertEnd > size())
992 {
993 copyOldN = 0;
994 constructOldN = size() - insertBegin;
995 pConstructOld = begin() + insertEnd; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
996 }
997 else
998 {
999 copyOldN = size() - insertBegin - insertN;
1000 constructOldN = insertN;
1001 pConstructOld = pEnd;
1002 }
1003
1004 size_t copyNewN = constructOldN;
1005 size_t constructNewN = insertN - copyNewN;
1006
1007 // move-construct old on the new (uninitialized memory area).
1008 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1009 std::uninitialized_move(static_cast<iterator>(pEnd - constructOldN), pEnd, pConstructOld);
1010
1011 // move old to the remaining (already initialized) memory area.
1012 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1013 std::move_backward(begin() + insertBegin, begin() + insertBegin + copyOldN, begin() + insertEnd + copyOldN);
1014
1015 // construct new in the (uninitialized) memory area.
1016 std::uninitialized_fill_n(pEnd, constructNewN, x);
1017
1018 // copy new n values of T
1019 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1020 std::fill_n(begin() + insertBegin, copyNewN, x);
1021
1022 internalSetSize(size() + n);
1023
1024 return Ok(position);
1025}
1026
1027template <typename T>
1030 std::initializer_list<T> list) noexcept(nothrowCopyCons)
1031{
1032 SEN_VECTOR_TRY(checkIteratorRange(position))
1033 return insert(position, list.begin(), list.end());
1034}
1035
1036template <typename T>
1037template <class InputIt>
1039StaticVectorBase<T>::move_insert(iterator position, InputIt first, InputIt last) noexcept(nothrowMoveCons)
1040{
1041 // checks
1042 SEN_VECTOR_TRY(checkIteratorRange(position))
1043 SEN_VECTOR_TRY(checkIteratorPair(first, last))
1044
1045 if (size() + static_cast<size_type>(last - first) > capacity())
1046 {
1048 }
1049
1050 const size_t insertN = std::distance(first, last);
1051 const size_t insertBegin = std::distance(begin(), position);
1052 const size_t insertEnd = insertBegin + insertN;
1053
1054 // move old data.
1055 size_t moveOldN;
1056 size_t constructOldN;
1057 iterator pConstructOld;
1058 auto pEnd = end();
1059
1060 if (insertEnd > size())
1061 {
1062 moveOldN = 0;
1063 constructOldN = size() - insertBegin; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1064 pConstructOld = begin() + insertEnd; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1065 }
1066 else
1067 {
1068 moveOldN = size() - insertBegin - insertN;
1069 constructOldN = insertN;
1070 pConstructOld = pEnd;
1071 }
1072
1073 const size_t copyNewN = constructOldN;
1074 const size_t constructNewN = insertN - copyNewN;
1075
1076 // move-construct old on the new (uninitialized memory area).
1077 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1078 std::uninitialized_move(pEnd - constructOldN, pEnd, pConstructOld);
1079
1080 // move old to the remaining (already initialized) memory area.
1081 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1082 std::move_backward(begin() + insertBegin, begin() + insertBegin + moveOldN, begin() + insertEnd + moveOldN);
1083
1084 // move-construct new in the (uninitialized) memory area
1085 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1086 std::uninitialized_move(first + copyNewN, first + copyNewN + constructNewN, pEnd);
1087
1088 // move new to the final location
1089 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1090 std::move(first, first + copyNewN, begin() + insertBegin);
1091
1092 internalSetSize(size_ + insertN);
1093
1094 return Ok(position);
1095}
1096
1097template <typename T>
1099 const T& value) noexcept(nothrowCopyAndDes)
1100{
1101 static_assert(std::is_nothrow_copy_constructible<T>::value, "T is not supported");
1102
1103 // do nothing if the size is already the same
1104 if (newSize == size())
1105 {
1106 return Ok();
1107 }
1108
1109 if (newSize > capacity())
1110 {
1112 }
1113
1114 if (newSize > size())
1115 {
1116 // insert copies of value at the end
1117 return insert(end(), newSize - size(), value);
1118 }
1119
1120 // remove elements from the end
1121 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1122 return erase(end() - (size() - newSize), end());
1123}
1124
1125template <typename T>
1128{
1129 // do nothing if the size is already the same
1130 if (newSize == size())
1131 {
1132 return Ok();
1133 }
1134
1135 if (newSize > capacity())
1136 {
1138 }
1139
1140 if (newSize > size())
1141 {
1142 return emplaceMultiple(newSize - size());
1143 }
1144
1145 // remove elements from the end
1146 return erase(end() - (size() - newSize), end()); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1147}
1148
1149template <typename T>
1151 StaticVectorBase::iterator position) noexcept(nothrowDes)
1152{
1153 SEN_VECTOR_TRY(checkIteratorRange(position))
1154
1155 // move elements from [position + 1, end) to position
1156 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1157 std::move(position + 1, end(), position);
1158
1159 // destroy the last element
1160 auto ptr = end() - 1; // get the pointer to the last element NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1161 std::destroy_at(ptr); // do placement delete
1162 internalSetSize(size() - 1);
1163 return Ok(position);
1164}
1165
1166template <typename T>
1170{
1171 if (first == end()) // early exit
1172 {
1174 }
1175
1176 if (first == begin() && last == end())
1177 {
1178 clear();
1179 }
1180 else
1181 {
1182 SEN_VECTOR_TRY(checkIteratorPair(first, last))
1183 SEN_VECTOR_TRY(checkIteratorRange(first))
1184 SEN_VECTOR_TRY(checkIteratorRange(last))
1185
1186 // move the remaining elements on top of the erased range
1187 std::move(last, end(), first);
1188
1189 // destroy the elements left over at the end.
1190 const auto nDelete = std::distance(first, last);
1191 std::destroy(end() - nDelete, end()); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1192
1193 internalSetSize(size() - nDelete);
1194 }
1195
1196 return Ok(first);
1197}
1198
1199template <typename T>
1200inline typename StaticVectorBase<T>::Maybe StaticVectorBase<T>::emplaceMultiple(StaticVectorBase::size_type n) noexcept(
1201 nothrowDefaultCons)
1202{
1203 const size_type newSize = size() + n;
1204 SEN_EXPECT(newSize <= capacity());
1205
1206 while (newSize != size())
1207 {
1208 // cannot overflow as newSize != size() && newSize <= capacity
1209 std::ignore = emplace_back();
1210 }
1211
1212 return Ok();
1213}
1214
1215template <typename T>
1216template <typename Iterator>
1217inline typename StaticVectorBase<T>::Maybe StaticVectorBase<T>::checkIteratorRange(Iterator itr) noexcept
1218{
1219 if (itr >= begin() && itr <= end())
1220 {
1221 return Ok();
1222 }
1223
1225}
1226
1227template <typename T>
1228template <typename IteratorA, typename IteratorB>
1229inline typename StaticVectorBase<T>::Maybe StaticVectorBase<T>::checkIteratorPair(IteratorA first,
1230 IteratorB last) noexcept
1231{
1232 if (first > last)
1233 {
1235 }
1236 return Ok();
1237}
1238
1239template <typename T>
1240inline void StaticVectorBase<T>::internalSetSize(std::size_t newSize) noexcept
1241{
1242 SEN_EXPECT(newSize <= capacity()); // newSize out-of-bounds [0, Capacity)
1243 size_ = newSize;
1244}
1245
1246template <typename T>
1247template <class InputIt>
1248inline void StaticVectorBase<T>::internalDestroy(InputIt first, InputIt last) noexcept(nothrowDes)
1249{
1250 SEN_EXPECT(first >= data());
1251 SEN_EXPECT(first <= end());
1252 SEN_EXPECT(last >= data());
1253 SEN_EXPECT(last <= end());
1254
1255 for (; first != last; ++first) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1256 {
1257 std::destroy_at(first);
1258 }
1259}
1260
1261// StaticVector
1262
1263template <typename T, std::size_t c>
1264inline StaticVector<T, c>::StaticVector(std::size_t n) noexcept: StaticVectorBase<T>(c, &data_)
1265{
1266 auto result = this->resize(n);
1267 SEN_ASSERT(result.isOk());
1268 std::ignore = result;
1269}
1270
1271template <typename T, std::size_t c>
1272inline StaticVector<T, c>::StaticVector(std::size_t n, const T& value) noexcept(Base::nothrowCopyCons)
1273 : StaticVectorBase<T>(c, &data_)
1274{
1275 auto result = this->resize(n, value);
1276 SEN_ASSERT(result.isOk());
1277 std::ignore = result;
1278}
1279
1280template <typename T, std::size_t c>
1281inline StaticVector<T, c>::StaticVector(std::initializer_list<T> list) noexcept(Base::nothrowCopyCons)
1282 : StaticVectorBase<T>(c, &data_)
1283{
1284 auto result = this->assign(std::move(list));
1285 SEN_ASSERT(result.isOk());
1286 std::ignore = result;
1287}
1288
1289template <typename T, std::size_t c>
1290template <class InputIt>
1291inline StaticVector<T, c>::StaticVector(InputIt first, InputIt last) noexcept(Base::nothrowCopyCons)
1292 : StaticVectorBase<T>(c, &data_)
1293{
1294 auto result = this->assign(first, last);
1295 SEN_ASSERT(result.isOk());
1296 std::ignore = result;
1297}
1298
1299template <typename T, std::size_t c>
1301 : StaticVectorBase<T>(c, &data_)
1302{
1303 auto result = this->insert(this->begin(), other.begin(), other.end());
1304 SEN_ASSERT(result.isOk());
1305 std::ignore = result;
1306}
1307
1308template <typename T, std::size_t c>
1310{
1311 auto result = this->move_insert(this->begin(), other.begin(), other.end());
1312 SEN_ASSERT(result.isOk());
1313 std::ignore = result;
1314 other.internalSetSize(0U);
1315}
1316
1317template <typename T, std::size_t c>
1319{
1320 if (this != &other)
1321 {
1322 // clear and insert the elements at the beginning
1323 this->clear();
1324 auto result = this->insert(this->begin(), other.begin(), other.end());
1325 SEN_ASSERT(result.isOk());
1326 std::ignore = result;
1327 }
1328 return *this;
1329}
1330
1331template <typename T, std::size_t c>
1333{
1334 if (this != &other)
1335 {
1336 // clear and move-insert the elements at the beginning
1337 this->clear();
1338 auto result = this->move_insert(this->begin(), other.begin(), other.end());
1339 SEN_ASSERT(result.isOk());
1340 std::ignore = result;
1341 other.internalSetSize(0U);
1342 }
1343 return *this;
1344}
1345
1346template <typename T, std::size_t c>
1347inline void StaticVector<T, c>::swap(StaticVector& other) noexcept
1348{
1349 StaticVector tmp = std::move(other);
1350 other = std::move(*this);
1351 (*this) = std::move(tmp);
1352}
1353
1354} // namespace sen
1355
1356#undef SEN_VECTOR_TRY
1357
1358#endif // SEN_CORE_BASE_STATIC_VECTOR_H
The following macros implement a replacement of assert that is connected to the overall fault handlin...
Result<T, E> is a template type that can be used to return and propagate errors. The intent is to rep...
Definition result.h:135
const_reverse_iterator rbegin() const noexcept
Reverse iterator to the first element. Complexity: constant.
Definition static_vector.h:216
pointer data() noexcept
Direct access to the underlying storage. Complexity: constant.
Definition static_vector.h:135
virtual ~StaticVectorBase() noexcept
Definition static_vector.h:542
Result< void, StaticVectorError > Maybe
Definition static_vector.h:104
size_type maxSize() const noexcept
Max element count (same as capacity()). Complexity: constant.
Definition static_vector.h:124
static constexpr bool nothrowMoveCons
Definition static_vector.h:84
static constexpr bool nothrowDefaultConsAndDes
Definition static_vector.h:86
reverse_iterator rend() noexcept
Returns a reverse iterator to the element following the last element of the reversed vector....
Definition static_vector.h:222
pointer iterator
Definition static_vector.h:97
size_type capacity() const noexcept
Maximum number of elements that can be allocated in the storage. Complexity: constant.
Definition static_vector.h:120
const_iterator begin() const noexcept
Returns an iterator to the first element of the vector. If the vector is empty, the returned iterator...
Definition static_vector.h:196
static constexpr bool nothrowCopyCons
Definition static_vector.h:83
Maybe assign(size_type n, const T &u) noexcept(nothrowCopyCons)
Clears the vector and assigns n copies of u to it. Complexity: linear in n.
Definition static_vector.h:684
ptrdiff_t difference_type
Definition static_vector.h:91
void clear() noexcept(nothrowDes)
Clears the vector. This function destroys all the elements. Complexity: linear in size().
Definition static_vector.h:320
const_iterator cend() noexcept
Constant iterator to the element following the last element. Complexity: constant.
Definition static_vector.h:242
StaticVectorBase(StaticVectorBase &&) noexcept=delete
Maybe assign(std::initializer_list< T > &&list) noexcept(nothrowMoveCons)
Initializer list assignment (r-value version). Complexity: linear in list.size().
Definition static_vector.h:711
const_reference front() const noexcept
The element at the beginning of the container (const version). Calling front on an empty container is...
Definition static_vector.h:288
const_pointer const_iterator
Definition static_vector.h:98
const_reference back() const noexcept
The element at the end of the container (const version). Calling back on an empty container is undefi...
Definition static_vector.h:308
Maybe resize(size_type newSize, const Value &value) noexcept(nothrowCopyAndDes)
Definition static_vector.h:1098
reverse_iterator rbegin() noexcept
Reverse iterator to the first element. Complexity: constant.
Definition static_vector.h:212
void internalSetSize(std::size_t newSize) noexcept
Changes the container size to newSize.
Definition static_vector.h:1240
const_reference operator[](size_type i) const noexcept
Gets the element at index i. Complexity: constant.
Definition static_vector.h:271
MaybeIterator insert(iterator position, const_reference x) noexcept(nothrowCopyCons)
Definition static_vector.h:856
bool empty() const noexcept
true if the container is empty. Complexity: constant
Definition static_vector.h:142
static constexpr bool nothrowCopyAndDes
Definition static_vector.h:85
Maybe emplace_back(Args &&... args) noexcept(//NOLINT(readability-identifier-naming) nothrowMoveCons)
Definition static_vector.h:824
Maybe pop_back() noexcept(nothrowDes)
Definition static_vector.h:841
Result< iterator, StaticVectorError > MaybeIterator
Definition static_vector.h:105
const_iterator cend() const noexcept
Constant iterator to the element following the last element. Complexity: constant.
Definition static_vector.h:246
StaticVectorBase(std::size_t capacity, void *dataPtr) noexcept
Definition static_vector.h:538
MaybeIterator emplace(iterator position, Args &&... args) noexcept(nothrowMoveCons)
Definition static_vector.h:784
std::reverse_iterator< iterator > reverse_iterator
Definition static_vector.h:100
MaybeIterator move_insert(iterator position, InputIt first, InputIt last) noexcept(nothrowMoveCons)
Definition static_vector.h:1039
const_iterator cbegin() noexcept
Returns a const iterator to the first element of the vector. If the vector is empty,...
Definition static_vector.h:233
T && rvalue_reference
Definition static_vector.h:96
T const & const_reference
Definition static_vector.h:95
MaybeIterator erase(iterator position) noexcept(nothrowDes)
Definition static_vector.h:1150
std::size_t size_type
Definition static_vector.h:99
Maybe push_back(const T &value) noexcept(nothrowCopyCons)
Appends a value to the end of the container. Complexity: constant.
Definition static_vector.h:758
StaticVectorBase(const StaticVectorBase &) noexcept=delete
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition static_vector.h:101
reference back() noexcept
The element at the end of the container. Calling back on an empty container is undefined....
Definition static_vector.h:298
const_iterator cbegin() const noexcept
Returns a const iterator to the first element of the vector. If the vector is empty,...
Definition static_vector.h:238
iterator end() noexcept
Iterator to the element following the last element. Complexity: constant.
Definition static_vector.h:200
reference front() noexcept
The element at the beginning of the container. Calling front on an empty container is undefined....
Definition static_vector.h:278
const_reverse_iterator rend() const noexcept
Returns a reverse iterator to the element following the last element of the reversed vector....
Definition static_vector.h:228
bool full() const noexcept
true if the container is full. Complexity: constant
Definition static_vector.h:146
Maybe push_back() noexcept(nothrowDefaultCons)
Appends a value (default constructed) to the end of the container. Complexity: constant.
Definition static_vector.h:770
T & reference
Definition static_vector.h:94
reference operator[](size_type i) noexcept
Gets the element at index i. Complexity: constant.
Definition static_vector.h:259
T const * const_pointer
Definition static_vector.h:93
const_iterator end() const noexcept
Iterator to the element following the last element. Complexity: constant. NOLINTNEXTLINE(cppcoreguide...
Definition static_vector.h:208
const_pointer data() const noexcept
Direct access to the underlying storage. Complexity: constant.
Definition static_vector.h:128
iterator begin() noexcept
Returns an iterator to the first element of the vector. If the vector is empty, the returned iterator...
Definition static_vector.h:191
Maybe assign(InputIt first, InputIt last) noexcept(nothrowCopyCons)
Clears the vector and assigns a range to it. Complexity: linear in distance(first,...
Definition static_vector.h:726
T * pointer
Definition static_vector.h:92
Maybe push_back(T &&value) noexcept(nothrowMoveCons)
Appends a value to the end of the container (r-value version). Complexity: constant.
Definition static_vector.h:747
static constexpr bool nothrowDes
Definition static_vector.h:81
static constexpr bool nothrowDefaultCons
Definition static_vector.h:82
Maybe assign(const std::initializer_list< T > &list) noexcept(nothrowCopyCons)
Initializer list assignment. Complexity: linear in list.size().
Definition static_vector.h:698
void internalDestroy(InputIt first, InputIt last) noexcept(nothrowDes)
Definition static_vector.h:1248
size_type size() const noexcept
Element count. Complexity: constant.
Definition static_vector.h:116
T value_type
Definition static_vector.h:90
Stack-based, exception-free and resizable vector with fixed-capacity.
Definition static_vector.h:571
Base & base() noexcept
This object, as its base class.
Definition static_vector.h:627
StaticVector & operator=(const StaticVector &other) noexcept(Base::nothrowCopyCons)
Copy assignment. Complexity: linear in other.size().
Definition static_vector.h:1318
~StaticVector() noexcept override=default
Deletes all internal elements. Complexity: linear in size().
const Base & base() const noexcept
This object, as its base class.
Definition static_vector.h:630
static constexpr std::size_t staticCapacity
Definition static_vector.h:573
void swap(StaticVector &other) noexcept
Definition static_vector.h:1347
StaticVector() noexcept
Creates an empty vector.
Definition static_vector.h:581
StaticVectorBase< T > Base
Definition static_vector.h:577
impl::Err< void > Err() noexcept
If E is void, use the void specialization of Err.
Definition result.h:439
impl::Ok< void > Ok() noexcept
If T is void, use the void specialization of Ok.
Definition result.h:434
#define SEN_ASSERT(expr)
Checks an intermediate result produced by a procedure (not an input or output). NOLINTNEXTLINE.
Definition assert.h:39
#define SEN_EXPECT(expr)
Checks a pre-condition of a procedure (function parameter for example). NOLINTNEXTLINE.
Definition assert.h:36
constexpr bool operator!=(const Span< T > &lhs, const Span< T > &rhs) noexcept
Definition span.h:190
constexpr bool operator==(const Span< T > &lhs, const Span< T > &rhs) noexcept
Definition span.h:184
StaticVectorError
Things that can go wrong when using a StaticVector.
Definition static_vector.h:57
@ empty
Invalid operation on an empty vector.
Definition static_vector.h:60
@ badRange
The range is invalid.
Definition static_vector.h:59
@ full
The vector cannot hold more elements.
Definition static_vector.h:58
Definition assert.h:17
STL namespace.
#define SEN_VECTOR_TRY(...)
Definition static_vector.h:671