Skip to content
Merged
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
72 changes: 72 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,18 @@ fn buffer_len(cap: usize) -> usize {
(cap + bits_per_storage() - 1) / bits_per_storage()
}

/// A typed representation of a `SmallBitVec`'s internal storage.
///
/// The layout of the data inside both enum variants is a private implementation detail.
pub enum InternalStorage {
/// The internal representation of a `SmallBitVec` that has not spilled to a
/// heap allocation.
Inline(usize),

/// The contents of the heap allocation of a spilled `SmallBitVec`.
Spilled(Box<[usize]>),
}

impl SmallBitVec {
/// Create an empty vector.
#[inline]
Expand Down Expand Up @@ -615,6 +627,66 @@ impl SmallBitVec {
}
}

/// Converts this `SmallBitVec` into its internal representation.
///
/// The layout of the data inside both enum variants is a private implementation detail.
#[inline]
pub fn into_storage(self) -> InternalStorage {
if self.is_heap() {
let alloc_len = header_len() + self.header().buffer_len;
let ptr = self.header_raw() as *mut Storage;
let slice = unsafe { Box::from_raw(slice::from_raw_parts_mut(ptr, alloc_len)) };
forget(self);
InternalStorage::Spilled(slice)
} else {
InternalStorage::Inline(self.data)
}
}

/// Creates a `SmallBitVec` directly from the internal storage of another
/// `SmallBitVec`.
///
/// # Safety
///
/// This is highly unsafe. `storage` needs to have been previously generated
/// via `SmallBitVec::into_storage` (at least, it's highly likely to be
/// incorrect if it wasn't.) Violating this may cause problems like corrupting the
/// allocator's internal data structures.
///
/// # Examples
///
/// ```
/// # use smallbitvec::{InternalStorage, SmallBitVec};
///
/// fn main() {
/// let v = SmallBitVec::from_elem(200, false);
///
/// // Get the internal representation of the SmallBitVec.
/// // unless we transfer its ownership somewhere else.
/// let storage = v.into_storage();
///
/// /// Make a copy of the SmallBitVec's data.
/// let cloned_storage = match storage {
/// InternalStorage::Spilled(vs) => InternalStorage::Spilled(vs.clone()),
/// inline => inline,
/// };
///
/// /// Create a new SmallBitVec from the coped storage.
/// let v = unsafe { SmallBitVec::from_storage(cloned_storage) };
/// }
/// ```
pub unsafe fn from_storage(storage: InternalStorage) -> SmallBitVec {
match storage {
InternalStorage::Inline(data) => SmallBitVec { data },
InternalStorage::Spilled(vs) => {
let ptr = Box::into_raw(vs);
SmallBitVec {
data: (ptr as *mut usize as usize) | HEAP_FLAG,
}
}
}
}

/// If the rightmost bit is set, then we treat it as inline storage.
#[inline]
fn is_inline(&self) -> bool {
Expand Down