HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
memory.hpp
1// Copyright Take Vos 2019-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 "utility.hpp"
8#include "assert.hpp"
9#include "concepts.hpp"
10#include "math.hpp"
11#include <concepts>
12#include <memory>
13#include <vector>
14#include <map>
15#include <unordered_map>
16#include <type_traits>
17#include <string.h>
18
19hi_warning_push();
20// C26474: Don't cast between pointer types when the conversion could be implicit (type.1).
21// False positive, template with potential two different pointer types.
22hi_warning_ignore_msvc(26474);
23
24namespace hi::inline v1 {
25
26[[nodiscard]] bool equal_ptr(auto *p1, auto *p2) noexcept
27{
28 return static_cast<void *>(p1) == static_cast<void *>(p2);
29}
30
31template<typename T, typename U>
32void memswap(T& dst, U& src)
33{
34 static_assert(sizeof(T) == sizeof(U), "memswap requires both objects of equal size");
35 std::byte tmp[sizeof(T)];
36 memcpy(tmp, &src, sizeof(T));
37 memcpy(&src, &dst, sizeof(U));
38 memcpy(&dst, tmp, sizeof(T));
39}
40
51template<typename InputIt, typename T>
52T *placement_copy(InputIt src, T *dst)
53{
55 return new (dst) T(*src);
56}
57
62template<typename InputIt, typename T>
63void placement_copy(InputIt src_first, InputIt src_last, T *dst_first)
64{
65 hi_axiom(src_first != dst_first);
66 hi_axiom(src_last >= src_first);
67
68 auto src = src_first;
69 auto dst = dst_first;
70 while (src != src_last) {
71 placement_copy(src++, dst++);
72 }
73}
74
88template<typename T>
89T *placement_move(T *src, T *dst)
90{
93
94 auto dst_ = new (dst) T(std::move(*src));
95 std::destroy_at(src);
96 return dst_;
97}
98
108template<typename T>
109void placement_move_within_array(T *src_first, T *src_last, T *dst_first)
110{
111 hi_axiom(src_last >= src_first);
112
113 if (src_first < dst_first) {
114 auto dst_last = dst_first + (src_last - src_first);
115
116 auto src = src_last;
117 auto dst = dst_last;
118 while (src != src_first) {
119 placement_move(--src, --dst);
120 }
121
122 } else if (src_first > dst_first) {
123 auto src = src_first;
124 auto dst = dst_first;
125 while (src != src_last) {
126 placement_move(src++, dst++);
127 }
128
129 } else {
130 // When src_first and dst_first are equal then no movement is necessary.
131 ;
132 }
133}
134
142template<typename T>
143void placement_move(T *src, T *src_last, T *dst)
144{
145 hi_axiom(src_last >= src);
146
147 while (src != src_last) {
148 placement_move(src++, dst++);
149 }
150}
151
154template<typename It, typename... Args>
155void construct(It first, It last, Args const&...args)
156{
157 for (auto it = first; it != last; ++it) {
158 std::construct_at(std::addressof(*it), args...);
159 }
160}
161
164template<typename T>
165constexpr bool is_aligned(T *p)
166{
167 return (reinterpret_cast<ptrdiff_t>(p) % std::alignment_of<T>::value) == 0;
168}
169
170
171
172template<typename T>
173constexpr T *ceil(T *ptr, std::size_t alignment) noexcept
174{
175 hilet aligned_byte_offset = ceil(reinterpret_cast<uintptr_t>(ptr), static_cast<uintptr_t>(alignment));
176 return reinterpret_cast<T *>(aligned_byte_offset);
177}
178
179template<typename T>
180constexpr T *floor(T *ptr, std::size_t alignment) noexcept
181{
182 hilet aligned_byte_offset = floor(reinterpret_cast<uintptr_t>(ptr), static_cast<uintptr_t>(alignment));
183 return reinterpret_cast<T *>(aligned_byte_offset);
184}
185
192inline void *advance_bytes(void *ptr, std::ptrdiff_t distance) noexcept
193{
195 return static_cast<char *>(ptr) + distance;
196}
197
204inline void const *advance_bytes(void const *ptr, std::ptrdiff_t distance) noexcept
205{
207 return static_cast<char const *>(ptr) + distance;
208}
209
210template<typename T>
211inline void cleanupWeakPointers(std::vector<std::weak_ptr<T>>& v) noexcept
212{
213 auto i = v.begin();
214 while (i != v.end()) {
215 if (i->expired()) {
216 i = v.erase(i);
217 } else {
218 i++;
219 }
220 }
221}
222
223template<typename K, typename T>
224inline void cleanupWeakPointers(std::unordered_map<K, std::weak_ptr<T>>& v) noexcept
225{
226 auto i = v.begin();
227 while (i != v.end()) {
228 if (i->second.expired()) {
229 i = v.erase(i);
230 } else {
231 i++;
232 }
233 }
234}
235
236template<typename K, typename T>
237inline void cleanupWeakPointers(std::unordered_map<K, std::vector<std::weak_ptr<T>>>& v) noexcept
238{
239 auto i = v.begin();
240 while (i != v.end()) {
241 cleanupWeakPointers(i->second);
242 if (i->second.size() == 0) {
243 i = v.erase(i);
244 } else {
245 i++;
246 }
247 }
248}
249
250template<typename Value, typename Map, typename Key, typename... Args>
251inline std::shared_ptr<Value> try_make_shared(Map& map, Key key, Args... args)
252{
254
255 hilet i = map.find(key);
256 if (i == map.end()) {
257 value = std::make_shared<Value>(std::forward<Args>(args)...);
258 map.insert_or_assign(key, value);
259 } else {
260 value = i->second;
261 }
262 return value;
263}
264
267template<numeric T>
268[[nodiscard]] hi_force_inline constexpr T load(uint8_t const *src) noexcept
269{
270 auto r = T{};
271
272 if (not std::is_constant_evaluated()) {
273 // MSVC, clang and gcc are able to optimize this fully on x86-64.
274 std::memcpy(&r, src, sizeof(T));
275 return r;
276 }
277
278 if constexpr (std::endian::native == std::endian::little) {
279 for (auto i = sizeof(T); i != 0; --i) {
280 r <<= 8;
281 r |= src[i-1];
282 }
283 } else {
284 for (auto i = 0; i != sizeof(T); ++i) {
285 r <<= 8;
286 r |= src[i];
287 }
288 }
289 return r;
290}
291
292template<numeric T>
293[[nodiscard]] hi_force_inline constexpr void store(T src, uint8_t const *dst) noexcept
294{
295 using unsigned_type = std::make_unsigned_t<T>;
296
297 hilet src_ = static_cast<unsigned_type>(src);
298
299 if (not std::is_constant_evaluated()) {
300#if HI_COMPILER == HI_CC_MSVC
301 *reinterpret_cast<__unaligned unsigned_type const *>(dst) = src_;
302 return;
303#else
304 std::memcpy(dst, &src, sizeof(T));
305 return;
306#endif
307 }
308
309 if constexpr (std::endian::native == std::endian::little) {
310 for (auto i = 0; i != sizeof(T); ++i) {
311 dst[i] = static_cast<uint8_t>(src_);
312 src_ >>= 8;
313 }
314 } else {
315 for (auto i = sizeof(T); i != 0; --i) {
316 dst[i] = static_cast<uint8_t>(src_);
317 src_ >>= 8;
318 }
319 }
320}
321
322template<numeric T>
323[[nodiscard]] hi_force_inline constexpr void store_or(T src, uint8_t *dst) noexcept
324{
325 using unsigned_type = std::make_unsigned_t<T>;
326
327 auto src_ = static_cast<unsigned_type>(src);
328
329 if (not std::is_constant_evaluated()) {
330#if HI_COMPILER == HI_CC_MSVC
331 *reinterpret_cast<__unaligned unsigned_type *>(dst) |= src_;
332 return;
333#else
334 decltype(src_) tmp;
335 std::memcpy(&tmp, dst, sizeof(T));
336 tmp |= src_;
337 std::memcpy(dst, &tmp, sizeof(T));
338#endif
339 }
340
341 if constexpr (std::endian::native == std::endian::little) {
342 for (auto i = 0; i != sizeof(T); ++i) {
343 dst[i] |= static_cast<uint8_t>(src_);
344 src_ >>= 8;
345 }
346 } else {
347 for (auto i = sizeof(T); i != 0; --i) {
348 dst[i] |= static_cast<uint8_t>(src_);
349 src_ >>= 8;
350 }
351 }
352}
353
354} // namespace hi::inline v1
355
356hi_warning_pop();
Utilities to assert and bound check.
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:133
#define hi_axiom_not_null(expression,...)
Assert if an expression is not nullptr.
Definition assert.hpp:141
Miscellaneous math functions.
Utilities used by the HikoGUI library itself.
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
DOXYGEN BUG.
Definition algorithm.hpp:15
hi_force_inline T load(void const *src) noexcept
Load an integer from unaligned memory in native byte-order.
Definition endian.hpp:201
T * placement_copy(InputIt src, T *dst)
Copy an object to another memory locations.
Definition memory.hpp:52
void * advance_bytes(void *ptr, std::ptrdiff_t distance) noexcept
Advance a pointer by a number of bytes.
Definition memory.hpp:192
void construct(It first, It last, Args const &...args)
Construct a set of objects.
Definition memory.hpp:155
constexpr bool is_aligned(T *p)
Check if a pointer is properly aligned for the object it is pointing at.
Definition memory.hpp:165
void placement_move_within_array(T *src_first, T *src_last, T *dst_first)
Move an objects between two memory locations.
Definition memory.hpp:109
T * placement_move(T *src, T *dst)
Move an object between two memory locations.
Definition memory.hpp:89
T addressof(T... args)
T floor(T... args)
T memcpy(T... args)
T move(T... args)