impl<'a> Writer<'a> { /// Creates a new `Writer` from a fully initialized buffer. #[inline] pubfn new(buf: &'a mut [u8]) -> Writer<'a> { // SAFETY: Because buf is a slice, most of the preconditions for // core::slice::from_raw_parts_mut are satisfied: // * buf.as_mut_ptr() is non-null. // * The memory range is within a single allocated object. // * buf is mutable, so the range is valid for both reads // and writes of up to buf.len() * size_of::<u8>() bytes. // * The contents of the slice are initialized. // * buf.as_mut_ptr() + buf.len() does not wrap around // the end of the address space. // The remaining precondition is enforced by the borrow checker when this function is called: // * The memory range cannot be accessed through any other pointer for the // duration of lifetime 'a. unsafe { Self::new_uninit(buf.as_mut_ptr(), buf.len()) }
}
/// Creates a new `Writer` from an uninitialized buffer. /// /// # Safety /// /// The arguments must satisfy the requirements of [`core::slice::from_raw_parts_mut`]. #[inline] pubunsafefn new_uninit(ptr: *mut u8, len: usize) -> Writer<'a> { // SAFETY: The preconditions for WeakSliceMut::from_raw_parts_mut are the same // as for core::slice::from_raw_parts_mut, and the caller is responsible for // ensuring the latter. let buf = unsafe { WeakSliceMut::from_raw_parts_mut(ptr as *mut MaybeUninit<u8>, len) };
Writer { buf, filled: 0 }
}
#[inline] pubunsafefn new_uninit_raw(ptr: *mut u8, len: usize, capacity: usize) -> Writer<'a> { let buf = unsafe { WeakSliceMut::from_raw_parts_mut(ptr as *mut MaybeUninit<u8>, capacity) };
Writer { buf, filled: len }
}
/// Pointer to where the next byte will be written #[inline] pubfn next_out(&mutself) -> *mut MaybeUninit<u8> { self.buf.as_mut_ptr().wrapping_add(self.filled).cast()
}
/// Returns the total capacity of the buffer. #[inline] pubfn capacity(&self) -> usize { self.buf.len()
}
/// Returns the length of the filled part of the buffer #[inline] pubfn len(&self) -> usize { self.filled
}
/// Returns a shared reference to the filled portion of the buffer. #[inline] pubfn filled(&self) -> &[u8] { // SAFETY: the filled area of the buffer is always initialized, and self.filled is always // in-bounds. unsafe { core::slice::from_raw_parts(self.buf.as_ptr().cast(), self.filled) }
}
/// Returns the number of bytes at the end of the slice that have not yet been filled. #[inline] pubfn remaining(&self) -> usize { self.capacity() - self.filled
}
/// Appends data to the buffer #[inline(always)] pubfn extend(&mutself, buf: &[u8]) { // using simd here (on x86_64) was not fruitful self.buf.as_mut_slice()[self.filled..][..buf.len()].copy_from_slice(slice_to_uninit(buf));
#[inline(always)] fn extend_from_window_help<const N: usize>(
&mutself,
window: &super::window::Window,
range: Range<usize>,
) { let len = range.end - range.start;
ifself.remaining() >= len + N { // SAFETY: we know that our window has at least a N extra bytes // at the end, making it always safe to perform an (unaligned) Chunk read anywhere in // the window slice. // // The calling function checks for CPU features requirements for C. unsafe { let src = window.as_ptr(); Self::copy_chunk_unchecked::<N>(
src.wrapping_add(range.start).cast(), self.next_out(),
len,
)
}
} else { let buf = &window.as_slice()[range]; self.buf.as_mut_slice()[self.filled..][..buf.len()]
.copy_from_slice(slice_to_uninit(buf));
}
self.filled += len;
}
/// Variant of `extend_from_window` used with `inflateBack`. It does not attempt a chunked /// copy, because there is no padding at the end and the window and output buffer alias. /// So a standard `memmove` will have to do. #[inline(always)] pubfn extend_from_window_back(&mutself, window: &super::window::Window, range: Range<usize>) { let len = range.end - range.start;
#[inline(always)] fn copy_match_help<const N: usize>(&mutself, offset_from_end: usize, length: usize) { let capacity = self.buf.len(); let len = Ord::min(self.filled + length + N, capacity); let buf = &mutself.buf.as_mut_slice()[..len];
let current = self.filled; self.filled += length;
// Note also that the referenced string may overlap the current // position; for example, if the last 2 bytes decoded have values // X and Y, a string reference with <length = 5, distance = 2> // adds X,Y,X,Y,X to the output stream.
if length > offset_from_end { match offset_from_end { 1 => { // this will just repeat this value many times let element = buf[current - 1];
buf[current..][..length].fill(element);
}
_ => { // there is a SIMD implementation of this logic, which _should_ be faster, but // isn't in measurements on x86_64. It still might be for other architectures, // adds a lot of complexity and unsafe code. for i in0..length {
buf[current + i] = buf[current - offset_from_end + i];
}
}
}
} else { Self::copy_chunked_within::<N>(buf, capacity, current, offset_from_end, length);
}
}
/// Variant of `copy_match` used with `inflateBack`. It does not attempt a chunked /// copy, because there is no padding at the end. #[inline(always)] pubfn copy_match_back(&mutself, offset_from_end: usize, length: usize) { let capacity = self.buf.len(); let len = Ord::min(self.filled + length, capacity); let buf = &mutself.buf.as_mut_slice()[..len];
let current = self.filled; self.filled += length;
// Note also that the referenced string may overlap the current // position; for example, if the last 2 bytes decoded have values // X and Y, a string reference with <length = 5, distance = 2> // adds X,Y,X,Y,X to the output stream.
match offset_from_end { 1 => { // this will just repeat this value many times let element = buf[current - 1];
buf[current..][..length].fill(element);
}
_ => { for i in0..length {
buf[current + i] = buf[current - offset_from_end + i];
}
}
}
}
if current + length + N < capacity { let ptr = buf.as_mut_ptr(); // SAFETY: if statement and checked_sub ensures we stay in bounds. unsafe { Self::copy_chunk_unchecked::<N>(ptr.add(start), ptr.add(current), length) }
} else { // a full simd copy does not fit in the output buffer
buf.copy_within(start..start + length, current);
}
}
/// # Safety /// /// `src..src + length` must be safe to perform reads in chunks of N elements until /// `src + length` is reached. `dst` must be safe to (unaligned) write that number of chunks. #[inline(always)] unsafefn copy_chunk_unchecked<const N: usize>( mut src: *const MaybeUninit<u8>, mut dst: *mut MaybeUninit<u8>,
length: usize,
) { if length == 0 { return;
}
// SAFETY: The caller ensured that src + length is within (or just at the end of) // a readable range of bytes. LLVM disallows allocations bigger than isize::MAX, // so if src..src+length is a valid allocation (a precondition of this function) // the length will never exceed isize::MAX. let end = unsafe { src.add(length) };
// SAFETY: We checked above that length != 0, so there is at least one chunk remaining. let chunk = unsafe { load_chunk::<N>(src) }; unsafe { store_chunk::<N>(dst, chunk) };
// SAFETY: src and dest haven't been modified yet, and we checked above that // length != 0, so adding one chunk (N bytes) to both src and dst will result in // a pointer in (or just at the end of) each of the underlying buffers.
src = unsafe { src.add(N) };
dst = unsafe { dst.add(N) };
while src < end { // SAFETY: The caller ensured that src and dst contain enough bytes to support // reads (from src) or writes (to dst) up to and including the chunk that contains // end. Note that, if length is not a multiple of N, we will copy up to N-1 bytes // past end. let chunk = unsafe { load_chunk::<N>(src) }; unsafe { store_chunk::<N>(dst, chunk) };
// SAFETY: Because src is currently < end, we have at least one more chunk available // to copy, so there is room to advance the pointers by N within both the src and // dst bufs.
src = unsafe { src.add(N) };
dst = unsafe { dst.add(N) };
}
}
}
/// # Safety /// /// Must be valid to read a `[u8; N]` value from `from` with an unaligned read. #[inline(always)] unsafefn load_chunk<const N: usize>(from: *const MaybeUninit<u8>) -> [MaybeUninit<u8>; N] { // SAFETY: Checked by the caller. unsafe { core::ptr::read_unaligned(from.cast::<[MaybeUninit<u8>; N]>()) }
}
/// # Safety /// /// Must be valid to write a `[u8; N]` value to `out` with an unaligned write. #[inline(always)] unsafefn store_chunk<const N: usize>(out: *mut MaybeUninit<u8>, chunk: [MaybeUninit<u8>; N]) { // SAFETY: checked by the caller. unsafe { core::ptr::write_unaligned(out.cast(), chunk) }
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.