-
Notifications
You must be signed in to change notification settings - Fork 2
/
Aligned.hpp
168 lines (158 loc) · 6.48 KB
/
Aligned.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
#ifndef ALIGNED_HPP_INCLUDED
#define ALIGNED_HPP_INCLUDED
#include <cstddef>
#include <cstdint>
#include <initializer_list>
#include <memory>
#include <type_traits>
#include "AlignedBase.hpp"
#include "AlignedArrayConstructorCaller.hpp"
#include "AlignedArrayDestructorCaller.hpp"
#include "InitializerListLongerThanSizeException.hpp"
#define ALIGNED_BYTES_SIZE(alignment, sizeOfTPaddedToAlignment) (alignment + sizeOfTPaddedToAlignment - 1)
#define ALIGNED_POINTER(T, bytes, sizeOfTPaddedToAlignment) (reinterpret_cast<T *>(uintptr_t(bytes) + (sizeOfTPaddedToAlignment - 1) & ~uintptr_t(sizeOfTPaddedToAlignment - 1)))
#define ALIGNED_ARRAY_BYTES_SIZE(T, sizeOfTPaddedToAlignment, size) (sizeof(T) + (sizeOfTPaddedToAlignment * size) - 1)
#define ALIGNED_ARRAY_INDEX_POINTER(T, pFirstElement, sizeOfTPaddedToAlignment, index) (reinterpret_cast<T *>(uintptr_t(pFirstElement) + (sizeOfTPaddedToAlignment * index)))
template<typename T, std::size_t Alignment = -1>
class Aligned : AlignedBase<T, Alignment> {
uint8_t bytes[ALIGNED_BYTES_SIZE(Alignment, sizeOfTPaddedToAlignment)];
T * const pValue;
Aligned(Aligned const &);
Aligned const & operator=(Aligned const &);
public:
template<typename... Args>
Aligned(Args &&... args) : pValue(ALIGNED_POINTER(T, bytes, sizeOfTPaddedToAlignment)) { new (pValue)T(std::forward<Args>(args)...); }
~Aligned() { pValue->T::~T(); }
T & Ref() { return *pValue; }
T const & Ref() const { return *pValue; }
};
template<typename T>
class Aligned<T, -1> : AlignedBase<T, -1> {
std::unique_ptr<uint8_t[]> const pBytes;
T * const pValue;
public:
template<typename... Args>
Aligned(std::size_t alignment, Args &&... args) : AlignedBase(alignment)
, pBytes(new uint8_t[ALIGNED_BYTES_SIZE(alignment, sizeOfTPaddedToAlignment)])
, pValue(ALIGNED_POINTER(T, pBytes.get(), sizeOfTPaddedToAlignment))
{
new (pValue)T(std::forward<Args>(args)...);
}
~Aligned() { pValue->T::~T(); }
T & Ref() { return *pValue; }
T const & Ref() const { return *pValue; }
};
template<typename T, std::size_t Size, std::size_t Alignment>
class Aligned<T[Size], Alignment> : AlignedBase<T, Alignment> {
Aligned(Aligned const &);
Aligned & operator=(Aligned const &);
static std::size_t const size = Size;
uint8_t bytes[ALIGNED_ARRAY_BYTES_SIZE(T, sizeOfTPaddedToAlignment, Size)];
T * const pFirstElement;
T & element(std::size_t index) { return *ALIGNED_ARRAY_INDEX_POINTER(T, pFirstElement, sizeOfTPaddedToAlignment, index); }
public:
Aligned()
: pFirstElement(ALIGNED_POINTER(T, bytes, sizeOfTPaddedToAlignment))
{
AlignedArrayConstructorCaller<T>::Call(size, pFirstElement, sizeOfTPaddedToAlignment);
}
Aligned(std::size_t size, std::initializer_list<T> const & list)
: pFirstElement(ALIGNED_POINTER(T, bytes, sizeOfTPaddedToAlignment))
{
if (size < list.size())
throw InitializerListLongerThanSizeException();
int i = 0;
for (auto it = list.begin(); it != list.end(); ++it)
this->element(i++) = *it;
}
Aligned(std::initializer_list<T> const & list)
: Aligned(list.size(), list)
{}
~Aligned() {
AlignedArrayDestructorCaller<T>::Call(size, pFirstElement, sizeOfTPaddedToAlignment);
}
T & operator[](std::size_t index) { return element(index); }
T const & operator[](std::size_t index) const { return element(index); }
std::size_t Size() const { return size; }
};
template<typename T, std::size_t Alignment>
class Aligned<T[], Alignment> : AlignedBase<T, Alignment> {
Aligned(Aligned const &);
Aligned & operator=(Aligned const &);
std::size_t const size;
std::unique_ptr<uint8_t[]> const pBytes;
T * const pFirstElement;
T & element(std::size_t index) { return *ALIGNED_ARRAY_INDEX_POINTER(T, pFirstElement, sizeOfTPaddedToAlignment, index); }
public:
Aligned(std::size_t size)
: size(size)
, pBytes(new uint8_t[ALIGNED_ARRAY_BYTES_SIZE(T, sizeOfTPaddedToAlignment, size)])
, pFirstElement(ALIGNED_POINTER(T, pBytes.get(), sizeOfTPaddedToAlignment))
{
AlignedArrayConstructorCaller<T>::Call(size, pFirstElement, sizeOfTPaddedToAlignment);
}
Aligned(std::size_t size, std::initializer_list<T> const & list)
: pFirstElement(ALIGNED_POINTER(T, bytes, sizeOfTPaddedToAlignment))
{
if (size < list.size())
throw InitializerListLongerThanSizeException();
int i = 0;
for (auto it = list.begin(); it != list.end(); ++it)
this->element(i++) = *it;
}
Aligned(std::initializer_list<T> const & list)
: Aligned(list.size(), list)
{}
~Aligned() {
AlignedArrayDestructorCaller<T>::Call(size, pFirstElement, sizeOfTPaddedToAlignment);
}
T & operator[](std::size_t index) { return element(index); }
T const & operator[](std::size_t index) const { return element(index); }
std::size_t Size() const { return size; }
};
template<typename T>
class Aligned<T[], -1> : AlignedBase<T, -1> {
Aligned(Aligned const &);
Aligned & operator=(Aligned const &);
std::size_t const size;
std::unique_ptr<uint8_t[]> const pBytes;
T * const pFirstElement;
Aligned();
protected:
T & element(std::size_t index) { return *ALIGNED_ARRAY_INDEX_POINTER(T, pFirstElement, sizeOfTPaddedToAlignment, index); }
public:
Aligned(std::size_t alignment, std::size_t size)
: AlignedBase<T, -1>(alignment)
, size(size)
, pBytes(new uint8_t[ALIGNED_ARRAY_BYTES_SIZE(T, sizeOfTPaddedToAlignment, size)])
, pFirstElement(ALIGNED_POINTER(T, pBytes.get(), sizeOfTPaddedToAlignment))
{
AlignedArrayConstructorCaller<T>::Call(size, pFirstElement, sizeOfTPaddedToAlignment);
}
Aligned(std::size_t alignment, std::size_t size, std::initializer_list<T> const & list)
: AlignedBase<T, -1>(alignment)
, size(size)
, pBytes(new uint8_t[ALIGNED_ARRAY_BYTES_SIZE(T, sizeOfTPaddedToAlignment, size)])
, pFirstElement(ALIGNED_POINTER(T, pBytes.get(), sizeOfTPaddedToAlignment))
{
if (size < list.size())
throw InitializerListLongerThanSizeException();
int i = 0;
for (auto it = list.begin(); it != list.end(); ++it)
this->element(i++) = *it;
}
Aligned(std::size_t alignment, std::initializer_list<T> const & list)
: Aligned(alignment, list.size(), list)
{}
~Aligned() {
AlignedArrayDestructorCaller<T>::Call(size, pFirstElement, sizeOfTPaddedToAlignment);
}
T & operator[](std::size_t index) { return element(index); }
T const & operator[](std::size_t index) const { return element(index); }
std::size_t Size() const { return size; }
};
#undef ALIGNED_BYTES_SIZE
#undef ALIGNED_POINTER
#undef ALIGNED_ARRAY_BYTES_SIZE
#undef ALIGNED_ARRAY_INDEX_POINTER
#endif