Skip to content

Commit 5f80461

Browse files
author
bors-servo
authored
Auto merge of #130 - heycam:from-raw-parts, r=mbrubeck
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 -->
2 parents 467ccd7 + 4046724 commit 5f80461

File tree

1 file changed

+80
-0
lines changed

1 file changed

+80
-0
lines changed

lib.rs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -940,6 +940,86 @@ impl<A: Array> SmallVec<A> {
940940
{
941941
self.dedup_by(|a, b| key(a) == key(b));
942942
}
943+
944+
/// Creates a `SmallVec` directly from the raw components of another
945+
/// `SmallVec`.
946+
///
947+
/// # Safety
948+
///
949+
/// This is highly unsafe, due to the number of invariants that aren't
950+
/// checked:
951+
///
952+
/// * `ptr` needs to have been previously allocated via `SmallVec` for its
953+
/// spilled storage (at least, it's highly likely to be incorrect if it
954+
/// wasn't).
955+
/// * `ptr`'s `A::Item` type needs to be the same size and alignment that
956+
/// it was allocated with
957+
/// * `length` needs to be less than or equal to `capacity`.
958+
/// * `capacity` needs to be the capacity that the pointer was allocated
959+
/// with.
960+
///
961+
/// Violating these may cause problems like corrupting the allocator's
962+
/// internal data structures.
963+
///
964+
/// Additionally, `capacity` must be greater than the amount of inline
965+
/// storage `A` has; that is, the new `SmallVec` must need to spill over
966+
/// into heap allocated storage. This condition is asserted against.
967+
///
968+
/// The ownership of `ptr` is effectively transferred to the
969+
/// `SmallVec` which may then deallocate, reallocate or change the
970+
/// contents of memory pointed to by the pointer at will. Ensure
971+
/// that nothing else uses the pointer after calling this
972+
/// function.
973+
///
974+
/// # Examples
975+
///
976+
/// ```
977+
/// # #[macro_use] extern crate smallvec;
978+
/// # use smallvec::SmallVec;
979+
/// use std::mem;
980+
/// use std::ptr;
981+
///
982+
/// fn main() {
983+
/// let mut v: SmallVec<[_; 1]> = smallvec![1, 2, 3];
984+
///
985+
/// // Pull out the important parts of `v`.
986+
/// let p = v.as_mut_ptr();
987+
/// let len = v.len();
988+
/// let cap = v.capacity();
989+
/// let spilled = v.spilled();
990+
///
991+
/// unsafe {
992+
/// // Forget all about `v`. The heap allocation that stored the
993+
/// // three values won't be deallocated.
994+
/// mem::forget(v);
995+
///
996+
/// // Overwrite memory with [4, 5, 6].
997+
/// //
998+
/// // This is only safe if `spilled` is true! Otherwise, we are
999+
/// // writing into the old `SmallVec`'s inline storage on the
1000+
/// // stack.
1001+
/// assert!(spilled);
1002+
/// for i in 0..len as isize {
1003+
/// ptr::write(p.offset(i), 4 + i);
1004+
/// }
1005+
///
1006+
/// // Put everything back together into a SmallVec with a different
1007+
/// // amount of inline storage, but which is still less than `cap`.
1008+
/// let rebuilt = SmallVec::<[_; 2]>::from_raw_parts(p, len, cap);
1009+
/// assert_eq!(&*rebuilt, &[4, 5, 6]);
1010+
/// }
1011+
/// }
1012+
pub unsafe fn from_raw_parts(
1013+
ptr: *mut A::Item,
1014+
length: usize,
1015+
capacity: usize,
1016+
) -> SmallVec<A> {
1017+
assert!(capacity > A::size());
1018+
SmallVec {
1019+
capacity,
1020+
data: SmallVecData::from_heap(ptr, length),
1021+
}
1022+
}
9431023
}
9441024

9451025
impl<A: Array> SmallVec<A> where A::Item: Copy {

0 commit comments

Comments
 (0)