sandbox
Loading...
Searching...
No Matches
static_vector.hpp
1#ifndef LIBSBX_MEMORY_STATIC_VECTOR_HPP_
2#define LIBSBX_MEMORY_STATIC_VECTOR_HPP_
3
4#include <memory>
5#include <type_traits>
6#include <ranges>
7#include <array>
8
9#include <fmt/format.h>
10
11#include <libsbx/utility/assert.hpp>
12
13#include <libsbx/memory/aligned_storage.hpp>
14
15namespace sbx::memory {
16
23template<typename Type, std::size_t Capacity>
25
26public:
27
28 using value_type = Type;
29 using reference = value_type&;
30 using const_reference = const value_type&;
31 using pointer = value_type*;
32 using const_pointer = const value_type*;
33 using size_type = std::size_t;
34 using iterator = pointer;
35 using const_iterator = const_pointer;
36
37 static_vector() noexcept
38 : _size{0u} { }
39
40 static_vector(const static_vector& other) noexcept
41 : _size{other._size} {
42 for (auto i : std::views::iota(0u, _size)) {
43 std::construct_at(_ptr(i), other[i]);
44 }
45 }
46
47 static_vector(static_vector&& other) noexcept
48 : _size{other._size} {
49 for (auto i : std::views::iota(0u, _size)) {
50 std::construct_at(_ptr(i), std::move(other[i]));
51 }
52 }
53
54 ~static_vector() noexcept {
55 clear();
56 }
57
58 auto operator=(static_vector other) noexcept -> static_vector& {
59 if (this != &other) {
60 other.swap(*this);
61 }
62
63 return *this;
64 }
65
66 auto size() const noexcept -> size_type {
67 return _size;
68 }
69
70 auto capacity() const noexcept -> size_type {
71 return Capacity;
72 }
73
74 auto is_empty() const noexcept -> bool {
75 return _size == 0u;
76 }
77
78 auto is_full() const noexcept -> bool {
79 return _size == Capacity;
80 }
81
82 auto begin() noexcept -> iterator {
83 return _ptr(0u);
84 }
85
86 auto begin() const noexcept -> const_iterator {
87 return _ptr(0u);
88 }
89
90 auto cbegin() const noexcept -> const_iterator {
91 return _ptr(0u);
92 }
93
94 auto end() noexcept -> iterator {
95 return _ptr(_size);
96 }
97
98 auto end() const noexcept -> const_iterator {
99 return _ptr(_size);
100 }
101
102 auto cend() const noexcept -> const_iterator {
103 return _ptr(_size);
104 }
105
106 auto front() noexcept -> reference {
107 return *begin();
108 }
109
110 auto front() const noexcept -> const_reference {
111 return *begin();
112 }
113
114 auto back() noexcept -> reference {
115 return *std::prev(end());
116 }
117
118 auto back() const noexcept -> const_reference {
119 return *std::prev(end());
120 }
121
122 auto operator[](const size_type index) noexcept -> reference {
123 return *_ptr(index);
124 }
125
126 auto operator[](const size_type index) const noexcept -> const_reference {
127 return *_ptr(index);
128 }
129
130 auto at(const size_type index) -> reference {
131 if (index >= _size) {
132 throw std::out_of_range(fmt::format("static_vector::at: index {} is out of range size {}", index, _size));
133 }
134
135 return *_ptr(index);
136 }
137
138 auto at(const size_type index) const -> const_reference {
139 if (index >= _size) {
140 throw std::out_of_range(fmt::format("static_vector::at: index {} is out of range size {}", index, _size));
141 }
142
143 return *_ptr(index);
144 }
145
146 auto data() noexcept -> pointer {
147 return _ptr(0u);
148 }
149
150 auto data() const noexcept -> const_pointer {
151 return _ptr(0u);
152 }
153
154 auto push_back(const value_type& value) noexcept -> void {
155 if (is_full()) {
156 return;
157 }
158
159 std::construct_at(_ptr(_size), value);
160 ++_size;
161 }
162
163 auto push_back(value_type&& value) noexcept -> void {
164 if (is_full()) {
165 return;
166 }
167
168 std::construct_at(_ptr(_size), std::move(value));
169 ++_size;
170 }
171
172 template<typename... Args>
173 requires (std::is_constructible_v<Type, Args...>)
174 auto emplace_back(Args&&... args) noexcept -> void {
175 if (is_full()) {
176 return;
177 }
178
179 std::construct_at(_ptr(_size), std::forward<Args>(args)...);
180 ++_size;
181 }
182
183 auto pop_back() noexcept -> void {
184 if (is_empty()) {
185 return;
186 }
187
188 std::destroy_at(std::prev(end()));
189 --_size;
190 }
191
192 auto clear() noexcept -> void {
193 for (auto i : std::views::iota(0u, _size)) {
194 std::destroy_at(_ptr(i));
195 }
196
197 _size = 0u;
198 }
199
200 auto swap(static_vector& other) -> void {
201 using std::swap;
202
203 swap(_size, other._size);
204 swap(_data, other._data);
205 }
206
207private:
208
209 auto _ptr(const size_type index) noexcept -> pointer {
210 utility::assert_that(index <= _size, "index is out of range");
211 return std::launder(reinterpret_cast<pointer>(_data[index]));
212 }
213
214 auto _ptr(const size_type index) const noexcept -> const_pointer {
215 utility::assert_that(index <= _size, "index is out of range");
216 return std::launder(reinterpret_cast<const_pointer>(_data[index]));
217 }
218
219 size_type _size;
220 std::array<storage_for_t<Type>, Capacity> _data;
221
222}; // class static_vector
223
224template<typename Type, std::size_t Capacity>
225auto operator==(const static_vector<Type, Capacity>& lhs, const static_vector<Type, Capacity>& rhs) -> bool {
226 return std::ranges::equal(lhs, rhs);
227}
228
229template<typename Type, std::size_t Capacity>
230auto swap(static_vector<Type, Capacity>& lhs, static_vector<Type, Capacity>& rhs) -> void {
231 lhs.swap(rhs);
232}
233
234} // namespace sbx::memory
235
236#endif // LIBSBX_MEMORY_STATIC_VECTOR_HPP_
static_vector implementation inspired by https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p08...
Definition: static_vector.hpp:24