use std::cell::{Cell, RefCell};
use alloc::vec::{self, Vec};
trait KeyFunction<A> {
type Key;
fn call_mut(&mut self, arg: A) -> Self::Key;
}
impl<'a, A, K, F: ?Sized> KeyFunction<A> for F
where F: FnMut(A) -> K
{
type Key = K;
#[inline]
fn call_mut(&mut self, arg: A) -> Self::Key {
(*self)(arg)
}
}
#[derive(Debug)]
struct ChunkIndex {
size: usize,
index: usize,
key: usize,
}
impl ChunkIndex {
#[inline(always)]
fn new(size: usize) -> Self {
ChunkIndex {
size,
index: 0,
key: 0,
}
}
}
impl<'a, A> KeyFunction<A> for ChunkIndex {
type Key = usize;
#[inline(always)]
fn call_mut(&mut self, _arg: A) -> Self::Key {
if self.index == self.size {
self.key += 1;
self.index = 0;
}
self.index += 1;
self.key
}
}
struct GroupInner<K, I, F>
where I: Iterator
{
key: F,
iter: I,
current_key: Option<K>,
current_elt: Option<I::Item>,
done: bool,
top_group: usize,
oldest_buffered_group: usize,
bottom_group: usize,
buffer: Vec<vec::IntoIter<I::Item>>,
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,
{
#[inline(always)]
fn step(&mut self, client: usize) -> Option<I::Item> {
if client < self.oldest_buffered_group {
None
} else if client < self.top_group ||
(client == self.top_group &&
self.buffer.len() > self.top_group - self.bottom_group)
{
self.lookup_buffer(client)
} else if self.done {
None
} else if self.top_group == client {
self.step_current()
} else {
self.step_buffering(client)
}
}
#[inline(never)]
fn lookup_buffer(&mut self, client: usize) -> Option<I::Item> {
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 {
self.oldest_buffered_group += 1;
while self.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 {
let mut 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
}
#[inline(always)]
fn next_element(&mut self) -> Option<I::Item> {
debug_assert!(!self.done);
match self.iter.next() {
None => { self.done = true; None }
otherwise => otherwise,
}
}
#[inline(never)]
fn step_buffering(&mut self, client: usize) -> Option<I::Item> {
debug_assert!(self.top_group + 1 == client);
let mut group = Vec::new();
if let Some(elt) = self.current_elt.take() {
if self.top_group != self.dropped_group {
group.push(elt);
}
}
let mut first_elt = None;
while let Some(elt) = self.next_element() {
let key = self.key.call_mut(&elt);
match self.current_key.take() {
None => {}
Some(old_key) => if old_key != key {
self.current_key = Some(key);
first_elt = Some(elt);
break;
},
}
self.current_key = Some(key);
if self.top_group != self.dropped_group {
group.push(elt);
}
}
if self.top_group != self.dropped_group {
self.push_next_group(group);
}
if first_elt.is_some() {
self.top_group += 1;
debug_assert!(self.top_group == client);
}
first_elt
}
fn push_next_group(&mut self, group: Vec<I::Item>) {
while self.top_group - self.bottom_group > self.buffer.len() {
if self.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());
}
#[inline]
fn step_current(&mut self) -> Option<I::Item> {
debug_assert!(!self.done);
if let elt @ Some(..) = self.current_elt.take() {
return elt;
}
match self.next_element() {
None => None,
Some(elt) => {
let key = self.key.call_mut(&elt);
match self.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)
}
}
}
fn group_key(&mut self, client: usize) -> K {
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();
if let 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,
{
fn drop_group(&mut self, client: usize) {
if self.dropped_group == !0 || client > self.dropped_group {
self.dropped_group = client;
}
}
}
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct GroupBy<K, I, F>
where I: Iterator,
{
inner: RefCell<GroupInner<K, I, F>>,
index: Cell<usize>,
}
pub fn new<K, J, F>(iter: J, f: F) -> GroupBy<K, J::IntoIter, F>
where J: IntoIterator,
F: FnMut(&J::Item) -> K,
{
GroupBy {
inner: RefCell::new(GroupInner {
key: f,
iter: iter.into_iter(),
current_key: None,
current_elt: None,
done: false,
top_group: 0,
oldest_buffered_group: 0,
bottom_group: 0,
buffer: Vec::new(),
dropped_group: !0,
}),
index: Cell::new(0),
}
}
impl<K, I, F> GroupBy<K, I, F>
where I: Iterator,
{
fn step(&self, client: usize) -> Option<I::Item>
where F: FnMut(&I::Item) -> K,
K: PartialEq,
{
self.inner.borrow_mut().step(client)
}
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>;
fn into_iter(self) -> Self::IntoIter {
Groups { parent: self }
}
}
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct 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(&mut self) -> 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),
})
})
}
}
pub struct 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(&mut self) {
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(&mut self) -> Option<Self::Item> {
if let elt @ Some(..) = self.first.take() {
return elt;
}
self.parent.step(self.index)
}
}
pub fn new_chunks<J>(iter: J, size: usize) -> IntoChunks<J::IntoIter>
where J: IntoIterator,
{
IntoChunks {
inner: RefCell::new(GroupInner {
key: ChunkIndex::new(size),
iter: iter.into_iter(),
current_key: None,
current_elt: None,
done: false,
top_group: 0,
oldest_buffered_group: 0,
bottom_group: 0,
buffer: Vec::new(),
dropped_group: !0,
}),
index: Cell::new(0),
}
}
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct IntoChunks<I>
where I: Iterator,
{
inner: RefCell<GroupInner<usize, I, ChunkIndex>>,
index: Cell<usize>,
}
impl<I> IntoChunks<I>
where I: Iterator,
{
fn step(&self, client: usize) -> Option<I::Item> {
self.inner.borrow_mut().step(client)
}
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>;
fn into_iter(self) -> Self::IntoIter {
Chunks {
parent: self,
}
}
}
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct 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>;
#[inline]
fn next(&mut self) -> 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| {
Chunk {
parent: self.parent,
index,
first: Some(elt),
}
})
}
}
pub struct 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(&mut self) {
self.parent.drop_group(self.index);
}
}
impl<'a, I> Iterator for Chunk<'a, I>
where I: Iterator,
I::Item: 'a,
{
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if let elt @ Some(..) = self.first.take() {
return elt;
}
self.parent.step(self.index)
}
}