1#[inline]
21pub fn slice_copy(src: *const u8, dst: *mut u8, num_bytes: usize) {
22 if num_bytes < 4 {
23 short_copy(src, dst, num_bytes);
24 return;
25 }
26
27 if num_bytes < 8 {
28 double_copy_trick::<4>(src, dst, num_bytes);
29 return;
30 }
31
32 if num_bytes <= 16 {
33 double_copy_trick::<8>(src, dst, num_bytes);
34 return;
35 }
36
37 wild_copy_from_src::<16>(src, dst, num_bytes)
60}
61
62#[inline]
64fn wild_copy_from_src<const SIZE: usize>(
65 mut source: *const u8,
66 mut dst: *mut u8,
67 num_bytes: usize,
68) {
69 let l_last = unsafe { source.add(num_bytes - SIZE) };
72 let r_last = unsafe { dst.add(num_bytes - SIZE) };
73 let num_bytes = (num_bytes / SIZE) * SIZE;
74
75 unsafe {
76 let dst_ptr_end = dst.add(num_bytes);
77 loop {
78 core::ptr::copy_nonoverlapping(source, dst, SIZE);
79 source = source.add(SIZE);
80 dst = dst.add(SIZE);
81 if dst >= dst_ptr_end {
82 break;
83 }
84 }
85 }
86
87 unsafe {
88 core::ptr::copy_nonoverlapping(l_last, r_last, SIZE);
89 }
90}
91
92#[inline]
93fn short_copy(src: *const u8, dst: *mut u8, len: usize) {
94 unsafe {
95 *dst = *src;
96 }
97 if len >= 2 {
98 double_copy_trick::<2>(src, dst, len);
99 }
100}
101
102#[inline(always)]
103fn double_copy_trick<const SIZE: usize>(src: *const u8, dst: *mut u8, len: usize) {
107 let l_end = unsafe { src.add(len - SIZE) };
108 let r_end = unsafe { dst.add(len - SIZE) };
109
110 unsafe {
111 core::ptr::copy_nonoverlapping(src, dst, SIZE);
112 core::ptr::copy_nonoverlapping(l_end, r_end, SIZE);
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use super::slice_copy;
119 use proptest::prelude::*;
120 proptest! {
121 #[test]
122 fn test_fast_short_slice_copy(left: Vec<u8>) {
123 if left.is_empty() {
124 return Ok(());
125 }
126 let mut right = vec![0u8; left.len()];
127 slice_copy(left.as_ptr(), right.as_mut_ptr(), left.len());
128 prop_assert_eq!(&left, &right);
129 }
130 }
131
132 #[test]
133 fn test_fast_short_slice_copy_edge_cases() {
134 for len in 1..(512 * 2) {
135 let left = (0..len).map(|i| i as u8).collect::<Vec<_>>();
136 let mut right = vec![0u8; len];
137 slice_copy(left.as_ptr(), right.as_mut_ptr(), left.len());
138 assert_eq!(left, right);
139 }
140 }
141
142 #[test]
143 fn test_fail2() {
144 let left = vec![
145 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
146 24, 25, 26, 27, 28, 29, 30, 31, 32,
147 ];
148 let mut right = vec![0u8; left.len()];
149 slice_copy(left.as_ptr(), right.as_mut_ptr(), left.len());
150 assert_eq!(left, right);
151 }
152
153 #[test]
154 fn test_fail() {
155 let left = vec![
156 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
157 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
158 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
159 ];
160 let mut right = vec![0u8; left.len()];
161 slice_copy(left.as_ptr(), right.as_mut_ptr(), left.len());
162 assert_eq!(left, right);
163 }
164}