@@ -55,7 +55,7 @@ extern crate core as std;
55
55
extern crate alloc;
56
56
57
57
#[ cfg( feature = "use_alloc" ) ]
58
- use alloc:: { string:: String , vec:: Vec } ;
58
+ use alloc:: { collections :: VecDeque , string:: String , vec:: Vec } ;
59
59
60
60
pub use either:: Either ;
61
61
@@ -72,6 +72,8 @@ use std::fmt::Write;
72
72
use std:: hash:: Hash ;
73
73
use std:: iter:: { once, IntoIterator } ;
74
74
#[ cfg( feature = "use_alloc" ) ]
75
+ type VecDequeIntoIter < T > = alloc:: collections:: vec_deque:: IntoIter < T > ;
76
+ #[ cfg( feature = "use_alloc" ) ]
75
77
type VecIntoIter < T > = alloc:: vec:: IntoIter < T > ;
76
78
use std:: iter:: FromIterator ;
77
79
@@ -3146,8 +3148,10 @@ pub trait Itertools: Iterator {
3146
3148
3147
3149
/// Consumes the iterator and return an iterator of the last `n` elements.
3148
3150
///
3149
- /// The iterator, if directly collected to a `Vec `, is converted
3151
+ /// The iterator, if directly collected to a `VecDeque `, is converted
3150
3152
/// without any extra copying or allocation cost.
3153
+ /// If directly collected to a `Vec`, it may need some data movement
3154
+ /// but no re-allocation.
3151
3155
///
3152
3156
/// ```
3153
3157
/// use itertools::{assert_equal, Itertools};
@@ -3165,20 +3169,22 @@ pub trait Itertools: Iterator {
3165
3169
/// `.rev().take(n).rev()` to have a similar result (lazy and non-allocating)
3166
3170
/// without consuming the entire iterator.
3167
3171
#[ cfg( feature = "use_alloc" ) ]
3168
- fn tail ( self , n : usize ) -> VecIntoIter < Self :: Item >
3172
+ fn tail ( self , n : usize ) -> VecDequeIntoIter < Self :: Item >
3169
3173
where
3170
3174
Self : Sized ,
3171
3175
{
3172
3176
match n {
3173
3177
0 => {
3174
3178
self . last ( ) ;
3175
- Vec :: new ( )
3179
+ VecDeque :: new ( )
3176
3180
}
3177
3181
1 => self . last ( ) . into_iter ( ) . collect ( ) ,
3178
3182
_ => {
3179
3183
// Skip the starting part of the iterator if possible.
3180
3184
let ( low, _) = self . size_hint ( ) ;
3181
3185
let mut iter = self . fuse ( ) . skip ( low. saturating_sub ( n) ) ;
3186
+ // TODO: If VecDeque has a more efficient method than
3187
+ // `.pop_front();.push_back(val)` in the future then maybe revisit this.
3182
3188
let mut data: Vec < _ > = iter. by_ref ( ) . take ( n) . collect ( ) ;
3183
3189
// Update `data` cyclically.
3184
3190
let idx = iter. fold ( 0 , |i, val| {
@@ -3189,7 +3195,8 @@ pub trait Itertools: Iterator {
3189
3195
i + 1
3190
3196
}
3191
3197
} ) ;
3192
- // Respect the insertion order.
3198
+ // Respect the insertion order, efficiently.
3199
+ let mut data = VecDeque :: from ( data) ;
3193
3200
data. rotate_left ( idx) ;
3194
3201
data
3195
3202
}
0 commit comments