use std::pin::Pin;
struct Block<T> {
vec: Vec<T>,
}
impl<T> Block<T> {
fn new(capacity: usize) -> Self {
Self {
vec: Vec::with_capacity(capacity),
}
}
fn get(&self, index: usize) -> Option<Pin<&T>> {
self.vec
.get(index)
.map(|p| unsafe { Pin::new_unchecked(p) })
}
fn get_mut(&mut self, index: usize) -> Option<Pin<&mut T>> {
self.vec
.get_mut(index)
.map(|p| unsafe { Pin::new_unchecked(p) })
}
fn push(&mut self, item: T) {
assert!(self.vec.len() < self.vec.capacity());
self.vec.push(item);
}
fn pop(&mut self) {
self.vec.truncate(self.vec.len() - 1);
}
fn replace(&mut self, index: usize, item: T) {
*self.vec.get_mut(index).unwrap() = item;
}
}
pub struct PinnedVec<T> {
blocks: Vec<Block<T>>,
len: usize,
}
impl<T> PinnedVec<T> {
fn outter_idx(index: usize) -> usize {
(usize::BITS - (index + 1).leading_zeros() - 1) as usize
}
fn split_idx(index: usize) -> (usize, usize) {
let m = index + 1;
let outter_idx = (usize::BITS - m.leading_zeros() - 1) as usize;
let inner_idx: usize = m & (!(1 << outter_idx));
(outter_idx, inner_idx)
}
pub fn new() -> Self {
Self {
blocks: Vec::new(),
len: 0,
}
}
pub fn len(&self) -> usize {
self.len
}
pub fn capacity(&self) -> usize {
let outter_idx = Self::outter_idx(self.len);
(1 << outter_idx) - 1
}
pub fn get(&self, index: usize) -> Option<Pin<&T>> {
if index >= self.len {
None
} else {
let (outter, inner) = Self::split_idx(index);
let block = self.blocks.get(outter).unwrap();
let item = block.get(inner).unwrap();
Some(item)
}
}
pub fn get_mut(&mut self, index: usize) -> Option<Pin<&mut T>> {
if index >= self.len {
None
} else {
let (outter, inner) = Self::split_idx(index);
let block = self.blocks.get_mut(outter).unwrap();
let item = block.get_mut(inner).unwrap();
Some(item)
}
}
pub fn push(&mut self, item: T) {
let outter_idx = Self::outter_idx(self.len);
if self.blocks.len() <= outter_idx {
let new_block = Block::new(1 << outter_idx);
self.blocks.push(new_block);
}
self.blocks[outter_idx].push(item);
self.len += 1;
}
pub fn pop(&mut self) {
assert!(self.len > 0);
self.len -= 1;
let outter_idx = Self::outter_idx(self.len);
self.blocks[outter_idx].pop();
}
pub fn replace(&mut self, index: usize, item: T) {
let (outter, inner) = Self::split_idx(index);
self.blocks[outter].replace(inner, item);
}
}
#[cfg(test)]
mod tests {
use std::fmt::Debug;
use super::*;
struct Both<T> {
normal: Vec<T>,
pinned: PinnedVec<T>,
}
impl<T> Both<T> {
fn new() -> Self {
Self {
normal: Vec::new(),
pinned: PinnedVec::new(),
}
}
}
impl<T: PartialEq + Debug> Both<T> {
fn check(&self) {
let len = self.normal.len();
assert_eq!(len, self.pinned.len());
for i in 0..len {
assert_eq!(self.normal.get(i), self.pinned.get(i).as_deref());
}
assert_eq!(self.pinned.get(len), None);
}
}
impl<T: Clone> Both<T> {
fn push(&mut self, item: T) {
self.normal.push(item.clone());
self.pinned.push(item);
}
fn pop(&mut self) {
self.normal.pop();
self.pinned.pop();
}
fn replace(&mut self, index: usize, item: T) {
self.normal[index] = item.clone();
self.pinned.replace(index, item);
}
}
#[test]
fn one() {
let mut b: Both<i32> = Both::new();
for i in 0..200 {
for j in 0..i {
b.push(j);
}
b.check();
for _ in 0..(i - 2) {
b.pop();
}
b.check();
for j in (0..(i / 5)).map(|x| x * 3) {
b.replace(j as usize, -j);
}
b.check();
}
}
#[test]
fn two() {
let mut b: Both<i32> = Both::new();
b.push(1);
b.push(2);
b.push(3);
b.push(4);
b.check();
b.push(5);
b.push(6);
b.push(7);
b.check();
b.pop();
b.check();
b.pop();
b.check();
b.pop();
b.check();
b.pop();
b.check();
b.push(5);
b.check()
}
}