use std::marker::PhantomData;
use diskann::utils::VectorId;
use diskann::{ANNError, ANNResult};
pub trait BfTreeId: VectorId {
const INDEX_CONVERSION_LOSSLESS: () = ();
fn from_index(index: usize) -> Self;
fn try_from_index(index: usize) -> Option<Self>;
fn as_index(&self) -> usize;
#[inline]
fn id_range(total: usize) -> IdRange<Self> {
IdRange::new(total)
}
}
impl BfTreeId for u32 {
#[inline(always)]
fn from_index(index: usize) -> Self {
index as u32
}
#[inline(always)]
fn try_from_index(index: usize) -> Option<Self> {
u32::try_from(index).ok()
}
#[inline(always)]
fn as_index(&self) -> usize {
*self as usize
}
}
impl BfTreeId for u64 {
const INDEX_CONVERSION_LOSSLESS: () = assert!(
usize::BITS >= u64::BITS,
"u64 bf-tree vertex ids require a 64-bit target: on a 32-bit `usize`, ids above \
u32::MAX would truncate when converted to a store index"
);
#[inline(always)]
fn from_index(index: usize) -> Self {
index as u64
}
#[inline(always)]
fn try_from_index(index: usize) -> Option<Self> {
u64::try_from(index).ok()
}
#[inline(always)]
fn as_index(&self) -> usize {
*self as usize
}
}
#[derive(Debug, Clone)]
pub struct IdRange<I> {
inner: std::ops::Range<usize>,
_marker: PhantomData<fn() -> I>,
}
impl<I: BfTreeId> IdRange<I> {
#[inline]
fn new(total: usize) -> Self {
Self {
inner: 0..total,
_marker: PhantomData,
}
}
}
impl<I: BfTreeId> Iterator for IdRange<I> {
type Item = I;
#[inline]
fn next(&mut self) -> Option<I> {
self.inner.next().map(I::from_index)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
impl<I: BfTreeId> DoubleEndedIterator for IdRange<I> {
#[inline]
fn next_back(&mut self) -> Option<I> {
self.inner.next_back().map(I::from_index)
}
}
impl<I: BfTreeId> ExactSizeIterator for IdRange<I> {
#[inline]
fn len(&self) -> usize {
self.inner.len()
}
}
pub(crate) fn validate_id_capacity<I: BfTreeId>(total: usize) -> ANNResult<()> {
let () = I::INDEX_CONVERSION_LOSSLESS;
if let Some(last) = total.checked_sub(1) {
if I::try_from_index(last).is_none() {
return Err(ANNError::message(format!(
"provider capacity of {total} ids exceeds the maximum representable by the \
{}-byte vertex id type",
std::mem::size_of::<I>()
)));
}
}
Ok(())
}