generic_simd/
alignment.rs1#[cfg(all(feature = "alloc", not(feature = "std")))]
4extern crate alloc;
5
6#[cfg(all(feature = "alloc", not(feature = "std")))]
7use alloc::{
8 alloc::{alloc, Layout},
9 boxed::Box,
10};
11
12#[cfg(feature = "std")]
13use std::alloc::{alloc, Layout};
14
15use crate::{
16 arch, scalar,
17 vector::{width, VectorOf},
18};
19
20#[repr(C)]
21#[derive(Copy, Clone)]
22struct Vectors<Token: arch::Token, Scalar: scalar::ScalarExt<Token>>(
23 VectorOf<Scalar, width::W1, Token>,
24 VectorOf<Scalar, width::W2, Token>,
25 VectorOf<Scalar, width::W4, Token>,
26 VectorOf<Scalar, width::W8, Token>,
27);
28
29macro_rules! max_alignment {
30 { $first:path, $($rest:path,)* } => {
31
32 #[doc(hidden)]
33 #[repr(C)]
34 #[derive(Copy, Clone)]
35 pub struct AllVectors<Scalar: scalar::ScalarExt<$first> $(+ scalar::ScalarExt<$rest>)*>(
36 Vectors<$first, Scalar>,
37 $(
38 Vectors<$rest, Scalar>,
39 )*
40 );
41
42 #[cfg(any(feature = "std", feature = "alloc"))]
48 pub fn allocate_max_aligned_slice<Scalar: Default + scalar::ScalarExt<$first> $(+ scalar::ScalarExt<$rest>)*>(count: usize) -> Box<[Scalar]> {
49 allocate_aligned_slice::<AllVectors<Scalar>, Scalar>(count)
50 }
51 }
52}
53
54crate::call_macro_with_tokens! { max_alignment }
55
56#[repr(C)]
58pub struct Aligned<AlignTo, T> {
59 alignment: [AlignTo; 0],
60 value: T,
61}
62
63impl<AlignTo, T> Aligned<AlignTo, T> {
64 pub fn new(value: T) -> Self {
65 Self {
66 alignment: [],
67 value,
68 }
69 }
70}
71
72impl<AlignTo, T> core::ops::Deref for Aligned<AlignTo, T> {
73 type Target = T;
74
75 fn deref(&self) -> &Self::Target {
76 &self.value
77 }
78}
79
80impl<AlignTo, T> core::ops::DerefMut for Aligned<AlignTo, T> {
81 fn deref_mut(&mut self) -> &mut Self::Target {
82 &mut self.value
83 }
84}
85
86impl<AlignTo: Copy, T: Copy> Copy for Aligned<AlignTo, T> {}
87
88impl<AlignTo, T: Clone> Clone for Aligned<AlignTo, T> {
89 fn clone(&self) -> Self {
90 Self::new(self.value.clone())
91 }
92}
93
94impl<AlignTo, T: Default> Default for Aligned<AlignTo, T> {
95 fn default() -> Self {
96 Self::new(T::default())
97 }
98}
99
100impl<AlignTo, T: core::fmt::Debug> core::fmt::Debug for Aligned<AlignTo, T> {
101 #[inline]
102 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
103 f.debug_tuple("Aligned").field(&self.value).finish()
104 }
105}
106
107impl<AlignTo, T: core::cmp::PartialEq> core::cmp::PartialEq for Aligned<AlignTo, T> {
108 #[inline]
109 fn eq(&self, other: &Self) -> bool {
110 self.value.eq(&other.value)
111 }
112}
113
114impl<AlignTo, T: core::cmp::Eq> core::cmp::Eq for Aligned<AlignTo, T> {}
115
116impl<AlignTo, T: core::cmp::PartialOrd> core::cmp::PartialOrd for Aligned<AlignTo, T> {
117 #[inline]
118 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
119 self.value.partial_cmp(&other.value)
120 }
121}
122
123impl<AlignTo, T: core::cmp::Ord> core::cmp::Ord for Aligned<AlignTo, T> {
124 #[inline]
125 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
126 self.value.cmp(&other.value)
127 }
128}
129
130impl<AlignTo, T: core::hash::Hash> core::hash::Hash for Aligned<AlignTo, T> {
131 #[inline]
132 fn hash<H: core::hash::Hasher>(&self, hasher: &mut H) {
133 self.value.hash(hasher)
134 }
135}
136
137#[cfg(any(feature = "std", feature = "alloc"))]
142pub fn allocate_aligned_slice<AlignTo, T: Default>(count: usize) -> Box<[T]> {
143 assert!(count > 0, "size must be nonzero");
144 let layout = Layout::from_size_align(
145 count * core::mem::size_of::<T>(),
146 core::cmp::max(core::mem::align_of::<AlignTo>(), core::mem::align_of::<T>()),
147 )
148 .unwrap();
149 unsafe {
150 let ptr = alloc(layout) as *mut T;
151 assert!(!ptr.is_null());
152 for i in 0..count {
153 ptr.add(i).write(T::default());
154 }
155 Box::from_raw(core::ptr::slice_from_raw_parts_mut(ptr, count))
156 }
157}
158
159pub type MaxAligned<Scalar, T> = Aligned<AllVectors<Scalar>, T>;
162
163#[cfg(test)]
164mod test {
165 use super::*;
166
167 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
168 #[test]
169 fn check_x86() {
170 type Foo = [f32; 8];
171 type AlignedFoo = MaxAligned<f32, Foo>;
172 assert_eq!(core::mem::align_of::<AlignedFoo>(), 32);
173 }
174}