Skip to content

Commit e9d8e90

Browse files
Itertools::tail: return VecDeque rather than Vec
`rotate_left` is more efficient on `VecDeque` than on a slice. `VecDeque::from(vec)` is O(1) on recent rust. Co-Authored-By: scottmcm <[email protected]>
1 parent cd6f902 commit e9d8e90

File tree

1 file changed

+12
-5
lines changed

1 file changed

+12
-5
lines changed

src/lib.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ extern crate core as std;
5555
extern crate alloc;
5656

5757
#[cfg(feature = "use_alloc")]
58-
use alloc::{string::String, vec::Vec};
58+
use alloc::{collections::VecDeque, string::String, vec::Vec};
5959

6060
pub use either::Either;
6161

@@ -72,6 +72,8 @@ use std::fmt::Write;
7272
use std::hash::Hash;
7373
use std::iter::{once, IntoIterator};
7474
#[cfg(feature = "use_alloc")]
75+
type VecDequeIntoIter<T> = alloc::collections::vec_deque::IntoIter<T>;
76+
#[cfg(feature = "use_alloc")]
7577
type VecIntoIter<T> = alloc::vec::IntoIter<T>;
7678
use std::iter::FromIterator;
7779

@@ -3136,8 +3138,10 @@ pub trait Itertools: Iterator {
31363138
/// Consumes the iterator and return an iterator of the last `n` elements.
31373139
///
31383140
/// It allocates up to `n` elements.
3139-
/// The iterator, if directly collected to a `Vec`, is converted
3141+
/// The iterator, if directly collected to a `VecDeque`, is converted
31403142
/// without any extra copying or allocation cost.
3143+
/// If directly collected to a `Vec`, it may need some data movement
3144+
/// but no re-allocation.
31413145
///
31423146
/// ```
31433147
/// use itertools::{assert_equal, Itertools};
@@ -3155,20 +3159,22 @@ pub trait Itertools: Iterator {
31553159
/// `.rev().take(n).rev()` to have a similar result (lazy and non-allocating)
31563160
/// without consuming the entire iterator.
31573161
#[cfg(feature = "use_alloc")]
3158-
fn tail(self, n: usize) -> VecIntoIter<Self::Item>
3162+
fn tail(self, n: usize) -> VecDequeIntoIter<Self::Item>
31593163
where
31603164
Self: Sized,
31613165
{
31623166
match n {
31633167
0 => {
31643168
self.last();
3165-
Vec::new()
3169+
VecDeque::new()
31663170
}
31673171
1 => self.last().into_iter().collect(),
31683172
_ => {
31693173
// Skip the starting part of the iterator if possible.
31703174
let (low, _) = self.size_hint();
31713175
let mut iter = self.fuse().skip(low.saturating_sub(n));
3176+
// TODO: If VecDeque has a more efficient method than
3177+
// `.pop_front();.push_back(val)` in the future then maybe revisit this.
31723178
let mut data: Vec<_> = iter.by_ref().take(n).collect();
31733179
// Update `data` cyclically.
31743180
let idx = iter.fold(0, |i, val| {
@@ -3179,7 +3185,8 @@ pub trait Itertools: Iterator {
31793185
i + 1
31803186
}
31813187
});
3182-
// Respect the insertion order.
3188+
// Respect the insertion order, efficiently.
3189+
let mut data = VecDeque::from(data);
31833190
data.rotate_left(idx);
31843191
data
31853192
}

0 commit comments

Comments
 (0)