1#[cfg(target_arch = "x86_64")]
2mod avx2;
3#[cfg(feature = "avx512")]
4#[cfg(target_arch = "x86_64")]
5mod avx512;
6mod generic;
7#[cfg(target_arch = "aarch64")]
8mod neon;
9#[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
10mod wasm;
11
12pub fn adler32(start_checksum: u32, data: &[u8]) -> u32 {
13 #[cfg(feature = "avx512")]
14 #[cfg(target_arch = "x86_64")]
15 if cfg!(all(target_feature = "avx512f", target_feature = "avx512bw")) {
16 return unsafe { avx512::adler32_avx512(start_checksum, data) };
17 }
18
19 #[cfg(target_arch = "x86_64")]
20 if crate::cpu_features::is_enabled_avx2_and_bmi2() {
21 return avx2::adler32_avx2(start_checksum, data);
22 }
23
24 #[cfg(target_arch = "aarch64")]
25 if crate::cpu_features::is_enabled_neon() {
26 return self::neon::adler32_neon(start_checksum, data);
27 }
28
29 #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
30 if crate::cpu_features::is_enabled_simd128() {
31 return self::wasm::adler32_wasm(start_checksum, data);
32 }
33
34 generic::adler32_rust(start_checksum, data)
35}
36
37pub fn adler32_fold_copy(start_checksum: u32, dst: &mut [u8], src: &[u8]) -> u32 {
38 debug_assert!(dst.len() >= src.len(), "{} < {}", dst.len(), src.len());
39
40 dst[..src.len()].copy_from_slice(src);
43 adler32(start_checksum, src)
44}
45
46pub fn adler32_combine(adler1: u32, adler2: u32, len2: u64) -> u32 {
47 const BASE: u64 = self::BASE as u64;
48
49 let rem = len2 % BASE;
50
51 let adler1 = adler1 as u64;
52 let adler2 = adler2 as u64;
53
54 let mut sum1 = adler1 & 0xffff;
56 let mut sum2 = rem * sum1;
57 sum2 %= BASE;
58 sum1 += (adler2 & 0xffff) + BASE - 1;
59 sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
60
61 if sum1 >= BASE {
62 sum1 -= BASE;
63 }
64 if sum1 >= BASE {
65 sum1 -= BASE;
66 }
67 if sum2 >= (BASE << 1) {
68 sum2 -= BASE << 1;
69 }
70 if sum2 >= BASE {
71 sum2 -= BASE;
72 }
73
74 (sum1 | (sum2 << 16)) as u32
75}
76
77#[cfg(test)]
79fn naive_adler32(start_checksum: u32, data: &[u8]) -> u32 {
80 const MOD_ADLER: u32 = 65521; let mut a = start_checksum & 0xFFFF;
83 let mut b = (start_checksum >> 16) & 0xFFFF;
84
85 for &byte in data {
86 a = (a + byte as u32) % MOD_ADLER;
87 b = (b + a) % MOD_ADLER;
88 }
89
90 (b << 16) | a
91}
92
93const BASE: u32 = 65521; const NMAX: u32 = 5552;
95
96#[cfg(test)]
97mod test {
98 use super::*;
99
100 #[test]
101 fn naive_is_fancy_small_inputs() {
102 for i in 0..128 {
103 let v = (0u8..i).collect::<Vec<_>>();
104 assert_eq!(naive_adler32(1, &v), generic::adler32_rust(1, &v));
105 }
106 }
107
108 #[test]
109 fn test_adler32_combine() {
110 ::quickcheck::quickcheck(test as fn(_) -> _);
111
112 fn test(data: Vec<u8>) -> bool {
113 let Some(buf_len) = data.first().copied() else {
114 return true;
115 };
116
117 let buf_size = Ord::max(buf_len, 1) as usize;
118
119 let mut adler1 = 1;
120 let mut adler2 = 1;
121
122 for chunk in data.chunks(buf_size) {
123 adler1 = adler32(adler1, chunk);
124 }
125
126 adler2 = adler32(adler2, &data);
127
128 assert_eq!(adler1, adler2);
129
130 let combine1 = adler32_combine(adler1, adler2, data.len() as _);
131 let combine2 = adler32_combine(adler1, adler1, data.len() as _);
132 assert_eq!(combine1, combine2);
133
134 true
135 }
136 }
137}