use std::marker::PhantomData;
use rawdb::{Reader, Region};
use crate::{AnyStoredVec, HEADER_OFFSET, ReadOnlyRawVec, VecIndex, VecValue};
use super::super::{RawStrategy, ReadWriteRawVec};
pub struct VecReader<I, T, S> {
_reader: Reader,
data: *const u8,
stored_len: usize,
_marker: PhantomData<(I, T, S)>,
}
pub struct VecReaderCursor<I, T, S> {
reader: VecReader<I, T, S>,
pos: usize,
}
unsafe impl<I: Send, T: Send, S: Send> Send for VecReader<I, T, S> {}
unsafe impl<I: Sync, T: Sync, S: Sync> Sync for VecReader<I, T, S> {}
impl<I, T, S> VecReader<I, T, S>
where
T: VecValue,
S: RawStrategy<T>,
{
const SIZE_OF_T: usize = size_of::<T>();
pub(crate) fn from_region(region: &Region, stored_len: usize) -> Self {
let reader = region.create_reader();
let slice = reader.prefixed(HEADER_OFFSET);
let ptr = slice.as_ptr();
Self {
_reader: reader,
data: ptr,
stored_len,
_marker: PhantomData,
}
}
pub(crate) fn from_read_write(vec: &ReadWriteRawVec<I, T, S>) -> Self
where
I: VecIndex,
{
Self::from_region(vec.region(), vec.stored_len())
}
pub(crate) fn from_read_only(vec: &ReadOnlyRawVec<I, T, S>) -> Self
where
I: VecIndex,
{
Self::from_region(vec.region(), vec.stored_len())
}
#[inline(always)]
pub fn get(&self, index: I) -> T
where
I: VecIndex,
{
self.get_at(index.to_usize())
}
#[inline(always)]
pub fn get_at(&self, index: usize) -> T {
assert!(
index < self.stored_len,
"index {index} out of bounds (len {})",
self.stored_len
);
unsafe { S::read_from_ptr(self.data, index * Self::SIZE_OF_T) }
}
#[inline(always)]
pub fn try_get(&self, index: I) -> Option<T>
where
I: VecIndex,
{
self.try_get_at(index.to_usize())
}
#[inline(always)]
pub fn try_get_at(&self, index: usize) -> Option<T> {
if index >= self.stored_len {
return None;
}
Some(unsafe { S::read_from_ptr(self.data, index * Self::SIZE_OF_T) })
}
#[inline(always)]
pub fn len(&self) -> usize {
self.stored_len
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.stored_len == 0
}
#[inline(always)]
#[cfg(feature = "zerocopy")]
pub(crate) fn as_bytes(&self) -> &[u8] {
unsafe { std::slice::from_raw_parts(self.data, self.stored_len * Self::SIZE_OF_T) }
}
#[inline]
pub fn cursor(self) -> VecReaderCursor<I, T, S> {
VecReaderCursor {
reader: self,
pos: 0,
}
}
}
impl<I, T, S> VecReaderCursor<I, T, S>
where
T: VecValue,
S: RawStrategy<T>,
{
#[inline(always)]
pub fn position(&self) -> usize {
self.pos
}
#[inline(always)]
pub fn remaining(&self) -> usize {
self.reader.len().saturating_sub(self.pos)
}
#[inline(always)]
pub fn advance(&mut self, n: usize) {
self.pos = self.pos.saturating_add(n).min(self.reader.len());
}
#[inline(always)]
pub fn get(&self, index: usize) -> Option<T> {
self.reader.try_get_at(index)
}
#[inline(always)]
#[allow(clippy::should_implement_trait)]
pub fn next(&mut self) -> Option<T> {
let value = self.reader.try_get_at(self.pos)?;
self.pos += 1;
Some(value)
}
#[inline]
pub fn fold<B>(&mut self, n: usize, mut init: B, mut f: impl FnMut(B, T) -> B) -> B {
let end = self.pos.saturating_add(n).min(self.reader.len());
while self.pos < end {
init = f(init, self.reader.get_at(self.pos));
self.pos += 1;
}
init
}
#[inline]
pub fn for_each(&mut self, n: usize, mut f: impl FnMut(T)) {
self.fold(n, (), |(), value| f(value));
}
}