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
use super::Alignment;
use alloc::alloc::Layout;
use alloc::boxed::Box;
use alloc::vec::Vec;
use core::mem::{align_of, size_of};
#[allow(unsafe_code)]
#[must_use]
pub fn align_first<T, A: Alignment>(t_capacity: usize) -> Vec<T> {
if align_of::<A>() <= align_of::<T>() || t_capacity == 0 || size_of::<T>() == 0 {
return Vec::<T>::with_capacity(t_capacity);
}
let min_bytes_to_allocate = size_of::<T>() * t_capacity;
let layout = Layout::from_size_align(min_bytes_to_allocate, align_of::<A>()).unwrap();
let ptr = unsafe { alloc::alloc::alloc(layout) };
let type_vec = unsafe { Vec::<T>::from_raw_parts(ptr as *mut T, 0, t_capacity) };
debug_assert_eq!(type_vec.as_ptr() as usize % align_of::<A>(), 0);
debug_assert_eq!(type_vec.as_ptr() as usize, ptr as usize);
type_vec
}
#[must_use]
pub fn align_first_boxed<T, A: Alignment, F: FnMut(usize) -> T>(s_capacity: usize, mut f: F) -> Box<[T]> {
let mut v = align_first::<T, A>(s_capacity);
(0..s_capacity).for_each(|i| v.push(f(i)));
v.into_boxed_slice()
}
#[must_use]
pub fn align_first_boxed_default<T: Default, A: Alignment>(s_capacity: usize) -> Box<[T]> {
align_first_boxed::<T, A, _>(s_capacity, |_| T::default())
}
#[must_use]
pub fn align_first_boxed_cloned<T: Clone, A: Alignment>(s_capacity: usize, initial: T) -> Box<[T]> {
align_first_boxed::<T, A, _>(s_capacity, |_| initial.clone())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::*;
macro_rules! assert_alignment {
($t:ty, $a:ty) => {
let v = align_first::<$t, $a>(17);
assert_eq!(v.len(), 0, "len not equal");
if size_of::<$t>() == 0 {
assert_eq!(v.capacity(), usize::max_value(), "Zero-sized type capacity incorrect");
} else {
assert_eq!(v.as_ptr() as usize % align_of::<$a>(), 0, "ptr not aligned");
assert_eq!(v.capacity(), 17, "capacity not correct");
}
};
}
#[repr(C)]
struct NonPowerOf2Size {
a: u8,
b: u8,
c: u32,
}
#[test]
fn test_align_first() {
assert_alignment!(u16, Bit16);
assert_alignment!(u32, Bit32);
assert_alignment!(u64, Bit64);
assert_alignment!(u128, Bit128);
assert_alignment!([u64; 4], Bit256);
assert_alignment!(u64, A8);
assert_alignment!([u32; 2], Bit64);
assert_alignment!([u8; 8], Bit64);
assert_alignment!([u8; 16], A16);
assert_alignment!([u8; 1024], A512);
assert_alignment!([u8; 97], Bit16);
assert_alignment!([u64; 101], Bit64);
assert_alignment!([u8; 103], Bit32);
assert_alignment!([u64; 107], Bit64);
assert_alignment!([u32; 109], Bit16);
assert_alignment!([A32; 139], A8);
assert_alignment!([u32; 19], Bit16);
assert_alignment!([A32; 31], A8);
assert_alignment!(NonPowerOf2Size, A32);
assert_alignment!([NonPowerOf2Size; 3], Bit1024);
assert_alignment!([u16; 197], Bit32);
assert_alignment!([A8; 191], A32);
assert_alignment!([u16; 131], Bit32);
assert_alignment!([u8; 7], A256);
assert_alignment!([u8; 0], A512);
struct ZeroSized;
assert_alignment!(ZeroSized, A128);
}
}