Skip to main content

zrip_core/simd/
copy.rs

1#[cfg(feature = "alloc")]
2use alloc::vec::Vec;
3
4#[cfg(all(target_arch = "x86_64", not(feature = "paranoid")))]
5use super::CpuTier;
6
7#[inline]
8pub fn append_literals(dst: &mut Vec<u8>, src: &[u8]) {
9    if src.is_empty() {
10        return;
11    }
12
13    #[cfg(not(feature = "paranoid"))]
14    {
15        let len = src.len();
16        dst.reserve(len + 32);
17        let dst_offset = dst.len();
18
19        #[cfg(target_arch = "x86_64")]
20        {
21            let tier = super::cpu_tier();
22            if tier >= CpuTier::Avx2 && len >= 32 {
23                unsafe {
24                    let dst_ptr = dst.as_mut_ptr().add(dst_offset);
25                    super::x86_64::avx2::wildcopy_avx2(src.as_ptr(), dst_ptr, len);
26                    dst.set_len(dst_offset + len);
27                }
28                return;
29            }
30            if tier >= CpuTier::Sse2 && len >= 16 {
31                unsafe {
32                    let dst_ptr = dst.as_mut_ptr().add(dst_offset);
33                    super::x86_64::sse2::wildcopy_sse2(src.as_ptr(), dst_ptr, len);
34                    dst.set_len(dst_offset + len);
35                }
36                return;
37            }
38        }
39
40        #[cfg(target_arch = "aarch64")]
41        {
42            if len >= 16 {
43                unsafe {
44                    let dst_ptr = dst.as_mut_ptr().add(dst_offset);
45                    super::aarch64::neon::wildcopy_neon(src.as_ptr(), dst_ptr, len);
46                    dst.set_len(dst_offset + len);
47                }
48                return;
49            }
50        }
51
52        if len >= 8 {
53            unsafe {
54                let dst_ptr = dst.as_mut_ptr().add(dst_offset);
55                super::scalar::wildcopy_nonoverlap(src.as_ptr(), dst_ptr, len);
56                dst.set_len(dst_offset + len);
57            }
58        } else {
59            dst.extend_from_slice(src);
60        }
61    }
62
63    #[cfg(feature = "paranoid")]
64    dst.extend_from_slice(src);
65}
66
67#[inline]
68pub fn append_match(dst: &mut Vec<u8>, offset: usize, match_length: usize) {
69    if match_length == 0 {
70        return;
71    }
72
73    debug_assert!(offset <= dst.len());
74    debug_assert!(offset > 0);
75
76    #[cfg(not(feature = "paranoid"))]
77    {
78        dst.reserve(match_length + 32);
79        let dst_len = dst.len();
80        unsafe {
81            let base = dst.as_mut_ptr();
82            let write_ptr = base.add(dst_len);
83            super::scalar::copy_match(write_ptr, offset, match_length);
84            dst.set_len(dst_len + match_length);
85        }
86    }
87
88    #[cfg(feature = "paranoid")]
89    {
90        dst.reserve(match_length);
91        let start = dst.len() - offset;
92        if offset >= match_length {
93            let len = dst.len();
94            dst.resize(len + match_length, 0);
95            dst.copy_within(start..start + match_length, len);
96        } else {
97            for i in 0..match_length {
98                let b = dst[start + i % offset];
99                dst.push(b);
100            }
101        }
102    }
103}
104
105#[inline]
106pub fn common_prefix_len(a: &[u8], b: &[u8]) -> usize {
107    #[cfg(all(target_arch = "x86_64", not(feature = "paranoid")))]
108    {
109        let tier = super::cpu_tier();
110        if tier >= CpuTier::Avx2 && a.len() >= 32 && b.len() >= 32 {
111            return unsafe { super::x86_64::avx2::common_prefix_len_avx2(a, b) };
112        }
113    }
114    #[cfg(all(target_arch = "aarch64", not(feature = "paranoid")))]
115    {
116        if a.len() >= 16 && b.len() >= 16 {
117            return unsafe { super::aarch64::neon::common_prefix_len_neon(a, b) };
118        }
119    }
120    super::scalar::common_prefix_len(a, b)
121}
122
123#[inline]
124pub fn append_match_with_history(
125    dst: &mut Vec<u8>,
126    history: &[u8],
127    offset: usize,
128    match_length: usize,
129) {
130    if match_length == 0 {
131        return;
132    }
133
134    let out_len = dst.len();
135
136    if offset <= out_len {
137        append_match(dst, offset, match_length);
138    } else {
139        let history_reach = offset - out_len;
140        let history_start = history.len() - history_reach;
141        let from_history = history_reach.min(match_length);
142
143        dst.extend_from_slice(&history[history_start..history_start + from_history]);
144
145        let remaining = match_length - from_history;
146        if remaining > 0 {
147            append_match(dst, offset, remaining);
148        }
149    }
150}