From 04d812e490804d4488f4ede5370d6bf7de37cc37 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Mon, 4 Dec 2023 04:36:02 +0100 Subject: [PATCH] Introduce BitVec::{try_,}from_partial_vec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add BitVec::from_partial_vec and BitVec::try_from_partial_vec methods which construct the bit vector from part of the underlying vector. This makes it easy to create a bit vector which doesn’t start at the first bit of the underlying memory. --- src/ptr/single.rs | 10 ++-- src/vec.rs | 114 +++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 109 insertions(+), 15 deletions(-) diff --git a/src/ptr/single.rs b/src/ptr/single.rs index f896c9ea..1d3b378f 100644 --- a/src/ptr/single.rs +++ b/src/ptr/single.rs @@ -367,9 +367,7 @@ where /// departure from the subslice, *even within the original slice*, illegal. #[inline] pub fn from_mut_slice(slice: &mut [T]) -> Self { - unsafe { - Self::new_unchecked(slice.as_mut_ptr().into_address(), BitIdx::MIN) - } + Self::from_slice_with_index_mut(slice, BitIdx::MIN) } /// Constructs a mutable `BitPtr` to the zeroth bit in the zeroth element of @@ -381,8 +379,12 @@ where /// departure from the subslice, *even within the original slice*, illegal. #[inline] pub fn from_slice_mut(slice: &mut [T]) -> Self { + Self::from_slice_with_index_mut(slice, BitIdx::MIN) + } + + pub(crate) fn from_slice_with_index_mut(slice: &mut [T], bit: BitIdx) -> Self { unsafe { - Self::new_unchecked(slice.as_mut_ptr().into_address(), BitIdx::MIN) + Self::new_unchecked(slice.as_mut_ptr().into_address(), bit) } } diff --git a/src/vec.rs b/src/vec.rs index ead0b436..80591265 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -120,13 +120,8 @@ where #[inline] pub fn from_bitslice(slice: &BitSlice) -> Self { let bitspan = slice.as_bitspan(); - - let mut vec = bitspan - .elements() - .pipe(Vec::with_capacity) - .pipe(ManuallyDrop::new); - vec.extend(slice.domain()); - + let vec = slice.domain().into_iter().collect::>(); + let mut vec = ManuallyDrop::new(vec); let bitspan = unsafe { BitSpan::new_unchecked( vec.as_mut_ptr().cast::().into_address(), @@ -241,11 +236,108 @@ where /// It is not practical to allocate a vector that will fail this conversion. #[inline] pub fn try_from_vec(vec: Vec) -> Result> { - let mut vec = ManuallyDrop::new(vec); - let capacity = vec.capacity(); + Self::try_from_partial_vec(vec, BitIdx::MIN, None) + } - BitPtr::from_mut_slice(vec.as_mut_slice()) - .span(vec.len() * bits_of::()) + /// Converts a regular vector in-place into a bit-vector covering parts + /// of the elements. + /// + /// The produced bit-vector spans `length` bits of the original vector + /// starting at `head` bit of the first element. If `length` is `None`, + /// spans bits starting at `head` bit of the first element until the end + /// of the original vector. + /// + /// ## Panics + /// + /// This panics if the source vector is too long to view as a bit-slice, + /// or if specified total length of the vector goes beyond provided + /// bytes. + /// + /// ## Examples + /// + /// ```rust + /// use bitvec::prelude::*; + /// use bitvec::index::BitIdx; + /// + /// let bv = BitVec::<_, Msb0>::from_partial_vec( + /// vec![0u8, 1, 0x80], + /// BitIdx::new(4).unwrap(), + /// Some(18), + /// ); + /// assert_eq!(bits![0, 0, 0, 0, + /// 0, 0, 0, 0, 0, 0, 0, 1, + /// 1, 0, 0, 0, 0, 0], bv); + /// ``` + #[inline] + pub fn from_partial_vec( + vec: Vec, + head: crate::index::BitIdx, + length: Option, + ) -> Self { + Self::try_from_partial_vec(vec, head, length) + .expect("vector was too long to be converted into a `BitVec`") + } + + /// Attempts to converts a regular vector in-place into a bit-vector + /// covering parts of the elements. + /// + /// This fairs if the source vector is too long to view as a bit-slice, + /// or if specified total length of the vector goes beyond provided + /// bytes. + /// + /// On success, the produced bit-vector spans `length` bits of the + /// original vector starting at `head` bit of the first element. If + /// `length` is `None`, spans bits starting at `head` bit of the first + /// element until the end of the original vector. + /// + /// ## Examples + /// + /// ```rust + /// use bitvec::prelude::*; + /// use bitvec::index::BitIdx; + /// + /// let bv = BitVec::<_, Msb0>::try_from_partial_vec( + /// vec![0u8, 1, 0x80], + /// BitIdx::new(4).unwrap(), + /// Some(18), + /// ).unwrap(); + /// assert_eq!(bits![0, 0, 0, 0, + /// 0, 0, 0, 0, 0, 0, 0, 1, + /// 1, 0, 0, 0, 0, 0], bv); + /// + /// let bv = BitVec::<_, Msb0>::try_from_partial_vec( + /// vec![0u8, 1, 0x80], + /// BitIdx::new(4).unwrap(), + /// Some(24), + /// ); + /// assert_eq!(None, bv.ok()); + /// ``` + #[inline] + pub fn try_from_partial_vec( + vec: Vec, + head: crate::index::BitIdx, + length: Option, + ) -> Result> { + let start = usize::from(head.into_inner()); + let length = if let Some(len) = length { + len.checked_add(start) + .map(crate::mem::elts::) + .filter(|elts| *elts <= vec.len()) + .map(|_| len) + } else { + vec.len() + .checked_mul(bits_of::()) + .and_then(|len| len.checked_sub(start)) + }; + let length = match length { + None => return Err(vec), + Some(length) => length, + }; + + let capacity = vec.capacity(); + let mut vec = ManuallyDrop::new(vec); + BitPtr::from_slice_with_index_mut(vec.as_mut_slice(), head) + .span(length) .map(|bitspan| Self { bitspan, capacity }) .map_err(|_| ManuallyDrop::into_inner(vec)) }