weakauras_codec_base64/decode/arch/x86_64/
mod.rs

1// Copyright 2020-2025 Velithris
2// SPDX-License-Identifier: MIT
3
4pub mod avx2;
5pub mod sse41;
6
7#[allow(unused_imports)]
8use crate::{decode::scalar, macros::unsafe_runtime_dispatch};
9#[allow(unused_imports)]
10use core::mem::MaybeUninit;
11
12#[cfg(target_feature = "avx2")]
13pub use avx2::decode_into_unchecked;
14
15// Refer to the reexport for documentation, crate::decode::decode_into_unchecked.
16#[cfg(all(target_feature = "sse4.1", not(target_feature = "avx2")))]
17#[inline(always)]
18pub unsafe fn decode_into_unchecked(
19    input: &[u8],
20    output: &mut [MaybeUninit<u8>],
21) -> Result<usize, usize> {
22    unsafe_runtime_dispatch!(
23        decode_into_unchecked,
24        Result<usize, usize>,
25        input,
26        output,
27        is_x86_feature_detected,
28        ("avx2", avx2),
29        sse41,
30    )
31}
32
33// Refer to the reexport for documentation, crate::decode::decode_into_unchecked.
34#[cfg(not(any(target_feature = "sse4.1", target_feature = "avx2")))]
35#[inline(always)]
36pub unsafe fn decode_into_unchecked(
37    input: &[u8],
38    output: &mut [MaybeUninit<u8>],
39) -> Result<usize, usize> {
40    unsafe_runtime_dispatch!(
41        decode_into_unchecked,
42        Result<usize, usize>,
43        input,
44        output,
45        is_x86_feature_detected,
46        ("avx2", avx2),
47        ("sse4.1", sse41),
48        scalar,
49    )
50}
51
52#[cfg(test)]
53mod tests {
54    #![allow(unused_imports)]
55    use super::*;
56    use crate::decode::tests::*;
57
58    use alloc::vec::Vec;
59
60    #[test]
61    #[cfg(target_feature = "sse4.1")]
62    fn scalar_and_sse41_return_same_values() {
63        let data: Vec<u8> = base64_iter().take(1024 * 1024 + 3).collect();
64
65        let capacity = data.len() * 3 / 4;
66        let mut buf1 = Vec::with_capacity(capacity);
67        let mut buf2 = Vec::with_capacity(capacity);
68
69        unsafe {
70            let scalar_len =
71                scalar::decode_into_unchecked(&data, buf1.spare_capacity_mut()).unwrap();
72            buf1.set_len(scalar_len);
73
74            let sse41_len = sse41::decode_into_unchecked(&data, buf2.spare_capacity_mut()).unwrap();
75            buf2.set_len(sse41_len);
76        }
77
78        assert_eq!(buf1, buf2);
79    }
80
81    #[test]
82    #[cfg(target_feature = "avx2")]
83    fn scalar_and_avx2_return_same_values() {
84        let data: Vec<u8> = base64_iter().take(1024 * 1024 + 3).collect();
85
86        let capacity = data.len() * 3 / 4;
87        let mut buf1 = Vec::with_capacity(capacity);
88        let mut buf2 = Vec::with_capacity(capacity);
89
90        unsafe {
91            let scalar_len =
92                scalar::decode_into_unchecked(&data, buf1.spare_capacity_mut()).unwrap();
93            buf1.set_len(scalar_len);
94
95            let avx2_len = avx2::decode_into_unchecked(&data, buf2.spare_capacity_mut()).unwrap();
96            buf2.set_len(avx2_len);
97        }
98
99        assert_eq!(buf1, buf2);
100    }
101
102    #[test]
103    #[cfg(target_feature = "sse4.1")]
104    fn sse41_returns_index_of_invalid_byte() {
105        let test_cases = [
106            (
107                core::iter::once(b'=')
108                    .chain(base64_iter().take(39))
109                    .collect::<Vec<_>>(),
110                0usize,
111            ), // iteration #1
112            (
113                base64_iter()
114                    .take(1)
115                    .chain(core::iter::once(b'='))
116                    .chain(base64_iter().take(38))
117                    .collect::<Vec<_>>(),
118                1,
119            ), // iteration #1
120            (
121                base64_iter()
122                    .take(16)
123                    .chain(core::iter::once(b'='))
124                    .chain(base64_iter().take(23))
125                    .collect::<Vec<_>>(),
126                16,
127            ), // iteration #2
128            (
129                base64_iter()
130                    .take(35)
131                    .chain(core::iter::once(b'='))
132                    .chain(base64_iter().take(4))
133                    .collect::<Vec<_>>(),
134                35,
135            ), // scalar
136        ];
137
138        for (data, invalid_byte_at) in test_cases {
139            let capacity = data.len() * 3 / 4;
140            let mut buf = Vec::with_capacity(capacity);
141
142            let result = unsafe { sse41::decode_into_unchecked(&data, buf.spare_capacity_mut()) };
143
144            assert_eq!(result, Err(invalid_byte_at));
145        }
146    }
147
148    #[test]
149    #[cfg(target_feature = "avx2")]
150    fn avx2_returns_index_of_invalid_byte() {
151        let test_cases = [
152            (
153                core::iter::once(b'=')
154                    .chain(base64_iter().take(79))
155                    .collect::<Vec<_>>(),
156                0usize,
157            ), // iteration #1
158            (
159                base64_iter()
160                    .take(1)
161                    .chain(core::iter::once(b'='))
162                    .chain(base64_iter().take(78))
163                    .collect::<Vec<_>>(),
164                1,
165            ), // iteration #1
166            (
167                base64_iter()
168                    .take(32)
169                    .chain(core::iter::once(b'='))
170                    .chain(base64_iter().take(47))
171                    .collect::<Vec<_>>(),
172                32,
173            ), // iteration #2
174            (
175                base64_iter()
176                    .take(70)
177                    .chain(core::iter::once(b'='))
178                    .chain(base64_iter().take(9))
179                    .collect::<Vec<_>>(),
180                70,
181            ), // scalar
182        ];
183
184        for (data, invalid_byte_at) in test_cases {
185            let capacity = data.len() * 3 / 4;
186            let mut buf = Vec::with_capacity(capacity);
187
188            let result = unsafe { avx2::decode_into_unchecked(&data, buf.spare_capacity_mut()) };
189
190            assert_eq!(result, Err(invalid_byte_at));
191        }
192    }
193}