bitvec/boxed.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
#![cfg(feature = "alloc")]
#![doc = include_str!("../doc/boxed.md")]
use alloc::boxed::Box;
use core::{
mem::ManuallyDrop,
slice,
};
use tap::{
Pipe,
Tap,
};
use wyz::comu::Mut;
use crate::{
index::BitIdx,
mem,
order::{
BitOrder,
Lsb0,
},
ptr::{
BitPtr,
BitSpan,
},
slice::BitSlice,
store::BitStore,
vec::BitVec,
view::BitView,
};
mod api;
mod iter;
mod ops;
mod tests;
mod traits;
pub use self::iter::IntoIter;
#[repr(transparent)]
#[doc = include_str!("../doc/boxed/BitBox.md")]
pub struct BitBox<T = usize, O = Lsb0>
where
T: BitStore,
O: BitOrder,
{
/// Describes the region that the box owns.
bitspan: BitSpan<Mut, T, O>,
}
impl<T, O> BitBox<T, O>
where
T: BitStore,
O: BitOrder,
{
/// Copies a bit-slice region into a new bit-box allocation.
///
/// The referent memory is `memcpy`d into the heap, exactly preserving the
/// original bit-slice’s memory layout and contents. This allows the
/// function to run as fast as possible, but misaligned source bit-slices
/// may result in decreased performance or unexpected layout behavior during
/// use. You can use [`.force_align()`] to ensure that the referent
/// bit-slice is aligned in memory.
///
/// ## Notes
///
/// Bits in the allocation of the source bit-slice, but outside its own
/// description of that memory, have an **unspecified**, but initialized,
/// value. You may not rely on their contents in any way, and you *should*
/// call [`.force_align()`] and/or [`.fill_uninitialized()`] if you are
/// going to inspect the underlying memory of the new allocation.
///
/// ## Examples
///
/// ```rust
/// use bitvec::prelude::*;
///
/// let data = 0b0101_1011u8;
/// let bits = data.view_bits::<Msb0>();
/// let bb = BitBox::from_bitslice(&bits[2 ..]);
/// assert_eq!(bb, bits[2 ..]);
/// ```
///
/// [`.fill_uninitialized()`]: Self::fill_uninitialized
/// [`.force_align()`]: Self::force_align
#[inline]
pub fn from_bitslice(slice: &BitSlice<T, O>) -> Self {
BitVec::from_bitslice(slice).into_boxed_bitslice()
}
/// Converts a `Box<[T]>` into a `BitBox<T, O>`, in place.
///
/// This does not affect the referent buffer, and only transforms the
/// handle.
///
/// ## Panics
///
/// This panics if the provided `boxed` slice is too long to view as a
/// bit-slice region.
///
/// ## Examples
///
/// ```rust
/// use bitvec::prelude::*;
///
/// let boxed: Box<[u8]> = Box::new([0; 40]);
/// let addr = boxed.as_ptr();
/// let bb = BitBox::<u8>::from_boxed_slice(boxed);
/// assert_eq!(bb, bits![0; 320]);
/// assert_eq!(addr, bb.as_raw_slice().as_ptr());
/// ```
#[inline]
pub fn from_boxed_slice(boxed: Box<[T]>) -> Self {
Self::try_from_boxed_slice(boxed)
.expect("slice was too long to be converted into a `BitBox`")
}
/// Attempts to convert an ordinary boxed slice into a boxed bit-slice.
///
/// This does not perform a copy or reällocation; it only attempts to
/// transform the handle. Because `Box<[T]>` can be longer than `BitBox`es,
/// it may fail, and will return the original handle if it does.
///
/// It is unlikely that you have a single `Box<[_]>` that is too large to
/// convert into a bit-box. You can find the length restrictions as the
/// bit-slice associated constants [`MAX_BITS`] and [`MAX_ELTS`].
///
/// ## Examples
///
/// ```rust
/// use bitvec::prelude::*;
///
/// let boxed: Box<[u8]> = Box::new([0u8; 40]);
/// let addr = boxed.as_ptr();
/// let bb = BitBox::<u8>::try_from_boxed_slice(boxed).unwrap();
/// assert_eq!(bb, bits![0; 320]);
/// assert_eq!(addr, bb.as_raw_slice().as_ptr());
/// ```
///
/// [`MAX_BITS`]: crate::slice::BitSlice::MAX_BITS
/// [`MAX_ELTS`]: crate::slice::BitSlice::MAX_ELTS
#[inline]
pub fn try_from_boxed_slice(boxed: Box<[T]>) -> Result<Self, Box<[T]>> {
let mut boxed = ManuallyDrop::new(boxed);
BitPtr::from_mut_slice(boxed.as_mut())
.span(boxed.len() * mem::bits_of::<T::Mem>())
.map(|bitspan| Self { bitspan })
.map_err(|_| ManuallyDrop::into_inner(boxed))
}
/// Converts the bit-box back into an ordinary boxed element slice.
///
/// This does not touch the allocator or the buffer contents; it is purely a
/// handle transform.
///
/// ## Examples
///
/// ```rust
/// use bitvec::prelude::*;
///
/// let bb = bitbox![0; 5];
/// let addr = bb.as_raw_slice().as_ptr();
/// let boxed = bb.into_boxed_slice();
/// assert_eq!(boxed[..], [0][..]);
/// assert_eq!(addr, boxed.as_ptr());
/// ```
#[inline]
pub fn into_boxed_slice(self) -> Box<[T]> {
self.pipe(ManuallyDrop::new)
.as_raw_mut_slice()
.pipe(|slice| unsafe { Box::from_raw(slice) })
}
/// Converts the bit-box into a bit-vector.
///
/// This uses the Rust allocator API, and does not guarantee whether or not
/// a reällocation occurs internally.
///
/// The resulting bit-vector can be converted back into a bit-box via
/// [`BitBox::into_boxed_bitslice`][0].
///
/// ## Original
///
/// [`slice::into_vec`](https://doc.rust-lang.org/std/primitive.slice.html#method.into_vec)
///
/// ## API Differences
///
/// The original function is implemented in an `impl<T> [T]` block, despite
/// taking a `Box<[T]>` receiver. Since `BitBox` cannot be used as an
/// explicit receiver outside its own `impl` blocks, the method is relocated
/// here.
///
/// ## Examples
///
/// ```rust
/// use bitvec::prelude::*;
///
/// let bb = bitbox![0, 1, 0, 0, 1];
/// let bv = bb.into_bitvec();
///
/// assert_eq!(bv, bitvec![0, 1, 0, 0, 1]);
/// ```
///
/// [0]: crate::vec::BitVec::into_boxed_bitslice
#[inline]
pub fn into_bitvec(self) -> BitVec<T, O> {
let bitspan = self.bitspan;
/* This pipeline converts the underlying `Box<[T]>` into a `Vec<T>`,
* then converts that into a `BitVec`. This handles any changes that
* may occur in the allocator. Once done, the original head/span
* values need to be written into the `BitVec`, since the conversion
* from `Vec` always fully spans the live elements.
*/
self.pipe(ManuallyDrop::new)
.with_box(|b| unsafe { ManuallyDrop::take(b) })
.into_vec()
.pipe(BitVec::from_vec)
.tap_mut(|bv| unsafe {
// len first! Otherwise, the descriptor might briefly go out of
// bounds.
bv.set_len_unchecked(bitspan.len());
bv.set_head(bitspan.head());
})
}
/// Explicitly views the bit-box as a bit-slice.
#[inline]
pub fn as_bitslice(&self) -> &BitSlice<T, O> {
unsafe { self.bitspan.into_bitslice_ref() }
}
/// Explicitly views the bit-box as a mutable bit-slice.
#[inline]
pub fn as_mut_bitslice(&mut self) -> &mut BitSlice<T, O> {
unsafe { self.bitspan.into_bitslice_mut() }
}
/// Views the bit-box as a slice of its underlying memory elements.
///
/// Because bit-boxes uniquely own their buffer, they can safely view the
/// underlying buffer without dealing with contending neighbors.
#[inline]
pub fn as_raw_slice(&self) -> &[T] {
let (data, len) =
(self.bitspan.address().to_const(), self.bitspan.elements());
unsafe { slice::from_raw_parts(data, len) }
}
/// Views the bit-box as a mutable slice of its underlying memory elements.
///
/// Because bit-boxes uniquely own their buffer, they can safely view the
/// underlying buffer without dealing with contending neighbors.
#[inline]
pub fn as_raw_mut_slice(&mut self) -> &mut [T] {
let (data, len) =
(self.bitspan.address().to_mut(), self.bitspan.elements());
unsafe { slice::from_raw_parts_mut(data, len) }
}
/// Sets the unused bits outside the `BitBox` buffer to a fixed value.
///
/// This method modifies all bits that the allocated buffer owns but which
/// are outside the `self.as_bitslice()` view. `bitvec` guarantees that all
/// owned bits are initialized to *some* value, but does not guarantee
/// *which* value. This method can be used to make all such unused bits have
/// a known value after the call, so that viewing the underlying memory
/// directly has consistent results.
///
/// Note that the crate implementation guarantees that all bits owned by its
/// handles are stably initialized according to the language and compiler
/// rules! `bitvec` will never cause UB by using uninitialized memory.
///
/// ## Examples
///
/// ```rust
/// use bitvec::prelude::*;
///
/// let bits = 0b1011_0101u8.view_bits::<Msb0>();
/// let mut bb = BitBox::from_bitslice(&bits[2 .. 6]);
/// assert_eq!(bb.count_ones(), 3);
/// // Remember, the two bits on each edge are unspecified, and cannot be
/// // observed! They must be masked away for the test to be meaningful.
/// assert_eq!(bb.as_raw_slice()[0] & 0x3C, 0b00_1101_00u8);
///
/// bb.fill_uninitialized(false);
/// assert_eq!(bb.as_raw_slice(), &[0b00_1101_00u8]);
///
/// bb.fill_uninitialized(true);
/// assert_eq!(bb.as_raw_slice(), &[0b11_1101_11u8]);
/// ```
#[inline]
pub fn fill_uninitialized(&mut self, value: bool) {
let (_, head, bits) = self.bitspan.raw_parts();
let head = head.into_inner() as usize;
let tail = head + bits;
let all = self.as_raw_mut_slice().view_bits_mut::<O>();
unsafe {
all.get_unchecked_mut(.. head).fill(value);
all.get_unchecked_mut(tail ..).fill(value);
}
}
/// Ensures that the allocated buffer has no dead bits between the start of
/// the buffer and the start of the live bit-slice.
///
/// This is useful for ensuring a consistent memory layout in bit-boxes
/// created by cloning an arbitrary bit-slice into the heap. As bit-slices
/// can begin and end anywhere in memory, the [`::from_bitslice()`] function
/// does not attempt to normalize them and only does a fast element-wise
/// copy when creating the bit-box.
///
/// The value of dead bits that are in the allocation but not in the live
/// region are *initialized*, but do not have a *specified* value. After
/// calling this method, you should use [`.fill_uninitialized()`] to set the
/// excess bits in the buffer to a fixed value.
///
/// ## Examples
///
/// ```rust
/// use bitvec::prelude::*;
///
/// let bits = &0b10_1101_01u8.view_bits::<Msb0>()[2 .. 6];
/// let mut bb = BitBox::from_bitslice(bits);
/// // Remember, the two bits on each edge are unspecified, and cannot be
/// // observed! They must be masked away for the test to be meaningful.
/// assert_eq!(bb.as_raw_slice()[0] & 0x3C, 0b00_1101_00u8);
///
/// bb.force_align();
/// bb.fill_uninitialized(false);
/// assert_eq!(bb.as_raw_slice(), &[0b1101_0000u8]);
/// ```
///
/// [`::from_bitslice()`]: Self::from_bitslice
/// [`.fill_uninitialized()`]: Self::fill_uninitialized
#[inline]
pub fn force_align(&mut self) {
let head = self.bitspan.head();
if head == BitIdx::MIN {
return;
}
let head = head.into_inner() as usize;
let last = self.len() + head;
unsafe {
self.bitspan.set_head(BitIdx::MIN);
self.copy_within_unchecked(head .. last, 0);
}
}
/// Permits a function to modify the `Box` backing storage of a `BitBox`
/// handle.
///
/// This produces a temporary `Box` view of the bit-box’s buffer and allows
/// a function to have mutable access to it. After the callback returns, the
/// `Box` is written back into `self` and forgotten.
#[inline]
fn with_box<F, R>(&mut self, func: F) -> R
where F: FnOnce(&mut ManuallyDrop<Box<[T]>>) -> R {
self.as_raw_mut_slice()
.pipe(|raw| unsafe { Box::from_raw(raw) })
.pipe(ManuallyDrop::new)
.pipe_ref_mut(func)
}
}