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#include "sen/core/base/span.h"
14
15// std
16#include <algorithm>
17#include <cstddef>
18#include <cstdint>
19#include <iterator>
20#include <memory>
21#include <utility>
22
23// Like SEN_EXPECT and SEN_ASSERT, but a passing check makes no call into the library. NOLINTNEXTLINE
24#define SEN_VECTOR_CHECK(expr, type) \
25 ((expr) ? static_cast<void>(0) : ::sen::impl::senCheckImpl(false, ::sen::impl::CheckType::type, #expr, SEN_SL()))
26
27namespace sen
28{
29
30namespace impl
31{
32
34template <typename T, typename Range, typename Index>
35inline T& index(Range&& range, Index&& i) noexcept
36{
37 // check that the index is within the range
38 SEN_VECTOR_CHECK(static_cast<ptrdiff_t>(i) < (std::end(range) - std::begin(range)), expect);
39
40 // go to the beginning of the range and fetch the element at index i
41 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
42 return std::begin(std::forward<Range>(range))[std::forward<Index>(i)];
43}
44
46template <typename T, typename Range, typename Index>
47inline const T& cindex(Range&& range, Index&& i) noexcept
48{
49 // check that the index is within the range
50 SEN_VECTOR_CHECK(static_cast<ptrdiff_t>(i) < (std::end(range) - std::begin(range)), expect);
51
52 // go to the beginning of the range and fetch the element at index i
53 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
54 return std::begin(std::forward<Range>(range))[std::forward<Index>(i)];
55}
56
57} // namespace impl
58
61
63enum class StaticVectorError : std::uint8_t
64{
68};
69
84template <typename T>
86{
87public: // checks
88 static constexpr bool nothrowDes = std::is_nothrow_destructible_v<T>;
89 static constexpr bool nothrowDefaultCons = std::is_nothrow_default_constructible_v<T>;
90 static constexpr bool nothrowCopyCons = std::is_nothrow_copy_constructible_v<T>;
91 static constexpr bool nothrowMoveCons = std::is_nothrow_move_constructible_v<T>;
92 static constexpr bool nothrowCopyAndDes = nothrowDes && nothrowCopyCons;
94
95 // the following types allow compatibility with stdlib algorithms
96public:
97 using value_type = T; // NOLINT(readability-identifier-naming)
98 using difference_type = ptrdiff_t; // NOLINT(readability-identifier-naming)
99 using pointer = T*; // NOLINT(readability-identifier-naming)
100 using const_pointer = T const*; // NOLINT(readability-identifier-naming)
101 using reference = T&; // NOLINT(readability-identifier-naming)
102 using const_reference = T const&; // NOLINT(readability-identifier-naming)
103 using rvalue_reference = T&&; // NOLINT(readability-identifier-naming)
104 using iterator = pointer; // NOLINT(readability-identifier-naming)
105 using const_iterator = const_pointer; // NOLINT(readability-identifier-naming)
106 using size_type = std::size_t; // NOLINT(readability-identifier-naming)
107 using reverse_iterator = std::reverse_iterator<iterator>; // NOLINT(readability-identifier-naming)
108 using const_reverse_iterator = std::reverse_iterator<const_iterator>; // NOLINT(readability-identifier-naming)
109
110public:
113
114public: // special members
115 StaticVectorBase(const StaticVectorBase&) noexcept = delete;
116 StaticVectorBase(StaticVectorBase&&) noexcept = delete;
117 StaticVectorBase& operator=(StaticVectorBase&&) noexcept = delete;
118 StaticVectorBase& operator=(const StaticVectorBase&) noexcept = delete;
119
120public: // getters.
123 [[nodiscard]] size_type size() const noexcept { return size_; }
124
127 [[nodiscard]] size_type capacity() const noexcept { return capacity_; }
128
131 [[nodiscard]] size_type maxSize() const noexcept { return capacity(); }
132
135 [[nodiscard]] const_pointer data() const noexcept
136 {
137 return reinterpret_cast<const_pointer>(dataPtr_); // NOLINT NOSONAR
138 }
139
142 [[nodiscard]] pointer data() noexcept
143 {
144 return reinterpret_cast<pointer>(dataPtr_); // NOLINT NOSONAR
145 }
146
149 [[nodiscard]] bool empty() const noexcept { return size() == size_type {0U}; }
150
153 [[nodiscard]] bool full() const noexcept { return size() == capacity(); }
154
155public: // assignment
164 [[nodiscard]] Maybe assign(size_type n, const T& u) noexcept(nothrowCopyCons);
165
173 [[nodiscard]] Maybe assign(const std::initializer_list<T>& list) noexcept(nothrowCopyCons);
174
182 [[nodiscard]] Maybe assign(std::initializer_list<T>&& list) noexcept(nothrowMoveCons);
183
191 template <class InputIt>
192 [[nodiscard]] Maybe assign(InputIt first, InputIt last) noexcept(nothrowCopyCons);
193
194public: // positional iterator accessors
198 [[nodiscard]] iterator begin() noexcept { return data(); }
199
203 [[nodiscard]] const_iterator begin() const noexcept { return data(); }
204
207 [[nodiscard]] iterator end() noexcept
208 {
209 return data() + size(); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
210 }
211
215 [[nodiscard]] const_iterator end() const noexcept { return data() + size(); }
216
219 [[nodiscard]] reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
220
223 [[nodiscard]] const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
224
229 [[nodiscard]] reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
230
235 [[nodiscard]] const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
236
240 [[nodiscard]] const_iterator cbegin() noexcept { return begin(); }
241
245 [[nodiscard]] const_iterator cbegin() const noexcept { return begin(); }
246
249 [[nodiscard]] const_iterator cend() noexcept { return end(); }
250
253 [[nodiscard]] const_iterator cend() const noexcept { return end(); }
254
255public: // index-based value accessors
266 [[nodiscard]] reference operator[](size_type i) noexcept { return impl::index<value_type>(*this, i); }
267
278 [[nodiscard]] const_reference operator[](size_type i) const noexcept { return impl::cindex<value_type>(*this, i); }
279
280public: // position-based value accessors
285 [[nodiscard]] reference front() noexcept
286 {
287 SEN_VECTOR_CHECK(!empty(), expect);
288 return impl::index<value_type>(*this, 0U);
289 }
290
295 [[nodiscard]] const_reference front() const noexcept
296 {
297 SEN_VECTOR_CHECK(!empty(), expect);
298 return impl::cindex<value_type>(*this, 0U);
299 }
300
305 [[nodiscard]] reference back() noexcept
306 {
307 SEN_VECTOR_CHECK(!empty(), expect);
308 return impl::index<value_type>(*this, size() - 1);
309 }
310
315 [[nodiscard]] const_reference back() const noexcept
316 {
317 SEN_VECTOR_CHECK(!empty(), expect);
318 return impl::cindex<value_type>(*this, size() - 1);
319 }
320
321public: // modifiers
327 void clear() noexcept(nothrowDes)
328 {
329 internalDestroyAll();
330 internalSetSize(0U);
331 }
332
339 Maybe push_back(T&& value) noexcept(nothrowMoveCons);
340
347 Maybe push_back(const T& value) noexcept(nothrowCopyCons);
348
356
369 template <typename... Args>
370 MaybeIterator emplace(iterator position, Args&&... args) noexcept(nothrowMoveCons);
371
384 template <typename... Args>
385 Maybe emplace_back(Args&&... args) noexcept( // NOLINT(readability-identifier-naming)
387
393 Maybe pop_back() noexcept(nothrowDes); // NOLINT(readability-identifier-naming)
394
395public: // insert overloads
405
415
425 MaybeIterator insert(iterator position, size_type n, const T& x) noexcept(nothrowCopyCons);
426
436 MaybeIterator insert(iterator position, std::initializer_list<T> list) noexcept(nothrowCopyCons);
437
449 template <class InputIt>
450 MaybeIterator insert(iterator position, InputIt first, InputIt last) noexcept(nothrowCopyCons);
451
463 template <class InputIt>
464 MaybeIterator move_insert(iterator position, // NOLINT(readability-identifier-naming)
465 InputIt first,
466 InputIt last) noexcept(nothrowMoveCons);
467
468public: // resizing
477 Maybe resize(size_type newSize, const T& value) noexcept(nothrowCopyAndDes);
478
487
488public: // erase
504
518
519private: // implementation details
522 [[nodiscard]] Maybe emplaceMultiple(size_type n) noexcept(nothrowDefaultCons);
523
525 template <typename Iterator>
526 [[nodiscard]] Maybe checkIteratorRange(Iterator itr) noexcept;
527
529 template <typename IteratorA, typename IteratorB>
530 [[nodiscard]] Maybe checkIteratorPair(IteratorA first, IteratorB last) noexcept;
531
536 template <class Itr>
537 void internalDestroy(Itr first, Itr last) noexcept(nothrowDes);
538
542 void internalDestroyAll() noexcept(nothrowDes) { internalDestroy(data(), end()); }
543
544protected:
545 StaticVectorBase(std::size_t capacity, void* dataPtr) noexcept: capacity_(capacity), dataPtr_(dataPtr)
546 {
547 SEN_VECTOR_CHECK(dataPtr != nullptr, expect);
548 }
549 virtual ~StaticVectorBase() noexcept { internalDestroyAll(); }
550
555 void internalSetSize(std::size_t newSize) noexcept;
556
557private:
558 std::size_t capacity_;
559 void* dataPtr_;
560 std::size_t size_ = 0U;
561};
562
576template <typename T, std::size_t s>
578{
579public:
580 static constexpr std::size_t staticCapacity = s;
581 static_assert(staticCapacity != 0U, "Vectors of no capacity are not supported");
582
583public:
585
586public:
588 StaticVector() noexcept: StaticVectorBase<T>(s, &data_) {}
589
592 explicit StaticVector(std::size_t n) noexcept;
593
596 StaticVector(std::size_t n, T const& value) noexcept(Base::nothrowCopyCons);
597
600 StaticVector(std::initializer_list<T> list) noexcept(Base::nothrowCopyCons);
601
604 template <class InputIt>
605 StaticVector(InputIt first, InputIt last) noexcept(Base::nothrowCopyCons);
606
609 StaticVector(const StaticVector& other) noexcept(Base::nothrowCopyCons);
610
614 StaticVector(StaticVector&& other) noexcept;
615
618 ~StaticVector() noexcept override = default;
619
622 StaticVector& operator=(const StaticVector& other) noexcept(Base::nothrowCopyCons);
623
627 StaticVector& operator=(StaticVector&& other) noexcept;
628
631 void swap(StaticVector& other) noexcept;
632
634 [[nodiscard]] Base& base() noexcept { return *this; }
635
637 [[nodiscard]] const Base& base() const noexcept { return *this; }
638
639private:
640 alignas(T) std::byte data_[sizeof(T) * s];
641};
642
643//--------------------------------------------------------------------------------------------------------------
644// Comparison operators
645//--------------------------------------------------------------------------------------------------------------
646
652template <typename T, std::size_t size>
653std::enable_if_t<HasOperator<T>::eq, bool> operator==(
654 StaticVector<T, size> const& lhs,
655 StaticVector<T, size> const& rhs) noexcept(noexcept(std::declval<T const&>() == std::declval<T const&>()))
656{
657 if (lhs.size() != rhs.size())
658 {
659 return false;
660 }
661
662 return lhs.size() == 0 || std::equal(lhs.begin(), lhs.end(), rhs.begin(), std::equal_to<T> {});
663}
664
668template <typename T, std::size_t size>
669std::enable_if_t<HasOperator<T>::ne, bool> operator!=(
670 StaticVector<T, size> const& lhs,
671 StaticVector<T, size> const& rhs) noexcept(noexcept(std::declval<StaticVector<T, size> const&>() ==
672 std::declval<StaticVector<T, size> const&>()))
673{
674 return !(lhs == rhs);
675}
676
681template <typename T, std::size_t size>
682std::enable_if_t<HasOperator<T>::lt, bool> operator<(const StaticVector<T, size>& lhs,
683 const StaticVector<T, size>& rhs) //
684 noexcept(noexcept(std::declval<const T&>() < std::declval<const T&>()))
685{
686 return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
687}
688
695template <typename T, std::size_t size>
696std::enable_if_t<HasOperator<T>::lt, bool> operator>(const StaticVector<T, size>& lhs,
697 const StaticVector<T, size>& rhs) //
698 noexcept(noexcept(std::declval<const T&>() < std::declval<const T&>()))
699{
700 return std::lexicographical_compare(rhs.begin(), rhs.end(), lhs.begin(), lhs.end());
701}
702
706template <typename T, std::size_t size>
707[[nodiscard]] Span<const T> makeConstSpan(const StaticVector<T, size>& vector) noexcept
708{
709 return makeConstSpan(vector.data(), vector.size());
710}
711
713
714} // namespace sen
715
716//----------------------------------------------------------------------------------------------------------------------
717// Inline implementation
718//----------------------------------------------------------------------------------------------------------------------
719
720// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
721#define SEN_VECTOR_TRY(...) \
722 { \
723 auto res = __VA_ARGS__; \
724 if (res.isError()) \
725 { \
726 return Err(res.getError()); \
727 } \
728 }
729
730namespace sen
731{
732
733template <typename T>
735 const T& u) noexcept(nothrowCopyCons)
736{
737 if (n > capacity())
738 {
740 }
741
742 // clear and insert the elements at the beginning
743 clear();
744 return insert(begin(), n, u);
745}
746
747template <typename T>
748inline typename StaticVectorBase<T>::Maybe StaticVectorBase<T>::assign(const std::initializer_list<T>& list) noexcept(
750{
751 if (list.size() > capacity())
752 {
754 }
755
756 clear();
757 return insert(begin(), list.begin(), list.end());
758}
759
760template <typename T>
761inline typename StaticVectorBase<T>::Maybe StaticVectorBase<T>::assign(std::initializer_list<T>&& list) noexcept(
763{
764 if (list.size() > capacity())
765 {
767 }
768
769 // clear and move-insert the elements at the beginning
770 clear();
771 return move_insert(begin(), list.begin(), list.end());
772}
773
774template <typename T>
775template <class InputIt>
777 InputIt last) noexcept(nothrowCopyCons)
778{
779 // check capacity
780 if (last - first < 0)
781 {
783 }
784
785 if (static_cast<size_type>(last - first) > capacity())
786 {
788 }
789
790 // clear and insert the elements at the beginning
791 clear();
792 return insert(begin(), first, last);
793}
794
795template <typename T>
796// NOLINTNEXTLINE(readability-identifier-naming)
798{
799 if (full())
800 {
802 }
803 return emplace_back(std::move(value));
804}
805
806template <typename T>
807// NOLINTNEXTLINE(readability-identifier-naming)
809{
810 if (full())
811 {
813 }
814
815 return emplace_back(value);
816}
817
818template <typename T>
819// NOLINTNEXTLINE(readability-identifier-naming)
821{
822 static_assert(std::is_default_constructible<T>::value,
823 "this version of push_back requires a default constructible type");
824
825 if (full())
826 {
828 }
829 return emplace_back(T {});
830}
831
832template <typename T>
833template <typename... Args>
836 Args&&... args) noexcept(nothrowMoveCons)
837{
838 if (full())
839 {
841 }
842
843 // check that the position is valid
844 SEN_VECTOR_TRY(checkIteratorRange(position))
845
846 if (position == end())
847 {
848 std::ignore = emplace_back(std::forward<Args>(args)...); // not full
849 return Ok(position);
850 }
851
852 const auto previousEnd = end();
853
854 // move the back to a new extra place
855 std::ignore = emplace_back(std::move(back())); // not full
856
857 if (std::distance(position, previousEnd) != 1)
858 {
859 // move the rest of the elements to make room
860 std::move_backward(position, end() - 2, end() - 1); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
861
862 // destroy the element that was in position
863 std::destroy_at(position);
864 }
865
866 // place the new element in position
867 ::new (std::addressof(*position)) T(std::forward<Args>(args)...);
868
869 return Ok(position);
870}
871
872template <typename T>
873template <typename... Args>
875{
876 if (full())
877 {
879 }
880
881 // placement new at the end of the array
882 new (end()) T(std::forward<Args>(args)...);
883
884 // increase the size
885 internalSetSize(size() + 1);
886 return Ok();
887}
888
889template <typename T>
890// NOLINTNEXTLINE(readability-identifier-naming)
892{
893 if (empty())
894 {
896 }
897
898 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
899 auto ptr = end() - 1; // get the pointer to the last element
900 std::destroy_at(ptr); // do placement delete
901 internalSetSize(size() - 1); // decrease the size
902 return Ok();
903}
904
905template <typename T>
909{
910 if (full())
911 {
913 }
914
915 SEN_VECTOR_TRY(checkIteratorRange(position))
916 return insert(position, static_cast<size_type>(1), x);
917}
918
919template <typename T>
920template <class InputIt>
922 InputIt first,
923 InputIt last) noexcept(nothrowCopyCons)
924{
925 // checks
926 SEN_VECTOR_TRY(checkIteratorRange(position))
927 SEN_VECTOR_TRY(checkIteratorPair(first, last))
928
929 // check if we would be inserting beyond the capacity
930 if (size() + static_cast<size_type>(last - first) > capacity())
931 {
933 }
934
935 const size_t insertN = std::distance(first, last);
936 const size_t insertBegin = std::distance(begin(), position);
937 const size_t insertEnd = insertBegin + insertN;
938
939 // move old data.
940 size_t copyOldN;
941 size_t constructOldN;
942 iterator pConstructOld;
943
944 auto pEnd = end();
945
946 // Elements after the position. insertBegin <= size() is checked above, so no count below wraps.
947 const size_t tailN = size() - insertBegin;
948
949 if (insertN > tailN)
950 {
951 copyOldN = 0;
952 constructOldN = tailN;
953 pConstructOld = begin() + insertEnd; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
954 }
955 else
956 {
957 copyOldN = tailN - insertN;
958 constructOldN = insertN;
959 pConstructOld = pEnd;
960 }
961
962 const size_t copyNewN = constructOldN;
963 const size_t constructNewN = insertN - copyNewN;
964
965 // move-construct old on the new (uninitialized memory area).
966 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
967 std::uninitialized_move(pEnd - constructOldN, pEnd, pConstructOld);
968
969 // move old to the remaining (already initialized) memory area.
970 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
971 std::move_backward(begin() + insertBegin, begin() + insertBegin + copyOldN, begin() + insertEnd + copyOldN);
972
973 // copy-construct new in the (uninitialized) memory area
974 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
975 std::uninitialized_copy(first + copyNewN, first + copyNewN + constructNewN, pEnd);
976
977 // copy new to the final location
978 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
979 std::copy(first, first + copyNewN, begin() + insertBegin);
980
981 internalSetSize(size_ + insertN);
982
983 return Ok(position);
984}
985
986template <typename T>
988 value_type&& x) noexcept(nothrowMoveCons)
989{
990 if (full())
991 {
993 }
994
995 SEN_VECTOR_TRY(checkIteratorRange(position))
996
997 if (position == end())
998 {
999 std::ignore = emplace_back(std::move(x)); // not full, so cannot fail
1000 }
1001 else
1002 {
1003 // move the back to a new extra place
1004 std::ignore = emplace_back(std::move(back())); // not full, so cannot fail
1005
1006 // move affected range one position
1007 std::move_backward(position, end() - 2, end() - 1); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1008
1009 // move our value into the desired position
1010 *position = std::move(x);
1011 }
1012
1013 return Ok(position);
1014}
1015
1016template <typename T>
1019 const T& x) noexcept(nothrowCopyCons)
1020{
1021 SEN_VECTOR_TRY(checkIteratorRange(position))
1022
1023 if (const auto newSize = size() + n; newSize > capacity())
1024 {
1026 }
1027
1028 if (n == 0U)
1029 {
1030 return Ok(position);
1031 }
1032
1033 const size_t insertN = n;
1034 const size_t insertBegin = std::distance(begin(), position);
1035 const size_t insertEnd = insertBegin + insertN;
1036
1037 // copy old data.
1038 size_t copyOldN;
1039 size_t constructOldN;
1040 iterator pConstructOld;
1041
1042 auto pEnd = end();
1043
1044 // Elements after the position. insertBegin <= size() is checked above, so no count below wraps.
1045 const size_t tailN = size() - insertBegin;
1046
1047 if (insertN > tailN)
1048 {
1049 copyOldN = 0;
1050 constructOldN = tailN;
1051 pConstructOld = begin() + insertEnd; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1052 }
1053 else
1054 {
1055 copyOldN = tailN - insertN;
1056 constructOldN = insertN;
1057 pConstructOld = pEnd;
1058 }
1059
1060 size_t copyNewN = constructOldN;
1061 size_t constructNewN = insertN - copyNewN;
1062
1063 // move-construct old on the new (uninitialized memory area).
1064 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1065 std::uninitialized_move(static_cast<iterator>(pEnd - constructOldN), pEnd, pConstructOld);
1066
1067 // move old to the remaining (already initialized) memory area.
1068 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1069 std::move_backward(begin() + insertBegin, begin() + insertBegin + copyOldN, begin() + insertEnd + copyOldN);
1070
1071 // construct new in the (uninitialized) memory area.
1072 std::uninitialized_fill_n(pEnd, constructNewN, x);
1073
1074 // copy new n values of T
1075 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1076 std::fill_n(begin() + insertBegin, copyNewN, x);
1077
1078 internalSetSize(size() + n);
1079
1080 return Ok(position);
1081}
1082
1083template <typename T>
1086 std::initializer_list<T> list) noexcept(nothrowCopyCons)
1087{
1088 SEN_VECTOR_TRY(checkIteratorRange(position))
1089 return insert(position, list.begin(), list.end());
1090}
1091
1092template <typename T>
1093template <class InputIt>
1095StaticVectorBase<T>::move_insert(iterator position, InputIt first, InputIt last) noexcept(nothrowMoveCons)
1096{
1097 // checks
1098 SEN_VECTOR_TRY(checkIteratorRange(position))
1099 SEN_VECTOR_TRY(checkIteratorPair(first, last))
1100
1101 if (size() + static_cast<size_type>(last - first) > capacity())
1102 {
1104 }
1105
1106 const size_t insertN = std::distance(first, last);
1107 const size_t insertBegin = std::distance(begin(), position);
1108 const size_t insertEnd = insertBegin + insertN;
1109
1110 // move old data.
1111 size_t moveOldN;
1112 size_t constructOldN;
1113 iterator pConstructOld;
1114 auto pEnd = end();
1115
1116 // Elements after the position. insertBegin <= size() is checked above, so no count below wraps.
1117 const size_t tailN = size() - insertBegin;
1118
1119 if (insertN > tailN)
1120 {
1121 moveOldN = 0;
1122 constructOldN = tailN;
1123 pConstructOld = begin() + insertEnd; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1124 }
1125 else
1126 {
1127 moveOldN = tailN - insertN;
1128 constructOldN = insertN;
1129 pConstructOld = pEnd;
1130 }
1131
1132 const size_t copyNewN = constructOldN;
1133 const size_t constructNewN = insertN - copyNewN;
1134
1135 // move-construct old on the new (uninitialized memory area).
1136 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1137 std::uninitialized_move(pEnd - constructOldN, pEnd, pConstructOld);
1138
1139 // move old to the remaining (already initialized) memory area.
1140 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1141 std::move_backward(begin() + insertBegin, begin() + insertBegin + moveOldN, begin() + insertEnd + moveOldN);
1142
1143 // move-construct new in the (uninitialized) memory area
1144 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1145 std::uninitialized_move(first + copyNewN, first + copyNewN + constructNewN, pEnd);
1146
1147 // move new to the final location
1148 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1149 std::move(first, first + copyNewN, begin() + insertBegin);
1150
1151 internalSetSize(size_ + insertN);
1152
1153 return Ok(position);
1154}
1155
1156template <typename T>
1158 const T& value) noexcept(nothrowCopyAndDes)
1159{
1160 static_assert(std::is_nothrow_copy_constructible<T>::value, "T is not supported");
1161
1162 // do nothing if the size is already the same
1163 if (newSize == size())
1164 {
1165 return Ok();
1166 }
1167
1168 if (newSize > capacity())
1169 {
1171 }
1172
1173 if (newSize > size())
1174 {
1175 // insert copies of value at the end
1176 return insert(end(), newSize - size(), value);
1177 }
1178
1179 // remove elements from the end
1180 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1181 return erase(end() - (size() - newSize), end());
1182}
1183
1184template <typename T>
1187{
1188 // do nothing if the size is already the same
1189 if (newSize == size())
1190 {
1191 return Ok();
1192 }
1193
1194 if (newSize > capacity())
1195 {
1197 }
1198
1199 if (newSize > size())
1200 {
1201 return emplaceMultiple(newSize - size());
1202 }
1203
1204 // remove elements from the end
1205 return erase(end() - (size() - newSize), end()); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1206}
1207
1208template <typename T>
1210 StaticVectorBase::iterator position) noexcept(nothrowDes)
1211{
1212 SEN_VECTOR_TRY(checkIteratorRange(position))
1213
1214 // move elements from [position + 1, end) to position
1215 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1216 std::move(position + 1, end(), position);
1217
1218 // destroy the last element
1219 auto ptr = end() - 1; // get the pointer to the last element NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1220 std::destroy_at(ptr); // do placement delete
1221 internalSetSize(size() - 1);
1222 return Ok(position);
1223}
1224
1225template <typename T>
1229{
1230 SEN_VECTOR_TRY(checkIteratorPair(first, last))
1231 SEN_VECTOR_TRY(checkIteratorRange(first))
1232 SEN_VECTOR_TRY(checkIteratorRange(last))
1233
1234 if (first == last)
1235 {
1236 return Ok(first);
1237 }
1238
1239 if (first == begin() && last == end())
1240 {
1241 clear();
1242 }
1243 else
1244 {
1245 // move the remaining elements on top of the erased range
1246 std::move(last, end(), first);
1247
1248 // destroy the elements left over at the end.
1249 const auto nDelete = std::distance(first, last);
1250 std::destroy(end() - nDelete, end()); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1251
1252 internalSetSize(size() - nDelete);
1253 }
1254
1255 return Ok(first);
1256}
1257
1258template <typename T>
1259inline typename StaticVectorBase<T>::Maybe StaticVectorBase<T>::emplaceMultiple(StaticVectorBase::size_type n) noexcept(
1260 nothrowDefaultCons)
1261{
1262 const size_type newSize = size() + n;
1263 SEN_VECTOR_CHECK(newSize <= capacity(), expect);
1264
1265 while (newSize != size())
1266 {
1267 // cannot overflow as newSize != size() && newSize <= capacity
1268 std::ignore = emplace_back();
1269 }
1270
1271 return Ok();
1272}
1273
1274template <typename T>
1275template <typename Iterator>
1276inline typename StaticVectorBase<T>::Maybe StaticVectorBase<T>::checkIteratorRange(Iterator itr) noexcept
1277{
1278 if (itr >= begin() && itr <= end())
1279 {
1280 return Ok();
1281 }
1282
1284}
1285
1286template <typename T>
1287template <typename IteratorA, typename IteratorB>
1288inline typename StaticVectorBase<T>::Maybe StaticVectorBase<T>::checkIteratorPair(IteratorA first,
1289 IteratorB last) noexcept
1290{
1291 if (first > last)
1292 {
1294 }
1295 return Ok();
1296}
1297
1298template <typename T>
1299inline void StaticVectorBase<T>::internalSetSize(std::size_t newSize) noexcept
1300{
1301 SEN_VECTOR_CHECK(newSize <= capacity(), expect); // newSize out-of-bounds [0, Capacity)
1302 size_ = newSize;
1303}
1304
1305template <typename T>
1306template <class InputIt>
1307inline void StaticVectorBase<T>::internalDestroy(InputIt first, InputIt last) noexcept(nothrowDes)
1308{
1309 SEN_VECTOR_CHECK(first >= data(), expect);
1310 SEN_VECTOR_CHECK(first <= end(), expect);
1311 SEN_VECTOR_CHECK(last >= data(), expect);
1312 SEN_VECTOR_CHECK(last <= end(), expect);
1313
1314 for (; first != last; ++first) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1315 {
1316 std::destroy_at(first);
1317 }
1318}
1319
1320// StaticVector
1321
1322template <typename T, std::size_t c>
1323inline StaticVector<T, c>::StaticVector(std::size_t n) noexcept: StaticVectorBase<T>(c, &data_)
1324{
1325 auto result = this->resize(n);
1326 SEN_VECTOR_CHECK(result.isOk(), assert);
1327 std::ignore = result;
1328}
1329
1330template <typename T, std::size_t c>
1331inline StaticVector<T, c>::StaticVector(std::size_t n, const T& value) noexcept(Base::nothrowCopyCons)
1332 : StaticVectorBase<T>(c, &data_)
1333{
1334 auto result = this->resize(n, value);
1335 SEN_VECTOR_CHECK(result.isOk(), assert);
1336 std::ignore = result;
1337}
1338
1339template <typename T, std::size_t c>
1340inline StaticVector<T, c>::StaticVector(std::initializer_list<T> list) noexcept(Base::nothrowCopyCons)
1341 : StaticVectorBase<T>(c, &data_)
1342{
1343 auto result = this->assign(std::move(list));
1344 SEN_VECTOR_CHECK(result.isOk(), assert);
1345 std::ignore = result;
1346}
1347
1348template <typename T, std::size_t c>
1349template <class InputIt>
1350inline StaticVector<T, c>::StaticVector(InputIt first, InputIt last) noexcept(Base::nothrowCopyCons)
1351 : StaticVectorBase<T>(c, &data_)
1352{
1353 auto result = this->assign(first, last);
1354 SEN_VECTOR_CHECK(result.isOk(), assert);
1355 std::ignore = result;
1356}
1357
1358template <typename T, std::size_t c>
1360 : StaticVectorBase<T>(c, &data_)
1361{
1362 auto result = this->insert(this->begin(), other.begin(), other.end());
1363 SEN_VECTOR_CHECK(result.isOk(), assert);
1364 std::ignore = result;
1365}
1366
1367template <typename T, std::size_t c>
1369{
1370 auto result = this->move_insert(this->begin(), other.begin(), other.end());
1371 SEN_VECTOR_CHECK(result.isOk(), assert);
1372 std::ignore = result;
1373 other.internalSetSize(0U);
1374}
1375
1376template <typename T, std::size_t c>
1378{
1379 if (this != &other)
1380 {
1381 // clear and insert the elements at the beginning
1382 this->clear();
1383 auto result = this->insert(this->begin(), other.begin(), other.end());
1384 SEN_VECTOR_CHECK(result.isOk(), assert);
1385 std::ignore = result;
1386 }
1387 return *this;
1388}
1389
1390template <typename T, std::size_t c>
1392{
1393 if (this != &other)
1394 {
1395 // clear and move-insert the elements at the beginning
1396 this->clear();
1397 auto result = this->move_insert(this->begin(), other.begin(), other.end());
1398 SEN_VECTOR_CHECK(result.isOk(), assert);
1399 std::ignore = result;
1400 other.internalSetSize(0U);
1401 }
1402 return *this;
1403}
1404
1405template <typename T, std::size_t c>
1406inline void StaticVector<T, c>::swap(StaticVector& other) noexcept
1407{
1408 StaticVector tmp = std::move(other);
1409 other = std::move(*this);
1410 (*this) = std::move(tmp);
1411}
1412
1413} // namespace sen
1414
1415#undef SEN_VECTOR_TRY
1416#undef SEN_VECTOR_CHECK
1417
1418#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
Contiguous view of elements of type T. Inspired by http://www.open-std.org/jtc1/sc22/wg21/docs/papers...
Definition span.h:34
const_reverse_iterator rbegin() const noexcept
Reverse iterator to the first element. Complexity: constant.
Definition static_vector.h:223
pointer data() noexcept
Direct access to the underlying storage. Complexity: constant.
Definition static_vector.h:142
virtual ~StaticVectorBase() noexcept
Definition static_vector.h:549
Result< void, StaticVectorError > Maybe
Definition static_vector.h:111
size_type maxSize() const noexcept
Max element count (same as capacity()). Complexity: constant.
Definition static_vector.h:131
static constexpr bool nothrowMoveCons
Definition static_vector.h:91
static constexpr bool nothrowDefaultConsAndDes
Definition static_vector.h:93
reverse_iterator rend() noexcept
Returns a reverse iterator to the element following the last element of the reversed vector....
Definition static_vector.h:229
pointer iterator
Definition static_vector.h:104
size_type capacity() const noexcept
Maximum number of elements that can be allocated in the storage. Complexity: constant.
Definition static_vector.h:127
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:203
static constexpr bool nothrowCopyCons
Definition static_vector.h:90
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:734
ptrdiff_t difference_type
Definition static_vector.h:98
void clear() noexcept(nothrowDes)
Clears the vector. This function destroys all the elements. Complexity: linear in size().
Definition static_vector.h:327
const_iterator cend() noexcept
Constant iterator to the element following the last element. Complexity: constant.
Definition static_vector.h:249
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:761
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:295
const_pointer const_iterator
Definition static_vector.h:105
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:315
Maybe resize(size_type newSize, const Value &value) noexcept(nothrowCopyAndDes)
Definition static_vector.h:1157
reverse_iterator rbegin() noexcept
Reverse iterator to the first element. Complexity: constant.
Definition static_vector.h:219
void internalSetSize(std::size_t newSize) noexcept
Changes the container size to newSize.
Definition static_vector.h:1299
const_reference operator[](size_type i) const noexcept
Gets the element at index i. Complexity: constant.
Definition static_vector.h:278
MaybeIterator insert(iterator position, const_reference x) noexcept(nothrowCopyCons)
Definition static_vector.h:906
bool empty() const noexcept
true if the container is empty. Complexity: constant
Definition static_vector.h:149
static constexpr bool nothrowCopyAndDes
Definition static_vector.h:92
Maybe emplace_back(Args &&... args) noexcept(//NOLINT(readability-identifier-naming) nothrowMoveCons)
Definition static_vector.h:874
Maybe pop_back() noexcept(nothrowDes)
Definition static_vector.h:891
Result< iterator, StaticVectorError > MaybeIterator
Definition static_vector.h:112
const_iterator cend() const noexcept
Constant iterator to the element following the last element. Complexity: constant.
Definition static_vector.h:253
StaticVectorBase(std::size_t capacity, void *dataPtr) noexcept
Definition static_vector.h:545
MaybeIterator emplace(iterator position, Args &&... args) noexcept(nothrowMoveCons)
Definition static_vector.h:834
std::reverse_iterator< iterator > reverse_iterator
Definition static_vector.h:107
MaybeIterator move_insert(iterator position, InputIt first, InputIt last) noexcept(nothrowMoveCons)
Definition static_vector.h:1095
const_iterator cbegin() noexcept
Returns a const iterator to the first element of the vector. If the vector is empty,...
Definition static_vector.h:240
T && rvalue_reference
Definition static_vector.h:103
T const & const_reference
Definition static_vector.h:102
MaybeIterator erase(iterator position) noexcept(nothrowDes)
Definition static_vector.h:1209
std::size_t size_type
Definition static_vector.h:106
Maybe push_back(const T &value) noexcept(nothrowCopyCons)
Appends a value to the end of the container. Complexity: constant.
Definition static_vector.h:808
StaticVectorBase(const StaticVectorBase &) noexcept=delete
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition static_vector.h:108
reference back() noexcept
The element at the end of the container. Calling back on an empty container is undefined....
Definition static_vector.h:305
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:245
iterator end() noexcept
Iterator to the element following the last element. Complexity: constant.
Definition static_vector.h:207
reference front() noexcept
The element at the beginning of the container. Calling front on an empty container is undefined....
Definition static_vector.h:285
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:235
bool full() const noexcept
true if the container is full. Complexity: constant
Definition static_vector.h:153
Maybe push_back() noexcept(nothrowDefaultCons)
Appends a value (default constructed) to the end of the container. Complexity: constant.
Definition static_vector.h:820
T & reference
Definition static_vector.h:101
reference operator[](size_type i) noexcept
Gets the element at index i. Complexity: constant.
Definition static_vector.h:266
T const * const_pointer
Definition static_vector.h:100
const_iterator end() const noexcept
Iterator to the element following the last element. Complexity: constant. NOLINTNEXTLINE(cppcoreguide...
Definition static_vector.h:215
const_pointer data() const noexcept
Direct access to the underlying storage. Complexity: constant.
Definition static_vector.h:135
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:198
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:776
T * pointer
Definition static_vector.h:99
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:797
static constexpr bool nothrowDes
Definition static_vector.h:88
static constexpr bool nothrowDefaultCons
Definition static_vector.h:89
Maybe assign(const std::initializer_list< T > &list) noexcept(nothrowCopyCons)
Initializer list assignment. Complexity: linear in list.size().
Definition static_vector.h:748
void internalDestroy(InputIt first, InputIt last) noexcept(nothrowDes)
Definition static_vector.h:1307
size_type size() const noexcept
Element count. Complexity: constant.
Definition static_vector.h:123
T value_type
Definition static_vector.h:97
Stack-based, exception-free and resizable vector with fixed-capacity.
Definition static_vector.h:578
Base & base() noexcept
This object, as its base class.
Definition static_vector.h:634
StaticVector & operator=(const StaticVector &other) noexcept(Base::nothrowCopyCons)
Copy assignment. Complexity: linear in other.size().
Definition static_vector.h:1377
~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:637
static constexpr std::size_t staticCapacity
Definition static_vector.h:580
void swap(StaticVector &other) noexcept
Definition static_vector.h:1406
StaticVector() noexcept
Creates an empty vector.
Definition static_vector.h:588
StaticVectorBase< T > Base
Definition static_vector.h:584
impl::Err< void > Err() noexcept
If E is void, use the void specialization of Err.
Definition result.h:442
impl::Ok< void > Ok() noexcept
If T is void, use the void specialization of Ok.
Definition result.h:437
std::enable_if_t< HasOperator< T >::lt, bool > operator<(const StaticVector< T, size > &lhs, const StaticVector< T, size > &rhs) noexcept(noexcept(std::declval< const T & >()< std::declval< const T & >()))
Lexicographically compares two StaticVector objects.
Definition static_vector.h:682
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:64
constexpr Span< const T > makeConstSpan(const T *ptr, std::size_t size) noexcept
Takes in a type that can be passed to a contiguous range and returns a Span. The element types will b...
Definition span.h:248
std::enable_if_t< HasOperator< T >::lt, bool > operator>(const StaticVector< T, size > &lhs, const StaticVector< T, size > &rhs) noexcept(noexcept(std::declval< const T & >()< std::declval< const T & >()))
Lexicographically compares two StaticVector objects.
Definition static_vector.h:696
@ empty
Invalid operation on an empty vector.
Definition static_vector.h:67
@ badRange
The range is invalid.
Definition static_vector.h:66
@ full
The vector cannot hold more elements.
Definition static_vector.h:65
Definition assert.h:19
STL namespace.
#define SEN_VECTOR_TRY(...)
Definition static_vector.h:721
#define SEN_VECTOR_CHECK(expr, type)
Definition static_vector.h:24