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