use crate::HeapSize;
#[derive(Debug)]
pub struct Deque<T> {
storage: Vec<Vec<T>>,
next_chunk_capacity: usize,
}
const MIN_CHUNK_CAPACITY: usize = 1 << 10;
const MAX_CHUNK_CAPACITY: usize = MIN_CHUNK_CAPACITY * (1 << 10);
impl<T> Default for Deque<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> Deque<T> {
pub fn new() -> Self {
let mut result = Self {
storage: Default::default(),
next_chunk_capacity: MIN_CHUNK_CAPACITY,
};
result.new_chunk();
result
}
pub fn push(&mut self, val: T) -> &T {
let chunk = self.storage.last().unwrap();
if chunk.len() >= chunk.capacity() {
self.new_chunk();
}
let chunk = self.storage.last_mut().unwrap();
debug_assert!(
chunk.len() < chunk.capacity(),
"Invalid attempt to expand a chunk"
);
chunk.push(val);
chunk.last().unwrap()
}
pub fn len(&self) -> usize {
let mut result = 0;
for chunk in &self.storage {
result += chunk.len();
}
result
}
pub fn is_empty(&self) -> bool {
self.storage.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.storage.iter().flatten()
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
self.storage.iter_mut().flatten()
}
pub fn truncate(&mut self, len: usize) {
debug_assert!(len <= self.len(), "truncate beyond deque length");
let mut remaining = len;
let mut keep = 0usize; for chunk in &mut self.storage {
keep += 1;
if remaining < chunk.len() {
chunk.truncate(remaining);
break;
}
remaining -= chunk.len();
if remaining == 0 {
break;
}
}
self.storage.truncate(keep.max(1));
}
pub fn iter_from(&self, index: usize) -> impl Iterator<Item = &T> {
let mut skip = index;
let mut start_chunk = self.storage.len();
for (i, chunk) in self.storage.iter().enumerate() {
if skip < chunk.len() {
start_chunk = i;
break;
}
skip -= chunk.len();
}
self.storage[start_chunk..]
.iter()
.enumerate()
.flat_map(move |(i, chunk)| {
let s = if i == 0 { skip } else { 0 };
chunk[s..].iter()
})
}
fn new_chunk(&mut self) {
let capacity = self.next_chunk_capacity;
self.storage.push(Vec::with_capacity(capacity));
if capacity < MAX_CHUNK_CAPACITY {
self.next_chunk_capacity = capacity * 2;
}
}
}
impl<T> HeapSize for Deque<T> {
fn heap_size(&self) -> usize {
let mut result = 0;
for chunk in &self.storage {
result += chunk.heap_size();
}
result
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn append() {
let mut d = Deque::new();
d.push(1);
d.push(2);
assert_eq!(d.iter().count(), 2);
}
#[test]
fn multi_chunks() {
let mut d = Deque::<usize>::new();
let count = MIN_CHUNK_CAPACITY * 2;
let mut addr = 0usize;
for i in 0..count {
let elem = d.push(i);
if i == 1000 {
addr = elem as *const usize as usize;
}
}
assert_eq!(d.iter().count(), count);
let again = d.iter().nth(1000).unwrap();
assert_eq!(again as *const usize as usize, addr);
assert_eq!(*again, 1000);
}
#[test]
fn truncate_within_and_across_chunks() {
let mut d = Deque::new();
for i in 0..2500usize {
d.push(i);
}
assert_eq!(d.len(), 2500);
d.truncate(1500);
assert_eq!(d.len(), 1500);
assert_eq!(d.iter().copied().last(), Some(1499));
assert_eq!(d.iter().nth(1023).copied(), Some(1023));
d.push(9999);
assert_eq!(d.len(), 1501);
assert_eq!(d.iter().copied().last(), Some(9999));
d.truncate(500);
assert_eq!(d.len(), 500);
d.truncate(0);
assert_eq!(d.len(), 0);
d.push(1);
assert_eq!(d.len(), 1);
d.truncate(1);
assert_eq!(d.len(), 1);
}
#[test]
fn iter_from_positions_correctly() {
let mut d = Deque::new();
for i in 0..2500usize {
d.push(i);
}
let v: Vec<usize> = d.iter_from(1030).copied().take(3).collect();
assert_eq!(v, vec![1030, 1031, 1032]);
assert_eq!(d.iter_from(1024).copied().next(), Some(1024));
assert_eq!(d.iter_from(0).count(), 2500);
assert_eq!(d.iter_from(2500).count(), 0);
assert_eq!(d.iter_from(9999).count(), 0);
}
}