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
17hi_warning_push();
18// C26474: Don't cast between pointer types when the conversion could be implicit (type.1).
19// False positive, template with potential two different pointer types.
20hi_warning_ignore_msvc(26474);
21
22namespace hi::inline v1 {
23
24[[nodiscard]] bool equal_ptr(auto *p1, auto *p2) noexcept
25{
26 return static_cast<void *>(p1) == static_cast<void *>(p2);
27}
28
29template<typename T, typename U>
30void memswap(T& dst, U& src)
31{
32 static_assert(sizeof(T) == sizeof(U), "memswap requires both objects of equal size");
33 std::byte tmp[sizeof(T)];
34 memcpy(tmp, &src, sizeof(T));
35 memcpy(&src, &dst, sizeof(U));
36 memcpy(&dst, tmp, sizeof(T));
37}
38
49template<typename InputIt, typename T>
50T *placement_copy(InputIt src, T *dst)
51{
52 hi_axiom(dst != nullptr);
53 return new (dst) T(*src);
54}
55
60template<typename InputIt, typename T>
61void placement_copy(InputIt src_first, InputIt src_last, T *dst_first)
62{
63 hi_axiom(src_first != dst_first);
64 hi_axiom(src_last >= src_first);
65
66 auto src = src_first;
67 auto dst = dst_first;
68 while (src != src_last) {
69 placement_copy(src++, dst++);
70 }
71}
72
86template<typename T>
87T *placement_move(T *src, T *dst)
88{
89 hi_axiom(src != nullptr);
90 hi_axiom(dst != nullptr);
91
92 auto dst_ = new (dst) T(std::move(*src));
93 std::destroy_at(src);
94 return dst_;
95}
96
106template<typename T>
107void placement_move_within_array(T *src_first, T *src_last, T *dst_first)
108{
109 hi_axiom(src_last >= src_first);
110
111 if (src_first < dst_first) {
112 auto dst_last = dst_first + (src_last - src_first);
113
114 auto src = src_last;
115 auto dst = dst_last;
116 while (src != src_first) {
117 placement_move(--src, --dst);
118 }
119
120 } else if (src_first > dst_first) {
121 auto src = src_first;
122 auto dst = dst_first;
123 while (src != src_last) {
124 placement_move(src++, dst++);
125 }
126
127 } else {
128 // When src_first and dst_first are equal then no movement is necessary.
129 ;
130 }
131}
132
140template<typename T>
141void placement_move(T *src, T *src_last, T *dst)
142{
143 hi_axiom(src_last >= src);
144
145 while (src != src_last) {
146 placement_move(src++, dst++);
147 }
148}
149
152template<typename It, typename... Args>
153void construct(It first, It last, Args const&...args)
154{
155 for (auto it = first; it != last; ++it) {
156 std::construct_at(std::addressof(*it), args...);
157 }
158}
159
162template<typename T>
163constexpr bool is_aligned(T *p)
164{
165 return (reinterpret_cast<ptrdiff_t>(p) % std::alignment_of<T>::value) == 0;
166}
167
173template<std::unsigned_integral T>
174constexpr T floor(T value, T alignment) noexcept
175{
176 return (value / alignment) * alignment;
177}
178
184template<std::unsigned_integral T>
185constexpr T ceil(T value, T alignment) noexcept
186{
187 return floor(value + (alignment - 1), alignment);
188}
189
190template<typename T>
191constexpr T *ceil(T *ptr, std::size_t alignment) noexcept
192{
193 hilet aligned_byte_offset = ceil(reinterpret_cast<uintptr_t>(ptr), static_cast<uintptr_t>(alignment));
194 return reinterpret_cast<T *>(aligned_byte_offset);
195}
196
197template<typename T>
198constexpr T *floor(T *ptr, std::size_t alignment) noexcept
199{
200 hilet aligned_byte_offset = floor(reinterpret_cast<uintptr_t>(ptr), static_cast<uintptr_t>(alignment));
201 return reinterpret_cast<T *>(aligned_byte_offset);
202}
203
210inline void *advance_bytes(void *ptr, std::ptrdiff_t distance) noexcept
211{
212 hi_axiom(ptr != nullptr);
213 return static_cast<char *>(ptr) + distance;
214}
215
222inline void const *advance_bytes(void const *ptr, std::ptrdiff_t distance) noexcept
223{
224 hi_axiom(ptr != nullptr);
225 return static_cast<char const *>(ptr) + distance;
226}
227
228template<typename T>
229inline void cleanupWeakPointers(std::vector<std::weak_ptr<T>>& v) noexcept
230{
231 auto i = v.begin();
232 while (i != v.end()) {
233 if (i->expired()) {
234 i = v.erase(i);
235 } else {
236 i++;
237 }
238 }
239}
240
241template<typename K, typename T>
242inline void cleanupWeakPointers(std::unordered_map<K, std::weak_ptr<T>>& v) noexcept
243{
244 auto i = v.begin();
245 while (i != v.end()) {
246 if (i->second.expired()) {
247 i = v.erase(i);
248 } else {
249 i++;
250 }
251 }
252}
253
254template<typename K, typename T>
255inline void cleanupWeakPointers(std::unordered_map<K, std::vector<std::weak_ptr<T>>>& v) noexcept
256{
257 auto i = v.begin();
258 while (i != v.end()) {
259 cleanupWeakPointers(i->second);
260 if (i->second.size() == 0) {
261 i = v.erase(i);
262 } else {
263 i++;
264 }
265 }
266}
267
268template<typename Value, typename Map, typename Key, typename... Args>
269inline std::shared_ptr<Value> try_make_shared(Map& map, Key key, Args... args)
270{
272
273 hilet i = map.find(key);
274 if (i == map.end()) {
275 value = std::make_shared<Value>(std::forward<Args>(args)...);
276 map.insert_or_assign(key, value);
277 } else {
278 value = i->second;
279 }
280 return value;
281}
282
283} // namespace hi::inline v1
284
285hi_warning_pop();
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)