Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,7 @@ libdeflater = "1.25.0"
[[bench]]
name = "bench_main"
harness = false

[[bench]]
name = "encoder_perf"
harness = false
28 changes: 28 additions & 0 deletions benches/encoder_perf.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use criterion::{Criterion, Throughput, criterion_group, criterion_main};
use libdeflate::stream::DeflateEncoder;
use std::io::Write;

fn bench_encoder_parallel(c: &mut Criterion) {
let size = 10 * 1024 * 1024; // 10MB
let mut data = Vec::with_capacity(size);
for i in 0..size {
data.push((i % 256) as u8);
}

let mut group = c.benchmark_group("DeflateEncoder Parallel");
group.throughput(Throughput::Bytes(size as u64));

group.bench_function("write_all 10MB", |b| {
b.iter(|| {
let sink = std::io::sink();
let mut encoder = DeflateEncoder::new(sink, 6); // Default 1MB buffer
encoder.write_all(&data).unwrap();
encoder.finish().unwrap();
});
});

group.finish();
}

criterion_group!(benches, bench_encoder_parallel);
criterion_main!(benches);
4 changes: 2 additions & 2 deletions src/adler32/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ fn adler32_chunk(s1: &mut u32, s2: &mut u32, p: &[u8]) {
+ (b12 * 4)
+ (b13 * 3)
+ (b14 * 2)
+ (b15 * 1);
+ b15;

s1_local +=
b0 + b1 + b2 + b3 + b4 + b5 + b6 + b7 + b8 + b9 + b10 + b11 + b12 + b13 + b14 + b15;
Expand All @@ -63,7 +63,7 @@ fn adler32_chunk(s1: &mut u32, s2: &mut u32, p: &[u8]) {
let b2 = unsafe { *ptr.add(2) as u32 };
let b3 = unsafe { *ptr.add(3) as u32 };

s2_local += (s1_local << 2) + (b0 * 4) + (b1 * 3) + (b2 * 2) + (b3 * 1);
s2_local += (s1_local << 2) + (b0 * 4) + (b1 * 3) + (b2 * 2) + b3;
s1_local += b0 + b1 + b2 + b3;

unsafe {
Expand Down
20 changes: 13 additions & 7 deletions src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub struct Compressor {

impl Compressor {
pub fn new(level: i32) -> io::Result<Self> {
if level < 0 || level > 12 {
if !(0..=12).contains(&level) {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Compression level must be between 0 and 12",
Expand Down Expand Up @@ -79,7 +79,7 @@ impl Compressor {
let mut output = Vec::new();
output
.try_reserve_exact(bound)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
.map_err(io::Error::other)?;

// Use spare_capacity_mut to avoid zero-initialization.
// Since len is 0, this returns the entire capacity as MaybeUninit.
Expand All @@ -96,7 +96,7 @@ impl Compressor {
Ok(output)
}
CompressResult::InsufficientSpace => {
Err(io::Error::new(io::ErrorKind::Other, "Insufficient space"))
Err(io::Error::other("Insufficient space"))
}
}
}
Expand Down Expand Up @@ -131,7 +131,7 @@ impl Compressor {
if res == CompressResult::Success {
Ok(size)
} else {
Err(io::Error::new(io::ErrorKind::Other, error_msg))
Err(io::Error::other(error_msg))
}
}
}
Expand All @@ -142,6 +142,12 @@ pub struct Decompressor {
limit_ratio: usize,
}

impl Default for Decompressor {
fn default() -> Self {
Self::new()
}
}

impl Decompressor {
pub fn new() -> Self {
Self {
Expand Down Expand Up @@ -239,7 +245,7 @@ impl Decompressor {
let mut output = Vec::new();
output
.try_reserve_exact(expected_size)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
.map_err(io::Error::other)?;

// Use spare_capacity_mut to avoid zero-initialization.
let out_uninit = output.spare_capacity_mut();
Expand Down Expand Up @@ -304,8 +310,8 @@ fn is_overlapping(s1: &[u8], s2: &[u8]) -> bool {
let p2 = s2.as_ptr() as usize;
let len2 = s2.len();

let end1 = p1.checked_add(len1).unwrap_or(usize::MAX);
let end2 = p2.checked_add(len2).unwrap_or(usize::MAX);
let end1 = p1.saturating_add(len1);
let end2 = p2.saturating_add(len2);

use std::cmp::{max, min};
max(p1, p2) < min(end1, end2)
Expand Down
6 changes: 6 additions & 0 deletions src/batch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ impl BatchCompressor {

pub struct BatchDecompressor;

impl Default for BatchDecompressor {
fn default() -> Self {
Self::new()
}
}

impl BatchDecompressor {
pub fn new() -> Self {
Self
Expand Down
2 changes: 1 addition & 1 deletion src/compress/huffman_comp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ fn build_tree(a: &mut [u32], sym_count: usize) {
let mut e = 0;
while e < last_idx {
let new_freq;
if i + 1 <= last_idx && (b == e || (a[i + 1] & FREQ_MASK) <= (a[b] & FREQ_MASK)) {
if i < last_idx && (b == e || (a[i + 1] & FREQ_MASK) <= (a[b] & FREQ_MASK)) {
new_freq = (a[i] & FREQ_MASK) + (a[i + 1] & FREQ_MASK);
i += 2;
} else if b + 2 <= e && (i > last_idx || (a[b + 1] & FREQ_MASK) < (a[i] & FREQ_MASK)) {
Expand Down
45 changes: 21 additions & 24 deletions src/compress/matchfinder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -441,16 +441,14 @@ unsafe fn match_len_avx2(a: *const u8, b: *const u8, max_len: usize) -> usize {
let mask = _mm256_movemask_epi8(cmp) as u32;
return len + 32 + (!mask).trailing_zeros() as usize;
}
} else if _mm256_testz_si256(xor3, xor3) == 0 {
let cmp = _mm256_cmpeq_epi8(xor3, v_zero);
let mask = _mm256_movemask_epi8(cmp) as u32;
return len + 64 + (!mask).trailing_zeros() as usize;
} else {
if _mm256_testz_si256(xor3, xor3) == 0 {
let cmp = _mm256_cmpeq_epi8(xor3, v_zero);
let mask = _mm256_movemask_epi8(cmp) as u32;
return len + 64 + (!mask).trailing_zeros() as usize;
} else {
let cmp = _mm256_cmpeq_epi8(xor4, v_zero);
let mask = _mm256_movemask_epi8(cmp) as u32;
return len + 96 + (!mask).trailing_zeros() as usize;
}
let cmp = _mm256_cmpeq_epi8(xor4, v_zero);
let mask = _mm256_movemask_epi8(cmp) as u32;
return len + 96 + (!mask).trailing_zeros() as usize;
}
}

Expand Down Expand Up @@ -691,7 +689,7 @@ impl MatchFinder {
where
F: FnMut(usize, usize),
{
if pos.checked_add(3).map_or(true, |end| end > data.len()) {
if pos.checked_add(3).is_none_or(|end| end > data.len()) {
return (0, 0);
}

Expand All @@ -705,7 +703,7 @@ impl MatchFinder {
src_val_4 = (src as *const u32).read_unaligned();
src_val = src_val_4 & 0xFFFFFF;
} else {
src_val = ((src.read() as u32) << 0)
src_val = (src.read() as u32)
| ((src.add(1).read() as u32) << 8)
| ((src.add(2).read() as u32) << 16);
}
Expand Down Expand Up @@ -756,11 +754,10 @@ impl MatchFinder {
}

let mut match_ok = true;
if best_len >= 3 {
if *match_ptr.add(best_len) != *src.add(best_len) {
if best_len >= 3
&& *match_ptr.add(best_len) != *src.add(best_len) {
match_ok = false;
}
}

if match_ok {
if safe_to_read_u32 {
Expand All @@ -787,7 +784,7 @@ impl MatchFinder {
if p_rel + 4 <= data.len() {
match_val = (match_ptr as *const u32).read_unaligned() & 0xFFFFFF;
} else {
match_val = ((match_ptr.read() as u32) << 0)
match_val = (match_ptr.read() as u32)
| ((match_ptr.add(1).read() as u32) << 8)
| ((match_ptr.add(2).read() as u32) << 16);
}
Expand Down Expand Up @@ -949,7 +946,7 @@ impl MatchFinder {
}
}
pub fn skip_match(&mut self, data: &[u8], pos: usize) {
if pos.checked_add(3).map_or(true, |end| end > data.len()) {
if pos.checked_add(3).is_none_or(|end| end > data.len()) {
return;
}
unsafe {
Expand All @@ -958,7 +955,7 @@ impl MatchFinder {
if pos + 4 <= data.len() {
src_val = (src as *const u32).read_unaligned() & 0xFFFFFF;
} else {
src_val = ((src.read() as u32) << 0)
src_val = (src.read() as u32)
| ((src.add(1).read() as u32) << 8)
| ((src.add(2).read() as u32) << 16);
}
Expand Down Expand Up @@ -993,7 +990,7 @@ impl MatchFinder {
}
if pos
.checked_add(count + 3)
.map_or(true, |end| end > data.len())
.is_none_or(|end| end > data.len())
{
for i in 0..count {
self.skip_match(data, pos + i);
Expand Down Expand Up @@ -1068,7 +1065,7 @@ impl HtMatchFinder {
}

pub fn find_match(&mut self, data: &[u8], pos: usize) -> (usize, usize) {
if pos.checked_add(3).map_or(true, |end| end > data.len()) {
if pos.checked_add(3).is_none_or(|end| end > data.len()) {
return (0, 0);
}

Expand All @@ -1081,7 +1078,7 @@ impl HtMatchFinder {
if safe_to_read_u32 {
src_val = (src as *const u32).read_unaligned() & 0xFFFFFF;
} else {
src_val = ((src.read() as u32) << 0)
src_val = (src.read() as u32)
| ((src.add(1).read() as u32) << 8)
| ((src.add(2).read() as u32) << 16);
}
Expand Down Expand Up @@ -1112,7 +1109,7 @@ impl HtMatchFinder {
} else if p_rel + 4 <= data.len() {
match_val = (match_ptr as *const u32).read_unaligned() & 0xFFFFFF;
} else {
match_val = ((match_ptr.read() as u32) << 0)
match_val = (match_ptr.read() as u32)
| ((match_ptr.add(1).read() as u32) << 8)
| ((match_ptr.add(2).read() as u32) << 16);
}
Expand All @@ -1139,7 +1136,7 @@ impl HtMatchFinder {
}

pub fn skip_match(&mut self, data: &[u8], pos: usize) {
if pos.checked_add(3).map_or(true, |end| end > data.len()) {
if pos.checked_add(3).is_none_or(|end| end > data.len()) {
return;
}
unsafe {
Expand All @@ -1148,7 +1145,7 @@ impl HtMatchFinder {
if pos + 4 <= data.len() {
src_val = (src as *const u32).read_unaligned() & 0xFFFFFF;
} else {
src_val = ((src.read() as u32) << 0)
src_val = (src.read() as u32)
| ((src.add(1).read() as u32) << 8)
| ((src.add(2).read() as u32) << 16);
}
Expand Down Expand Up @@ -1281,7 +1278,7 @@ impl BtMatchFinder {
max_depth: usize,
mut visitor: V,
) -> V {
if pos.checked_add(4).map_or(true, |end| end > data.len()) {
if pos.checked_add(4).is_none_or(|end| end > data.len()) {
return visitor;
}

Expand Down
Loading