Skip to content

Commit 353c8eb

Browse files
committed
shared_from_iter/Rc: Use specialization to elide allocation.
1 parent bf8f6c3 commit 353c8eb

File tree

2 files changed

+168
-39
lines changed

2 files changed

+168
-39
lines changed

src/liballoc/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
#![feature(try_reserve)]
103103
#![feature(unboxed_closures)]
104104
#![feature(unicode_internals)]
105+
#![feature(untagged_unions)]
105106
#![feature(unsize)]
106107
#![feature(unsized_locals)]
107108
#![feature(allocator_internals)]

src/liballoc/rc.rs

Lines changed: 167 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -238,12 +238,13 @@ use core::cmp::Ordering;
238238
use core::fmt;
239239
use core::hash::{Hash, Hasher};
240240
use core::intrinsics::abort;
241+
use core::iter;
241242
use core::marker::{self, Unpin, Unsize, PhantomData};
242243
use core::mem::{self, align_of, align_of_val, forget, size_of_val};
243244
use core::ops::{Deref, Receiver, CoerceUnsized, DispatchFromDyn};
244245
use core::pin::Pin;
245246
use core::ptr::{self, NonNull};
246-
use core::slice::from_raw_parts_mut;
247+
use core::slice::{self, from_raw_parts_mut};
247248
use core::convert::From;
248249
use core::usize;
249250

@@ -698,21 +699,29 @@ impl Rc<dyn Any> {
698699
}
699700

700701
impl<T: ?Sized> Rc<T> {
701-
// Allocates an `RcBox<T>` with sufficient space for an unsized value
702-
unsafe fn allocate_for_ptr(ptr: *const T) -> *mut RcBox<T> {
703-
// Calculate layout using the given value.
702+
// Allocates an `RcBox<T>` with sufficient space for
703+
// an unsized value where the value has the layout provided.
704+
//
705+
// The function `mem_to_rcbox` is called with the data pointer
706+
// and must return back a (potentially fat)-pointer for the `RcBox<T>`.
707+
unsafe fn allocate_for_unsized(
708+
value_layout: Layout,
709+
mem_to_rcbox: impl FnOnce(*mut u8) -> *mut RcBox<T>
710+
) -> *mut RcBox<T> {
711+
// Calculate layout using the given value layout.
704712
// Previously, layout was calculated on the expression
705713
// `&*(ptr as *const RcBox<T>)`, but this created a misaligned
706714
// reference (see #54908).
707715
let layout = Layout::new::<RcBox<()>>()
708-
.extend(Layout::for_value(&*ptr)).unwrap().0
716+
.extend(value_layout).unwrap().0
709717
.pad_to_align().unwrap();
710718

719+
// Allocate for the layout.
711720
let mem = Global.alloc(layout)
712721
.unwrap_or_else(|_| handle_alloc_error(layout));
713722

714723
// Initialize the RcBox
715-
let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut RcBox<T>;
724+
let inner = mem_to_rcbox(mem.as_ptr());
716725
debug_assert_eq!(Layout::for_value(&*inner), layout);
717726

718727
ptr::write(&mut (*inner).strong, Cell::new(1));
@@ -721,6 +730,15 @@ impl<T: ?Sized> Rc<T> {
721730
inner
722731
}
723732

733+
// Allocates an `RcBox<T>` with sufficient space for an unsized value
734+
unsafe fn allocate_for_ptr(ptr: *const T) -> *mut RcBox<T> {
735+
// Allocate for the `RcBox<T>` using the given value.
736+
Self::allocate_for_unsized(
737+
Layout::for_value(&*ptr),
738+
|mem| set_data_ptr(ptr as *mut T, mem) as *mut RcBox<T>,
739+
)
740+
}
741+
724742
fn from_box(v: Box<T>) -> Rc<T> {
725743
unsafe {
726744
let box_unique = Box::into_unique(v);
@@ -743,6 +761,32 @@ impl<T: ?Sized> Rc<T> {
743761
}
744762
}
745763

764+
impl<T> Rc<[T]> {
765+
// Allocates an `RcBox<[T]>` with the given length.
766+
unsafe fn allocate_for_slice(len: usize) -> *mut RcBox<[T]> {
767+
// FIXME(#60667): Deduplicate.
768+
fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
769+
#[repr(C)]
770+
union Repr<T> {
771+
rust_mut: *mut [T],
772+
raw: FatPtr<T>,
773+
}
774+
775+
#[repr(C)]
776+
struct FatPtr<T> {
777+
data: *const T,
778+
len: usize,
779+
}
780+
unsafe { Repr { raw: FatPtr { data, len } }.rust_mut }
781+
}
782+
783+
Self::allocate_for_unsized(
784+
Layout::array::<T>(len).unwrap(),
785+
|mem| slice_from_raw_parts_mut(mem as *mut T, len) as *mut RcBox<[T]>,
786+
)
787+
}
788+
}
789+
746790
// Sets the data pointer of a `?Sized` raw pointer.
747791
//
748792
// For a slice/trait object, this sets the `data` field and leaves the rest
@@ -757,8 +801,7 @@ impl<T> Rc<[T]> {
757801
//
758802
// Unsafe because the caller must either take ownership or bind `T: Copy`
759803
unsafe fn copy_from_slice(v: &[T]) -> Rc<[T]> {
760-
let v_ptr = v as *const [T];
761-
let ptr = Self::allocate_for_ptr(v_ptr);
804+
let ptr = Self::allocate_for_slice(v.len());
762805

763806
ptr::copy_nonoverlapping(
764807
v.as_ptr(),
@@ -767,15 +810,11 @@ impl<T> Rc<[T]> {
767810

768811
Self::from_ptr(ptr)
769812
}
770-
}
771813

772-
trait RcFromSlice<T> {
773-
fn from_slice(slice: &[T]) -> Self;
774-
}
775-
776-
impl<T: Clone> RcFromSlice<T> for Rc<[T]> {
777-
#[inline]
778-
default fn from_slice(v: &[T]) -> Self {
814+
/// Constructs an `Rc<[T]>` from an iterator known to be of a certain size.
815+
///
816+
/// Behavior is undefined should the size be wrong.
817+
unsafe fn from_iter_exact(iter: impl iter::Iterator<Item = T>, len: usize) -> Rc<[T]> {
779818
// Panic guard while cloning T elements.
780819
// In the event of a panic, elements that have been written
781820
// into the new RcBox will be dropped, then the memory freed.
@@ -797,32 +836,42 @@ impl<T: Clone> RcFromSlice<T> for Rc<[T]> {
797836
}
798837
}
799838

800-
unsafe {
801-
let v_ptr = v as *const [T];
802-
let ptr = Self::allocate_for_ptr(v_ptr);
839+
let ptr = Self::allocate_for_slice(len);
803840

804-
let mem = ptr as *mut _ as *mut u8;
805-
let layout = Layout::for_value(&*ptr);
841+
let mem = ptr as *mut _ as *mut u8;
842+
let layout = Layout::for_value(&*ptr);
806843

807-
// Pointer to first element
808-
let elems = &mut (*ptr).value as *mut [T] as *mut T;
844+
// Pointer to first element
845+
let elems = &mut (*ptr).value as *mut [T] as *mut T;
809846

810-
let mut guard = Guard {
811-
mem: NonNull::new_unchecked(mem),
812-
elems: elems,
813-
layout: layout,
814-
n_elems: 0,
815-
};
847+
let mut guard = Guard {
848+
mem: NonNull::new_unchecked(mem),
849+
elems,
850+
layout,
851+
n_elems: 0,
852+
};
816853

817-
for (i, item) in v.iter().enumerate() {
818-
ptr::write(elems.add(i), item.clone());
819-
guard.n_elems += 1;
820-
}
854+
for (i, item) in iter.enumerate() {
855+
ptr::write(elems.add(i), item);
856+
guard.n_elems += 1;
857+
}
821858

822-
// All clear. Forget the guard so it doesn't free the new RcBox.
823-
forget(guard);
859+
// All clear. Forget the guard so it doesn't free the new RcBox.
860+
forget(guard);
824861

825-
Self::from_ptr(ptr)
862+
Self::from_ptr(ptr)
863+
}
864+
}
865+
866+
trait RcFromSlice<T> {
867+
fn from_slice(slice: &[T]) -> Self;
868+
}
869+
870+
impl<T: Clone> RcFromSlice<T> for Rc<[T]> {
871+
#[inline]
872+
default fn from_slice(v: &[T]) -> Self {
873+
unsafe {
874+
Self::from_iter_exact(v.iter().cloned(), v.len())
826875
}
827876
}
828877
}
@@ -1221,9 +1270,88 @@ impl<T> From<Vec<T>> for Rc<[T]> {
12211270
}
12221271

12231272
#[stable(feature = "shared_from_iter", since = "1.37.0")]
1224-
impl<T> core::iter::FromIterator<T> for Rc<[T]> {
1225-
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
1226-
iter.into_iter().collect::<Vec<T>>().into()
1273+
impl<T> iter::FromIterator<T> for Rc<[T]> {
1274+
/// Takes each element in the `Iterator` and collects it into an `Rc<[T]>`.
1275+
///
1276+
/// # Performance characteristics
1277+
///
1278+
/// ## The general case
1279+
///
1280+
/// In the general case, collecting into `Rc<[T]>` is done by first
1281+
/// collecting into a `Vec<T>`. That is, when writing the following:
1282+
///
1283+
/// ```rust
1284+
/// # use std::rc::Rc;
1285+
/// let evens: Rc<[u8]> = (0..10).filter(|&x| x % 2 == 0).collect();
1286+
/// # assert_eq!(&*evens, &[0, 2, 4, 6, 8]);
1287+
/// ```
1288+
///
1289+
/// this behaves as if we wrote:
1290+
///
1291+
/// ```rust
1292+
/// # use std::rc::Rc;
1293+
/// let evens: Rc<[u8]> = (0..10).filter(|&x| x % 2 == 0)
1294+
/// .collect::<Vec<_>>() // The first set of allocations happens here.
1295+
/// .into(); // A second allocation for `Rc<[T]>` happens here.
1296+
/// # assert_eq!(&*evens, &[0, 2, 4, 6, 8]);
1297+
/// ```
1298+
///
1299+
/// This will allocate as many times as needed for constructing the `Vec<T>`
1300+
/// and then it will allocate once for turning the `Vec<T>` into the `Rc<[T]>`.
1301+
///
1302+
/// ## Iterators of known length
1303+
///
1304+
/// When your `Iterator` implements `TrustedLen` and is of an exact size,
1305+
/// a single allocation will be made for the `Rc<[T]>`. For example:
1306+
///
1307+
/// ```rust
1308+
/// # use std::rc::Rc;
1309+
/// let evens: Rc<[u8]> = (0..10).collect(); // Just a single allocation happens here.
1310+
/// # assert_eq!(&*evens, &*(0..10).collect::<Vec<_>>());
1311+
/// ```
1312+
fn from_iter<I: iter::IntoIterator<Item = T>>(iter: I) -> Self {
1313+
RcFromIter::from_iter(iter.into_iter())
1314+
}
1315+
}
1316+
1317+
/// Specialization trait used for collecting into `Rc<[T]>`.
1318+
trait RcFromIter<T, I> {
1319+
fn from_iter(iter: I) -> Self;
1320+
}
1321+
1322+
impl<T, I: Iterator<Item = T>> RcFromIter<T, I> for Rc<[T]> {
1323+
default fn from_iter(iter: I) -> Self {
1324+
iter.collect::<Vec<T>>().into()
1325+
}
1326+
}
1327+
1328+
impl<T, I: iter::TrustedLen<Item = T>> RcFromIter<T, I> for Rc<[T]> {
1329+
default fn from_iter(iter: I) -> Self {
1330+
// This is the case for a `TrustedLen` iterator.
1331+
let (low, high) = iter.size_hint();
1332+
if let Some(high) = high {
1333+
debug_assert_eq!(
1334+
low, high,
1335+
"TrustedLen iterator's size hint is not exact: {:?}",
1336+
(low, high)
1337+
);
1338+
1339+
unsafe {
1340+
// SAFETY: We need to ensure that the iterator has an exact length and we have.
1341+
Rc::from_iter_exact(iter, low)
1342+
}
1343+
} else {
1344+
// Fall back to normal implementation.
1345+
iter.collect::<Vec<T>>().into()
1346+
}
1347+
}
1348+
}
1349+
1350+
impl<'a, T: 'a + Clone> RcFromIter<&'a T, slice::Iter<'a, T>> for Rc<[T]> {
1351+
fn from_iter(iter: slice::Iter<'a, T>) -> Self {
1352+
// Delegate to `impl<T: Clone> From<&[T]> for Rc<[T]>`
1353+
// which will use `ptr::copy_nonoverlapping`.
1354+
iter.as_slice().into()
12271355
}
12281356
}
12291357

0 commit comments

Comments
 (0)