Use a union to reduce the size of SmallVec [v2]#94
Conversation
|
☔ The latest upstream changes (presumably #97) made this pull request unmergeable. Please resolve the merge conflicts. |
|
I rebased on master now, the only change I kept was to add the return type to remove_no_inline (to prevent over optimization, specially for Vec). |
lib.rs
Outdated
| //! Note that `smallvec` can still be larger than `Vec` if the inline buffer is larger than two | ||
| //! machine words. | ||
| //! | ||
| //! To use this feature add `features = ["uuid"]` in the `smallvec` section of Cargo.toml. |
|
It'd be nice to get this moving. It may be interesting for rustc as well. |
|
@mbrubeck Do you have time to review these changes? |
mbrubeck
left a comment
There was a problem hiding this comment.
This is great, thanks! Some requests/suggestions below.
Cargo.toml
Outdated
|
|
||
| [dependencies] | ||
| unreachable = "1.0.0" | ||
| debug_unreachable = "0.1" |
There was a problem hiding this comment.
We may not want to use debug_unreachable, because it is unmaintained and doesn't work correctly in Rust > 1.0: reem/rust-debug-unreachable#6
We could just use unreachable all the time, or write our own debug_unreachable macro, or write a new debug_unreachable-like crate...
There was a problem hiding this comment.
Makes sense, I'll remove the dependency and add the equivalent macro.
| pub fn from_vec(mut vec: Vec<A::Item>) -> SmallVec<A> { | ||
| let (ptr, cap, len) = (vec.as_mut_ptr(), vec.capacity(), vec.len()); | ||
| mem::forget(vec); | ||
| if vec.capacity() <= A::size() { |
There was a problem hiding this comment.
The documentation says that from_vec does not copy the elements. I think we should keep the current behavior of keeping the items on the heap. Users who want to move them inline if possible can use shrink_to_fit or other methods.
There was a problem hiding this comment.
This is unfortunately not possible with the new design: there is no way of representing a heap-allocated buffer with a capacity less than A::size(). If self.capacity <= A::size() then the code assumes that the data is in the inline buffer.
There was a problem hiding this comment.
Oh, right. In that case the documentation should be updated.
| /// ``` | ||
| pub struct SmallVec<A: Array> { | ||
| len: usize, | ||
| capacity: usize, |
There was a problem hiding this comment.
Using capacity here is a little confusing to me, but I'm not sure what a better name would be. Maybe something like len_cap? Maybe capacity is okay, but there should be a comment here describing the semantics.
| } | ||
|
|
||
| #[inline] | ||
| fn triple(&self) -> (*const A::Item, usize, usize) { |
There was a problem hiding this comment.
Please add a comment to say what the return value means.
lib.rs
Outdated
| while len < *len_ptr { | ||
| let last_index = *len_ptr - 1; | ||
| *len_ptr = last_index; | ||
| ptr::read(ptr.offset(last_index as isize)); |
There was a problem hiding this comment.
This could use ptr::drop_in_place instead of ptr::read.
lib.rs
Outdated
| } else { | ||
| let ptr = self.as_ptr(); | ||
| for i in 0..self.len() { | ||
| ptr::read(ptr.offset(i as isize)); |
There was a problem hiding this comment.
This could use ptr::drop_in_place instead.
|
Great, thanks! I think this is ready but I just want to double-check all the unsafe code before merging it (and give a chance for others to do the same). |
|
@bors-servo r+ |
|
📌 Commit cfa1f0c has been approved by |
Use a union to reduce the size of SmallVec [v2] Building on top of #92 by @Amanieu I introduced `triple()` and `triple_mut()` which removed almost all of the runtime overhead. Performance is very comparable. ``` name master:: ns/iter union:: ns/iter diff ns/iter diff % speedup bench_extend 45 47 2 4.44% x 0.96 bench_extend_from_slice 45 43 -2 -4.44% x 1.05 bench_from_slice 45 44 -1 -2.22% x 1.02 bench_insert 615 622 7 1.14% x 0.99 bench_insert_from_slice 101 99 -2 -1.98% x 1.02 bench_insert_many 309 266 -43 -13.92% x 1.16 bench_macro_from_elem 41 37 -4 -9.76% x 1.11 bench_macro_from_list 40 42 2 5.00% x 0.95 bench_push 381 370 -11 -2.89% x 1.03 bench_pushpop 404 420 16 3.96% x 0.96 bench_remove 458 436 -22 -4.80% x 1.05 ``` <!-- 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/94) <!-- Reviewable:end -->
|
☀️ Test successful - status-travis |
Changes in this release: * Fix possible double-free in `insert_many` when passed an iterator that panics in `next` (servo#103) * Add a new `union` feature (disabled by default) that reduces the size of the SmallVec struct (servo#94) * Improve performance of `extend` and `from_elem` (servo#93) * Improve performance of `drop` (servo#100) * Update dev-dependency on `bincode` (servo#102) * Update to build without `std` on current Rust nightly (servo#104) * Additional benchmarks (servo#95, servo#97).
Changes in this release: * Fix possible double-free in `insert_many` when passed an iterator that panics in `next` (servo#103) * Add a new `union` feature (disabled by default) that reduces the size of the SmallVec struct (servo#94) * Improve performance of `extend` and `from_elem` (servo#93) * Improve performance of `drop` (servo#100) * Update dev-dependency on `bincode` (servo#102) * Update to build without `std` on current Rust nightly (servo#104) * Additional benchmarks (servo#95, servo#97).
Version 0.6.3 Changes in this release: * Fix possible double-free in `insert_many` when passed an iterator that panics in `next` (#103) * Add a new `union` feature (disabled by default) that reduces the size of the SmallVec struct (#94) * Improve performance of `extend` and `from_elem` (#93) * Improve performance of `drop` (#100) * Update to build without `std` feature on current Rust nightly (#104) * Additional benchmarks (#95, #97) * Update dev-dependency on `bincode` (#102) <!-- 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/105) <!-- Reviewable:end -->
This is what the standard Vec does; see rust-lang/rust#32012.
Building on top of #92 by @Amanieu
I introduced
triple()andtriple_mut()which removed almost all of the runtime overhead. Performance is very comparable.This change is