use std::ops::{Index, IndexMut, Range};
pub unsafe fn allocate<T>(len: usize) -> Box<[T]> {
let mut vec = Vec::with_capacity(len);
vec.set_len(len);
vec.into_boxed_slice()
}
#[inline]
pub fn copy<T: Copy>(src: &[T], dest: &mut [T]) -> usize {
let len = src.len().min(dest.len());
(&mut dest[..len]).copy_from_slice(&src[..len]);
len
}
pub fn copy_from_seq<T: Copy>(src_seq: &[&[T]], dest: &mut [T]) -> usize {
let mut copied = 0;
for src in src_seq {
if copied < dest.len() {
copied += copy(src, &mut dest[copied..]);
} else {
break;
}
}
copied
}
pub fn copy_to_seq<T: Copy>(src: &[T], dest_seq: &mut [&mut [T]]) -> usize {
let mut copied = 0;
for dest in dest_seq {
if copied < src.len() {
copied += copy(&src[copied..], *dest);
} else {
break;
}
}
copied
}
pub struct CircularArray<T> {
array: Box<[T]>,
mask: usize,
}
impl<T> CircularArray<T> {
pub unsafe fn uninitialized(len: usize) -> Self {
let len = len.next_power_of_two();
Self {
array: allocate(len),
mask: len - 1,
}
}
#[inline]
pub fn len(&self) -> usize {
self.array.len()
}
pub fn as_slices(&self, range: Range<usize>) -> [&[T]; 2] {
let start = self.internal_index(range.start);
let end = self.internal_index(range.end);
if start < end {
[&self.array[start..end], &[]]
} else {
[&self.array[start..], &self.array[..end]]
}
}
pub fn as_slices_mut(&mut self, range: Range<usize>) -> [&mut [T]; 2] {
let start = self.internal_index(range.start);
let end = self.internal_index(range.end);
if start < end {
[&mut self.array[start..end], &mut []]
} else {
let (mid, right) = self.array.split_at_mut(start);
let left = mid.split_at_mut(end).0;
[right, left]
}
}
#[inline]
fn internal_index(&self, virtual_index: usize) -> usize {
virtual_index & self.mask
}
}
impl<T> AsRef<[T]> for CircularArray<T> {
fn as_ref(&self) -> &[T] {
&self.array
}
}
impl<T> AsMut<[T]> for CircularArray<T> {
fn as_mut(&mut self) -> &mut [T] {
&mut self.array
}
}
impl<T> Index<usize> for CircularArray<T> {
type Output = T;
fn index(&self, index: usize) -> &T {
self.array.index(self.internal_index(index))
}
}
impl<T> IndexMut<usize> for CircularArray<T> {
fn index_mut(&mut self, index: usize) -> &mut T {
let index = self.internal_index(index);
self.array.index_mut(index)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn copy_from_seq_with_less_elements() {
let chunks: [&[i32]; 3] = [&[], &[1, 2], &[3]];
let mut dest = [0; 6];
assert_eq!(copy_from_seq(&chunks, &mut dest), 3);
assert_eq!(&dest, &[1, 2, 3, 0, 0, 0]);
}
#[test]
fn copy_from_seq_with_more_elements() {
let chunks: [&[i32]; 5] = [&[], &[1, 2], &[], &[3], &[4, 5, 6]];
let mut dest = [0; 4];
assert_eq!(copy_from_seq(&chunks, &mut dest), 4);
assert_eq!(&dest, &[1, 2, 3, 4]);
}
#[test]
fn copy_to_seq_with_less_elements() {
let src = [1, 2, 3];
let mut dest_1 = [0; 1];
let mut dest_2 = [0; 4];
{
let mut dest: [&mut [u8]; 2] = [&mut dest_1, &mut dest_2];
assert_eq!(copy_to_seq(&src, &mut dest), 3);
}
assert_eq!(&dest_1, &[1]);
assert_eq!(&dest_2, &[2, 3, 0, 0]);
}
#[test]
fn copy_to_seq_with_more_elements() {
let src = [1, 2, 3, 4];
let mut dest_1 = [0; 1];
let mut dest_2 = [0; 2];
{
let mut dest: [&mut [u8]; 2] = [&mut dest_1, &mut dest_2];
assert_eq!(copy_to_seq(&src, &mut dest), 3);
}
assert_eq!(&dest_1, &[1]);
assert_eq!(&dest_2, &[2, 3]);
}
}