use std::cell::{Cell, RefCell}; use alloc::vec::{self, Vec};
/// A trait to unify `FnMut` for `GroupBy` with the chunk key in `IntoChunks` trait KeyFunction<A> { type Key; fn call_mut(&mutself, arg: A) -> Self::Key;
}
impl<A, K, F: ?Sized> KeyFunction<A> for F where F: FnMut(A) -> K
{ type Key = K; #[inline] fn call_mut(&mutself, arg: A) -> Self::Key {
(*self)(arg)
}
}
/// `ChunkIndex` acts like the grouping key function for `IntoChunks` #[derive(Debug)] struct ChunkIndex {
size: usize,
index: usize,
key: usize,
}
struct GroupInner<K, I, F> where I: Iterator
{
key: F,
iter: I,
current_key: Option<K>,
current_elt: Option<I::Item>, /// flag set if iterator is exhausted
done: bool, /// Index of group we are currently buffering or visiting
top_group: usize, /// Least index for which we still have elements buffered
oldest_buffered_group: usize, /// Group index for `buffer[0]` -- the slots /// bottom_group..oldest_buffered_group are unused and will be erased when /// that range is large enough.
bottom_group: usize, /// Buffered groups, from `bottom_group` (index 0) to `top_group`.
buffer: Vec<vec::IntoIter<I::Item>>, /// index of last group iter that was dropped, usize::MAX == none
dropped_group: usize,
}
impl<K, I, F> GroupInner<K, I, F> where I: Iterator,
F: for<'a> KeyFunction<&'a I::Item, Key=K>,
K: PartialEq,
{ /// `client`: Index of group that requests next element #[inline(always)] fn step(&mutself, client: usize) -> Option<I::Item> { /* println!("client={},bottom_group={},oldest_buffered_group={},top_group={},buffers=[{}]", client,self.bottom_group,self.oldest_buffered_group, self.top_group, self.buffer.iter().map(|elt|elt.len()).format(","));
*/ if client < self.oldest_buffered_group {
None
} elseif client < self.top_group ||
(client == self.top_group && self.buffer.len() > self.top_group - self.bottom_group)
{ self.lookup_buffer(client)
} elseifself.done {
None
} elseifself.top_group == client { self.step_current()
} else { self.step_buffering(client)
}
}
#[inline(never)] fn lookup_buffer(&mutself, client: usize) -> Option<I::Item> { // if `bufidx` doesn't exist in self.buffer, it might be empty let bufidx = client - self.bottom_group; if client < self.oldest_buffered_group { return None;
} let elt = self.buffer.get_mut(bufidx).and_then(|queue| queue.next()); if elt.is_none() && client == self.oldest_buffered_group { // FIXME: VecDeque is unfortunately not zero allocation when empty, // so we do this job manually. // `bottom_group..oldest_buffered_group` is unused, and if it's large enough, erase it. self.oldest_buffered_group += 1; // skip forward further empty queues too whileself.buffer.get(self.oldest_buffered_group - self.bottom_group)
.map_or(false, |buf| buf.len() == 0)
{ self.oldest_buffered_group += 1;
}
let nclear = self.oldest_buffered_group - self.bottom_group; if nclear > 0 && nclear >= self.buffer.len() / 2 { letmut i = 0; self.buffer.retain(|buf| {
i += 1;
debug_assert!(buf.len() == 0 || i > nclear);
i > nclear
}); self.bottom_group = self.oldest_buffered_group;
}
}
elt
}
/// Take the next element from the iterator, and set the done /// flag if exhausted. Must not be called after done. #[inline(always)] fn next_element(&mutself) -> Option<I::Item> {
debug_assert!(!self.done); matchself.iter.next() {
None => { self.done = true; None }
otherwise => otherwise,
}
}
#[inline(never)] fn step_buffering(&mutself, client: usize) -> Option<I::Item> { // requested a later group -- walk through the current group up to // the requested group index, and buffer the elements (unless // the group is marked as dropped). // Because the `Groups` iterator is always the first to request // each group index, client is the next index efter top_group.
debug_assert!(self.top_group + 1 == client); letmut group = Vec::new();
iflet Some(elt) = self.current_elt.take() { ifself.top_group != self.dropped_group {
group.push(elt);
}
} letmut first_elt = None; // first element of the next group
fn push_next_group(&mutself, group: Vec<I::Item>) { // When we add a new buffered group, fill up slots between oldest_buffered_group and top_group whileself.top_group - self.bottom_group > self.buffer.len() { ifself.buffer.is_empty() { self.bottom_group += 1; self.oldest_buffered_group += 1;
} else { self.buffer.push(Vec::new().into_iter());
}
} self.buffer.push(group.into_iter());
debug_assert!(self.top_group + 1 - self.bottom_group == self.buffer.len());
}
/// This is the immediate case, where we use no buffering #[inline] fn step_current(&mutself) -> Option<I::Item> {
debug_assert!(!self.done); iflet elt @ Some(..) = self.current_elt.take() { return elt;
} matchself.next_element() {
None => None,
Some(elt) => { let key = self.key.call_mut(&elt); matchself.current_key.take() {
None => {}
Some(old_key) => if old_key != key { self.current_key = Some(key); self.current_elt = Some(elt); self.top_group += 1; return None;
},
} self.current_key = Some(key);
Some(elt)
}
}
}
/// Request the just started groups' key. /// /// `client`: Index of group /// /// **Panics** if no group key is available. fn group_key(&mutself, client: usize) -> K { // This can only be called after we have just returned the first // element of a group. // Perform this by simply buffering one more element, grabbing the // next key.
debug_assert!(!self.done);
debug_assert!(client == self.top_group);
debug_assert!(self.current_key.is_some());
debug_assert!(self.current_elt.is_none()); let old_key = self.current_key.take().unwrap(); iflet Some(elt) = self.next_element() { let key = self.key.call_mut(&elt); if old_key != key { self.top_group += 1;
} self.current_key = Some(key); self.current_elt = Some(elt);
}
old_key
}
}
impl<K, I, F> GroupInner<K, I, F> where I: Iterator,
{ /// Called when a group is dropped fn drop_group(&mutself, client: usize) { // It's only useful to track the maximal index ifself.dropped_group == !0 || client > self.dropped_group { self.dropped_group = client;
}
}
}
/// `GroupBy` is the storage for the lazy grouping operation. /// /// If the groups are consumed in their original order, or if each /// group is dropped without keeping it around, then `GroupBy` uses /// no allocations. It needs allocations only if several group iterators /// are alive at the same time. /// /// This type implements [`IntoIterator`] (it is **not** an iterator /// itself), because the group iterators need to borrow from this /// value. It should be stored in a local variable or temporary and /// iterated. /// /// See [`.group_by()`](crate::Itertools::group_by) for more information. #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] pubstruct GroupBy<K, I, F> where I: Iterator,
{
inner: RefCell<GroupInner<K, I, F>>, // the group iterator's current index. Keep this in the main value // so that simultaneous iterators all use the same state.
index: Cell<usize>,
}
impl<K, I, F> GroupBy<K, I, F> where I: Iterator,
{ /// `client`: Index of group that requests next element fn step(&self, client: usize) -> Option<I::Item> where F: FnMut(&I::Item) -> K,
K: PartialEq,
{ self.inner.borrow_mut().step(client)
}
/// `client`: Index of group fn drop_group(&self, client: usize) { self.inner.borrow_mut().drop_group(client);
}
}
impl<'a, K, I, F> IntoIterator for &'a GroupBy<K, I, F> where I: Iterator,
I::Item: 'a,
F: FnMut(&I::Item) -> K,
K: PartialEq
{ type Item = (K, Group<'a, K, I, F>); type IntoIter = Groups<'a, K, I, F>;
/// An iterator that yields the Group iterators. /// /// Iterator element type is `(K, Group)`: /// the group's key `K` and the group's iterator. /// /// See [`.group_by()`](crate::Itertools::group_by) for more information. #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] pubstruct Groups<'a, K: 'a, I: 'a, F: 'a> where I: Iterator,
I::Item: 'a
{
parent: &'a GroupBy<K, I, F>,
}
impl<'a, K, I, F> Iterator for Groups<'a, K, I, F> where I: Iterator,
I::Item: 'a,
F: FnMut(&I::Item) -> K,
K: PartialEq
{ type Item = (K, Group<'a, K, I, F>);
#[inline] fn next(&mutself) -> Option<Self::Item> { let index = self.parent.index.get(); self.parent.index.set(index + 1); let inner = &mut *self.parent.inner.borrow_mut();
inner.step(index).map(|elt| { let key = inner.group_key(index);
(key, Group {
parent: self.parent,
index,
first: Some(elt),
})
})
}
}
/// An iterator for the elements in a single group. /// /// Iterator element type is `I::Item`. pubstruct Group<'a, K: 'a, I: 'a, F: 'a> where I: Iterator,
I::Item: 'a,
{
parent: &'a GroupBy<K, I, F>,
index: usize,
first: Option<I::Item>,
}
impl<'a, K, I, F> Drop for Group<'a, K, I, F> where I: Iterator,
I::Item: 'a,
{ fn drop(&mutself) { self.parent.drop_group(self.index);
}
}
impl<'a, K, I, F> Iterator for Group<'a, K, I, F> where I: Iterator,
I::Item: 'a,
F: FnMut(&I::Item) -> K,
K: PartialEq,
{ type Item = I::Item; #[inline] fn next(&mutself) -> Option<Self::Item> { iflet elt @ Some(..) = self.first.take() { return elt;
} self.parent.step(self.index)
}
}
/// `ChunkLazy` is the storage for a lazy chunking operation. /// /// `IntoChunks` behaves just like `GroupBy`: it is iterable, and /// it only buffers if several chunk iterators are alive at the same time. /// /// This type implements [`IntoIterator`] (it is **not** an iterator /// itself), because the chunk iterators need to borrow from this /// value. It should be stored in a local variable or temporary and /// iterated. /// /// Iterator element type is `Chunk`, each chunk's iterator. /// /// See [`.chunks()`](crate::Itertools::chunks) for more information. #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] pubstruct IntoChunks<I> where I: Iterator,
{
inner: RefCell<GroupInner<usize, I, ChunkIndex>>, // the chunk iterator's current index. Keep this in the main value // so that simultaneous iterators all use the same state.
index: Cell<usize>,
}
impl<I> IntoChunks<I> where I: Iterator,
{ /// `client`: Index of chunk that requests next element fn step(&self, client: usize) -> Option<I::Item> { self.inner.borrow_mut().step(client)
}
/// `client`: Index of chunk fn drop_group(&self, client: usize) { self.inner.borrow_mut().drop_group(client);
}
}
impl<'a, I> IntoIterator for &'a IntoChunks<I> where I: Iterator,
I::Item: 'a,
{ type Item = Chunk<'a, I>; type IntoIter = Chunks<'a, I>;
/// An iterator that yields the Chunk iterators. /// /// Iterator element type is `Chunk`. /// /// See [`.chunks()`](crate::Itertools::chunks) for more information. #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] pubstruct Chunks<'a, I: 'a> where I: Iterator,
I::Item: 'a,
{
parent: &'a IntoChunks<I>,
}
impl<'a, I> Iterator for Chunks<'a, I> where I: Iterator,
I::Item: 'a,
{ type Item = Chunk<'a, I>;
/// An iterator for the elements in a single chunk. /// /// Iterator element type is `I::Item`. pubstruct Chunk<'a, I: 'a> where I: Iterator,
I::Item: 'a,
{
parent: &'a IntoChunks<I>,
index: usize,
first: Option<I::Item>,
}
impl<'a, I> Drop for Chunk<'a, I> where I: Iterator,
I::Item: 'a,
{ fn drop(&mutself) { self.parent.drop_group(self.index);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.