HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
memory.hpp
1// Copyright Take Vos 2019-2021.
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 "required.hpp"
8#include "assert.hpp"
9#include <concepts>
10#include <memory>
11#include <vector>
12#include <map>
13#include <unordered_map>
14#include <type_traits>
15#include <string.h>
16
17namespace hi::inline v1 {
18
19[[nodiscard]] bool equal_ptr(auto *p1, auto *p2) noexcept
20{
21 return static_cast<void *>(p1) == static_cast<void *>(p2);
22}
23
24template<typename T, typename U>
25void memswap(T& dst, U& src)
26{
27 static_assert(sizeof(T) == sizeof(U), "memswap requires both objects of equal size");
28 std::byte tmp[sizeof(T)];
29 memcpy(tmp, &src, sizeof(T));
30 memcpy(&src, &dst, sizeof(U));
31 memcpy(&dst, tmp, sizeof(T));
32}
33
44template<typename InputIt, typename T>
45T *placement_copy(InputIt src, T *dst)
46{
47 hi_axiom(dst != nullptr);
48 return new (dst) T(*src);
49}
50
55template<typename InputIt, typename T>
56void placement_copy(InputIt src_first, InputIt src_last, T *dst_first)
57{
58 hi_axiom(src_first != dst_first);
59 hi_axiom(src_last >= src_first);
60
61 auto src = src_first;
62 auto dst = dst_first;
63 while (src != src_last) {
64 placement_copy(src++, dst++);
65 }
66}
67
81template<typename T>
82T *placement_move(T *src, T *dst)
83{
84 hi_axiom(src != nullptr);
85 hi_axiom(dst != nullptr);
86
87 auto dst_ = new (dst) T(std::move(*src));
88 std::destroy_at(src);
89 return dst_;
90}
91
101template<typename T>
102void placement_move_within_array(T *src_first, T *src_last, T *dst_first)
103{
104 hi_axiom(src_last >= src_first);
105
106 if (src_first < dst_first) {
107 auto dst_last = dst_first + (src_last - src_first);
108
109 auto src = src_last;
110 auto dst = dst_last;
111 while (src != src_first) {
112 placement_move(--src, --dst);
113 }
114
115 } else if (src_first > dst_first) {
116 auto src = src_first;
117 auto dst = dst_first;
118 while (src != src_last) {
119 placement_move(src++, dst++);
120 }
121
122 } else {
123 // When src_first and dst_first are equal then no movement is necessary.
124 ;
125 }
126}
127
135template<typename T>
136void placement_move(T *src, T *src_last, T *dst)
137{
138 hi_axiom(src_last >= src);
139
140 while (src != src_last) {
141 placement_move(src++, dst++);
142 }
143}
144
147template<typename It, typename... Args>
148void construct(It first, It last, Args const&...args)
149{
150 for (auto it = first; it != last; ++it) {
151 std::construct_at(std::addressof(*it), args...);
152 }
153}
154
157template<typename T>
158constexpr bool is_aligned(T *p)
159{
160 return (reinterpret_cast<ptrdiff_t>(p) % std::alignment_of<T>::value) == 0;
161}
162
168template<std::unsigned_integral T>
169constexpr T floor(T value, T alignment) noexcept
170{
171 return (value / alignment) * alignment;
172}
173
179template<std::unsigned_integral T>
180constexpr T ceil(T value, T alignment) noexcept
181{
182 return floor(value + (alignment - 1), alignment);
183}
184
185template<typename T>
186constexpr T *ceil(T *ptr, std::size_t alignment) noexcept
187{
188 hilet aligned_byte_offset = ceil(reinterpret_cast<uintptr_t>(ptr), static_cast<uintptr_t>(alignment));
189 return reinterpret_cast<T *>(aligned_byte_offset);
190}
191
192template<typename T>
193constexpr T *floor(T *ptr, std::size_t alignment) noexcept
194{
195 hilet aligned_byte_offset = floor(reinterpret_cast<uintptr_t>(ptr), static_cast<uintptr_t>(alignment));
196 return reinterpret_cast<T *>(aligned_byte_offset);
197}
198
199template<typename T>
200inline void cleanupWeakPointers(std::vector<std::weak_ptr<T>>& v) noexcept
201{
202 auto i = v.begin();
203 while (i != v.end()) {
204 if (i->expired()) {
205 i = v.erase(i);
206 } else {
207 i++;
208 }
209 }
210}
211
212template<typename K, typename T>
213inline void cleanupWeakPointers(std::unordered_map<K, std::weak_ptr<T>>& v) noexcept
214{
215 auto i = v.begin();
216 while (i != v.end()) {
217 if (i->second.expired()) {
218 i = v.erase(i);
219 } else {
220 i++;
221 }
222 }
223}
224
225template<typename K, typename T>
226inline void cleanupWeakPointers(std::unordered_map<K, std::vector<std::weak_ptr<T>>>& v) noexcept
227{
228 auto i = v.begin();
229 while (i != v.end()) {
230 cleanupWeakPointers(i->second);
231 if (i->second.size() == 0) {
232 i = v.erase(i);
233 } else {
234 i++;
235 }
236 }
237}
238
239template<typename Value, typename Map, typename Key, typename... Args>
240inline std::shared_ptr<Value> try_make_shared(Map& map, Key key, Args... args)
241{
243
244 hilet i = map.find(key);
245 if (i == map.end()) {
246 value = std::make_shared<Value>(std::forward<Args>(args)...);
247 map.insert_or_assign(key, value);
248 } else {
249 value = i->second;
250 }
251 return value;
252}
253
264inline uint64_t ptr_to_uint48(auto *ptr) noexcept
265{
266 hi_axiom(static_cast<uint64_t>(ptr) % 16 == 0);
267
268 if constexpr (processor::current == processor::x64) {
269 // Only the bottom 48 bits are needed.
270 hi_axiom(
271 (static_cast<uint64_t>(ptr) & 0xffff'8000'0000'0000) == 0 ||
272 (static_cast<uint64_t>(ptr) & 0xffff'8000'0000'0000) == 0xffff'8000'0000'0000);
273 return (static_cast<uint64_t>(ptr) << 16) >> 16;
274
275 } else if constexpr (processor::current == processor::arm) {
276 // The top 8 bits may contain a tag.
277 hi_axiom(
278 (static_cast<uint64_t>(ptr) & 0x00ff'8000'0000'0000) == 0 ||
279 (static_cast<uint64_t>(ptr) & 0x00ff'8000'0000'0000) == 0x00ff'8000'0000'0000);
280
281 // Take the 4 sign bits + 44 msb bits of address.
282 auto u64 = (static_cast<uint64_t>(ptr) << 12) >> 16;
283
284 // Extract the 4 bit key.
285 auto key = (static_cast<uint64_t>(ptr) >> 56) << 44;
286
287 // XOR the key with the sign bits in the upper part of the 48 bit result.
288 return key ^ u64;
289
290 } else {
291 hi_static_no_default();
292 }
293}
294
305template<typename T>
306T *uint48_to_ptr(uint64_t x) noexcept
307{
308 hi_axiom((x >> 48) == 0);
309
310 if constexpr (processor::current == processor::x64) {
311 // Shift the upper bits away and sign extend the upper 16 bits.
312 auto i64 = (static_cast<int64_t>(x) << 16) >> 16;
313 return reinterpret_cast<T *>(i64);
314
315 } else if constexpr (processor::current == processor::arm) {
316 // Get 4 bit key (xor-ed with the sign bits).
317 auto key = (static_cast<uint64_t>(x) >> 44) << 56;
318
319 // Sign extend the address and make the bottom 4 bits zero.
320 auto i64 = (static_cast<int64_t>(x) << 20) >> 16;
321
322 // Add the original key by XOR with the sign.
323 return reinterpret_cast<T *>(key ^ static_cast<uint64_t>(i64));
324
325 } else {
326 hi_static_no_default();
327 }
328}
329
330} // namespace hi::inline v1
This file includes required definitions.
#define hilet
Invariant should be the default for variables.
Definition required.hpp:23
T addressof(T... args)
T ceil(T... args)
T floor(T... args)
T memcpy(T... args)
T move(T... args)