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
23namespace sen
24{
25
26namespace impl
27{
28
30template <typename T, typename Range, typename Index>
31inline T& index(Range&& range, Index&& i) noexcept
32{
33 // check that the index is within the range
34 SEN_EXPECT(static_cast<ptrdiff_t>(i) < (std::end(range) - std::begin(range)));
35
36 // go to the beginning of the range and fetch the element at index i
37 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
38 return std::begin(std::forward<Range>(range))[std::forward<Index>(i)];
39}
40
42template <typename T, typename Range, typename Index>
43inline const T& cindex(Range&& range, Index&& i) noexcept
44{
45 // check that the index is within the range
46 SEN_EXPECT(static_cast<ptrdiff_t>(i) < (std::end(range) - std::begin(range)));
47
48 // go to the beginning of the range and fetch the element at index i
49 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
50 return std::begin(std::forward<Range>(range))[std::forward<Index>(i)];
51}
52
53} // namespace impl
54
57
59enum class StaticVectorError : std::uint8_t
60{
64};
65
80template <typename T>
82{
83public: // checks
84 static constexpr bool nothrowDes = std::is_nothrow_destructible_v<T>;
85 static constexpr bool nothrowDefaultCons = std::is_nothrow_default_constructible_v<T>;
86 static constexpr bool nothrowCopyCons = std::is_nothrow_copy_constructible_v<T>;
87 static constexpr bool nothrowMoveCons = std::is_nothrow_move_constructible_v<T>;
88 static constexpr bool nothrowCopyAndDes = nothrowDes && nothrowCopyCons;
90
91 // the following types allow compatibility with stdlib algorithms
92public:
93 using value_type = T; // NOLINT(readability-identifier-naming)
94 using difference_type = ptrdiff_t; // NOLINT(readability-identifier-naming)
95 using pointer = T*; // NOLINT(readability-identifier-naming)
96 using const_pointer = T const*; // NOLINT(readability-identifier-naming)
97 using reference = T&; // NOLINT(readability-identifier-naming)
98 using const_reference = T const&; // NOLINT(readability-identifier-naming)
99 using rvalue_reference = T&&; // NOLINT(readability-identifier-naming)
100 using iterator = pointer; // NOLINT(readability-identifier-naming)
101 using const_iterator = const_pointer; // NOLINT(readability-identifier-naming)
102 using size_type = std::size_t; // NOLINT(readability-identifier-naming)
103 using reverse_iterator = std::reverse_iterator<iterator>; // NOLINT(readability-identifier-naming)
104 using const_reverse_iterator = std::reverse_iterator<const_iterator>; // NOLINT(readability-identifier-naming)
105
106public:
109
110public: // special members
111 StaticVectorBase(const StaticVectorBase&) noexcept = delete;
112 StaticVectorBase(StaticVectorBase&&) noexcept = delete;
113 StaticVectorBase& operator=(StaticVectorBase&&) noexcept = delete;
114 StaticVectorBase& operator=(const StaticVectorBase&) noexcept = delete;
115
116public: // getters.
119 [[nodiscard]] size_type size() const noexcept { return size_; }
120
123 [[nodiscard]] size_type capacity() const noexcept { return capacity_; }
124
127 [[nodiscard]] size_type maxSize() const noexcept { return capacity(); }
128
131 [[nodiscard]] const_pointer data() const noexcept
132 {
133 return reinterpret_cast<const_pointer>(dataPtr_); // NOLINT NOSONAR
134 }
135
138 [[nodiscard]] pointer data() noexcept
139 {
140 return reinterpret_cast<pointer>(dataPtr_); // NOLINT NOSONAR
141 }
142
145 [[nodiscard]] bool empty() const noexcept { return size() == size_type {0U}; }
146
149 [[nodiscard]] bool full() const noexcept { return size() == capacity(); }
150
151public: // assignment
160 [[nodiscard]] Maybe assign(size_type n, const T& u) noexcept(nothrowCopyCons);
161
169 [[nodiscard]] Maybe assign(const std::initializer_list<T>& list) noexcept(nothrowCopyCons);
170
178 [[nodiscard]] Maybe assign(std::initializer_list<T>&& list) noexcept(nothrowMoveCons);
179
187 template <class InputIt>
188 [[nodiscard]] Maybe assign(InputIt first, InputIt last) noexcept(nothrowCopyCons);
189
190public: // positional iterator accessors
194 [[nodiscard]] iterator begin() noexcept { return data(); }
195
199 [[nodiscard]] const_iterator begin() const noexcept { return data(); }
200
203 [[nodiscard]] iterator end() noexcept
204 {
205 return data() + size(); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
206 }
207
211 [[nodiscard]] const_iterator end() const noexcept { return data() + size(); }
212
215 [[nodiscard]] reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
216
219 [[nodiscard]] const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
220
225 [[nodiscard]] reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
226
231 [[nodiscard]] const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
232
236 [[nodiscard]] const_iterator cbegin() noexcept { return begin(); }
237
241 [[nodiscard]] const_iterator cbegin() const noexcept { return begin(); }
242
245 [[nodiscard]] const_iterator cend() noexcept { return end(); }
246
249 [[nodiscard]] const_iterator cend() const noexcept { return end(); }
250
251public: // index-based value accessors
262 [[nodiscard]] reference operator[](size_type i) noexcept { return impl::index<value_type>(*this, i); }
263
274 [[nodiscard]] const_reference operator[](size_type i) const noexcept { return impl::cindex<value_type>(*this, i); }
275
276public: // position-based value accessors
281 [[nodiscard]] reference front() noexcept
282 {
283 SEN_EXPECT(!empty());
284 return impl::index<value_type>(*this, 0U);
285 }
286
291 [[nodiscard]] const_reference front() const noexcept
292 {
293 SEN_EXPECT(!empty());
294 return impl::cindex<value_type>(*this, 0U);
295 }
296
301 [[nodiscard]] reference back() noexcept
302 {
303 SEN_EXPECT(!empty());
304 return impl::index<value_type>(*this, size() - 1);
305 }
306
311 [[nodiscard]] const_reference back() const noexcept
312 {
313 SEN_EXPECT(!empty());
314 return impl::cindex<value_type>(*this, size() - 1);
315 }
316
317public: // modifiers
323 void clear() noexcept(nothrowDes)
324 {
325 internalDestroyAll();
326 internalSetSize(0U);
327 }
328
335 Maybe push_back(T&& value) noexcept(nothrowMoveCons);
336
343 Maybe push_back(const T& value) noexcept(nothrowCopyCons);
344
352
365 template <typename... Args>
366 MaybeIterator emplace(iterator position, Args&&... args) noexcept(nothrowMoveCons);
367
380 template <typename... Args>
381 Maybe emplace_back(Args&&... args) noexcept( // NOLINT(readability-identifier-naming)
383
389 Maybe pop_back() noexcept(nothrowDes); // NOLINT(readability-identifier-naming)
390
391public: // insert overloads
401
411
421 MaybeIterator insert(iterator position, size_type n, const T& x) noexcept(nothrowCopyCons);
422
432 MaybeIterator insert(iterator position, std::initializer_list<T> list) noexcept(nothrowCopyCons);
433
445 template <class InputIt>
446 MaybeIterator insert(iterator position, InputIt first, InputIt last) noexcept(nothrowCopyCons);
447
459 template <class InputIt>
460 MaybeIterator move_insert(iterator position, // NOLINT(readability-identifier-naming)
461 InputIt first,
462 InputIt last) noexcept(nothrowMoveCons);
463
464public: // resizing
473 Maybe resize(size_type newSize, const T& value) noexcept(nothrowCopyAndDes);
474
483
484public: // erase
500
514
515private: // implementation details
518 [[nodiscard]] Maybe emplaceMultiple(size_type n) noexcept(nothrowDefaultCons);
519
521 template <typename Iterator>
522 [[nodiscard]] Maybe checkIteratorRange(Iterator itr) noexcept;
523
525 template <typename IteratorA, typename IteratorB>
526 [[nodiscard]] Maybe checkIteratorPair(IteratorA first, IteratorB last) noexcept;
527
532 template <class Itr>
533 void internalDestroy(Itr first, Itr last) noexcept(nothrowDes);
534
538 void internalDestroyAll() noexcept(nothrowDes) { internalDestroy(data(), end()); }
539
540protected:
541 StaticVectorBase(std::size_t capacity, void* dataPtr) noexcept: capacity_(capacity), dataPtr_(dataPtr)
542 {
543 SEN_EXPECT(dataPtr != nullptr);
544 }
545 virtual ~StaticVectorBase() noexcept { internalDestroyAll(); }
546
551 void internalSetSize(std::size_t newSize) noexcept;
552
553private:
554 std::size_t capacity_;
555 void* dataPtr_;
556 std::size_t size_ = 0U;
557};
558
572template <typename T, std::size_t s>
574{
575public:
576 static constexpr std::size_t staticCapacity = s;
577 static_assert(staticCapacity != 0U, "Vectors of no capacity are not supported");
578
579public:
581
582public:
584 StaticVector() noexcept: StaticVectorBase<T>(s, &data_) {}
585
588 explicit StaticVector(std::size_t n) noexcept;
589
592 StaticVector(std::size_t n, T const& value) noexcept(Base::nothrowCopyCons);
593
596 StaticVector(std::initializer_list<T> list) noexcept(Base::nothrowCopyCons);
597
600 template <class InputIt>
601 StaticVector(InputIt first, InputIt last) noexcept(Base::nothrowCopyCons);
602
605 StaticVector(const StaticVector& other) noexcept(Base::nothrowCopyCons);
606
610 StaticVector(StaticVector&& other) noexcept;
611
614 ~StaticVector() noexcept override = default;
615
618 StaticVector& operator=(const StaticVector& other) noexcept(Base::nothrowCopyCons);
619
623 StaticVector& operator=(StaticVector&& other) noexcept;
624
627 void swap(StaticVector& other) noexcept;
628
630 [[nodiscard]] Base& base() noexcept { return *this; }
631
633 [[nodiscard]] const Base& base() const noexcept { return *this; }
634
635private:
636 alignas(T) std::byte data_[sizeof(T) * s];
637};
638
639//--------------------------------------------------------------------------------------------------------------
640// Comparison operators
641//--------------------------------------------------------------------------------------------------------------
642
648template <typename T, std::size_t size>
649std::enable_if_t<HasOperator<T>::eq, bool> operator==(
650 StaticVector<T, size> const& lhs,
651 StaticVector<T, size> const& rhs) noexcept(noexcept(std::declval<T const&>() == std::declval<T const&>()))
652{
653 if (lhs.size() != rhs.size())
654 {
655 return false;
656 }
657
658 return lhs.size() == 0 || std::equal(lhs.begin(), lhs.end(), rhs.begin(), std::equal_to<T> {});
659}
660
664template <typename T, std::size_t size>
665std::enable_if_t<HasOperator<T>::ne, bool> operator!=(
666 StaticVector<T, size> const& lhs,
667 StaticVector<T, size> const& rhs) noexcept(noexcept(std::declval<StaticVector<T, size> const&>() ==
668 std::declval<StaticVector<T, size> const&>()))
669{
670 return !(lhs == rhs);
671}
672
677template <typename T, std::size_t size>
678std::enable_if_t<HasOperator<T>::lt, bool> operator<(const StaticVector<T, size>& lhs,
679 const StaticVector<T, size>& rhs) //
680 noexcept(noexcept(std::declval<const T&>() < std::declval<const T&>()))
681{
682 return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
683}
684
691template <typename T, std::size_t size>
692std::enable_if_t<HasOperator<T>::lt, bool> operator>(const StaticVector<T, size>& lhs,
693 const StaticVector<T, size>& rhs) //
694 noexcept(noexcept(std::declval<const T&>() < std::declval<const T&>()))
695{
696 return std::lexicographical_compare(rhs.begin(), rhs.end(), lhs.begin(), lhs.end());
697}
698
702template <typename T, std::size_t size>
703[[nodiscard]] Span<const T> makeConstSpan(const StaticVector<T, size>& vector) noexcept
704{
705 return makeConstSpan(vector.data(), vector.size());
706}
707
709
710} // namespace sen
711
712//----------------------------------------------------------------------------------------------------------------------
713// Inline implementation
714//----------------------------------------------------------------------------------------------------------------------
715
716// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
717#define SEN_VECTOR_TRY(...) \
718 { \
719 auto res = __VA_ARGS__; \
720 if (res.isError()) \
721 { \
722 return Err(res.getError()); \
723 } \
724 }
725
726namespace sen
727{
728
729template <typename T>
731 const T& u) noexcept(nothrowCopyCons)
732{
733 if (n > capacity())
734 {
736 }
737
738 // clear and insert the elements at the beginning
739 clear();
740 return insert(begin(), n, u);
741}
742
743template <typename T>
744inline typename StaticVectorBase<T>::Maybe StaticVectorBase<T>::assign(const std::initializer_list<T>& list) noexcept(
746{
747 if (list.size() > capacity())
748 {
750 }
751
752 clear();
753 return insert(begin(), list.begin(), list.end());
754}
755
756template <typename T>
757inline typename StaticVectorBase<T>::Maybe StaticVectorBase<T>::assign(std::initializer_list<T>&& list) noexcept(
759{
760 if (list.size() > capacity())
761 {
763 }
764
765 // clear and move-insert the elements at the beginning
766 clear();
767 return move_insert(begin(), list.begin(), list.end());
768}
769
770template <typename T>
771template <class InputIt>
773 InputIt last) noexcept(nothrowCopyCons)
774{
775 // check capacity
776 if (last - first < 0)
777 {
779 }
780
781 if (static_cast<size_type>(last - first) > capacity())
782 {
784 }
785
786 // clear and insert the elements at the beginning
787 clear();
788 return insert(begin(), first, last);
789}
790
791template <typename T>
792// NOLINTNEXTLINE(readability-identifier-naming)
794{
795 if (full())
796 {
798 }
799 return emplace_back(std::move(value));
800}
801
802template <typename T>
803// NOLINTNEXTLINE(readability-identifier-naming)
805{
806 if (full())
807 {
809 }
810
811 return emplace_back(value);
812}
813
814template <typename T>
815// NOLINTNEXTLINE(readability-identifier-naming)
817{
818 static_assert(std::is_default_constructible<T>::value,
819 "this version of push_back requires a default constructible type");
820
821 if (full())
822 {
824 }
825 return emplace_back(T {});
826}
827
828template <typename T>
829template <typename... Args>
832 Args&&... args) noexcept(nothrowMoveCons)
833{
834 if (full())
835 {
837 }
838
839 // check that the position is valid
840 SEN_VECTOR_TRY(checkIteratorRange(position))
841
842 if (position == end())
843 {
844 std::ignore = emplace_back(std::forward<Args>(args)...); // not full
845 return Ok(position);
846 }
847
848 const auto previousEnd = end();
849
850 // move the back to a new extra place
851 std::ignore = emplace_back(std::move(back())); // not full
852
853 if (std::distance(position, previousEnd) != 1)
854 {
855 // move the rest of the elements to make room
856 std::move_backward(position, end() - 2, end() - 1); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
857
858 // destroy the element that was in position
859 std::destroy_at(position);
860 }
861
862 // place the new element in position
863 ::new (std::addressof(*position)) T(std::forward<Args>(args)...);
864
865 return Ok(position);
866}
867
868template <typename T>
869template <typename... Args>
871{
872 if (full())
873 {
875 }
876
877 // placement new at the end of the array
878 new (end()) T(std::forward<Args>(args)...);
879
880 // increase the size
881 internalSetSize(size() + 1);
882 return Ok();
883}
884
885template <typename T>
886// NOLINTNEXTLINE(readability-identifier-naming)
888{
889 if (empty())
890 {
892 }
893
894 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
895 auto ptr = end() - 1; // get the pointer to the last element
896 std::destroy_at(ptr); // do placement delete
897 internalSetSize(size() - 1); // decrease the size
898 return Ok();
899}
900
901template <typename T>
905{
906 if (full())
907 {
909 }
910
911 SEN_VECTOR_TRY(checkIteratorRange(position))
912 return insert(position, static_cast<size_type>(1), x);
913}
914
915template <typename T>
916template <class InputIt>
918 InputIt first,
919 InputIt last) noexcept(nothrowCopyCons)
920{
921 // checks
922 SEN_VECTOR_TRY(checkIteratorRange(position))
923 SEN_VECTOR_TRY(checkIteratorPair(first, last))
924
925 // check if we would be inserting beyond the capacity
926 if (size() + static_cast<size_type>(last - first) > capacity())
927 {
929 }
930
931 const size_t insertN = std::distance(first, last);
932 const size_t insertBegin = std::distance(begin(), position);
933 const size_t insertEnd = insertBegin + insertN;
934
935 // move old data.
936 size_t copyOldN;
937 size_t constructOldN;
938 iterator pConstructOld;
939
940 auto pEnd = end();
941
942 if (insertEnd > size())
943 {
944 copyOldN = 0;
945 constructOldN = size() - insertBegin;
946 pConstructOld = begin() + insertEnd; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
947 }
948 else
949 {
950 copyOldN = size() - insertBegin - insertN;
951 constructOldN = insertN;
952 pConstructOld = pEnd;
953 }
954
955 const size_t copyNewN = constructOldN;
956 const size_t constructNewN = insertN - copyNewN;
957
958 // move-construct old on the new (uninitialized memory area).
959 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
960 std::uninitialized_move(pEnd - constructOldN, pEnd, pConstructOld);
961
962 // move old to the remaining (already initialized) memory area.
963 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
964 std::move_backward(begin() + insertBegin, begin() + insertBegin + copyOldN, begin() + insertEnd + copyOldN);
965
966 // copy-construct new in the (uninitialized) memory area
967 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
968 std::uninitialized_copy(first + copyNewN, first + copyNewN + constructNewN, pEnd);
969
970 // copy new to the final location
971 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
972 std::copy(first, first + copyNewN, begin() + insertBegin);
973
974 internalSetSize(size_ + insertN);
975
976 return Ok(position);
977}
978
979template <typename T>
981 value_type&& x) noexcept(nothrowMoveCons)
982{
983 if (full())
984 {
986 }
987
988 SEN_VECTOR_TRY(checkIteratorRange(position))
989
990 if (position == end())
991 {
992 std::ignore = emplace_back(std::move(x)); // not full, so cannot fail
993 }
994 else
995 {
996 // move the back to a new extra place
997 std::ignore = emplace_back(std::move(back())); // not full, so cannot fail
998
999 // move affected range one position
1000 std::move_backward(position, end() - 2, end() - 1); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1001
1002 // move our value into the desired position
1003 *position = std::move(x);
1004 }
1005
1006 return Ok(position);
1007}
1008
1009template <typename T>
1012 const T& x) noexcept(nothrowCopyCons)
1013{
1014 SEN_VECTOR_TRY(checkIteratorRange(position))
1015
1016 if (const auto newSize = size() + n; newSize > capacity())
1017 {
1019 }
1020
1021 if (n == 0U)
1022 {
1023 return Ok(position);
1024 }
1025
1026 const size_t insertN = n;
1027 const size_t insertBegin = std::distance(begin(), position);
1028 const size_t insertEnd = insertBegin + insertN;
1029
1030 // copy old data.
1031 size_t copyOldN;
1032 size_t constructOldN;
1033 iterator pConstructOld;
1034
1035 auto pEnd = end();
1036
1037 if (insertEnd > size())
1038 {
1039 copyOldN = 0;
1040 constructOldN = size() - insertBegin;
1041 pConstructOld = begin() + insertEnd; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1042 }
1043 else
1044 {
1045 copyOldN = size() - insertBegin - insertN;
1046 constructOldN = insertN;
1047 pConstructOld = pEnd;
1048 }
1049
1050 size_t copyNewN = constructOldN;
1051 size_t constructNewN = insertN - copyNewN;
1052
1053 // move-construct old on the new (uninitialized memory area).
1054 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1055 std::uninitialized_move(static_cast<iterator>(pEnd - constructOldN), pEnd, pConstructOld);
1056
1057 // move old to the remaining (already initialized) memory area.
1058 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1059 std::move_backward(begin() + insertBegin, begin() + insertBegin + copyOldN, begin() + insertEnd + copyOldN);
1060
1061 // construct new in the (uninitialized) memory area.
1062 std::uninitialized_fill_n(pEnd, constructNewN, x);
1063
1064 // copy new n values of T
1065 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1066 std::fill_n(begin() + insertBegin, copyNewN, x);
1067
1068 internalSetSize(size() + n);
1069
1070 return Ok(position);
1071}
1072
1073template <typename T>
1076 std::initializer_list<T> list) noexcept(nothrowCopyCons)
1077{
1078 SEN_VECTOR_TRY(checkIteratorRange(position))
1079 return insert(position, list.begin(), list.end());
1080}
1081
1082template <typename T>
1083template <class InputIt>
1085StaticVectorBase<T>::move_insert(iterator position, InputIt first, InputIt last) noexcept(nothrowMoveCons)
1086{
1087 // checks
1088 SEN_VECTOR_TRY(checkIteratorRange(position))
1089 SEN_VECTOR_TRY(checkIteratorPair(first, last))
1090
1091 if (size() + static_cast<size_type>(last - first) > capacity())
1092 {
1094 }
1095
1096 const size_t insertN = std::distance(first, last);
1097 const size_t insertBegin = std::distance(begin(), position);
1098 const size_t insertEnd = insertBegin + insertN;
1099
1100 // move old data.
1101 size_t moveOldN;
1102 size_t constructOldN;
1103 iterator pConstructOld;
1104 auto pEnd = end();
1105
1106 if (insertEnd > size())
1107 {
1108 moveOldN = 0;
1109 constructOldN = size() - insertBegin; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1110 pConstructOld = begin() + insertEnd; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1111 }
1112 else
1113 {
1114 moveOldN = size() - insertBegin - insertN;
1115 constructOldN = insertN;
1116 pConstructOld = pEnd;
1117 }
1118
1119 const size_t copyNewN = constructOldN;
1120 const size_t constructNewN = insertN - copyNewN;
1121
1122 // move-construct old on the new (uninitialized memory area).
1123 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1124 std::uninitialized_move(pEnd - constructOldN, pEnd, pConstructOld);
1125
1126 // move old to the remaining (already initialized) memory area.
1127 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1128 std::move_backward(begin() + insertBegin, begin() + insertBegin + moveOldN, begin() + insertEnd + moveOldN);
1129
1130 // move-construct new in the (uninitialized) memory area
1131 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1132 std::uninitialized_move(first + copyNewN, first + copyNewN + constructNewN, pEnd);
1133
1134 // move new to the final location
1135 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1136 std::move(first, first + copyNewN, begin() + insertBegin);
1137
1138 internalSetSize(size_ + insertN);
1139
1140 return Ok(position);
1141}
1142
1143template <typename T>
1145 const T& value) noexcept(nothrowCopyAndDes)
1146{
1147 static_assert(std::is_nothrow_copy_constructible<T>::value, "T is not supported");
1148
1149 // do nothing if the size is already the same
1150 if (newSize == size())
1151 {
1152 return Ok();
1153 }
1154
1155 if (newSize > capacity())
1156 {
1158 }
1159
1160 if (newSize > size())
1161 {
1162 // insert copies of value at the end
1163 return insert(end(), newSize - size(), value);
1164 }
1165
1166 // remove elements from the end
1167 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1168 return erase(end() - (size() - newSize), end());
1169}
1170
1171template <typename T>
1174{
1175 // do nothing if the size is already the same
1176 if (newSize == size())
1177 {
1178 return Ok();
1179 }
1180
1181 if (newSize > capacity())
1182 {
1184 }
1185
1186 if (newSize > size())
1187 {
1188 return emplaceMultiple(newSize - size());
1189 }
1190
1191 // remove elements from the end
1192 return erase(end() - (size() - newSize), end()); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1193}
1194
1195template <typename T>
1197 StaticVectorBase::iterator position) noexcept(nothrowDes)
1198{
1199 SEN_VECTOR_TRY(checkIteratorRange(position))
1200
1201 // move elements from [position + 1, end) to position
1202 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1203 std::move(position + 1, end(), position);
1204
1205 // destroy the last element
1206 auto ptr = end() - 1; // get the pointer to the last element NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1207 std::destroy_at(ptr); // do placement delete
1208 internalSetSize(size() - 1);
1209 return Ok(position);
1210}
1211
1212template <typename T>
1216{
1217 SEN_VECTOR_TRY(checkIteratorPair(first, last))
1218 SEN_VECTOR_TRY(checkIteratorRange(first))
1219 SEN_VECTOR_TRY(checkIteratorRange(last))
1220
1221 if (first == last)
1222 {
1223 return Ok(first);
1224 }
1225
1226 if (first == begin() && last == end())
1227 {
1228 clear();
1229 }
1230 else
1231 {
1232 // move the remaining elements on top of the erased range
1233 std::move(last, end(), first);
1234
1235 // destroy the elements left over at the end.
1236 const auto nDelete = std::distance(first, last);
1237 std::destroy(end() - nDelete, end()); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1238
1239 internalSetSize(size() - nDelete);
1240 }
1241
1242 return Ok(first);
1243}
1244
1245template <typename T>
1246inline typename StaticVectorBase<T>::Maybe StaticVectorBase<T>::emplaceMultiple(StaticVectorBase::size_type n) noexcept(
1247 nothrowDefaultCons)
1248{
1249 const size_type newSize = size() + n;
1250 SEN_EXPECT(newSize <= capacity());
1251
1252 while (newSize != size())
1253 {
1254 // cannot overflow as newSize != size() && newSize <= capacity
1255 std::ignore = emplace_back();
1256 }
1257
1258 return Ok();
1259}
1260
1261template <typename T>
1262template <typename Iterator>
1263inline typename StaticVectorBase<T>::Maybe StaticVectorBase<T>::checkIteratorRange(Iterator itr) noexcept
1264{
1265 if (itr >= begin() && itr <= end())
1266 {
1267 return Ok();
1268 }
1269
1271}
1272
1273template <typename T>
1274template <typename IteratorA, typename IteratorB>
1275inline typename StaticVectorBase<T>::Maybe StaticVectorBase<T>::checkIteratorPair(IteratorA first,
1276 IteratorB last) noexcept
1277{
1278 if (first > last)
1279 {
1281 }
1282 return Ok();
1283}
1284
1285template <typename T>
1286inline void StaticVectorBase<T>::internalSetSize(std::size_t newSize) noexcept
1287{
1288 SEN_EXPECT(newSize <= capacity()); // newSize out-of-bounds [0, Capacity)
1289 size_ = newSize;
1290}
1291
1292template <typename T>
1293template <class InputIt>
1294inline void StaticVectorBase<T>::internalDestroy(InputIt first, InputIt last) noexcept(nothrowDes)
1295{
1296 SEN_EXPECT(first >= data());
1297 SEN_EXPECT(first <= end());
1298 SEN_EXPECT(last >= data());
1299 SEN_EXPECT(last <= end());
1300
1301 for (; first != last; ++first) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1302 {
1303 std::destroy_at(first);
1304 }
1305}
1306
1307// StaticVector
1308
1309template <typename T, std::size_t c>
1310inline StaticVector<T, c>::StaticVector(std::size_t n) noexcept: StaticVectorBase<T>(c, &data_)
1311{
1312 auto result = this->resize(n);
1313 SEN_ASSERT(result.isOk());
1314 std::ignore = result;
1315}
1316
1317template <typename T, std::size_t c>
1318inline StaticVector<T, c>::StaticVector(std::size_t n, const T& value) noexcept(Base::nothrowCopyCons)
1319 : StaticVectorBase<T>(c, &data_)
1320{
1321 auto result = this->resize(n, value);
1322 SEN_ASSERT(result.isOk());
1323 std::ignore = result;
1324}
1325
1326template <typename T, std::size_t c>
1327inline StaticVector<T, c>::StaticVector(std::initializer_list<T> list) noexcept(Base::nothrowCopyCons)
1328 : StaticVectorBase<T>(c, &data_)
1329{
1330 auto result = this->assign(std::move(list));
1331 SEN_ASSERT(result.isOk());
1332 std::ignore = result;
1333}
1334
1335template <typename T, std::size_t c>
1336template <class InputIt>
1337inline StaticVector<T, c>::StaticVector(InputIt first, InputIt last) noexcept(Base::nothrowCopyCons)
1338 : StaticVectorBase<T>(c, &data_)
1339{
1340 auto result = this->assign(first, last);
1341 SEN_ASSERT(result.isOk());
1342 std::ignore = result;
1343}
1344
1345template <typename T, std::size_t c>
1347 : StaticVectorBase<T>(c, &data_)
1348{
1349 auto result = this->insert(this->begin(), other.begin(), other.end());
1350 SEN_ASSERT(result.isOk());
1351 std::ignore = result;
1352}
1353
1354template <typename T, std::size_t c>
1356{
1357 auto result = this->move_insert(this->begin(), other.begin(), other.end());
1358 SEN_ASSERT(result.isOk());
1359 std::ignore = result;
1360 other.internalSetSize(0U);
1361}
1362
1363template <typename T, std::size_t c>
1365{
1366 if (this != &other)
1367 {
1368 // clear and insert the elements at the beginning
1369 this->clear();
1370 auto result = this->insert(this->begin(), other.begin(), other.end());
1371 SEN_ASSERT(result.isOk());
1372 std::ignore = result;
1373 }
1374 return *this;
1375}
1376
1377template <typename T, std::size_t c>
1379{
1380 if (this != &other)
1381 {
1382 // clear and move-insert the elements at the beginning
1383 this->clear();
1384 auto result = this->move_insert(this->begin(), other.begin(), other.end());
1385 SEN_ASSERT(result.isOk());
1386 std::ignore = result;
1387 other.internalSetSize(0U);
1388 }
1389 return *this;
1390}
1391
1392template <typename T, std::size_t c>
1393inline void StaticVector<T, c>::swap(StaticVector& other) noexcept
1394{
1395 StaticVector tmp = std::move(other);
1396 other = std::move(*this);
1397 (*this) = std::move(tmp);
1398}
1399
1400} // namespace sen
1401
1402#undef SEN_VECTOR_TRY
1403
1404#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:219
pointer data() noexcept
Direct access to the underlying storage. Complexity: constant.
Definition static_vector.h:138
virtual ~StaticVectorBase() noexcept
Definition static_vector.h:545
Result< void, StaticVectorError > Maybe
Definition static_vector.h:107
size_type maxSize() const noexcept
Max element count (same as capacity()). Complexity: constant.
Definition static_vector.h:127
static constexpr bool nothrowMoveCons
Definition static_vector.h:87
static constexpr bool nothrowDefaultConsAndDes
Definition static_vector.h:89
reverse_iterator rend() noexcept
Returns a reverse iterator to the element following the last element of the reversed vector....
Definition static_vector.h:225
pointer iterator
Definition static_vector.h:100
size_type capacity() const noexcept
Maximum number of elements that can be allocated in the storage. Complexity: constant.
Definition static_vector.h:123
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:199
static constexpr bool nothrowCopyCons
Definition static_vector.h:86
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:730
ptrdiff_t difference_type
Definition static_vector.h:94
void clear() noexcept(nothrowDes)
Clears the vector. This function destroys all the elements. Complexity: linear in size().
Definition static_vector.h:323
const_iterator cend() noexcept
Constant iterator to the element following the last element. Complexity: constant.
Definition static_vector.h:245
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:757
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:291
const_pointer const_iterator
Definition static_vector.h:101
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:311
Maybe resize(size_type newSize, const Value &value) noexcept(nothrowCopyAndDes)
Definition static_vector.h:1144
reverse_iterator rbegin() noexcept
Reverse iterator to the first element. Complexity: constant.
Definition static_vector.h:215
void internalSetSize(std::size_t newSize) noexcept
Changes the container size to newSize.
Definition static_vector.h:1286
const_reference operator[](size_type i) const noexcept
Gets the element at index i. Complexity: constant.
Definition static_vector.h:274
MaybeIterator insert(iterator position, const_reference x) noexcept(nothrowCopyCons)
Definition static_vector.h:902
bool empty() const noexcept
true if the container is empty. Complexity: constant
Definition static_vector.h:145
static constexpr bool nothrowCopyAndDes
Definition static_vector.h:88
Maybe emplace_back(Args &&... args) noexcept(//NOLINT(readability-identifier-naming) nothrowMoveCons)
Definition static_vector.h:870
Maybe pop_back() noexcept(nothrowDes)
Definition static_vector.h:887
Result< iterator, StaticVectorError > MaybeIterator
Definition static_vector.h:108
const_iterator cend() const noexcept
Constant iterator to the element following the last element. Complexity: constant.
Definition static_vector.h:249
StaticVectorBase(std::size_t capacity, void *dataPtr) noexcept
Definition static_vector.h:541
MaybeIterator emplace(iterator position, Args &&... args) noexcept(nothrowMoveCons)
Definition static_vector.h:830
std::reverse_iterator< iterator > reverse_iterator
Definition static_vector.h:103
MaybeIterator move_insert(iterator position, InputIt first, InputIt last) noexcept(nothrowMoveCons)
Definition static_vector.h:1085
const_iterator cbegin() noexcept
Returns a const iterator to the first element of the vector. If the vector is empty,...
Definition static_vector.h:236
T && rvalue_reference
Definition static_vector.h:99
T const & const_reference
Definition static_vector.h:98
MaybeIterator erase(iterator position) noexcept(nothrowDes)
Definition static_vector.h:1196
std::size_t size_type
Definition static_vector.h:102
Maybe push_back(const T &value) noexcept(nothrowCopyCons)
Appends a value to the end of the container. Complexity: constant.
Definition static_vector.h:804
StaticVectorBase(const StaticVectorBase &) noexcept=delete
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition static_vector.h:104
reference back() noexcept
The element at the end of the container. Calling back on an empty container is undefined....
Definition static_vector.h:301
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:241
iterator end() noexcept
Iterator to the element following the last element. Complexity: constant.
Definition static_vector.h:203
reference front() noexcept
The element at the beginning of the container. Calling front on an empty container is undefined....
Definition static_vector.h:281
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:231
bool full() const noexcept
true if the container is full. Complexity: constant
Definition static_vector.h:149
Maybe push_back() noexcept(nothrowDefaultCons)
Appends a value (default constructed) to the end of the container. Complexity: constant.
Definition static_vector.h:816
T & reference
Definition static_vector.h:97
reference operator[](size_type i) noexcept
Gets the element at index i. Complexity: constant.
Definition static_vector.h:262
T const * const_pointer
Definition static_vector.h:96
const_iterator end() const noexcept
Iterator to the element following the last element. Complexity: constant. NOLINTNEXTLINE(cppcoreguide...
Definition static_vector.h:211
const_pointer data() const noexcept
Direct access to the underlying storage. Complexity: constant.
Definition static_vector.h:131
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:194
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:772
T * pointer
Definition static_vector.h:95
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:793
static constexpr bool nothrowDes
Definition static_vector.h:84
static constexpr bool nothrowDefaultCons
Definition static_vector.h:85
Maybe assign(const std::initializer_list< T > &list) noexcept(nothrowCopyCons)
Initializer list assignment. Complexity: linear in list.size().
Definition static_vector.h:744
void internalDestroy(InputIt first, InputIt last) noexcept(nothrowDes)
Definition static_vector.h:1294
size_type size() const noexcept
Element count. Complexity: constant.
Definition static_vector.h:119
T value_type
Definition static_vector.h:93
Stack-based, exception-free and resizable vector with fixed-capacity.
Definition static_vector.h:574
Base & base() noexcept
This object, as its base class.
Definition static_vector.h:630
StaticVector & operator=(const StaticVector &other) noexcept(Base::nothrowCopyCons)
Copy assignment. Complexity: linear in other.size().
Definition static_vector.h:1364
~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:633
static constexpr std::size_t staticCapacity
Definition static_vector.h:576
void swap(StaticVector &other) noexcept
Definition static_vector.h:1393
StaticVector() noexcept
Creates an empty vector.
Definition static_vector.h:584
StaticVectorBase< T > Base
Definition static_vector.h:580
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
#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
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:678
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:60
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:692
@ empty
Invalid operation on an empty vector.
Definition static_vector.h:63
@ badRange
The range is invalid.
Definition static_vector.h:62
@ full
The vector cannot hold more elements.
Definition static_vector.h:61
Definition assert.h:17
STL namespace.
#define SEN_VECTOR_TRY(...)
Definition static_vector.h:717