refactor: moving Splice into splice.rs
This commit is contained in:
parent
434e5d1422
commit
17593f258b
2 changed files with 138 additions and 128 deletions
|
@ -79,6 +79,11 @@ pub use self::drain_filter::DrainFilter;
|
||||||
|
|
||||||
mod drain_filter;
|
mod drain_filter;
|
||||||
|
|
||||||
|
#[stable(feature = "vec_splice", since = "1.21.0")]
|
||||||
|
pub use self::splice::Splice;
|
||||||
|
|
||||||
|
mod splice;
|
||||||
|
|
||||||
/// A contiguous growable array type, written `Vec<T>` but pronounced 'vector'.
|
/// A contiguous growable array type, written `Vec<T>` but pronounced 'vector'.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
@ -3462,131 +3467,3 @@ unsafe impl<T, A: Allocator> TrustedLen for Drain<'_, T, A> {}
|
||||||
|
|
||||||
#[stable(feature = "fused", since = "1.26.0")]
|
#[stable(feature = "fused", since = "1.26.0")]
|
||||||
impl<T, A: Allocator> FusedIterator for Drain<'_, T, A> {}
|
impl<T, A: Allocator> FusedIterator for Drain<'_, T, A> {}
|
||||||
|
|
||||||
/// A splicing iterator for `Vec`.
|
|
||||||
///
|
|
||||||
/// This struct is created by [`Vec::splice()`].
|
|
||||||
/// See its documentation for more.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// let mut v = vec![0, 1, 2];
|
|
||||||
/// let new = [7, 8];
|
|
||||||
/// let iter: std::vec::Splice<_> = v.splice(1.., new.iter().cloned());
|
|
||||||
/// ```
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[stable(feature = "vec_splice", since = "1.21.0")]
|
|
||||||
pub struct Splice<
|
|
||||||
'a,
|
|
||||||
I: Iterator + 'a,
|
|
||||||
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + 'a = Global,
|
|
||||||
> {
|
|
||||||
drain: Drain<'a, I::Item, A>,
|
|
||||||
replace_with: I,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[stable(feature = "vec_splice", since = "1.21.0")]
|
|
||||||
impl<I: Iterator, A: Allocator> Iterator for Splice<'_, I, A> {
|
|
||||||
type Item = I::Item;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
self.drain.next()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
||||||
self.drain.size_hint()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[stable(feature = "vec_splice", since = "1.21.0")]
|
|
||||||
impl<I: Iterator, A: Allocator> DoubleEndedIterator for Splice<'_, I, A> {
|
|
||||||
fn next_back(&mut self) -> Option<Self::Item> {
|
|
||||||
self.drain.next_back()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[stable(feature = "vec_splice", since = "1.21.0")]
|
|
||||||
impl<I: Iterator, A: Allocator> ExactSizeIterator for Splice<'_, I, A> {}
|
|
||||||
|
|
||||||
#[stable(feature = "vec_splice", since = "1.21.0")]
|
|
||||||
impl<I: Iterator, A: Allocator> Drop for Splice<'_, I, A> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
self.drain.by_ref().for_each(drop);
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
if self.drain.tail_len == 0 {
|
|
||||||
self.drain.vec.as_mut().extend(self.replace_with.by_ref());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// First fill the range left by drain().
|
|
||||||
if !self.drain.fill(&mut self.replace_with) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// There may be more elements. Use the lower bound as an estimate.
|
|
||||||
// FIXME: Is the upper bound a better guess? Or something else?
|
|
||||||
let (lower_bound, _upper_bound) = self.replace_with.size_hint();
|
|
||||||
if lower_bound > 0 {
|
|
||||||
self.drain.move_tail(lower_bound);
|
|
||||||
if !self.drain.fill(&mut self.replace_with) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collect any remaining elements.
|
|
||||||
// This is a zero-length vector which does not allocate if `lower_bound` was exact.
|
|
||||||
let mut collected = self.replace_with.by_ref().collect::<Vec<I::Item>>().into_iter();
|
|
||||||
// Now we have an exact count.
|
|
||||||
if collected.len() > 0 {
|
|
||||||
self.drain.move_tail(collected.len());
|
|
||||||
let filled = self.drain.fill(&mut collected);
|
|
||||||
debug_assert!(filled);
|
|
||||||
debug_assert_eq!(collected.len(), 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Let `Drain::drop` move the tail back if necessary and restore `vec.len`.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Private helper methods for `Splice::drop`
|
|
||||||
impl<T, A: Allocator> Drain<'_, T, A> {
|
|
||||||
/// The range from `self.vec.len` to `self.tail_start` contains elements
|
|
||||||
/// that have been moved out.
|
|
||||||
/// Fill that range as much as possible with new elements from the `replace_with` iterator.
|
|
||||||
/// Returns `true` if we filled the entire range. (`replace_with.next()` didn’t return `None`.)
|
|
||||||
unsafe fn fill<I: Iterator<Item = T>>(&mut self, replace_with: &mut I) -> bool {
|
|
||||||
let vec = unsafe { self.vec.as_mut() };
|
|
||||||
let range_start = vec.len;
|
|
||||||
let range_end = self.tail_start;
|
|
||||||
let range_slice = unsafe {
|
|
||||||
slice::from_raw_parts_mut(vec.as_mut_ptr().add(range_start), range_end - range_start)
|
|
||||||
};
|
|
||||||
|
|
||||||
for place in range_slice {
|
|
||||||
if let Some(new_item) = replace_with.next() {
|
|
||||||
unsafe { ptr::write(place, new_item) };
|
|
||||||
vec.len += 1;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Makes room for inserting more elements before the tail.
|
|
||||||
unsafe fn move_tail(&mut self, additional: usize) {
|
|
||||||
let vec = unsafe { self.vec.as_mut() };
|
|
||||||
let len = self.tail_start + self.tail_len;
|
|
||||||
vec.buf.reserve(len, additional);
|
|
||||||
|
|
||||||
let new_tail_start = self.tail_start + additional;
|
|
||||||
unsafe {
|
|
||||||
let src = vec.as_ptr().add(self.tail_start);
|
|
||||||
let dst = vec.as_mut_ptr().add(new_tail_start);
|
|
||||||
ptr::copy(src, dst, self.tail_len);
|
|
||||||
}
|
|
||||||
self.tail_start = new_tail_start;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
133
library/alloc/src/vec/splice.rs
Normal file
133
library/alloc/src/vec/splice.rs
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
use crate::alloc::{Allocator, Global};
|
||||||
|
use core::ptr::{self};
|
||||||
|
use core::slice::{self};
|
||||||
|
|
||||||
|
use super::{Vec, Drain};
|
||||||
|
|
||||||
|
/// A splicing iterator for `Vec`.
|
||||||
|
///
|
||||||
|
/// This struct is created by [`Vec::splice()`].
|
||||||
|
/// See its documentation for more.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let mut v = vec![0, 1, 2];
|
||||||
|
/// let new = [7, 8];
|
||||||
|
/// let iter: std::vec::Splice<_> = v.splice(1.., new.iter().cloned());
|
||||||
|
/// ```
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[stable(feature = "vec_splice", since = "1.21.0")]
|
||||||
|
pub struct Splice<
|
||||||
|
'a,
|
||||||
|
I: Iterator + 'a,
|
||||||
|
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + 'a = Global,
|
||||||
|
> {
|
||||||
|
pub(super) drain: Drain<'a, I::Item, A>,
|
||||||
|
pub(super) replace_with: I,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[stable(feature = "vec_splice", since = "1.21.0")]
|
||||||
|
impl<I: Iterator, A: Allocator> Iterator for Splice<'_, I, A> {
|
||||||
|
type Item = I::Item;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
self.drain.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
self.drain.size_hint()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[stable(feature = "vec_splice", since = "1.21.0")]
|
||||||
|
impl<I: Iterator, A: Allocator> DoubleEndedIterator for Splice<'_, I, A> {
|
||||||
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
|
self.drain.next_back()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[stable(feature = "vec_splice", since = "1.21.0")]
|
||||||
|
impl<I: Iterator, A: Allocator> ExactSizeIterator for Splice<'_, I, A> {}
|
||||||
|
|
||||||
|
#[stable(feature = "vec_splice", since = "1.21.0")]
|
||||||
|
impl<I: Iterator, A: Allocator> Drop for Splice<'_, I, A> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.drain.by_ref().for_each(drop);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
if self.drain.tail_len == 0 {
|
||||||
|
self.drain.vec.as_mut().extend(self.replace_with.by_ref());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// First fill the range left by drain().
|
||||||
|
if !self.drain.fill(&mut self.replace_with) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// There may be more elements. Use the lower bound as an estimate.
|
||||||
|
// FIXME: Is the upper bound a better guess? Or something else?
|
||||||
|
let (lower_bound, _upper_bound) = self.replace_with.size_hint();
|
||||||
|
if lower_bound > 0 {
|
||||||
|
self.drain.move_tail(lower_bound);
|
||||||
|
if !self.drain.fill(&mut self.replace_with) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect any remaining elements.
|
||||||
|
// This is a zero-length vector which does not allocate if `lower_bound` was exact.
|
||||||
|
let mut collected = self.replace_with.by_ref().collect::<Vec<I::Item>>().into_iter();
|
||||||
|
// Now we have an exact count.
|
||||||
|
if collected.len() > 0 {
|
||||||
|
self.drain.move_tail(collected.len());
|
||||||
|
let filled = self.drain.fill(&mut collected);
|
||||||
|
debug_assert!(filled);
|
||||||
|
debug_assert_eq!(collected.len(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Let `Drain::drop` move the tail back if necessary and restore `vec.len`.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Private helper methods for `Splice::drop`
|
||||||
|
impl<T, A: Allocator> Drain<'_, T, A> {
|
||||||
|
/// The range from `self.vec.len` to `self.tail_start` contains elements
|
||||||
|
/// that have been moved out.
|
||||||
|
/// Fill that range as much as possible with new elements from the `replace_with` iterator.
|
||||||
|
/// Returns `true` if we filled the entire range. (`replace_with.next()` didn’t return `None`.)
|
||||||
|
unsafe fn fill<I: Iterator<Item = T>>(&mut self, replace_with: &mut I) -> bool {
|
||||||
|
let vec = unsafe { self.vec.as_mut() };
|
||||||
|
let range_start = vec.len;
|
||||||
|
let range_end = self.tail_start;
|
||||||
|
let range_slice = unsafe {
|
||||||
|
slice::from_raw_parts_mut(vec.as_mut_ptr().add(range_start), range_end - range_start)
|
||||||
|
};
|
||||||
|
|
||||||
|
for place in range_slice {
|
||||||
|
if let Some(new_item) = replace_with.next() {
|
||||||
|
unsafe { ptr::write(place, new_item) };
|
||||||
|
vec.len += 1;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Makes room for inserting more elements before the tail.
|
||||||
|
unsafe fn move_tail(&mut self, additional: usize) {
|
||||||
|
let vec = unsafe { self.vec.as_mut() };
|
||||||
|
let len = self.tail_start + self.tail_len;
|
||||||
|
vec.buf.reserve(len, additional);
|
||||||
|
|
||||||
|
let new_tail_start = self.tail_start + additional;
|
||||||
|
unsafe {
|
||||||
|
let src = vec.as_ptr().add(self.tail_start);
|
||||||
|
let dst = vec.as_mut_ptr().add(new_tail_start);
|
||||||
|
ptr::copy(src, dst, self.tail_len);
|
||||||
|
}
|
||||||
|
self.tail_start = new_tail_start;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue