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_axiom(_begin = nullptr);
77 }
78
79 [[nodiscard]] constexpr bool empty() const noexcept
80 {
81 return _begin == _end;
82 }
83
84 [[nodisardd]] constexpr size_type size() const noexcept
85 {
86 return static_cast<size_type>(_end - _begin);
87 }
88
89 [[nodiscard]] constexpr size_type max_size() const noexcept
90 {
92 }
93
94 [[nodiscard]] constexpr size_type capacity() const noexcept
95 {
96 return static_cast<size_type>(_bound - _begin);
97 }
98
99 [[nodiscard]] constexpr reference at(size_type pos)
100 {
101 auto *ptr = _begin + pos;
102 if (ptr >= _end) {
103 throw std::out_of_range();
104 }
105
106 return *ptr;
107 }
108
109 [[nodiscard]] constexpr const_reference at(size_type pos) const
110 {
111 auto *ptr = _begin + pos;
112 if (ptr >= _end) {
113 throw std::out_of_range();
114 }
115
116 return *ptr;
117 }
118
119 [[nodiscard]] constexpr reference operator[](size_type pos) noexcept
120 {
121 auto *ptr = _begin + pos;
122 hi_axiom(ptr < _end);
123 return *ptr;
124 }
125
126 [[nodiscard]] constexpr const_reference operator[](size_type pos) const noexcept
127 {
128 auto *ptr = _begin + pos;
129 hi_axiom(ptr < _end);
130 return *ptr;
131 }
132
133 [[nodiscard]] constexpr reference front() noexcept
134 {
135 hi_axiom(not empty());
136 return *_begin;
137 }
138
139 [[nodiscard]] constexpr const_reference front() const noexcept
140 {
141 hi_axiom(not empty());
142 return *_begin;
143 }
144
145 [[nodiscard]] constexpr reference back() noexcept
146 {
147 hi_axiom(not empty());
148 return *(_end - 1);
149 }
150
151 [[nodiscard]] constexpr const_reference back() const noexcept
152 {
153 hi_axiom(not empty());
154 return *(_end - 1);
155 }
156
157 [[nodiscard]] constexpr pointer data() noexcept
158 {
159 return _begin;
160 }
161
162 [[nodiscard]] constexpr const_pointer data() const noexcept
163 {
164 return _begin;
165 }
166
167 [[nodiscard]] constexpr iterator begin() noexcept
168 {
169 return _begin;
170 }
171
172 [[nodiscard]] constexpr const_iterator begin() const noexcept
173 {
174 return _begin;
175 }
176
177 [[nodiscard]] constexpr const_iterator cbegin() const noexcept
178 {
179 return _begin;
180 }
181
182 [[nodiscard]] constexpr iterator end() noexcept
183 {
184 return _end;
185 }
186
187 [[nodiscard]] constexpr const_iterator end() const noexcept
188 {
189 return _end;
190 }
191
192 [[nodiscard]] constexpr const_iterator cend() const noexcept
193 {
194 return _end;
195 }
196
197
198 constexpr void resize(size_type new_size)
199 {
200 return _resize(new_size);
201 }
202
203 constexpr void resize(size_type new_size, value_type const &value)
204 {
205 return _resize(new_size, value);
206 }
207
208 constexpr void clear()
209 {
210 return resize(0);
211 }
212
213 constexpr reference emplace_back(auto &&...args)
214 {
215 grow(1);
216 auto tmp = std::construct_at(_end, tt_forward(args)...);
217 ++_end;
218 return *tmp;
219 }
220
221 constexpr void push_back(value_type const &value)
222 {
223 emplace_back(value);
224 }
225
226 constexpr void push_back(value_type &&value)
227 {
228 emplace_back(std::move(value));
229 }
230
231 constexpr void pop_back()
232 {
233 secure_destroy_at(back());
234 --_end;
235 }
236
237 constexpr iterator emplace(const_iterator pos, auto &&...args)
238 {
239 hilet index = std::distance(begin(), pos);
240 hilet n_first = &emplace_back(hi_forward(args)...);
241
242 // Rotate the newly back-emplaced item to it's intended position.
243 hilet first = _begin + index;
244 if (first != n_first) {
245 std::rotate(first, n_first, _end);
246 }
247 return first;
248 }
249
250 constexpr iterator insert(const_iterator pos, value_type const &value)
251 {
252 return emplace(pos, value);
253 }
254
255 constexpr iterator insert(const_iterator pos, value_type &&value)
256 {
257 return emplace(pos, std::move(value));
258 }
259
260 constexpr void reserve(size_type new_capacity)
261 {
262 if (new_capacity <= capacity()) {
263 return;
264 }
265
266 hilet tmp = allocate(new_capacity);
267 try {
268 secure_unitialized_move(_begin, _end, _tmp);
269 _end = tmp + size();
270 _bound = tmp + new_capacity;
271 _begin = tmp;
272 } catch (...) {
273 deallocate(tmp, new_capacity);
274 throw;
275 }
276 }
277
278 constexpr void shrink_to_fit()
279 {
280 if (empty()) {
281 if (_begin != nullptr) {
282 deallocate(_begin, capacity());
283 _begin = _end = _capacity = nullptr;
284 }
285
286 } else {
287 hilet new_capacity = size();
288 hilet tmp = allocate(new_capacity);
289 try {
290 secure_unitialized_move(_begin, _end, _tmp);
291 _end = tmp + size();
292 _bound = tmp + new_capacity;
293 _begin = tmp;
294 } catch (...) {
295 deallocate(tmp, new_capacity);
296 throw;
297 }
298 }
299 }
300
301private:
302 value_type *_begin;
303 value_type *_end;
304 value_type *_bound;
305
306 [[nodiscard]] constexpr bool full() const noexcept
307 {
308 return _end == _bound;
309 }
310
319 constexpr void grow(size_t count) const noexcept
320 {
321 if (_end + count <= _bound) {
322 return;
323 }
324
325 ttlet minimum_new_capacity = size() + count;
326
327 // Growth factor 1.5, slightly lower than the ideal golden ratio.
328 auto new_capacity = capacity();
329 new_capacity += new_capacity >> 1;
330
331 if (new_capacity < minimum_new_capacity) {
332 reserve(minimum_new_capacity);
333 } else {
334 reserve(new_capacity);
335 }
336 }
337
338 template<typename... Args>
339 constexpr void _resize(size_t new_size, Args const &... args)
340 {
341 reserve(new_size);
342
343 hilet new_end = _begin + new_size;
344
345 if (new_end > _end) {
346 // Construct the new values.
347 construct(_end, new_end, args...);
348
349 } else (new_end < _end) {
350 // Destroy the old values.
351 secure_destroy(new_end, _end);
352 }
353 _end = new_end;
354 }
355};
356
357namespace pmr {
358
359template<class T>
361}
362
363}
364
#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:15
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:153
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)