Skip to content

Commit

Permalink
Auto merge of #130 - heycam:from-raw-parts, r=mbrubeck
Browse files Browse the repository at this point in the history
Add from_raw_parts.

I have a need to create a `SmallVec` using a heap allocation that I control.  Something that works just like `Vec::from_raw_parts` fits the bill.  The PR here adds a similar method, with the important difference that it panics if asked to conjure up a `SmallVec` that would use its inline storage rather than spilled, heap storage.

This is a dependency of my work in https://bugzilla.mozilla.org/show_bug.cgi?id=1474793.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/rust-smallvec/130)
<!-- Reviewable:end -->
  • Loading branch information
bors-servo committed Nov 13, 2018
2 parents 467ccd7 + 4046724 commit 5f80461
Showing 1 changed file with 80 additions and 0 deletions.
80 changes: 80 additions & 0 deletions lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -940,6 +940,86 @@ impl<A: Array> SmallVec<A> {
{
self.dedup_by(|a, b| key(a) == key(b));
}

/// Creates a `SmallVec` directly from the raw components of another
/// `SmallVec`.
///
/// # Safety
///
/// This is highly unsafe, due to the number of invariants that aren't
/// checked:
///
/// * `ptr` needs to have been previously allocated via `SmallVec` for its
/// spilled storage (at least, it's highly likely to be incorrect if it
/// wasn't).
/// * `ptr`'s `A::Item` type needs to be the same size and alignment that
/// it was allocated with
/// * `length` needs to be less than or equal to `capacity`.
/// * `capacity` needs to be the capacity that the pointer was allocated
/// with.
///
/// Violating these may cause problems like corrupting the allocator's
/// internal data structures.
///
/// Additionally, `capacity` must be greater than the amount of inline
/// storage `A` has; that is, the new `SmallVec` must need to spill over
/// into heap allocated storage. This condition is asserted against.
///
/// The ownership of `ptr` is effectively transferred to the
/// `SmallVec` which may then deallocate, reallocate or change the
/// contents of memory pointed to by the pointer at will. Ensure
/// that nothing else uses the pointer after calling this
/// function.
///
/// # Examples
///
/// ```
/// # #[macro_use] extern crate smallvec;
/// # use smallvec::SmallVec;
/// use std::mem;
/// use std::ptr;
///
/// fn main() {
/// let mut v: SmallVec<[_; 1]> = smallvec![1, 2, 3];
///
/// // Pull out the important parts of `v`.
/// let p = v.as_mut_ptr();
/// let len = v.len();
/// let cap = v.capacity();
/// let spilled = v.spilled();
///
/// unsafe {
/// // Forget all about `v`. The heap allocation that stored the
/// // three values won't be deallocated.
/// mem::forget(v);
///
/// // Overwrite memory with [4, 5, 6].
/// //
/// // This is only safe if `spilled` is true! Otherwise, we are
/// // writing into the old `SmallVec`'s inline storage on the
/// // stack.
/// assert!(spilled);
/// for i in 0..len as isize {
/// ptr::write(p.offset(i), 4 + i);
/// }
///
/// // Put everything back together into a SmallVec with a different
/// // amount of inline storage, but which is still less than `cap`.
/// let rebuilt = SmallVec::<[_; 2]>::from_raw_parts(p, len, cap);
/// assert_eq!(&*rebuilt, &[4, 5, 6]);
/// }
/// }
pub unsafe fn from_raw_parts(
ptr: *mut A::Item,
length: usize,
capacity: usize,
) -> SmallVec<A> {
assert!(capacity > A::size());
SmallVec {
capacity,
data: SmallVecData::from_heap(ptr, length),
}
}
}

impl<A: Array> SmallVec<A> where A::Item: Copy {
Expand Down

0 comments on commit 5f80461

Please sign in to comment.