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