Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/src/common/align.h
4223 views
1
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <[email protected]>
2
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
3
4
#pragma once
5
6
#include "types.h"
7
8
#include <cstdlib>
9
#include <memory>
10
#include <type_traits>
11
12
#ifdef _MSC_VER
13
#include <malloc.h>
14
#endif
15
16
namespace Common {
17
template<typename T>
18
ALWAYS_INLINE constexpr bool IsAligned(T value, unsigned int alignment)
19
{
20
return (value % static_cast<T>(alignment)) == 0;
21
}
22
template<typename T>
23
ALWAYS_INLINE constexpr T AlignUp(T value, unsigned int alignment)
24
{
25
return (value + static_cast<T>(alignment - 1)) / static_cast<T>(alignment) * static_cast<T>(alignment);
26
}
27
template<typename T>
28
ALWAYS_INLINE constexpr T AlignDown(T value, unsigned int alignment)
29
{
30
return value / static_cast<T>(alignment) * static_cast<T>(alignment);
31
}
32
template<typename T>
33
ALWAYS_INLINE constexpr bool IsAlignedPow2(T value, unsigned int alignment)
34
{
35
return (value & static_cast<T>(alignment - 1)) == 0;
36
}
37
template<typename T>
38
ALWAYS_INLINE constexpr T AlignUpPow2(T value, unsigned int alignment)
39
{
40
return (value + static_cast<T>(alignment - 1)) & static_cast<T>(~static_cast<T>(alignment - 1));
41
}
42
template<typename T>
43
ALWAYS_INLINE constexpr T AlignDownPow2(T value, unsigned int alignment)
44
{
45
return value & static_cast<T>(~static_cast<T>(alignment - 1));
46
}
47
template<typename T>
48
ALWAYS_INLINE constexpr bool IsPow2(T value)
49
{
50
return (value & (value - 1)) == 0;
51
}
52
template<typename T>
53
ALWAYS_INLINE constexpr T PreviousPow2(T value)
54
{
55
if (value == static_cast<T>(0))
56
return 0;
57
58
value |= (value >> 1);
59
value |= (value >> 2);
60
value |= (value >> 4);
61
if constexpr (sizeof(T) >= 2)
62
value |= (value >> 8);
63
if constexpr (sizeof(T) >= 4)
64
value |= (value >> 16);
65
if constexpr (sizeof(T) >= 8)
66
value |= (value >> 32);
67
68
return (value >> 1) + 1;
69
}
70
71
/// NOTE: Undefined for values greater than (1 << BITS-1), i.e. 0x80000000 for 32-bit.
72
template<typename T>
73
ALWAYS_INLINE constexpr T NextPow2(T value)
74
{
75
// https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
76
if (value == static_cast<T>(0))
77
return 0;
78
79
value--;
80
value |= (value >> 1);
81
value |= (value >> 2);
82
value |= (value >> 4);
83
if constexpr (sizeof(T) >= 2)
84
value |= (value >> 8);
85
if constexpr (sizeof(T) >= 4)
86
value |= (value >> 16);
87
if constexpr (sizeof(T) >= 8)
88
value |= (value >> 32);
89
value++;
90
return value;
91
}
92
93
ALWAYS_INLINE void* AlignedMalloc(size_t size, size_t alignment)
94
{
95
#ifdef _MSC_VER
96
return _aligned_malloc(size, alignment);
97
#else
98
// Unaligned sizes are slow on macOS.
99
#ifdef __APPLE__
100
if (IsPow2(alignment))
101
size = (size + alignment - 1) & ~(alignment - 1);
102
#endif
103
void* ret = nullptr;
104
return (posix_memalign(&ret, alignment, size) == 0) ? ret : nullptr;
105
#endif
106
}
107
108
ALWAYS_INLINE void AlignedFree(void* ptr)
109
{
110
#ifdef _MSC_VER
111
_aligned_free(ptr);
112
#else
113
free(ptr);
114
#endif
115
}
116
117
namespace detail {
118
template<class T>
119
struct unique_aligned_ptr_deleter
120
{
121
ALWAYS_INLINE void operator()(T* ptr) { Common::AlignedFree(ptr); }
122
};
123
124
template<class>
125
constexpr bool is_unbounded_array_v = false;
126
template<class T>
127
constexpr bool is_unbounded_array_v<T[]> = true;
128
129
template<class>
130
constexpr bool is_bounded_array_v = false;
131
template<class T, std::size_t N>
132
constexpr bool is_bounded_array_v<T[N]> = true;
133
} // namespace detail
134
135
template<class T>
136
using unique_aligned_ptr = std::unique_ptr<T, detail::unique_aligned_ptr_deleter<std::remove_extent_t<T>>>;
137
138
template<class T, class... Args>
139
requires(std::is_unbounded_array_v<T>, std::is_trivially_default_constructible_v<std::remove_extent_t<T>>,
140
std::is_trivially_destructible_v<std::remove_extent_t<T>>)
141
unique_aligned_ptr<T> make_unique_aligned(size_t alignment, size_t n)
142
{
143
unique_aligned_ptr<T> ptr(
144
static_cast<std::remove_extent_t<T>*>(AlignedMalloc(sizeof(std::remove_extent_t<T>) * n, alignment)));
145
if (ptr)
146
new (ptr.get()) std::remove_extent_t<T>[ n ]();
147
return ptr;
148
}
149
150
template<class T, class... Args>
151
requires(std::is_unbounded_array_v<T>, std::is_trivially_default_constructible_v<std::remove_extent_t<T>>,
152
std::is_trivially_destructible_v<std::remove_extent_t<T>>)
153
unique_aligned_ptr<T> make_unique_aligned_for_overwrite(size_t alignment, size_t n)
154
{
155
return unique_aligned_ptr<T>(
156
static_cast<std::remove_extent_t<T>*>(AlignedMalloc(sizeof(std::remove_extent_t<T>) * n, alignment)));
157
}
158
159
} // namespace Common
160
161