HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
secure_vector.hpp
1
2#pragma once
3
4#include "security.hpp"
5
6namespace hi::inline v1 {
7
8template<typename Allocator>
10public:
12
13protected:
14 [[nodiscard]] constexpr pointer allocate(size_t n)
15 {
16 return std::allocator_traits<Allocator>::allocate(Allocator{}, n);
17 }
18
19 constexpr void deallocate(pointer p, size_t n)
20 {
21 return std::allocator_traits<Allocator>::deallocate(Allocator{}, p, n);
22 }
23};
24
25template<typename Allocator> requires(not std::allocator_traits<Allocator>::is_always_equal::value)
27public:
29
30protected:
31 Allocator _allocator;
32
33 [[nodiscard]] constexpr pointer allocate(size_t n)
34 {
36 }
37
38 constexpr void deallocate(pointer p, size_t n)
39 {
40 return std::allocator_traits<Allocator>::deallocate(_allocator, p, n);
41 }
42};
43
49template<typename T, typename Alloctor = std::allocator<T>>
50class secure_vector : public secure_vector_base<Allocator> {
51public:
52 using value_type = T;
53 using allocator_type = Allocator;
54 using size_type = std::size_t;
56 using reference = value_type &;
57 using const_reference = value_type const &;
60 using iterator = value_type *;
61 using const_iterator = value_type const *;
64
65 constexpr static bool is_static_allocator = std::allocator_traits<allocator_type>::is_always_equal::value;
66
67 constexpr secure_vector() noexcept : _begin(nullptr), _end(nullptr), _bound(nullptr) {}
68
69 constexpr ~secure_vector()
70 {
71 resize(0);
72 shrink_to_fit();
73 hi_axiom(_begin = nullptr);
74 }
75
76 [[nodiscard]] constexpr bool empty() const noexcept
77 {
78 return _begin == _end;
79 }
80
81 [[nodisardd]] constexpr size_type size() const noexcept
82 {
83 return static_cast<size_type>(_end - _begin);
84 }
85
86 [[nodiscard]] constexpr size_type max_size() const noexcept
87 {
89 }
90
91 [[nodiscard]] constexpr size_type capacity() const noexcept
92 {
93 return static_cast<size_type>(_bound - _begin);
94 }
95
96 [[nodiscard]] constexpr reference at(size_type pos)
97 {
98 auto *ptr = _begin + pos;
99 if (ptr >= _end) {
100 throw std::out_of_range();
101 }
102
103 return *ptr;
104 }
105
106 [[nodiscard]] constexpr const_reference at(size_type pos) const
107 {
108 auto *ptr = _begin + pos;
109 if (ptr >= _end) {
110 throw std::out_of_range();
111 }
112
113 return *ptr;
114 }
115
116 [[nodiscard]] constexpr reference operator[](size_type pos) noexcept
117 {
118 auto *ptr = _begin + pos;
119 hi_axiom(ptr < _end);
120 return *ptr;
121 }
122
123 [[nodiscard]] constexpr const_reference operator[](size_type pos) const noexcept
124 {
125 auto *ptr = _begin + pos;
126 hi_axiom(ptr < _end);
127 return *ptr;
128 }
129
130 [[nodiscard]] constexpr reference front() noexcept
131 {
132 hi_axiom(not empty());
133 return *_begin;
134 }
135
136 [[nodiscard]] constexpr const_reference front() const noexcept
137 {
138 hi_axiom(not empty());
139 return *_begin;
140 }
141
142 [[nodiscard]] constexpr reference back() noexcept
143 {
144 hi_axiom(not empty());
145 return *(_end - 1);
146 }
147
148 [[nodiscard]] constexpr const_reference back() const noexcept
149 {
150 hi_axiom(not empty());
151 return *(_end - 1);
152 }
153
154 [[nodiscard]] constexpr pointer data() noexcept
155 {
156 return _begin;
157 }
158
159 [[nodiscard]] constexpr const_pointer data() const noexcept
160 {
161 return _begin;
162 }
163
164 [[nodiscard]] constexpr iterator begin() noexcept
165 {
166 return _begin;
167 }
168
169 [[nodiscard]] constexpr const_iterator begin() const noexcept
170 {
171 return _begin;
172 }
173
174 [[nodiscard]] constexpr const_iterator cbegin() const noexcept
175 {
176 return _begin;
177 }
178
179 [[nodiscard]] constexpr iterator end() noexcept
180 {
181 return _end;
182 }
183
184 [[nodiscard]] constexpr const_iterator end() const noexcept
185 {
186 return _end;
187 }
188
189 [[nodiscard]] constexpr const_iterator cend() const noexcept
190 {
191 return _end;
192 }
193
194
195 constexpr void resize(size_type new_size)
196 {
197 return _resize(new_size);
198 }
199
200 constexpr void resize(size_type new_size, value_type const &value)
201 {
202 return _resize(new_size, value);
203 }
204
205 constexpr void clear()
206 {
207 return resize(0);
208 }
209
210 constexpr reference emplace_back(auto &&...args)
211 {
212 grow();
213 auto tmp = std::construct_at(_end, hi_forward(args)...);
214 ++_end;
215 return *tmp;
216 }
217
218 constexpr void push_back(value_type const &value)
219 {
220 emplace_back(value);
221 }
222
223 constexpr void push_back(value_type &&value)
224 {
225 emplace_back(std::move(value));
226 }
227
228 constexpr void pop_back()
229 {
230 secure_destroy_at(back());
231 --_end;
232 }
233
234 constexpr iterator emplace(const_iterator pos, auto &&...args)
235 {
236 hilet index = std::distance(begin(), pos);
237 hilet n_first = &emplace_back(hi_forward(args)...);
238
239 // Rotate the newly back-emplaced item to it's intended position.
240 hilet first = _begin + index;
241 if (first != n_first) {
242 std::rotate(first, n_first, _end);
243 }
244 return first;
245 }
246
247 constexpr iterator insert(const_iterator pos, value_type const &value)
248 {
249 return emplace(pos, value);
250 }
251
252 constexpr iterator insert(const_iterator pos, value_type &&value)
253 {
254 return emplace(pos, std::move(value));
255 }
256
257 constexpr void reserve(size_type new_capacity)
258 {
259 if (new_capacity <= capacity()) {
260 return;
261 }
262
263 hilet tmp = allocate(new_capacity);
264 try {
265 secure_unitialized_move(_begin, _end, _tmp);
266 _end = tmp + size();
267 _bound = tmp + new_capacity;
268 _begin = tmp;
269 } catch (...) {
270 deallocate(tmp, new_capacity);
271 throw;
272 }
273 }
274
275 constexpr void shrink_to_fit()
276 {
277 if (empty()) {
278 if (_begin != nullptr) {
279 deallocate(_begin, capacity());
280 _begin = _end = _capacity = nullptr;
281 }
282
283 } else {
284 hilet new_capacity = size();
285 hilet tmp = allocate(new_capacity);
286 try {
287 secure_unitialized_move(_begin, _end, _tmp);
288 _end = tmp + size();
289 _bound = tmp + new_capacity;
290 _begin = tmp;
291 } catch (...) {
292 deallocate(tmp, new_capacity);
293 throw;
294 }
295 }
296 }
297
298private:
299 value_type *_begin;
300 value_type *_end;
301 value_type *_bound;
302
303 [[nodiscard]] constexpr bool full() const noexcept
304 {
305 return _end == _bound;
306 }
307
308 constexpr void grow(size_t count) const noexcept
309 {
310 auto new_size = size();
311 new_size = new_size ? new_size : 8;
312
313 hilet minimum_new_size = new_size + count;
314
315 while (new_size < minimum_new_size) {
316 new_size += new_size >> 1;
317 }
318
319 resize(new_size);
320 }
321
322 template<typename... Args>
323 constexpr void _resize(size_t new_size, Args const &... args)
324 {
325 reserve(new_size);
326
327 hilet new_end = _begin + new_size;
328
329 if (new_end > _end) {
330 // Construct the new values.
331 construct(_end, new_end, args...);
332
333 } else (new_end < _end) {
334 // Destroy the old values.
335 secure_destroy(new_end, _end);
336 }
337 _end = new_end;
338 }
339};
340
341namespace pmr {
342
343template<class T>
345}
346
347}
348
#define hilet
Invariant should be the default for variables.
Definition required.hpp:23
#define hi_forward(x)
Forward a value, based on the decltype of the value.
Definition required.hpp:29
Definition secure_vector.hpp:9
Secure vector.
Definition secure_vector.hpp:50
Definition concepts.hpp:35
Definition concepts.hpp:38
T allocate(T... args)
T deallocate(T... args)
T distance(T... args)
T max_size(T... args)
T move(T... args)
T rotate(T... args)