HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
aligned_array.hpp
1// Copyright Take Vos 2020.
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 "os_detect.hpp"
8
9#if TT_PROCESSOR == TT_CPU_X64
10#include <xmmintrin.h>
11#include <immintrin.h>
12#endif
13
14#include <array>
15#include <algorithm>
16#include <type_traits>
17#include <bit>
18#include <stdexcept>
19
20namespace tt {
21
22template<typename T, size_t N>
23struct alignas(sizeof(T) * std::bit_ceil(N)) aligned_array {
24public:
26 using value_type = typename container_type::value_type;
27 using size_type = typename container_type::size_type;
28 using difference_type = typename container_type::difference_type;
29 using reference = typename container_type::reference;
30 using const_reference = typename container_type::const_reference;
31 using pointer = typename container_type::pointer;
32 using const_pointer = typename container_type::const_pointer;
33 using iterator = typename container_type::iterator;
34 using const_iterator = typename container_type::const_iterator;
35
36 constexpr aligned_array() = default;
37 constexpr aligned_array(aligned_array const &) noexcept = default;
38 constexpr aligned_array(aligned_array &&) noexcept = default;
39 constexpr aligned_array &operator=(aligned_array const &) noexcept = default;
40 constexpr aligned_array &operator=(aligned_array &&) noexcept = default;
41
42 [[nodiscard]] constexpr aligned_array(std::initializer_list<T> rhs) noexcept : v(rhs) {}
43
44 [[nodiscard]] explicit aligned_array(__m128 const &rhs) noexcept requires(N == 4 && std::is_same_v<T, float> && has_sse)
45 {
46 _mm_store_ps(v.data(), rhs);
47 }
48
49 [[nodiscard]] explicit aligned_array(__m128d const &rhs) noexcept requires(N == 2 && std::is_same_v<T, double> && has_sse)
50 {
51 _mm_store_pd(v.data(), rhs);
52 }
53
54 [[nodiscard]] explicit aligned_array(__m128i const &rhs) noexcept
55 requires(std::is_integral_v<T> &&std::is_signed_v<T> && sizeof(T) * N == 16 && has_sse)
56 {
57 _mm_store_si128(reinterpret_cast<__m128i *>(v.data()), rhs);
58 }
59
60 [[nodiscard]] explicit aligned_array(__m256 const &rhs) noexcept requires(N == 8 && std::is_same_v<T, float> && has_sse)
61 {
62 _mm256_store_ps(v.data(), rhs);
63 }
64
65 [[nodiscard]] explicit aligned_array(__m256d const &rhs) noexcept requires(N == 4 && std::is_same_v<T, double> && has_sse)
66 {
67 _mm256_store_pd(v.data(), rhs);
68 }
69
70 [[nodiscard]] explicit aligned_array(__m256i const &rhs) noexcept
71 requires(std::is_integral_v<T> &&std::is_signed_v<T> && sizeof(T) * N == 32 && has_sse)
72 {
73 _mm256_store_si256(reinterpret_cast<__m256i *>(v.data()), rhs);
74 }
75
76 [[nodiscard]] explicit operator __m128() const noexcept requires(N == 4 && std::is_same_v<T, float> && has_sse)
77 {
78 return _mm_load_ps(v.data());
79 }
80
81 [[nodiscard]] explicit operator __m128d() const noexcept requires(N == 2 && std::is_same_v<T, double> && has_sse)
82 {
83 return _mm_load_pd(v.data());
84 }
85
86 [[nodiscard]] explicit operator __m128i() const noexcept
87 requires(std::is_integral_v<T> &&std::is_signed_v<T> && sizeof(T) * N == 16 && has_sse)
88 {
89 return _mm_load_si128(reinterpret_cast<__m128i*>(data()));
90 }
91
92 [[nodiscard]] explicit operator __m256() const noexcept requires(N == 8 && std::is_same_v<T, float> && has_sse)
93 {
94 return _mm256_load_ps(data());
95 }
96
97 [[nodiscard]] explicit operator __m256d() const noexcept requires(N == 4 && std::is_same_v<T, double> && has_sse)
98 {
99 return _mm256_load_pd(data());
100 }
101
102 [[nodiscard]] explicit operator __m256i() const noexcept
103 requires(std::is_integral_v<T> &&std::is_signed_v<T> && sizeof(T) * N == 32 && has_sse)
104 {
105 return _mm256_load_si256(reinterpret_cast<__m256i *>(data()));
106 }
107
113 [[nodiscard]] constexpr reference at(size_t pos)
114 {
115 if (pos < size()) {
116 throw std::out_of_range("index out of range");
117 }
118 return v[pos];
119 }
120
121 [[nodiscard]] constexpr const_reference at(size_t pos) const
122 {
123 if (pos < size()) {
124 throw std::out_of_range("index out of range");
125 }
126 return v[pos];
127 }
128
129 [[nodiscard]] constexpr reference operator[](size_t pos) noexcept
130 {
131 return v[pos];
132 }
133
134 [[nodiscard]] constexpr const_reference operator[](size_t pos) const noexcept
135 {
136 return v[pos];
137 }
138
139 [[nodiscard]] constexpr reference front() noexcept
140 {
141 return v[0];
142 }
143
144 [[nodiscard]] constexpr const_reference front() const noexcept
145 {
146 return v[0];
147 }
148
149 [[nodiscard]] constexpr reference back() noexcept
150 {
151 return v[N - 1];
152 }
153
154 [[nodiscard]] constexpr const_reference back() const noexcept
155 {
156 return v[N - 1];
157 }
158
159 [[nodiscard]] constexpr pointer data() noexcept
160 {
161 return v.data();
162 }
163
164 [[nodiscard]] constexpr const_pointer data() const noexcept
165 {
166 return v.data();
167 }
168
169 [[nodiscard]] constexpr iterator begin() noexcept
170 {
171 return v.begin();
172 }
173
174 [[nodiscard]] constexpr const_iterator begin() const noexcept
175 {
176 return v.begin();
177 }
178
179 [[nodiscard]] constexpr const_iterator cbegin() const noexcept
180 {
181 return v.cbegin();
182 }
183
184 [[nodiscard]] constexpr iterator end() noexcept
185 {
186 return v.end();
187 }
188
189 [[nodiscard]] constexpr const_iterator end() const noexcept
190 {
191 return v.end();
192 }
193
194 [[nodiscard]] constexpr const_iterator cend() const noexcept
195 {
196 return v.cend();
197 }
198
199 [[nodiscard]] constexpr bool empty() const noexcept
200 {
201 return v.empty();
202 }
203
204 [[nodiscard]] constexpr size_type size() const noexcept
205 {
206 return v.size();
207 }
208
209 [[nodiscard]] constexpr size_type max_size() const noexcept
210 {
211 return v.max_size();
212 }
213
214 constexpr void fill(T const &value) noexcept
215 {
216 for (size_t i = 0; i != N; ++i) {
217 v[i] = value;
218 }
219 }
220
221 constexpr void swap(aligned_array &other) noexcept
222 {
223 for (size_t i = 0; i != N; ++i) {
224 std::swap(v[i], other[i]);
225 }
226 }
227
228 constexpr void swap(std::array<T, N> &other) noexcept
229 {
230 for (size_t i = 0; i != N; ++i) {
231 std::swap(v[i], other[i]);
232 }
233 }
234
235 template<std::size_t I>
236 [[nodiscard]] friend constexpr T &get(aligned_array &rhs) noexcept
237 {
238 static_assert(I < N, "Index out of bounds");
239 return get<I>(rhs.v);
240 }
241
242 template<std::size_t I>
243 [[nodiscard]] friend constexpr T get(aligned_array &&rhs) noexcept
244 {
245 static_assert(I < N, "Index out of bounds");
246 return get<I>(rhs.v);
247 }
248
249 template<std::size_t I>
250 [[nodiscard]] friend constexpr T const &get(aligned_array const &rhs) noexcept
251 {
252 static_assert(I < N, "Index out of bounds");
253 return get<I>(rhs.v);
254 }
255
256 [[nodiscard]] constexpr friend bool operator==(aligned_array const &lhs, aligned_array const &rhs) noexcept
257 {
258 for (size_t i = 0; i != N; ++i) {
259 if (!(lhs == rhs)) {
260 return false;
261 }
262 }
263 return true;
264 }
265
266private:
267 container_type v;
268};
269
270template<class T, class... U>
271aligned_array(T, U...) -> aligned_array<T, 1 + sizeof...(U)>;
272
273using i8x1_raw = aligned_array<int8_t, 1>;
274using i8x2_raw = aligned_array<int8_t, 2>;
275using i8x4_raw = aligned_array<int8_t, 4>;
276using i8x8_raw = aligned_array<int8_t, 8>;
277using i8x16_raw = aligned_array<int8_t, 16>;
278using i8x32_raw = aligned_array<int8_t, 32>;
279using i8x64_raw = aligned_array<int8_t, 64>;
280
281using u8x1_raw = aligned_array<uint8_t, 1>;
282using u8x2_raw = aligned_array<uint8_t, 2>;
283using u8x4_raw = aligned_array<uint8_t, 4>;
284using u8x8_raw = aligned_array<uint8_t, 8>;
285using u8x16_raw = aligned_array<uint8_t, 16>;
286using u8x32_raw = aligned_array<uint8_t, 32>;
287using u8x64_raw = aligned_array<uint8_t, 64>;
288
289using i16x1_raw = aligned_array<int16_t, 1>;
290using i16x2_raw = aligned_array<int16_t, 2>;
291using i16x4_raw = aligned_array<int16_t, 4>;
292using i16x8_raw = aligned_array<int16_t, 8>;
293using i16x16_raw = aligned_array<int16_t, 16>;
294using i16x32_raw = aligned_array<int16_t, 32>;
295
296using u16x1_raw = aligned_array<uint16_t, 1>;
297using u16x2_raw = aligned_array<uint16_t, 2>;
298using u16x4_raw = aligned_array<uint16_t, 4>;
299using u16x8_raw = aligned_array<uint16_t, 8>;
300using u16x16_raw = aligned_array<uint16_t, 16>;
301using u16x32_raw = aligned_array<uint16_t, 32>;
302
303using i32x1_raw = aligned_array<int32_t, 1>;
304using i32x2_raw = aligned_array<int32_t, 2>;
305using i32x4_raw = aligned_array<int32_t, 4>;
306using i32x8_raw = aligned_array<int32_t, 8>;
307using i32x16_raw = aligned_array<int32_t, 16>;
308
309using u32x1_raw = aligned_array<uint32_t, 1>;
310using u32x2_raw = aligned_array<uint32_t, 2>;
311using u32x4_raw = aligned_array<uint32_t, 4>;
312using u32x8_raw = aligned_array<uint32_t, 8>;
313using u32x16_raw = aligned_array<uint32_t, 16>;
314
315using f32x1_raw = aligned_array<float, 1>;
316using f32x2_raw = aligned_array<float, 2>;
317using f32x4_raw = aligned_array<float, 4>;
318using f32x8_raw = aligned_array<float, 8>;
319using f32x16_raw = aligned_array<float, 16>;
320
321using i64x1_raw = aligned_array<int64_t, 1>;
322using i64x2_raw = aligned_array<int64_t, 2>;
323using i64x4_raw = aligned_array<int64_t, 4>;
324using i64x8_raw = aligned_array<int64_t, 8>;
325
326using u64x1_raw = aligned_array<uint64_t, 1>;
327using u64x2_raw = aligned_array<uint64_t, 2>;
328using u64x4_raw = aligned_array<uint64_t, 4>;
329using u64x8_raw = aligned_array<uint64_t, 8>;
330
331using f64x1_raw = aligned_array<double, 1>;
332using f64x2_raw = aligned_array<double, 2>;
333using f64x4_raw = aligned_array<double, 4>;
334using f64x8_raw = aligned_array<double, 8>;
335
336
337} // namespace tt
338
339namespace std {
340
341template<class T, std::size_t N>
342struct tuple_size<tt::aligned_array<T, N>> : std::integral_constant<std::size_t, N> {
343};
344
345template<std::size_t I, class T, std::size_t N>
346struct tuple_element<I, tt::aligned_array<T, N>> {
347 using type = T;
348};
349
350} // namespace std
STL namespace.
Definition aligned_array.hpp:23
constexpr reference at(size_t pos)
Select item at pos.
Definition aligned_array.hpp:113
Definition concepts.hpp:18
Definition concepts.hpp:21
T begin(T... args)
T data(T... args)
T empty(T... args)
T end(T... args)
T max_size(T... args)
T size(T... args)
T swap(T... args)