use crate::inline_array::InlineArray;
use std::borrow::{Borrow, BorrowMut};
use std::cmp::Ordering;
use std::fmt::{Debug, Error, Formatter};
use std::hash::{Hash, Hasher};
use std::io;
use std::iter::FromIterator;
use std::mem::{replace, MaybeUninit};
use std::ops::{Deref, DerefMut, Index, IndexMut};
use std::ptr;
use std::slice::{
from_raw_parts, from_raw_parts_mut, Iter as SliceIter, IterMut as SliceIterMut, SliceIndex,
};
use typenum::U64;
use crate::types::ChunkLength;
mod iter;
pub use self::iter::{Drain, Iter};
#[cfg(feature = "refpool")]
mod refpool;
pub struct Chunk<A, N = U64>
where
N: ChunkLength<A>,
{
left: usize,
right: usize,
data: MaybeUninit<N::SizedType>,
}
impl<A, N> Drop for Chunk<A, N>
where
N: ChunkLength<A>,
{
fn drop(&mut self) {
unsafe { ptr::drop_in_place(self.as_mut_slice()) }
}
}
impl<A, N> Clone for Chunk<A, N>
where
A: Clone,
N: ChunkLength<A>,
{
fn clone(&self) -> Self {
let mut out = Self::new();
out.left = self.left;
out.right = self.right;
for index in self.left..self.right {
unsafe { Chunk::force_write(index, (*self.ptr(index)).clone(), &mut out) }
}
out
}
}
impl<A, N> Chunk<A, N>
where
N: ChunkLength<A>,
{
pub const CAPACITY: usize = N::USIZE;
pub fn new() -> Self {
Self {
left: 0,
right: 0,
data: MaybeUninit::uninit(),
}
}
pub fn unit(value: A) -> Self {
let mut chunk = Self {
left: 0,
right: 1,
data: MaybeUninit::uninit(),
};
unsafe {
Chunk::force_write(0, value, &mut chunk);
}
chunk
}
pub fn pair(left: A, right: A) -> Self {
let mut chunk = Self {
left: 0,
right: 2,
data: MaybeUninit::uninit(),
};
unsafe {
Chunk::force_write(0, left, &mut chunk);
Chunk::force_write(1, right, &mut chunk);
}
chunk
}
pub fn drain_from(other: &mut Self) -> Self {
let other_len = other.len();
Self::from_front(other, other_len)
}
pub fn collect_from<I>(iter: &mut I, mut count: usize) -> Self
where
I: Iterator<Item = A>,
{
let mut chunk = Self::new();
while count > 0 {
count -= 1;
chunk.push_back(
iter.next()
.expect("Chunk::collect_from: underfull iterator"),
);
}
chunk
}
pub fn from_front(other: &mut Self, count: usize) -> Self {
let other_len = other.len();
debug_assert!(count <= other_len);
let mut chunk = Self::new();
unsafe { Chunk::force_copy_to(other.left, 0, count, other, &mut chunk) };
chunk.right = count;
other.left += count;
chunk
}
pub fn from_back(other: &mut Self, count: usize) -> Self {
let other_len = other.len();
debug_assert!(count <= other_len);
let mut chunk = Self::new();
unsafe { Chunk::force_copy_to(other.right - count, 0, count, other, &mut chunk) };
chunk.right = count;
other.right -= count;
chunk
}
#[inline]
pub fn len(&self) -> usize {
self.right - self.left
}
#[inline]
pub fn is_empty(&self) -> bool {
self.left == self.right
}
#[inline]
pub fn is_full(&self) -> bool {
self.left == 0 && self.right == N::USIZE
}
#[inline]
unsafe fn ptr(&self, index: usize) -> *const A {
(&self.data as *const _ as *const A).add(index)
}
#[inline]
unsafe fn mut_ptr(&mut self, index: usize) -> *mut A {
(&mut self.data as *mut _ as *mut A).add(index)
}
#[inline]
unsafe fn force_read(index: usize, chunk: &mut Self) -> A {
chunk.ptr(index).read()
}
#[inline]
unsafe fn force_write(index: usize, value: A, chunk: &mut Self) {
chunk.mut_ptr(index).write(value)
}
#[inline]
unsafe fn force_copy(from: usize, to: usize, count: usize, chunk: &mut Self) {
if count > 0 {
ptr::copy(chunk.ptr(from), chunk.mut_ptr(to), count)
}
}
#[inline]
unsafe fn force_copy_to(
from: usize,
to: usize,
count: usize,
chunk: &mut Self,
other: &mut Self,
) {
if count > 0 {
ptr::copy_nonoverlapping(chunk.ptr(from), other.mut_ptr(to), count)
}
}
pub fn push_front(&mut self, value: A) {
if self.is_full() {
panic!("Chunk::push_front: can't push to full chunk");
}
if self.is_empty() {
self.left = N::USIZE;
self.right = N::USIZE;
} else if self.left == 0 {
self.left = N::USIZE - self.right;
unsafe { Chunk::force_copy(0, self.left, self.right, self) };
self.right = N::USIZE;
}
self.left -= 1;
unsafe { Chunk::force_write(self.left, value, self) }
}
pub fn push_back(&mut self, value: A) {
if self.is_full() {
panic!("Chunk::push_back: can't push to full chunk");
}
if self.is_empty() {
self.left = 0;
self.right = 0;
} else if self.right == N::USIZE {
unsafe { Chunk::force_copy(self.left, 0, self.len(), self) };
self.right = N::USIZE - self.left;
self.left = 0;
}
unsafe { Chunk::force_write(self.right, value, self) }
self.right += 1;
}
pub fn pop_front(&mut self) -> A {
if self.is_empty() {
panic!("Chunk::pop_front: can't pop from empty chunk");
} else {
let value = unsafe { Chunk::force_read(self.left, self) };
self.left += 1;
value
}
}
pub fn pop_back(&mut self) -> A {
if self.is_empty() {
panic!("Chunk::pop_back: can't pop from empty chunk");
} else {
self.right -= 1;
unsafe { Chunk::force_read(self.right, self) }
}
}
pub fn drop_left(&mut self, index: usize) {
if index > 0 {
unsafe { ptr::drop_in_place(&mut self[..index]) }
self.left += index;
}
}
pub fn drop_right(&mut self, index: usize) {
if index != self.len() {
unsafe { ptr::drop_in_place(&mut self[index..]) }
self.right = self.left + index;
}
}
pub fn split_off(&mut self, index: usize) -> Self {
if index > self.len() {
panic!("Chunk::split_off: index out of bounds");
}
if index == self.len() {
return Self::new();
}
let mut right_chunk = Self::new();
let start = self.left + index;
let len = self.right - start;
unsafe { Chunk::force_copy_to(start, 0, len, self, &mut right_chunk) };
right_chunk.right = len;
self.right = start;
right_chunk
}
pub fn append(&mut self, other: &mut Self) {
let self_len = self.len();
let other_len = other.len();
if self_len + other_len > N::USIZE {
panic!("Chunk::append: chunk size overflow");
}
if self.right + other_len > N::USIZE {
unsafe { Chunk::force_copy(self.left, 0, self_len, self) };
self.right -= self.left;
self.left = 0;
}
unsafe { Chunk::force_copy_to(other.left, self.right, other_len, other, self) };
self.right += other_len;
other.left = 0;
other.right = 0;
}
pub fn drain_from_front(&mut self, other: &mut Self, count: usize) {
let self_len = self.len();
let other_len = other.len();
assert!(self_len + count <= N::USIZE);
assert!(other_len >= count);
if self.right + count > N::USIZE {
unsafe { Chunk::force_copy(self.left, 0, self_len, self) };
self.right -= self.left;
self.left = 0;
}
unsafe { Chunk::force_copy_to(other.left, self.right, count, other, self) };
self.right += count;
other.left += count;
}
pub fn drain_from_back(&mut self, other: &mut Self, count: usize) {
let self_len = self.len();
let other_len = other.len();
assert!(self_len + count <= N::USIZE);
assert!(other_len >= count);
if self.left < count {
unsafe { Chunk::force_copy(self.left, N::USIZE - self_len, self_len, self) };
self.left = N::USIZE - self_len;
self.right = N::USIZE;
}
unsafe { Chunk::force_copy_to(other.right - count, self.left - count, count, other, self) };
self.left -= count;
other.right -= count;
}
pub fn set(&mut self, index: usize, value: A) -> A {
replace(&mut self[index], value)
}
pub fn insert(&mut self, index: usize, value: A) {
if self.is_full() {
panic!("Chunk::insert: chunk is full");
}
if index > self.len() {
panic!("Chunk::insert: index out of bounds");
}
let real_index = index + self.left;
let left_size = index;
let right_size = self.right - real_index;
if self.right == N::USIZE || (self.left > 0 && left_size < right_size) {
unsafe {
Chunk::force_copy(self.left, self.left - 1, left_size, self);
Chunk::force_write(real_index - 1, value, self);
}
self.left -= 1;
} else {
unsafe {
Chunk::force_copy(real_index, real_index + 1, right_size, self);
Chunk::force_write(real_index, value, self);
}
self.right += 1;
}
}
pub fn insert_ordered(&mut self, value: A)
where
A: Ord,
{
if self.is_full() {
panic!("Chunk::insert: chunk is full");
}
match self.binary_search(&value) {
Ok(index) => self.insert(index, value),
Err(index) => self.insert(index, value),
}
}
pub fn insert_from<Iterable, I>(&mut self, index: usize, iter: Iterable)
where
Iterable: IntoIterator<Item = A, IntoIter = I>,
I: ExactSizeIterator<Item = A>,
{
let iter = iter.into_iter();
let insert_size = iter.len();
if self.len() + insert_size > Self::CAPACITY {
panic!(
"Chunk::insert_from: chunk cannot fit {} elements",
insert_size
);
}
if index > self.len() {
panic!("Chunk::insert_from: index out of bounds");
}
let real_index = index + self.left;
let left_size = index;
let right_size = self.right - real_index;
if self.right == N::USIZE || (self.left >= insert_size && left_size < right_size) {
unsafe {
Chunk::force_copy(self.left, self.left - insert_size, left_size, self);
let mut write_index = real_index - insert_size;
for value in iter {
Chunk::force_write(write_index, value, self);
write_index += 1;
}
}
self.left -= insert_size;
} else if self.left == 0 || (self.right + insert_size <= Self::CAPACITY) {
unsafe {
Chunk::force_copy(real_index, real_index + insert_size, right_size, self);
let mut write_index = real_index;
for value in iter {
Chunk::force_write(write_index, value, self);
write_index += 1;
}
}
self.right += insert_size;
} else {
unsafe {
Chunk::force_copy(self.left, 0, left_size, self);
Chunk::force_copy(real_index, left_size + insert_size, right_size, self);
let mut write_index = left_size;
for value in iter {
Chunk::force_write(write_index, value, self);
write_index += 1;
}
}
self.right -= self.left;
self.right += insert_size;
self.left = 0;
}
}
pub fn remove(&mut self, index: usize) -> A {
if index >= self.len() {
panic!("Chunk::remove: index out of bounds");
}
let real_index = index + self.left;
let value = unsafe { Chunk::force_read(real_index, self) };
let left_size = index;
let right_size = self.right - real_index - 1;
if left_size < right_size {
unsafe { Chunk::force_copy(self.left, self.left + 1, left_size, self) };
self.left += 1;
} else {
unsafe { Chunk::force_copy(real_index + 1, real_index, right_size, self) };
self.right -= 1;
}
value
}
pub fn drain(&mut self) -> Drain<'_, A, N> {
Drain { chunk: self }
}
pub fn clear(&mut self) {
unsafe { ptr::drop_in_place(self.as_mut_slice()) }
self.left = 0;
self.right = 0;
}
pub fn as_slice(&self) -> &[A] {
unsafe {
from_raw_parts(
(&self.data as *const MaybeUninit<N::SizedType> as *const A).add(self.left),
self.len(),
)
}
}
pub fn as_mut_slice(&mut self) -> &mut [A] {
unsafe {
from_raw_parts_mut(
(&mut self.data as *mut MaybeUninit<N::SizedType> as *mut A).add(self.left),
self.len(),
)
}
}
}
impl<A, N> Default for Chunk<A, N>
where
N: ChunkLength<A>,
{
fn default() -> Self {
Self::new()
}
}
impl<A, N, I> Index<I> for Chunk<A, N>
where
I: SliceIndex<[A]>,
N: ChunkLength<A>,
{
type Output = I::Output;
fn index(&self, index: I) -> &Self::Output {
self.as_slice().index(index)
}
}
impl<A, N, I> IndexMut<I> for Chunk<A, N>
where
I: SliceIndex<[A]>,
N: ChunkLength<A>,
{
fn index_mut(&mut self, index: I) -> &mut Self::Output {
self.as_mut_slice().index_mut(index)
}
}
impl<A, N> Debug for Chunk<A, N>
where
A: Debug,
N: ChunkLength<A>,
{
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
f.write_str("Chunk")?;
f.debug_list().entries(self.iter()).finish()
}
}
impl<A, N> Hash for Chunk<A, N>
where
A: Hash,
N: ChunkLength<A>,
{
fn hash<H>(&self, hasher: &mut H)
where
H: Hasher,
{
for item in self {
item.hash(hasher)
}
}
}
impl<A, N, Slice> PartialEq<Slice> for Chunk<A, N>
where
Slice: Borrow<[A]>,
A: PartialEq,
N: ChunkLength<A>,
{
fn eq(&self, other: &Slice) -> bool {
self.as_slice() == other.borrow()
}
}
impl<A, N> Eq for Chunk<A, N>
where
A: Eq,
N: ChunkLength<A>,
{
}
impl<A, N> PartialOrd for Chunk<A, N>
where
A: PartialOrd,
N: ChunkLength<A>,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.iter().partial_cmp(other.iter())
}
}
impl<A, N> Ord for Chunk<A, N>
where
A: Ord,
N: ChunkLength<A>,
{
fn cmp(&self, other: &Self) -> Ordering {
self.iter().cmp(other.iter())
}
}
impl<N> io::Write for Chunk<u8, N>
where
N: ChunkLength<u8>,
{
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let old_len = self.len();
self.extend(buf.iter().cloned().take(N::USIZE - old_len));
Ok(self.len() - old_len)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl<N: ChunkLength<u8>> std::io::Read for Chunk<u8, N> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
let read_size = buf.len().min(self.len());
if read_size == 0 {
Ok(0)
} else {
for p in buf.iter_mut().take(read_size) {
*p = self.pop_front();
}
Ok(read_size)
}
}
}
impl<A, N, T> From<InlineArray<A, T>> for Chunk<A, N>
where
N: ChunkLength<A>,
{
#[inline]
fn from(mut array: InlineArray<A, T>) -> Self {
Self::from(&mut array)
}
}
impl<'a, A, N, T> From<&'a mut InlineArray<A, T>> for Chunk<A, N>
where
N: ChunkLength<A>,
{
fn from(array: &mut InlineArray<A, T>) -> Self {
let mut out = Self::new();
out.left = 0;
out.right = array.len();
unsafe {
ptr::copy_nonoverlapping(array.data(), out.mut_ptr(0), out.right);
*array.len_mut() = 0;
}
out
}
}
impl<A, N> Borrow<[A]> for Chunk<A, N>
where
N: ChunkLength<A>,
{
fn borrow(&self) -> &[A] {
self.as_slice()
}
}
impl<A, N> BorrowMut<[A]> for Chunk<A, N>
where
N: ChunkLength<A>,
{
fn borrow_mut(&mut self) -> &mut [A] {
self.as_mut_slice()
}
}
impl<A, N> AsRef<[A]> for Chunk<A, N>
where
N: ChunkLength<A>,
{
fn as_ref(&self) -> &[A] {
self.as_slice()
}
}
impl<A, N> AsMut<[A]> for Chunk<A, N>
where
N: ChunkLength<A>,
{
fn as_mut(&mut self) -> &mut [A] {
self.as_mut_slice()
}
}
impl<A, N> Deref for Chunk<A, N>
where
N: ChunkLength<A>,
{
type Target = [A];
fn deref(&self) -> &Self::Target {
self.as_slice()
}
}
impl<A, N> DerefMut for Chunk<A, N>
where
N: ChunkLength<A>,
{
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut_slice()
}
}
impl<A, N> FromIterator<A> for Chunk<A, N>
where
N: ChunkLength<A>,
{
fn from_iter<I>(it: I) -> Self
where
I: IntoIterator<Item = A>,
{
let mut chunk = Self::new();
for item in it {
chunk.push_back(item);
}
chunk
}
}
impl<'a, A, N> IntoIterator for &'a Chunk<A, N>
where
N: ChunkLength<A>,
{
type Item = &'a A;
type IntoIter = SliceIter<'a, A>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, A, N> IntoIterator for &'a mut Chunk<A, N>
where
N: ChunkLength<A>,
{
type Item = &'a mut A;
type IntoIter = SliceIterMut<'a, A>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
impl<A, N> Extend<A> for Chunk<A, N>
where
N: ChunkLength<A>,
{
fn extend<I>(&mut self, it: I)
where
I: IntoIterator<Item = A>,
{
for item in it {
self.push_back(item);
}
}
}
impl<'a, A, N> Extend<&'a A> for Chunk<A, N>
where
A: 'a + Copy,
N: ChunkLength<A>,
{
fn extend<I>(&mut self, it: I)
where
I: IntoIterator<Item = &'a A>,
{
for item in it {
self.push_back(*item);
}
}
}
impl<A, N> IntoIterator for Chunk<A, N>
where
N: ChunkLength<A>,
{
type Item = A;
type IntoIter = Iter<A, N>;
fn into_iter(self) -> Self::IntoIter {
Iter { chunk: self }
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn is_full() {
let mut chunk = Chunk::<_, U64>::new();
for i in 0..64 {
assert_eq!(false, chunk.is_full());
chunk.push_back(i);
}
assert_eq!(true, chunk.is_full());
}
#[test]
fn push_back_front() {
let mut chunk = Chunk::<_, U64>::new();
for i in 12..20 {
chunk.push_back(i);
}
assert_eq!(8, chunk.len());
for i in (0..12).rev() {
chunk.push_front(i);
}
assert_eq!(20, chunk.len());
for i in 20..32 {
chunk.push_back(i);
}
assert_eq!(32, chunk.len());
let right: Vec<i32> = chunk.into_iter().collect();
let left: Vec<i32> = (0..32).collect();
assert_eq!(left, right);
}
#[test]
fn push_and_pop() {
let mut chunk = Chunk::<_, U64>::new();
for i in 0..64 {
chunk.push_back(i);
}
for i in 0..64 {
assert_eq!(i, chunk.pop_front());
}
for i in 0..64 {
chunk.push_front(i);
}
for i in 0..64 {
assert_eq!(i, chunk.pop_back());
}
}
#[test]
fn drop_left() {
let mut chunk = Chunk::<_, U64>::new();
for i in 0..6 {
chunk.push_back(i);
}
chunk.drop_left(3);
let vec: Vec<i32> = chunk.into_iter().collect();
assert_eq!(vec![3, 4, 5], vec);
}
#[test]
fn drop_right() {
let mut chunk = Chunk::<_, U64>::new();
for i in 0..6 {
chunk.push_back(i);
}
chunk.drop_right(3);
let vec: Vec<i32> = chunk.into_iter().collect();
assert_eq!(vec![0, 1, 2], vec);
}
#[test]
fn split_off() {
let mut left = Chunk::<_, U64>::new();
for i in 0..6 {
left.push_back(i);
}
let right = left.split_off(3);
let left_vec: Vec<i32> = left.into_iter().collect();
let right_vec: Vec<i32> = right.into_iter().collect();
assert_eq!(vec![0, 1, 2], left_vec);
assert_eq!(vec![3, 4, 5], right_vec);
}
#[test]
fn append() {
let mut left = Chunk::<_, U64>::new();
for i in 0..32 {
left.push_back(i);
}
let mut right = Chunk::<_, U64>::new();
for i in (32..64).rev() {
right.push_front(i);
}
left.append(&mut right);
let out_vec: Vec<i32> = left.into_iter().collect();
let should_vec: Vec<i32> = (0..64).collect();
assert_eq!(should_vec, out_vec);
}
#[test]
fn ref_iter() {
let mut chunk = Chunk::<_, U64>::new();
for i in 0..64 {
chunk.push_back(i);
}
let out_vec: Vec<&i32> = chunk.iter().collect();
let should_vec_p: Vec<i32> = (0..64).collect();
let should_vec: Vec<&i32> = should_vec_p.iter().collect();
assert_eq!(should_vec, out_vec);
}
#[test]
fn mut_ref_iter() {
let mut chunk = Chunk::<_, U64>::new();
for i in 0..64 {
chunk.push_back(i);
}
let out_vec: Vec<&mut i32> = chunk.iter_mut().collect();
let mut should_vec_p: Vec<i32> = (0..64).collect();
let should_vec: Vec<&mut i32> = should_vec_p.iter_mut().collect();
assert_eq!(should_vec, out_vec);
}
#[test]
fn consuming_iter() {
let mut chunk = Chunk::<_, U64>::new();
for i in 0..64 {
chunk.push_back(i);
}
let out_vec: Vec<i32> = chunk.into_iter().collect();
let should_vec: Vec<i32> = (0..64).collect();
assert_eq!(should_vec, out_vec);
}
#[test]
fn insert_middle() {
let mut chunk = Chunk::<_, U64>::new();
for i in 0..32 {
chunk.push_back(i);
}
for i in 33..64 {
chunk.push_back(i);
}
chunk.insert(32, 32);
let out_vec: Vec<i32> = chunk.into_iter().collect();
let should_vec: Vec<i32> = (0..64).collect();
assert_eq!(should_vec, out_vec);
}
#[test]
fn insert_back() {
let mut chunk = Chunk::<_, U64>::new();
for i in 0..63 {
chunk.push_back(i);
}
chunk.insert(63, 63);
let out_vec: Vec<i32> = chunk.into_iter().collect();
let should_vec: Vec<i32> = (0..64).collect();
assert_eq!(should_vec, out_vec);
}
#[test]
fn insert_front() {
let mut chunk = Chunk::<_, U64>::new();
for i in 1..64 {
chunk.push_front(64 - i);
}
chunk.insert(0, 0);
let out_vec: Vec<i32> = chunk.into_iter().collect();
let should_vec: Vec<i32> = (0..64).collect();
assert_eq!(should_vec, out_vec);
}
#[test]
fn remove_value() {
let mut chunk = Chunk::<_, U64>::new();
for i in 0..64 {
chunk.push_back(i);
}
chunk.remove(32);
let out_vec: Vec<i32> = chunk.into_iter().collect();
let should_vec: Vec<i32> = (0..32).chain(33..64).collect();
assert_eq!(should_vec, out_vec);
}
use crate::tests::DropTest;
use std::sync::atomic::{AtomicUsize, Ordering};
#[test]
fn dropping() {
let counter = AtomicUsize::new(0);
{
let mut chunk: Chunk<DropTest<'_>> = Chunk::new();
for _i in 0..20 {
chunk.push_back(DropTest::new(&counter))
}
for _i in 0..20 {
chunk.push_front(DropTest::new(&counter))
}
assert_eq!(40, counter.load(Ordering::Relaxed));
for _i in 0..10 {
chunk.pop_back();
}
assert_eq!(30, counter.load(Ordering::Relaxed));
}
assert_eq!(0, counter.load(Ordering::Relaxed));
}
}