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 "concepts"
9#include <memory>
10#include <vector>
11#include <map>
12#include <unordered_map>
13
14namespace tt {
15
16template<typename T, typename U>
17void memswap(T &dst, U &src)
18{
19 static_assert(sizeof(T) == sizeof(U), "memswap requires both objects of equal size");
20 std::byte tmp[sizeof(T)];
21 memcpy(tmp, &src, sizeof(T));
22 memcpy(&src, &dst, sizeof(U));
23 memcpy(&dst, tmp, sizeof(T));
24}
25
36template<typename InputIt, typename T>
37T *placement_copy(InputIt src, T *dst)
38{
39 tt_axiom(dst != nullptr);
40 return new (dst) T(*src);
41}
42
47template<typename InputIt, typename T>
48void placement_copy(InputIt src_first, InputIt src_last, T *dst_first)
49{
50 tt_axiom(src_first != dst_first);
51 tt_axiom(src_last >= src_first);
52
53 auto src = src_first;
54 auto dst = dst_first;
55 while (src != src_last) {
56 placement_copy(src++, dst++);
57 }
58}
59
73template<typename T>
74T *placement_move(T *src, T *dst)
75{
76 tt_axiom(src != nullptr);
77 tt_axiom(dst != nullptr);
78
79 auto dst_ = new (dst) T(std::move(*src));
80 std::destroy_at(src);
81 return dst_;
82}
83
93template<typename T>
94void placement_move_within_array(T *src_first, T *src_last, T *dst_first)
95{
96 tt_axiom(src_last >= src_first);
97
98 if (src_first < dst_first) {
99 auto dst_last = dst_first + (src_last - src_first);
100
101 auto src = src_last;
102 auto dst = dst_last;
103 while (src != src_first) {
104 placement_move(--src, --dst);
105 }
106
107 } else if (src_first > dst_first) {
108 auto src = src_first;
109 auto dst = dst_first;
110 while (src != src_last) {
111 placement_move(src++, dst++);
112 }
113
114 } else {
115 // When src_first and dst_first are equal then no movement is necessary.
116 ;
117 }
118}
119
127template<typename T>
128void placement_move(T *src, T *src_last, T *dst)
129{
130 tt_axiom(src_last >= src);
131
132 while (src != src_last) {
133 placement_move(src++, dst++);
134 }
135}
136
139template<typename T>
140constexpr bool is_aligned(T *p)
141{
142 return (reinterpret_cast<ptrdiff_t>(p) % std::alignment_of<T>::value) == 0;
143}
144
150template<std::unsigned_integral T>
151constexpr T floor(T value, T alignment) noexcept
152{
153 return (value / alignment) * alignment;
154}
155
161template<std::unsigned_integral T>
162constexpr T ceil(T value, T alignment) noexcept
163{
164 return floor(value + (alignment - 1), alignment);
165}
166
167template<typename T>
168constexpr T *ceil(T *ptr, size_t alignment) noexcept
169{
170 ttlet aligned_byte_offset = ceil(reinterpret_cast<uintptr_t>(ptr), static_cast<uintptr_t>(alignment));
171 return reinterpret_cast<T *>(aligned_byte_offset);
172}
173
174template<typename T>
175constexpr T *floor(T *ptr, size_t alignment) noexcept
176{
177 ttlet aligned_byte_offset = floor(reinterpret_cast<uintptr_t>(ptr), static_cast<uintptr_t>(alignment));
178 return reinterpret_cast<T *>(aligned_byte_offset);
179}
180
181template<typename T>
182inline void cleanupWeakPointers(std::vector<std::weak_ptr<T>> &v) noexcept
183{
184 auto i = v.begin();
185 while (i != v.end()) {
186 if (i->expired()) {
187 i = v.erase(i);
188 } else {
189 i++;
190 }
191 }
192}
193
194template<typename K, typename T>
195inline void cleanupWeakPointers(std::unordered_map<K, std::weak_ptr<T>> &v) noexcept
196{
197 auto i = v.begin();
198 while (i != v.end()) {
199 if (i->second.expired()) {
200 i = v.erase(i);
201 } else {
202 i++;
203 }
204 }
205}
206
207template<typename K, typename T>
208inline void cleanupWeakPointers(std::unordered_map<K, std::vector<std::weak_ptr<T>>> &v) noexcept
209{
210 auto i = v.begin();
211 while (i != v.end()) {
212 cleanupWeakPointers(i->second);
213 if (i->second.size() == 0) {
214 i = v.erase(i);
215 } else {
216 i++;
217 }
218 }
219}
220
221template<typename Value, typename Map, typename Key, typename... Args>
222inline std::shared_ptr<Value> try_make_shared(Map &map, Key key, Args... args)
223{
225
226 ttlet i = map.find(key);
227 if (i == map.end()) {
228 value = std::make_shared<Value>(std::forward<Args>(args)...);
229 map.insert_or_assign(key, value);
230 } else {
231 value = i->second;
232 }
233 return value;
234}
235
246inline uint64_t ptr_to_uint48(auto *ptr) noexcept
247{
248 tt_axiom(static_cast<uint64_t>(ptr) % 16 == 0);
249
250 if constexpr (Processor::current == Processor::x64) {
251 // Only the bottom 48 bits are needed.
252 tt_axiom(
253 (static_cast<uint64_t>(ptr) & 0xffff'8000'0000'0000) == 0 ||
254 (static_cast<uint64_t>(ptr) & 0xffff'8000'0000'0000) == 0xffff'8000'0000'0000);
255 return (static_cast<uint64_t>(ptr) << 16) >> 16;
256
257 } else if constexpr (Processor::current == Processor::ARM) {
258 // The top 8 bits may contain a tag.
259 tt_axiom(
260 (static_cast<uint64_t>(ptr) & 0x00ff'8000'0000'0000) == 0 ||
261 (static_cast<uint64_t>(ptr) & 0x00ff'8000'0000'0000) == 0x00ff'8000'0000'0000);
262
263 // Take the 4 sign bits + 44 msb bits of address.
264 auto u64 = (static_cast<uint64_t>(ptr) << 12) >> 16;
265
266 // Extract the 4 bit key.
267 auto key = (static_cast<uint64_t>(ptr) >> 56) << 44;
268
269 // XOR the key with the sign bits in the upper part of the 48 bit result.
270 return key ^ u64;
271
272 } else {
273 tt_static_no_default();
274 }
275}
276
287template<typename T>
288T *uint48_to_ptr(uint64_t x) noexcept
289{
290 tt_axiom((x >> 48) == 0);
291
292 if constexpr (Processor::current == Processor::x64) {
293 // Shift the upper bits away and sign extend the upper 16 bits.
294 auto i64 = (static_cast<int64_t>(x) << 16) >> 16;
295 return reinterpret_cast<T *>(i64);
296
297 } else if constexpr (Processor::current == Processor::ARM) {
298 // Get 4 bit key (xor-ed with the sign bits).
299 auto key = (static_cast<uint64_t>(x) >> 44) << 56;
300
301 // Sign extend the address and make the bottom 4 bits zero.
302 auto i64 = (static_cast<int64_t>(x) << 20) >> 16;
303
304 // Add the original key by XOR with the sign.
305 return reinterpret_cast<T *>(key ^ static_cast<uint64_t>(i64));
306
307 } else {
308 tt_static_no_default();
309 }
310}
311
312} // namespace tt
T ceil(T... args)
T floor(T... args)
T memcpy(T... args)
T move(T... args)