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#include <utility>
20
21namespace sen
22{
23
24namespace impl
25{
26
28template <typename T, typename Range, typename Index>
29inline T& index(Range&& range, Index&& i) noexcept
30{
31 // check that the index is within the range
32 SEN_EXPECT(static_cast<ptrdiff_t>(i) < (std::end(range) - std::begin(range)));
33
34 // go to the beginning of the range and fetch the element at index i
35 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
36 return std::begin(std::forward<Range>(range))[std::forward<Index>(i)];
37}
38
40template <typename T, typename Range, typename Index>
41inline const T& cindex(Range&& range, Index&& i) noexcept
42{
43 // check that the index is within the range
44 SEN_EXPECT(static_cast<ptrdiff_t>(i) < (std::end(range) - std::begin(range)));
45
46 // go to the beginning of the range and fetch the element at index i
47 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
48 return std::begin(std::forward<Range>(range))[std::forward<Index>(i)];
49}
50
51} // namespace impl
52
55
57enum class StaticVectorError : std::uint8_t
58{
62};
63
78template <typename T>
80{
81public: // checks
82 static constexpr bool nothrowDes = std::is_nothrow_destructible_v<T>;
83 static constexpr bool nothrowDefaultCons = std::is_nothrow_default_constructible_v<T>;
84 static constexpr bool nothrowCopyCons = std::is_nothrow_copy_constructible_v<T>;
85 static constexpr bool nothrowMoveCons = std::is_nothrow_move_constructible_v<T>;
86 static constexpr bool nothrowCopyAndDes = nothrowDes && nothrowCopyCons;
88
89 // the following types allow compatibility with stdlib algorithms
90public:
91 using value_type = T; // NOLINT(readability-identifier-naming)
92 using difference_type = ptrdiff_t; // NOLINT(readability-identifier-naming)
93 using pointer = T*; // NOLINT(readability-identifier-naming)
94 using const_pointer = T const*; // NOLINT(readability-identifier-naming)
95 using reference = T&; // NOLINT(readability-identifier-naming)
96 using const_reference = T const&; // NOLINT(readability-identifier-naming)
97 using rvalue_reference = T&&; // NOLINT(readability-identifier-naming)
98 using iterator = pointer; // NOLINT(readability-identifier-naming)
99 using const_iterator = const_pointer; // NOLINT(readability-identifier-naming)
100 using size_type = std::size_t; // NOLINT(readability-identifier-naming)
101 using reverse_iterator = std::reverse_iterator<iterator>; // NOLINT(readability-identifier-naming)
102 using const_reverse_iterator = std::reverse_iterator<const_iterator>; // NOLINT(readability-identifier-naming)
103
104public:
107
108public: // special members
109 StaticVectorBase(const StaticVectorBase&) noexcept = delete;
110 StaticVectorBase(StaticVectorBase&&) noexcept = delete;
111 StaticVectorBase& operator=(StaticVectorBase&&) noexcept = delete;
112 StaticVectorBase& operator=(const StaticVectorBase&) noexcept = delete;
113
114public: // getters.
117 [[nodiscard]] size_type size() const noexcept { return size_; }
118
121 [[nodiscard]] size_type capacity() const noexcept { return capacity_; }
122
125 [[nodiscard]] size_type maxSize() const noexcept { return capacity(); }
126
129 [[nodiscard]] const_pointer data() const noexcept
130 {
131 return reinterpret_cast<const_pointer>(dataPtr_); // NOLINT NOSONAR
132 }
133
136 [[nodiscard]] pointer data() noexcept
137 {
138 return reinterpret_cast<pointer>(dataPtr_); // NOLINT NOSONAR
139 }
140
143 [[nodiscard]] bool empty() const noexcept { return size() == size_type {0U}; }
144
147 [[nodiscard]] bool full() const noexcept { return size() == capacity(); }
148
149public: // assignment
158 [[nodiscard]] Maybe assign(size_type n, const T& u) noexcept(nothrowCopyCons);
159
167 [[nodiscard]] Maybe assign(const std::initializer_list<T>& list) noexcept(nothrowCopyCons);
168
176 [[nodiscard]] Maybe assign(std::initializer_list<T>&& list) noexcept(nothrowMoveCons);
177
185 template <class InputIt>
186 [[nodiscard]] Maybe assign(InputIt first, InputIt last) noexcept(nothrowCopyCons);
187
188public: // positional iterator accessors
192 [[nodiscard]] iterator begin() noexcept { return data(); }
193
197 [[nodiscard]] const_iterator begin() const noexcept { return data(); }
198
201 [[nodiscard]] iterator end() noexcept
202 {
203 return data() + size(); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
204 }
205
209 [[nodiscard]] const_iterator end() const noexcept { return data() + size(); }
210
213 [[nodiscard]] reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
214
217 [[nodiscard]] const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
218
223 [[nodiscard]] reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
224
229 [[nodiscard]] const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
230
234 [[nodiscard]] const_iterator cbegin() noexcept { return begin(); }
235
239 [[nodiscard]] const_iterator cbegin() const noexcept { return begin(); }
240
243 [[nodiscard]] const_iterator cend() noexcept { return end(); }
244
247 [[nodiscard]] const_iterator cend() const noexcept { return end(); }
248
249public: // index-based value accessors
260 [[nodiscard]] reference operator[](size_type i) noexcept { return impl::index<value_type>(*this, i); }
261
272 [[nodiscard]] const_reference operator[](size_type i) const noexcept { return impl::cindex<value_type>(*this, i); }
273
274public: // position-based value accessors
279 [[nodiscard]] reference front() noexcept
280 {
281 SEN_EXPECT(!empty());
282 return impl::index<value_type>(*this, 0U);
283 }
284
289 [[nodiscard]] const_reference front() const noexcept
290 {
291 SEN_EXPECT(!empty());
292 return impl::cindex<value_type>(*this, 0U);
293 }
294
299 [[nodiscard]] reference back() noexcept
300 {
301 SEN_EXPECT(!empty());
302 return impl::index<value_type>(*this, size() - 1);
303 }
304
309 [[nodiscard]] const_reference back() const noexcept
310 {
311 SEN_EXPECT(!empty());
312 return impl::cindex<value_type>(*this, size() - 1);
313 }
314
315public: // modifiers
321 void clear() noexcept(nothrowDes)
322 {
323 internalDestroyAll();
324 internalSetSize(0U);
325 }
326
333 Maybe push_back(T&& value) noexcept(nothrowMoveCons);
334
341 Maybe push_back(const T& value) noexcept(nothrowCopyCons);
342
350
363 template <typename... Args>
364 MaybeIterator emplace(iterator position, Args&&... args) noexcept(nothrowMoveCons);
365
378 template <typename... Args>
379 Maybe emplace_back(Args&&... args) noexcept( // NOLINT(readability-identifier-naming)
381
387 Maybe pop_back() noexcept(nothrowDes); // NOLINT(readability-identifier-naming)
388
389public: // insert overloads
399
409
419 MaybeIterator insert(iterator position, size_type n, const T& x) noexcept(nothrowCopyCons);
420
430 MaybeIterator insert(iterator position, std::initializer_list<T> list) noexcept(nothrowCopyCons);
431
443 template <class InputIt>
444 MaybeIterator insert(iterator position, InputIt first, InputIt last) noexcept(nothrowCopyCons);
445
457 template <class InputIt>
458 MaybeIterator move_insert(iterator position, // NOLINT(readability-identifier-naming)
459 InputIt first,
460 InputIt last) noexcept(nothrowMoveCons);
461
462public: // resizing
471 Maybe resize(size_type newSize, const T& value) noexcept(nothrowCopyAndDes);
472
481
482public: // erase
498
512
513private: // implementation details
516 [[nodiscard]] Maybe emplaceMultiple(size_type n) noexcept(nothrowDefaultCons);
517
519 template <typename Iterator>
520 [[nodiscard]] Maybe checkIteratorRange(Iterator itr) noexcept;
521
523 template <typename IteratorA, typename IteratorB>
524 [[nodiscard]] Maybe checkIteratorPair(IteratorA first, IteratorB last) noexcept;
525
530 template <class Itr>
531 void internalDestroy(Itr first, Itr last) noexcept(nothrowDes);
532
536 void internalDestroyAll() noexcept(nothrowDes) { internalDestroy(data(), end()); }
537
538protected:
539 StaticVectorBase(std::size_t capacity, void* dataPtr) noexcept: capacity_(capacity), dataPtr_(dataPtr)
540 {
541 SEN_EXPECT(dataPtr != nullptr);
542 }
543 virtual ~StaticVectorBase() noexcept { internalDestroyAll(); }
544
549 void internalSetSize(std::size_t newSize) noexcept;
550
551private:
552 std::size_t capacity_;
553 void* dataPtr_;
554 std::size_t size_ = 0U;
555};
556
570template <typename T, std::size_t s>
572{
573public:
574 static constexpr std::size_t staticCapacity = s;
575 static_assert(staticCapacity != 0U, "Vectors of no capacity are not supported");
576
577public:
579
580public:
582 StaticVector() noexcept: StaticVectorBase<T>(s, &data_) {}
583
586 explicit StaticVector(std::size_t n) noexcept;
587
590 StaticVector(std::size_t n, T const& value) noexcept(Base::nothrowCopyCons);
591
594 StaticVector(std::initializer_list<T> list) noexcept(Base::nothrowCopyCons);
595
598 template <class InputIt>
599 StaticVector(InputIt first, InputIt last) noexcept(Base::nothrowCopyCons);
600
603 StaticVector(const StaticVector& other) noexcept(Base::nothrowCopyCons);
604
608 StaticVector(StaticVector&& other) noexcept;
609
612 ~StaticVector() noexcept override = default;
613
616 StaticVector& operator=(const StaticVector& other) noexcept(Base::nothrowCopyCons);
617
621 StaticVector& operator=(StaticVector&& other) noexcept;
622
625 void swap(StaticVector& other) noexcept;
626
628 [[nodiscard]] Base& base() noexcept { return *this; }
629
631 [[nodiscard]] const Base& base() const noexcept { return *this; }
632
633private:
634 alignas(T) std::byte data_[sizeof(T) * s];
635};
636
637//--------------------------------------------------------------------------------------------------------------
638// Comparison operators
639//--------------------------------------------------------------------------------------------------------------
640
643template <typename T, std::size_t size>
644std::enable_if_t<HasOperator<T>::eq, bool> operator==(StaticVector<T, size> const& lhs,
645 StaticVector<T, size> const& rhs) noexcept
646{
647 if (lhs.size() != rhs.size())
648 {
649 return false;
650 }
651
652 return lhs.size() == 0 || std::equal(lhs.begin(), lhs.end(), rhs.begin(), std::equal_to<T> {});
653}
654
656template <typename T, std::size_t size>
657std::enable_if_t<HasOperator<T>::ne, bool> operator!=(StaticVector<T, size> const& lhs,
658 StaticVector<T, size> const& rhs) noexcept
659{
660 return !(lhs == rhs);
661}
662
664
665} // namespace sen
666
667//----------------------------------------------------------------------------------------------------------------------
668// Inline implementation
669//----------------------------------------------------------------------------------------------------------------------
670
671// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
672#define SEN_VECTOR_TRY(...) \
673 { \
674 auto res = __VA_ARGS__; \
675 if (res.isError()) \
676 { \
677 return Err(res.getError()); \
678 } \
679 }
680
681namespace sen
682{
683
684template <typename T>
686 const T& u) noexcept(nothrowCopyCons)
687{
688 if (n > capacity())
689 {
691 }
692
693 // clear and insert the elements at the beginning
694 clear();
695 return insert(begin(), n, u);
696}
697
698template <typename T>
699inline typename StaticVectorBase<T>::Maybe StaticVectorBase<T>::assign(const std::initializer_list<T>& list) noexcept(
701{
702 if (list.size() > capacity())
703 {
705 }
706
707 clear();
708 return insert(begin(), list.begin(), list.end());
709}
710
711template <typename T>
712inline typename StaticVectorBase<T>::Maybe StaticVectorBase<T>::assign(std::initializer_list<T>&& list) noexcept(
714{
715 if (list.size() > capacity())
716 {
718 }
719
720 // clear and move-insert the elements at the beginning
721 clear();
722 return move_insert(begin(), list.begin(), list.end());
723}
724
725template <typename T>
726template <class InputIt>
728 InputIt last) noexcept(nothrowCopyCons)
729{
730 // check capacity
731 if (last - first < 0)
732 {
734 }
735
736 if (static_cast<size_type>(last - first) > capacity())
737 {
739 }
740
741 // clear and insert the elements at the beginning
742 clear();
743 return insert(begin(), first, last);
744}
745
746template <typename T>
747// NOLINTNEXTLINE(readability-identifier-naming)
749{
750 if (full())
751 {
753 }
754 return emplace_back(std::move(value));
755}
756
757template <typename T>
758// NOLINTNEXTLINE(readability-identifier-naming)
760{
761 if (full())
762 {
764 }
765
766 return emplace_back(value);
767}
768
769template <typename T>
770// NOLINTNEXTLINE(readability-identifier-naming)
772{
773 static_assert(std::is_default_constructible<T>::value,
774 "this version of push_back requires a default constructible type");
775
776 if (full())
777 {
779 }
780 return emplace_back(T {});
781}
782
783template <typename T>
784template <typename... Args>
787 Args&&... args) noexcept(nothrowMoveCons)
788{
789 if (full())
790 {
792 }
793
794 // check that the position is valid
795 SEN_VECTOR_TRY(checkIteratorRange(position))
796
797 if (position == end())
798 {
799 std::ignore = emplace_back(std::forward<Args>(args)...); // not full
800 return Ok(position);
801 }
802
803 const auto previousEnd = end();
804
805 // move the back to a new extra place
806 std::ignore = emplace_back(std::move(back())); // not full
807
808 if (std::distance(position, previousEnd) != 1)
809 {
810 // move the rest of the elements to make room
811 std::move_backward(position, end() - 2, end() - 1); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
812
813 // destroy the element that was in position
814 std::destroy_at(position);
815 }
816
817 // place the new element in position
818 ::new (std::addressof(*position)) T(std::forward<Args>(args)...);
819
820 return Ok(position);
821}
822
823template <typename T>
824template <typename... Args>
826{
827 if (full())
828 {
830 }
831
832 // placement new at the end of the array
833 new (end()) T(std::forward<Args>(args)...);
834
835 // increase the size
836 internalSetSize(size() + 1);
837 return Ok();
838}
839
840template <typename T>
841// NOLINTNEXTLINE(readability-identifier-naming)
843{
844 if (empty())
845 {
847 }
848
849 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
850 auto ptr = end() - 1; // get the pointer to the last element
851 std::destroy_at(ptr); // do placement delete
852 internalSetSize(size() - 1); // decrease the size
853 return Ok();
854}
855
856template <typename T>
860{
861 if (full())
862 {
864 }
865
866 SEN_VECTOR_TRY(checkIteratorRange(position))
867 return insert(position, static_cast<size_type>(1), x);
868}
869
870template <typename T>
871template <class InputIt>
873 InputIt first,
874 InputIt last) noexcept(nothrowCopyCons)
875{
876 // checks
877 SEN_VECTOR_TRY(checkIteratorRange(position))
878 SEN_VECTOR_TRY(checkIteratorPair(first, last))
879
880 // check if we would be inserting beyond the capacity
881 if (size() + static_cast<size_type>(last - first) > capacity())
882 {
884 }
885
886 const size_t insertN = std::distance(first, last);
887 const size_t insertBegin = std::distance(begin(), position);
888 const size_t insertEnd = insertBegin + insertN;
889
890 // move old data.
891 size_t copyOldN;
892 size_t constructOldN;
893 iterator pConstructOld;
894
895 auto pEnd = end();
896
897 if (insertEnd > size())
898 {
899 copyOldN = 0;
900 constructOldN = size() - insertBegin;
901 pConstructOld = begin() + insertEnd; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
902 }
903 else
904 {
905 copyOldN = size() - insertBegin - insertN;
906 constructOldN = insertN;
907 pConstructOld = pEnd;
908 }
909
910 const size_t copyNewN = constructOldN;
911 const size_t constructNewN = insertN - copyNewN;
912
913 // move-construct old on the new (uninitialized memory area).
914 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
915 std::uninitialized_move(pEnd - constructOldN, pEnd, pConstructOld);
916
917 // move old to the remaining (already initialized) memory area.
918 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
919 std::move_backward(begin() + insertBegin, begin() + insertBegin + copyOldN, begin() + insertEnd + copyOldN);
920
921 // copy-construct new in the (uninitialized) memory area
922 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
923 std::uninitialized_copy(first + copyNewN, first + copyNewN + constructNewN, pEnd);
924
925 // copy new to the final location
926 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
927 std::copy(first, first + copyNewN, begin() + insertBegin);
928
929 internalSetSize(size_ + insertN);
930
931 return Ok(position);
932}
933
934template <typename T>
936 value_type&& x) noexcept(nothrowMoveCons)
937{
938 if (full())
939 {
941 }
942
943 SEN_VECTOR_TRY(checkIteratorRange(position))
944
945 if (position == end())
946 {
947 std::ignore = emplace_back(std::move(x)); // not full, so cannot fail
948 }
949 else
950 {
951 // move the back to a new extra place
952 std::ignore = emplace_back(std::move(back())); // not full, so cannot fail
953
954 // move affected range one position
955 std::move_backward(position, end() - 2, end() - 1); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
956
957 // move our value into the desired position
958 *position = std::move(x);
959 }
960
961 return Ok(position);
962}
963
964template <typename T>
967 const T& x) noexcept(nothrowCopyCons)
968{
969 SEN_VECTOR_TRY(checkIteratorRange(position))
970
971 if (const auto newSize = size() + n; newSize > capacity())
972 {
974 }
975
976 if (n == 0U)
977 {
978 return Ok(position);
979 }
980
981 const size_t insertN = n;
982 const size_t insertBegin = std::distance(begin(), position);
983 const size_t insertEnd = insertBegin + insertN;
984
985 // copy old data.
986 size_t copyOldN;
987 size_t constructOldN;
988 iterator pConstructOld;
989
990 auto pEnd = end();
991
992 if (insertEnd > size())
993 {
994 copyOldN = 0;
995 constructOldN = size() - insertBegin;
996 pConstructOld = begin() + insertEnd; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
997 }
998 else
999 {
1000 copyOldN = size() - insertBegin - insertN;
1001 constructOldN = insertN;
1002 pConstructOld = pEnd;
1003 }
1004
1005 size_t copyNewN = constructOldN;
1006 size_t constructNewN = insertN - copyNewN;
1007
1008 // move-construct old on the new (uninitialized memory area).
1009 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1010 std::uninitialized_move(static_cast<iterator>(pEnd - constructOldN), pEnd, pConstructOld);
1011
1012 // move old to the remaining (already initialized) memory area.
1013 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1014 std::move_backward(begin() + insertBegin, begin() + insertBegin + copyOldN, begin() + insertEnd + copyOldN);
1015
1016 // construct new in the (uninitialized) memory area.
1017 std::uninitialized_fill_n(pEnd, constructNewN, x);
1018
1019 // copy new n values of T
1020 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1021 std::fill_n(begin() + insertBegin, copyNewN, x);
1022
1023 internalSetSize(size() + n);
1024
1025 return Ok(position);
1026}
1027
1028template <typename T>
1031 std::initializer_list<T> list) noexcept(nothrowCopyCons)
1032{
1033 SEN_VECTOR_TRY(checkIteratorRange(position))
1034 return insert(position, list.begin(), list.end());
1035}
1036
1037template <typename T>
1038template <class InputIt>
1040StaticVectorBase<T>::move_insert(iterator position, InputIt first, InputIt last) noexcept(nothrowMoveCons)
1041{
1042 // checks
1043 SEN_VECTOR_TRY(checkIteratorRange(position))
1044 SEN_VECTOR_TRY(checkIteratorPair(first, last))
1045
1046 if (size() + static_cast<size_type>(last - first) > capacity())
1047 {
1049 }
1050
1051 const size_t insertN = std::distance(first, last);
1052 const size_t insertBegin = std::distance(begin(), position);
1053 const size_t insertEnd = insertBegin + insertN;
1054
1055 // move old data.
1056 size_t moveOldN;
1057 size_t constructOldN;
1058 iterator pConstructOld;
1059 auto pEnd = end();
1060
1061 if (insertEnd > size())
1062 {
1063 moveOldN = 0;
1064 constructOldN = size() - insertBegin; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1065 pConstructOld = begin() + insertEnd; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1066 }
1067 else
1068 {
1069 moveOldN = size() - insertBegin - insertN;
1070 constructOldN = insertN;
1071 pConstructOld = pEnd;
1072 }
1073
1074 const size_t copyNewN = constructOldN;
1075 const size_t constructNewN = insertN - copyNewN;
1076
1077 // move-construct old on the new (uninitialized memory area).
1078 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1079 std::uninitialized_move(pEnd - constructOldN, pEnd, pConstructOld);
1080
1081 // move old to the remaining (already initialized) memory area.
1082 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1083 std::move_backward(begin() + insertBegin, begin() + insertBegin + moveOldN, begin() + insertEnd + moveOldN);
1084
1085 // move-construct new in the (uninitialized) memory area
1086 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1087 std::uninitialized_move(first + copyNewN, first + copyNewN + constructNewN, pEnd);
1088
1089 // move new to the final location
1090 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1091 std::move(first, first + copyNewN, begin() + insertBegin);
1092
1093 internalSetSize(size_ + insertN);
1094
1095 return Ok(position);
1096}
1097
1098template <typename T>
1100 const T& value) noexcept(nothrowCopyAndDes)
1101{
1102 static_assert(std::is_nothrow_copy_constructible<T>::value, "T is not supported");
1103
1104 // do nothing if the size is already the same
1105 if (newSize == size())
1106 {
1107 return Ok();
1108 }
1109
1110 if (newSize > capacity())
1111 {
1113 }
1114
1115 if (newSize > size())
1116 {
1117 // insert copies of value at the end
1118 return insert(end(), newSize - size(), value);
1119 }
1120
1121 // remove elements from the end
1122 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1123 return erase(end() - (size() - newSize), end());
1124}
1125
1126template <typename T>
1129{
1130 // do nothing if the size is already the same
1131 if (newSize == size())
1132 {
1133 return Ok();
1134 }
1135
1136 if (newSize > capacity())
1137 {
1139 }
1140
1141 if (newSize > size())
1142 {
1143 return emplaceMultiple(newSize - size());
1144 }
1145
1146 // remove elements from the end
1147 return erase(end() - (size() - newSize), end()); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1148}
1149
1150template <typename T>
1152 StaticVectorBase::iterator position) noexcept(nothrowDes)
1153{
1154 SEN_VECTOR_TRY(checkIteratorRange(position))
1155
1156 // move elements from [position + 1, end) to position
1157 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1158 std::move(position + 1, end(), position);
1159
1160 // destroy the last element
1161 auto ptr = end() - 1; // get the pointer to the last element NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1162 std::destroy_at(ptr); // do placement delete
1163 internalSetSize(size() - 1);
1164 return Ok(position);
1165}
1166
1167template <typename T>
1171{
1172 SEN_VECTOR_TRY(checkIteratorPair(first, last))
1173 SEN_VECTOR_TRY(checkIteratorRange(first))
1174 SEN_VECTOR_TRY(checkIteratorRange(last))
1175
1176 if (first == last)
1177 {
1178 return Ok(first);
1179 }
1180
1181 if (first == begin() && last == end())
1182 {
1183 clear();
1184 }
1185 else
1186 {
1187 // move the remaining elements on top of the erased range
1188 std::move(last, end(), first);
1189
1190 // destroy the elements left over at the end.
1191 const auto nDelete = std::distance(first, last);
1192 std::destroy(end() - nDelete, end()); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1193
1194 internalSetSize(size() - nDelete);
1195 }
1196
1197 return Ok(first);
1198}
1199
1200template <typename T>
1201inline typename StaticVectorBase<T>::Maybe StaticVectorBase<T>::emplaceMultiple(StaticVectorBase::size_type n) noexcept(
1202 nothrowDefaultCons)
1203{
1204 const size_type newSize = size() + n;
1205 SEN_EXPECT(newSize <= capacity());
1206
1207 while (newSize != size())
1208 {
1209 // cannot overflow as newSize != size() && newSize <= capacity
1210 std::ignore = emplace_back();
1211 }
1212
1213 return Ok();
1214}
1215
1216template <typename T>
1217template <typename Iterator>
1218inline typename StaticVectorBase<T>::Maybe StaticVectorBase<T>::checkIteratorRange(Iterator itr) noexcept
1219{
1220 if (itr >= begin() && itr <= end())
1221 {
1222 return Ok();
1223 }
1224
1226}
1227
1228template <typename T>
1229template <typename IteratorA, typename IteratorB>
1230inline typename StaticVectorBase<T>::Maybe StaticVectorBase<T>::checkIteratorPair(IteratorA first,
1231 IteratorB last) noexcept
1232{
1233 if (first > last)
1234 {
1236 }
1237 return Ok();
1238}
1239
1240template <typename T>
1241inline void StaticVectorBase<T>::internalSetSize(std::size_t newSize) noexcept
1242{
1243 SEN_EXPECT(newSize <= capacity()); // newSize out-of-bounds [0, Capacity)
1244 size_ = newSize;
1245}
1246
1247template <typename T>
1248template <class InputIt>
1249inline void StaticVectorBase<T>::internalDestroy(InputIt first, InputIt last) noexcept(nothrowDes)
1250{
1251 SEN_EXPECT(first >= data());
1252 SEN_EXPECT(first <= end());
1253 SEN_EXPECT(last >= data());
1254 SEN_EXPECT(last <= end());
1255
1256 for (; first != last; ++first) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1257 {
1258 std::destroy_at(first);
1259 }
1260}
1261
1262// StaticVector
1263
1264template <typename T, std::size_t c>
1265inline StaticVector<T, c>::StaticVector(std::size_t n) noexcept: StaticVectorBase<T>(c, &data_)
1266{
1267 auto result = this->resize(n);
1268 SEN_ASSERT(result.isOk());
1269 std::ignore = result;
1270}
1271
1272template <typename T, std::size_t c>
1273inline StaticVector<T, c>::StaticVector(std::size_t n, const T& value) noexcept(Base::nothrowCopyCons)
1274 : StaticVectorBase<T>(c, &data_)
1275{
1276 auto result = this->resize(n, value);
1277 SEN_ASSERT(result.isOk());
1278 std::ignore = result;
1279}
1280
1281template <typename T, std::size_t c>
1282inline StaticVector<T, c>::StaticVector(std::initializer_list<T> list) noexcept(Base::nothrowCopyCons)
1283 : StaticVectorBase<T>(c, &data_)
1284{
1285 auto result = this->assign(std::move(list));
1286 SEN_ASSERT(result.isOk());
1287 std::ignore = result;
1288}
1289
1290template <typename T, std::size_t c>
1291template <class InputIt>
1292inline StaticVector<T, c>::StaticVector(InputIt first, InputIt last) noexcept(Base::nothrowCopyCons)
1293 : StaticVectorBase<T>(c, &data_)
1294{
1295 auto result = this->assign(first, last);
1296 SEN_ASSERT(result.isOk());
1297 std::ignore = result;
1298}
1299
1300template <typename T, std::size_t c>
1302 : StaticVectorBase<T>(c, &data_)
1303{
1304 auto result = this->insert(this->begin(), other.begin(), other.end());
1305 SEN_ASSERT(result.isOk());
1306 std::ignore = result;
1307}
1308
1309template <typename T, std::size_t c>
1311{
1312 auto result = this->move_insert(this->begin(), other.begin(), other.end());
1313 SEN_ASSERT(result.isOk());
1314 std::ignore = result;
1315 other.internalSetSize(0U);
1316}
1317
1318template <typename T, std::size_t c>
1320{
1321 if (this != &other)
1322 {
1323 // clear and insert the elements at the beginning
1324 this->clear();
1325 auto result = this->insert(this->begin(), other.begin(), other.end());
1326 SEN_ASSERT(result.isOk());
1327 std::ignore = result;
1328 }
1329 return *this;
1330}
1331
1332template <typename T, std::size_t c>
1334{
1335 if (this != &other)
1336 {
1337 // clear and move-insert the elements at the beginning
1338 this->clear();
1339 auto result = this->move_insert(this->begin(), other.begin(), other.end());
1340 SEN_ASSERT(result.isOk());
1341 std::ignore = result;
1342 other.internalSetSize(0U);
1343 }
1344 return *this;
1345}
1346
1347template <typename T, std::size_t c>
1348inline void StaticVector<T, c>::swap(StaticVector& other) noexcept
1349{
1350 StaticVector tmp = std::move(other);
1351 other = std::move(*this);
1352 (*this) = std::move(tmp);
1353}
1354
1355} // namespace sen
1356
1357#undef SEN_VECTOR_TRY
1358
1359#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:217
pointer data() noexcept
Direct access to the underlying storage. Complexity: constant.
Definition static_vector.h:136
virtual ~StaticVectorBase() noexcept
Definition static_vector.h:543
Result< void, StaticVectorError > Maybe
Definition static_vector.h:105
size_type maxSize() const noexcept
Max element count (same as capacity()). Complexity: constant.
Definition static_vector.h:125
static constexpr bool nothrowMoveCons
Definition static_vector.h:85
static constexpr bool nothrowDefaultConsAndDes
Definition static_vector.h:87
reverse_iterator rend() noexcept
Returns a reverse iterator to the element following the last element of the reversed vector....
Definition static_vector.h:223
pointer iterator
Definition static_vector.h:98
size_type capacity() const noexcept
Maximum number of elements that can be allocated in the storage. Complexity: constant.
Definition static_vector.h:121
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:197
static constexpr bool nothrowCopyCons
Definition static_vector.h:84
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:685
ptrdiff_t difference_type
Definition static_vector.h:92
void clear() noexcept(nothrowDes)
Clears the vector. This function destroys all the elements. Complexity: linear in size().
Definition static_vector.h:321
const_iterator cend() noexcept
Constant iterator to the element following the last element. Complexity: constant.
Definition static_vector.h:243
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:712
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:289
const_pointer const_iterator
Definition static_vector.h:99
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:309
Maybe resize(size_type newSize, const Value &value) noexcept(nothrowCopyAndDes)
Definition static_vector.h:1099
reverse_iterator rbegin() noexcept
Reverse iterator to the first element. Complexity: constant.
Definition static_vector.h:213
void internalSetSize(std::size_t newSize) noexcept
Changes the container size to newSize.
Definition static_vector.h:1241
const_reference operator[](size_type i) const noexcept
Gets the element at index i. Complexity: constant.
Definition static_vector.h:272
MaybeIterator insert(iterator position, const_reference x) noexcept(nothrowCopyCons)
Definition static_vector.h:857
bool empty() const noexcept
true if the container is empty. Complexity: constant
Definition static_vector.h:143
static constexpr bool nothrowCopyAndDes
Definition static_vector.h:86
Maybe emplace_back(Args &&... args) noexcept(//NOLINT(readability-identifier-naming) nothrowMoveCons)
Definition static_vector.h:825
Maybe pop_back() noexcept(nothrowDes)
Definition static_vector.h:842
Result< iterator, StaticVectorError > MaybeIterator
Definition static_vector.h:106
const_iterator cend() const noexcept
Constant iterator to the element following the last element. Complexity: constant.
Definition static_vector.h:247
StaticVectorBase(std::size_t capacity, void *dataPtr) noexcept
Definition static_vector.h:539
MaybeIterator emplace(iterator position, Args &&... args) noexcept(nothrowMoveCons)
Definition static_vector.h:785
std::reverse_iterator< iterator > reverse_iterator
Definition static_vector.h:101
MaybeIterator move_insert(iterator position, InputIt first, InputIt last) noexcept(nothrowMoveCons)
Definition static_vector.h:1040
const_iterator cbegin() noexcept
Returns a const iterator to the first element of the vector. If the vector is empty,...
Definition static_vector.h:234
T && rvalue_reference
Definition static_vector.h:97
T const & const_reference
Definition static_vector.h:96
MaybeIterator erase(iterator position) noexcept(nothrowDes)
Definition static_vector.h:1151
std::size_t size_type
Definition static_vector.h:100
Maybe push_back(const T &value) noexcept(nothrowCopyCons)
Appends a value to the end of the container. Complexity: constant.
Definition static_vector.h:759
StaticVectorBase(const StaticVectorBase &) noexcept=delete
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition static_vector.h:102
reference back() noexcept
The element at the end of the container. Calling back on an empty container is undefined....
Definition static_vector.h:299
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:239
iterator end() noexcept
Iterator to the element following the last element. Complexity: constant.
Definition static_vector.h:201
reference front() noexcept
The element at the beginning of the container. Calling front on an empty container is undefined....
Definition static_vector.h:279
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:229
bool full() const noexcept
true if the container is full. Complexity: constant
Definition static_vector.h:147
Maybe push_back() noexcept(nothrowDefaultCons)
Appends a value (default constructed) to the end of the container. Complexity: constant.
Definition static_vector.h:771
T & reference
Definition static_vector.h:95
reference operator[](size_type i) noexcept
Gets the element at index i. Complexity: constant.
Definition static_vector.h:260
T const * const_pointer
Definition static_vector.h:94
const_iterator end() const noexcept
Iterator to the element following the last element. Complexity: constant. NOLINTNEXTLINE(cppcoreguide...
Definition static_vector.h:209
const_pointer data() const noexcept
Direct access to the underlying storage. Complexity: constant.
Definition static_vector.h:129
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:192
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:727
T * pointer
Definition static_vector.h:93
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:748
static constexpr bool nothrowDes
Definition static_vector.h:82
static constexpr bool nothrowDefaultCons
Definition static_vector.h:83
Maybe assign(const std::initializer_list< T > &list) noexcept(nothrowCopyCons)
Initializer list assignment. Complexity: linear in list.size().
Definition static_vector.h:699
void internalDestroy(InputIt first, InputIt last) noexcept(nothrowDes)
Definition static_vector.h:1249
size_type size() const noexcept
Element count. Complexity: constant.
Definition static_vector.h:117
T value_type
Definition static_vector.h:91
Stack-based, exception-free and resizable vector with fixed-capacity.
Definition static_vector.h:572
Base & base() noexcept
This object, as its base class.
Definition static_vector.h:628
StaticVector & operator=(const StaticVector &other) noexcept(Base::nothrowCopyCons)
Copy assignment. Complexity: linear in other.size().
Definition static_vector.h:1319
~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:631
static constexpr std::size_t staticCapacity
Definition static_vector.h:574
void swap(StaticVector &other) noexcept
Definition static_vector.h:1348
StaticVector() noexcept
Creates an empty vector.
Definition static_vector.h:582
StaticVectorBase< T > Base
Definition static_vector.h:578
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:58
@ empty
Invalid operation on an empty vector.
Definition static_vector.h:61
@ badRange
The range is invalid.
Definition static_vector.h:60
@ full
The vector cannot hold more elements.
Definition static_vector.h:59
Definition assert.h:17
STL namespace.
#define SEN_VECTOR_TRY(...)
Definition static_vector.h:672