Encode base64 through fixed-size chunks, as clippy 1.99 asks
Agents / bot (pull_request) Successful in 4m8s
Agents / bot (pull_request) Successful in 4m8s
The encoder takes twelve-byte groups through as_chunks like the decoder now does, and reads each group's two words with one fixed eight-byte copy each, which compiles to a load: spelling the bytes out one by one pushed a 1 MiB save past the 20M fuel budget, while this keeps it at 12.9M. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+16
-12
@@ -162,6 +162,15 @@ fn quad(word: u64) -> u32 {
|
|||||||
| u32::from(HALVES[1][((word >> 8) & 0xff0f) as usize]) << 16
|
| u32::from(HALVES[1][((word >> 8) & 0xff0f) as usize]) << 16
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The eight bytes of `group` from `at`, as one little-endian word. Copied as
|
||||||
|
/// a fixed eight bytes, the read compiles to a single load; spelling out the
|
||||||
|
/// bytes one by one measured several times dearer in fuel.
|
||||||
|
fn word(group: &[u8; 12], at: usize) -> u64 {
|
||||||
|
let mut bytes = [0; 8];
|
||||||
|
bytes.copy_from_slice(&group[at..at + 8]);
|
||||||
|
u64::from_le_bytes(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
/// How many characters `bytes` bytes encode to, padding included.
|
/// How many characters `bytes` bytes encode to, padding included.
|
||||||
pub fn encoded_length(bytes: usize) -> usize {
|
pub fn encoded_length(bytes: usize) -> usize {
|
||||||
bytes.div_ceil(3) * 4
|
bytes.div_ceil(3) * 4
|
||||||
@@ -171,23 +180,18 @@ pub fn encoded_length(bytes: usize) -> usize {
|
|||||||
/// exactly `encoded_length` characters. Twelve bytes go through each step
|
/// exactly `encoded_length` characters. Twelve bytes go through each step
|
||||||
/// of the main loop, for the same reason sixteen characters do in `decode`.
|
/// of the main loop, for the same reason sixteen characters do in `decode`.
|
||||||
pub fn encode(bytes: &[u8], out: &mut [u8]) {
|
pub fn encode(bytes: &[u8], out: &mut [u8]) {
|
||||||
let wide = bytes.chunks_exact(12);
|
let (wide, rest) = bytes.as_chunks::<12>();
|
||||||
let (wide_out, rest_out) = out.split_at_mut(bytes.len() / 12 * 16);
|
let (wide_out, rest_out) = out.split_at_mut(wide.len() * 16);
|
||||||
let rest = wide.remainder();
|
let (wide_out, _) = wide_out.as_chunks_mut::<16>();
|
||||||
for (group, chars) in wide.zip(wide_out.chunks_exact_mut(16)) {
|
let (rest_out, _) = rest_out.as_chunks_mut::<4>();
|
||||||
let (Some(low), Some(high)) =
|
for (group, chars) in wide.iter().zip(wide_out) {
|
||||||
(group.first_chunk::<8>(), group.last_chunk::<8>())
|
let (low, high) = (word(group, 0), word(group, 4));
|
||||||
else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
let low = u64::from_le_bytes(*low);
|
|
||||||
let high = u64::from_le_bytes(*high);
|
|
||||||
let front = u64::from(quad(low)) | u64::from(quad(low >> 24)) << 32;
|
let front = u64::from(quad(low)) | u64::from(quad(low >> 24)) << 32;
|
||||||
let back = u64::from(quad(high >> 16)) | u64::from(quad(high >> 40)) << 32;
|
let back = u64::from(quad(high >> 16)) | u64::from(quad(high >> 40)) << 32;
|
||||||
chars[..8].copy_from_slice(&front.to_le_bytes());
|
chars[..8].copy_from_slice(&front.to_le_bytes());
|
||||||
chars[8..].copy_from_slice(&back.to_le_bytes());
|
chars[8..].copy_from_slice(&back.to_le_bytes());
|
||||||
}
|
}
|
||||||
for (group, chars) in rest.chunks(3).zip(rest_out.chunks_exact_mut(4)) {
|
for (group, chars) in rest.chunks(3).zip(rest_out) {
|
||||||
let mut padded = [0; 8];
|
let mut padded = [0; 8];
|
||||||
padded[..group.len()].copy_from_slice(group);
|
padded[..group.len()].copy_from_slice(group);
|
||||||
chars.copy_from_slice(&quad(u64::from_le_bytes(padded)).to_le_bytes());
|
chars.copy_from_slice(&quad(u64::from_le_bytes(padded)).to_le_bytes());
|
||||||
|
|||||||
Reference in New Issue
Block a user