-
Notifications
You must be signed in to change notification settings - Fork 0
/
align.hpp
210 lines (185 loc) · 5.54 KB
/
align.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
/**
* @file align.hpp
* @author Jens Munk Hansen <[email protected]>
* @date Thu Sep 13 23:00:27 2018
*
* @brief
*
* Copyright 2018 Jens Munk Hansen
*/
#pragma once
#ifndef __cplusplus
# error This is a C++ header
#endif
#include <sps/debug.h>
#include <sps/cenv.h> // TODO(JMH): Split this up
#include <sps/mm_malloc.h>
#include <cstdint> // uintptr_t
#include <stdexcept>
#include <sps/crtp_helper.hpp>
#ifndef CXX11
# error This header requires at least C++11
#endif
namespace sps {
template <unsigned int alignment>
struct is_aligned {
static_assert((alignment & (alignment - 1)) == 0,
"Alignment must be a power of 2");
static inline bool value(const void * ptr) {
return (((uintptr_t)ptr) & (alignment - 1)) == 0;
}
};
/*! \brief aligned struct for stack alignment
*
* @tparam A alignment
*
* VC++ doesn't like combining templates with __declspec. This is a
* work-around using inheritance.
*
* e.g. it is possible to do
*
* template <class T>
* class AlignedClass : sps::aligned<16> {
*
* };
*
* or even
*
* template <class T>
* class AlignedToFourOfAKind : sps::aligned<4*sizeof(T)> {
*
* };
*
* Using G++ or Clang, there is no need for this work-around and
* we can do stuff like
*
* template <class T>
* struct __attribute__((aligned(4*sizeof(T)))) Data
* {
* T a;
* };
*
*
* In the case of multiple inheritance, place this to the left. Storage is allocated
* and initializers are called from left to right - the order they appear
*/
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable:4324)
__declspec(align(1)) struct align1 {};
__declspec(align(2)) struct align2 {};
__declspec(align(4)) struct align4 {};
__declspec(align(8)) struct align8 {};
__declspec(align(16)) struct align16 {};
__declspec(align(32)) struct align32 {};
__declspec(align(64)) struct align64 {};
template<int A> struct aligned;
template<> struct aligned<1> : align1 {};
template<> struct aligned<2> : align2 {};
template<> struct aligned<4> : align4 {};
template<> struct aligned<8> : align8 {};
template<> struct aligned<16> : align16 {};
template<> struct aligned<32> : align32 {};
template<> struct aligned<64> : align64 {};
# pragma warning(pop)
#else
template<int A> struct aligned;
template<> struct __attribute__((aligned(1))) aligned<1> { };
template<> struct __attribute__((aligned(2))) aligned<2> { };
template<> struct __attribute__((aligned(4))) aligned<4> { };
template<> struct __attribute__((aligned(8))) aligned<8> { };
template<> struct __attribute__((aligned(16))) aligned<16> { };
template<> struct __attribute__((aligned(32))) aligned<32> { };
template<> struct __attribute__((aligned(64))) aligned<64> { };
#endif
// TODO(JMH): Invalid free(), delete, delete[] or realloc (when used with arrays)
/*! \brief Alignment helper for ensuring heap alignment
*
* A class supplying providing aligned single and array
* allocators. The class is implemented using the curious recurring
* template pattern (CRTP). When C++17 is used and structures are
* aligned using alignas, the default allocators and deallocators
* respect alignment on the heap. For C++14, this is not the case.
*
* @tparam T The descendant, which satisfy alignment on stack and heap
* @tparam Alignment The alignment, which must be a power of two
*
*/
template <typename T, size_t Alignment = 16>
class dynaligned : public sps::aligned<Alignment> {
public:
// Throwing
void* operator new(std::size_t size) {
debug_print("aligned\n");
T* ptr = static_cast<T*>(SPS_MM_MALLOC(size, Alignment));
return ptr ? ptr : throw std::bad_alloc{};
}
// Non-throwing
// void* operator new(std::size_t, const std::nothrow_t& nothrow_value) noexcept;
// Placement
// void* operator new(std::size_t, void* ptr) noexcept;
void operator delete(void* ptr) {
debug_print("aligned\n");
SPS_MM_FREE(ptr);
}
void* operator new[]( std::size_t size) {
debug_print("aligned\n");
T* ptr = static_cast<T*>(SPS_MM_MALLOC(size, Alignment));
return ptr ? ptr : throw std::bad_alloc{};
}
void operator delete[](void* ptr, size_t count) {
SPS_MM_FREE(ptr);
}
#if CXX17
/** @name C++17 provide over-aligned allocators and deallocators
*
* The (de)allocators are used provided that the structure is
* aligned using alignas() and alignment is larger than
* __STDCPP_DEFAULT_NEW_ALIGNMENT__
*/
///@{
void* operator new(std::size_t size, std::align_val_t al) {
debug_print("aligned\n");
static_assert((size_t)al == Alignment, "Alignment mismatch");
#if 1
return ::operator new(size, al);
#else
// The above should work
T* ptr = static_cast<T*>(SPS_MM_MALLOC(size, al));
return ptr ? ptr : throw std::bad_alloc{};
#endif
}
void operator delete(void* ptr, std::align_val_t align) {
debug_print("aligned\n");
#if 1
return ::operator delete(ptr);
#else
// The above should work
SPS_MM_FREE(ptr);
#endif
}
// Called if the above is left undefined
void operator delete(void* ptr, std::size_t size, std::align_val_t align) {
debug_print("aligned\n");
#if 1
return ::operator delete(ptr);
#else
SPS_MM_FREE(ptr);
#endif
}
void* operator new[]( std::size_t count, std::align_val_t al) {
debug_print("aligned\n");
return ::operator new[](count, al);
}
void operator delete[](void* ptr, std::size_t count, std::align_val_t al) {
debug_print("aligned\n");
return ::operator delete[](ptr, count, al); // Calls many dtors, free
}
#endif
///@}
private:
dynaligned() = default;
friend T;
};
} // namespace sps
// dynamic heap alignment