Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

remove VecSink #71

Merged
merged 1 commit into from
Jan 31, 2023
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
14 changes: 7 additions & 7 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ jobs:
run: cargo build --verbose
- name: Run tests
run: cargo test
- name: Run tests --features safe-encode
run: cargo test --features safe-encode --verbose
- name: Run tests safe-encode
run: cargo test --features safe-encode
- name: Run tests safe-decode
run: cargo test --verbose --features safe-decode
- name: Run tests no-default-features (no safe-decode)
run: cargo test --verbose --no-default-features --features frame
- name: Ensure no_std compiles for checked-decode
run: cargo build --no-default-features --features checked-decode
run: cargo test --features safe-decode
- name: Run tests --no-default-features (no safe-decode) with frame
run: cargo test --no-default-features --features frame
- name: Run tests unsafe with checked-decode and frame
run: cargo test --no-default-features --features checked-decode --features frame
- name: Ensure no_std compiles
run: cargo build --no-default-features
- name: Ensure no_std compiles for safe-decode
Expand Down
20 changes: 10 additions & 10 deletions benches/crit_bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,16 +161,16 @@ fn bench_block_compression_throughput(c: &mut Criterion) {
//&input,
//|b, i| b.iter(|| lz4_flex::block::compress_with_dict(i, &empty_vec)),
//);
group.bench_with_input(
BenchmarkId::new("lz4_redox_rust", input_bytes),
&input,
|b, i| b.iter(|| lz4_compress::compress(i)),
);
group.bench_with_input(
BenchmarkId::new("lz4_fear_rust", input_bytes),
&input,
|b, i| b.iter(|| compress_lz4_fear(i)),
);
//group.bench_with_input(
//BenchmarkId::new("lz4_redox_rust", input_bytes),
//&input,
//|b, i| b.iter(|| lz4_compress::compress(i)),
//);
//group.bench_with_input(
//BenchmarkId::new("lz4_fear_rust", input_bytes),
//&input,
//|b, i| b.iter(|| compress_lz4_fear(i)),
//);

group.bench_with_input(BenchmarkId::new("lz4_cpp", input_bytes), &input, |b, i| {
b.iter(|| lz4_cpp_block_compress(i))
Expand Down
17 changes: 10 additions & 7 deletions examples/compress.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use std::io;
fn main() {
let stdin = io::stdin();
let stdout = io::stdout();
let mut rdr = stdin.lock();
// Wrap the stdout writer in a LZ4 Frame writer.
let mut wtr = lz4_flex::frame::FrameEncoder::new(stdout.lock());
io::copy(&mut rdr, &mut wtr).expect("I/O operation failed");
let _stdout = wtr.finish().unwrap();
#[cfg(feature = "frame")]
{
let stdin = io::stdin();
let stdout = io::stdout();
let mut rdr = stdin.lock();
// Wrap the stdout writer in a LZ4 Frame writer.
let mut wtr = lz4_flex::frame::FrameEncoder::new(stdout.lock());
io::copy(&mut rdr, &mut wtr).expect("I/O operation failed");
let _stdout = wtr.finish().unwrap();
}
}
15 changes: 9 additions & 6 deletions examples/decompress.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use std::io;
fn main() {
let stdin = io::stdin();
let stdout = io::stdout();
// Wrap the stdin reader in a LZ4 FrameDecoder.
let mut rdr = lz4_flex::frame::FrameDecoder::new(stdin.lock());
let mut wtr = stdout.lock();
io::copy(&mut rdr, &mut wtr).expect("I/O operation failed");
#[cfg(feature = "frame")]
{
let stdin = io::stdin();
let stdout = io::stdout();
// Wrap the stdin reader in a LZ4 FrameDecoder.
let mut rdr = lz4_flex::frame::FrameDecoder::new(stdin.lock());
let mut wtr = stdout.lock();
io::copy(&mut rdr, &mut wtr).expect("I/O operation failed");
}
}
91 changes: 41 additions & 50 deletions src/block/compress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,20 @@ use crate::block::LZ4_MIN_LENGTH;
use crate::block::MAX_DISTANCE;
use crate::block::MFLIMIT;
use crate::block::MINMATCH;
use crate::sink::{vec_sink_for_compression, Sink, SliceSink};
use crate::sink::SliceSink;
use alloc::vec::Vec;

#[cfg(feature = "safe-encode")]
use core::convert::TryInto;

use super::{CompressError, WINDOW_SIZE};

pub(crate) fn get_vec_with_size(size: usize) -> Vec<u8> {
let mut compressed = Vec::with_capacity(size);
compressed.resize(size, 0);
compressed
}

/// Increase step size after 1<<INCREASE_STEPSIZE_BITSHIFT non matches
const INCREASE_STEPSIZE_BITSHIFT: usize = 5;

Expand Down Expand Up @@ -217,7 +223,7 @@ fn count_same_bytes(input: &[u8], cur: &mut usize, source: &[u8], candidate: usi
/// on. There can be any number of bytes of value "255" following token
#[inline]
#[cfg(feature = "safe-encode")]
fn write_integer(output: &mut impl Sink, mut n: usize) {
fn write_integer(output: &mut SliceSink, mut n: usize) {
// Note: Since `n` is usually < 0xFF and writing multiple bytes to the output
// requires 2 branches of bound check (due to the possibility of add overflows)
// the simple byte at a time implementation bellow is faster in most cases.
Expand All @@ -235,7 +241,7 @@ fn write_integer(output: &mut impl Sink, mut n: usize) {
/// on. There can be any number of bytes of value "255" following token
#[inline]
#[cfg(not(feature = "safe-encode"))]
fn write_integer(output: &mut impl Sink, mut n: usize) {
fn write_integer(output: &mut SliceSink, mut n: usize) {
// Write the 0xFF bytes as long as the integer is higher than said value.
if n >= 4 * 0xFF {
// In this unlikelly branch we use a fill instead of a loop,
Expand All @@ -260,7 +266,7 @@ fn write_integer(output: &mut impl Sink, mut n: usize) {

/// Handle the last bytes from the input as literals
#[cold]
fn handle_last_literals(output: &mut impl Sink, input: &[u8], start: usize) {
fn handle_last_literals(output: &mut SliceSink, input: &[u8], start: usize) {
let lit_len = input.len() - start;

let token = token_from_literal(lit_len);
Expand Down Expand Up @@ -341,10 +347,10 @@ fn backtrack_match(
// Intentionally avoid inlining.
// Empirical tests revealed it to be rarely better but often significantly detrimental.
#[inline(never)]
pub(crate) fn compress_internal<T: HashTable, SINK: Sink, const USE_DICT: bool>(
pub(crate) fn compress_internal<T: HashTable, const USE_DICT: bool>(
input: &[u8],
input_pos: usize,
output: &mut SINK,
output: &mut SliceSink,
dict: &mut T,
ext_dict: &[u8],
input_stream_offset: usize,
Expand Down Expand Up @@ -509,13 +515,13 @@ pub(crate) fn compress_internal<T: HashTable, SINK: Sink, const USE_DICT: bool>(

#[inline]
#[cfg(feature = "safe-encode")]
fn push_byte(output: &mut impl Sink, el: u8) {
fn push_byte(output: &mut SliceSink, el: u8) {
output.push(el);
}

#[inline]
#[cfg(not(feature = "safe-encode"))]
fn push_byte(output: &mut impl Sink, el: u8) {
fn push_byte(output: &mut SliceSink, el: u8) {
unsafe {
core::ptr::write(output.pos_mut_ptr(), el);
output.set_pos(output.pos() + 1);
Expand All @@ -524,13 +530,13 @@ fn push_byte(output: &mut impl Sink, el: u8) {

#[inline]
#[cfg(feature = "safe-encode")]
fn push_u16(output: &mut impl Sink, el: u16) {
fn push_u16(output: &mut SliceSink, el: u16) {
output.extend_from_slice(&el.to_le_bytes());
}

#[inline]
#[cfg(not(feature = "safe-encode"))]
fn push_u16(output: &mut impl Sink, el: u16) {
fn push_u16(output: &mut SliceSink, el: u16) {
unsafe {
core::ptr::copy_nonoverlapping(el.to_le_bytes().as_ptr(), output.pos_mut_ptr(), 2);
output.set_pos(output.pos() + 2);
Expand All @@ -539,7 +545,7 @@ fn push_u16(output: &mut impl Sink, el: u16) {

#[inline]
#[cfg(not(feature = "safe-encode"))]
fn push_u32(output: &mut impl Sink, el: u32) {
fn push_u32(output: &mut SliceSink, el: u32) {
unsafe {
core::ptr::copy_nonoverlapping(el.to_le_bytes().as_ptr(), output.pos_mut_ptr(), 4);
output.set_pos(output.pos() + 4);
Expand All @@ -548,7 +554,7 @@ fn push_u32(output: &mut impl Sink, el: u32) {

#[inline(always)] // (always) necessary otherwise compiler fails to inline it
#[cfg(feature = "safe-encode")]
fn copy_literals_wild(output: &mut impl Sink, input: &[u8], input_start: usize, len: usize) {
fn copy_literals_wild(output: &mut SliceSink, input: &[u8], input_start: usize, len: usize) {
match len {
0..=8 => output.extend_from_slice_wild(&input[input_start..input_start + 8], len),
9..=16 => output.extend_from_slice_wild(&input[input_start..input_start + 16], len),
Expand All @@ -559,7 +565,7 @@ fn copy_literals_wild(output: &mut impl Sink, input: &[u8], input_start: usize,

#[inline]
#[cfg(not(feature = "safe-encode"))]
fn copy_literals_wild(output: &mut impl Sink, input: &[u8], input_start: usize, len: usize) {
fn copy_literals_wild(output: &mut SliceSink, input: &[u8], input_start: usize, len: usize) {
debug_assert!(input_start + len / 8 * 8 + ((len % 8) != 0) as usize * 8 <= input.len());
debug_assert!(output.pos() + len / 8 * 8 + ((len % 8) != 0) as usize * 8 <= output.capacity());
unsafe {
Expand All @@ -580,41 +586,41 @@ fn copy_literals_wild(output: &mut impl Sink, input: &[u8], input_start: usize,
#[inline]
pub(crate) fn compress_into_sink(
input: &[u8],
output: &mut impl Sink,
output: &mut SliceSink,
) -> Result<usize, CompressError> {
let (dict_size, dict_bitshift) = get_table_size(input.len());
if input.len() < u16::MAX as usize {
let mut dict = HashTableU16::new(dict_size, dict_bitshift);
compress_internal::<_, _, false>(input, 0, output, &mut dict, b"", 0)
compress_internal::<_, false>(input, 0, output, &mut dict, b"", 0)
} else if input.len() < u32::MAX as usize {
let mut dict = HashTableU32::new(dict_size, dict_bitshift);
compress_internal::<_, _, false>(input, 0, output, &mut dict, b"", 0)
compress_internal::<_, false>(input, 0, output, &mut dict, b"", 0)
} else {
let mut dict = HashTableUsize::new(dict_size, dict_bitshift);
compress_internal::<_, _, false>(input, 0, output, &mut dict, b"", 0)
compress_internal::<_, false>(input, 0, output, &mut dict, b"", 0)
}
}

/// Same as compress_into_sink but with supports external dictionary
#[inline]
pub(crate) fn compress_into_sink_with_dict(
input: &[u8],
output: &mut impl Sink,
output: &mut SliceSink,
mut dict_data: &[u8],
) -> Result<usize, CompressError> {
let (dict_size, dict_bitshift) = get_table_size(input.len());
if dict_data.len() + input.len() < u16::MAX as usize {
let mut dict = HashTableU16::new(dict_size, dict_bitshift);
init_dict(&mut dict, &mut dict_data);
compress_internal::<_, _, true>(input, 0, output, &mut dict, dict_data, dict_data.len())
compress_internal::<_, true>(input, 0, output, &mut dict, dict_data, dict_data.len())
} else if dict_data.len() + input.len() < u32::MAX as usize {
let mut dict = HashTableU32::new(dict_size, dict_bitshift);
init_dict(&mut dict, &mut dict_data);
compress_internal::<_, _, true>(input, 0, output, &mut dict, dict_data, dict_data.len())
compress_internal::<_, true>(input, 0, output, &mut dict, dict_data, dict_data.len())
} else {
let mut dict = HashTableUsize::new(dict_size, dict_bitshift);
init_dict(&mut dict, &mut dict_data);
compress_internal::<_, _, true>(input, 0, output, &mut dict, dict_data, dict_data.len())
compress_internal::<_, true>(input, 0, output, &mut dict, dict_data, dict_data.len())
}
}

Expand Down Expand Up @@ -671,13 +677,10 @@ pub fn compress_into_with_dict(
#[inline]
pub fn compress_prepend_size(input: &[u8]) -> Vec<u8> {
let max_compressed_size = get_maximum_output_size(input.len());
let mut compressed = Vec::with_capacity(4 + max_compressed_size);
compressed.extend_from_slice(&(input.len() as u32).to_le_bytes());
let compressed_len = compress_into_sink(
input,
&mut vec_sink_for_compression(&mut compressed, 4, 0, max_compressed_size),
)
.unwrap();
let mut compressed = get_vec_with_size(4 + max_compressed_size);
compressed[..4].copy_from_slice(&(input.len() as u32).to_le_bytes());
let compressed_len = compress_into(input, &mut compressed[4..]).unwrap();

compressed.truncate(4 + compressed_len);
compressed
}
Expand All @@ -686,12 +689,8 @@ pub fn compress_prepend_size(input: &[u8]) -> Vec<u8> {
#[inline]
pub fn compress(input: &[u8]) -> Vec<u8> {
let max_compressed_size = get_maximum_output_size(input.len());
let mut compressed = Vec::with_capacity(max_compressed_size);
let compressed_len = compress_into_sink(
input,
&mut vec_sink_for_compression(&mut compressed, 0, 0, max_compressed_size),
)
.unwrap();
let mut compressed = get_vec_with_size(max_compressed_size);
let compressed_len = compress_into(input, &mut compressed[..]).unwrap();
compressed.truncate(compressed_len);
compressed
}
Expand All @@ -700,13 +699,8 @@ pub fn compress(input: &[u8]) -> Vec<u8> {
#[inline]
pub fn compress_with_dict(input: &[u8], ext_dict: &[u8]) -> Vec<u8> {
let max_compressed_size = get_maximum_output_size(input.len());
let mut compressed = Vec::with_capacity(max_compressed_size);
let compressed_len = compress_into_sink_with_dict(
input,
&mut vec_sink_for_compression(&mut compressed, 0, 0, max_compressed_size),
ext_dict,
)
.unwrap();
let mut compressed = get_vec_with_size(max_compressed_size);
let compressed_len = compress_into_with_dict(input, &mut compressed[..], ext_dict).unwrap();
compressed.truncate(compressed_len);
compressed
}
Expand All @@ -716,14 +710,11 @@ pub fn compress_with_dict(input: &[u8], ext_dict: &[u8]) -> Vec<u8> {
#[inline]
pub fn compress_prepend_size_with_dict(input: &[u8], ext_dict: &[u8]) -> Vec<u8> {
let max_compressed_size = get_maximum_output_size(input.len());
let mut compressed = Vec::with_capacity(4 + max_compressed_size);
compressed.extend_from_slice(&(input.len() as u32).to_le_bytes());
let compressed_len = compress_into_sink_with_dict(
input,
&mut vec_sink_for_compression(&mut compressed, 4, 0, max_compressed_size),
ext_dict,
)
.unwrap();

let mut compressed = get_vec_with_size(4 + max_compressed_size);
compressed[..4].copy_from_slice(&(input.len() as u32).to_le_bytes());
let compressed_len = compress_into_with_dict(input, &mut compressed[4..], ext_dict).unwrap();

compressed.truncate(4 + compressed_len);
compressed
}
Expand Down Expand Up @@ -888,7 +879,7 @@ mod tests {
uncompressed[..output_start].copy_from_slice(&dict[dict_cutoff..]);
let uncomp_len = {
let mut sink = SliceSink::new(&mut uncompressed[..], output_start);
crate::block::decompress::decompress_internal::<_, true>(
crate::block::decompress::decompress_internal::<true>(
&compressed,
&mut sink,
&dict[..dict_cutoff],
Expand Down
Loading