use crate::bits::BitFieldVec;
use crate::func::mix64;
use crate::func::{VFunc, shard_edge::ShardEdge};
use crate::traits::bit_field_slice::*;
use crate::utils::{BinSafe, Sig, ToSig};
use common_traits::CastableInto;
use mem_dbg::*;
use std::borrow::Borrow;
use std::ops::Index;
#[derive(Debug, MemDbg, MemSize)]
#[cfg_attr(feature = "epserde", derive(epserde::Epserde))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct VFilter<W: Word + BinSafe, F> {
pub(crate) func: F,
pub(crate) filter_mask: W,
pub(crate) hash_bits: u32,
}
impl<T: ?Sized + ToSig<S>, W: Word + BinSafe, D: BitFieldSlice<W>, S: Sig, E: ShardEdge<S, 3>>
VFilter<W, VFunc<T, W, D, S, E>>
where
u64: CastableInto<W>,
{
#[inline(always)]
pub fn get_by_sig(&self, sig: S) -> W {
self.func.get_by_sig(sig)
}
#[inline]
pub fn get(&self, key: impl Borrow<T>) -> W {
self.func.get(key)
}
#[inline(always)]
pub fn contains_by_sig(&self, sig: S) -> bool {
let shard_edge = &self.func.shard_edge;
self.func.get_by_sig(sig)
== mix64(shard_edge.edge_hash(shard_edge.local_sig(sig))).cast() & self.filter_mask
}
#[inline]
pub fn contains(&self, key: impl Borrow<T>) -> bool {
self.contains_by_sig(T::to_sig(key.borrow(), self.func.seed))
}
pub fn len(&self) -> usize {
self.func.len()
}
pub fn is_empty(&self) -> bool {
self.func.is_empty()
}
pub fn hash_bits(&self) -> u32 {
self.hash_bits
}
}
impl<T: ?Sized + ToSig<S>, W: Word + BinSafe, S: Sig, E: ShardEdge<S, 3>>
VFilter<W, VFunc<T, W, BitFieldVec<W>, S, E>>
where
u64: CastableInto<W>,
{
#[inline(always)]
pub fn get_by_sig_unaligned(&self, sig: S) -> W {
self.func.get_by_sig_unaligned(sig)
}
#[inline]
pub fn get_unaligned(&self, key: impl Borrow<T>) -> W {
self.func.get_unaligned(key)
}
#[inline(always)]
pub fn contains_by_sig_unaligned(&self, sig: S) -> bool {
let shard_edge = &self.func.shard_edge;
self.func.get_by_sig_unaligned(sig)
== mix64(shard_edge.edge_hash(shard_edge.local_sig(sig))).cast() & self.filter_mask
}
#[inline]
pub fn contains_unaligned(&self, key: impl Borrow<T>) -> bool {
self.contains_by_sig_unaligned(T::to_sig(key.borrow(), self.func.seed))
}
}
impl<
T: ?Sized + ToSig<S>,
W: Word + BinSafe,
D: BitFieldSlice<W>,
S: Sig,
E: ShardEdge<S, 3>,
B: Borrow<T>,
> Index<B> for VFilter<W, VFunc<T, W, D, S, E>>
where
u64: CastableInto<W>,
{
type Output = bool;
#[inline(always)]
fn index(&self, key: B) -> &Self::Output {
if self.contains(key) { &true } else { &false }
}
}
#[cfg(all(test, feature = "rayon"))]
mod tests {
use std::ops::{BitXor, BitXorAssign};
use common_traits::UpcastableFrom;
use dsi_progress_logger::no_logging;
use rdst::RadixKey;
use crate::{
func::{
VBuilder, mix64,
shard_edge::{FuseLge3NoShards, FuseLge3Shards},
},
utils::{EmptyVal, FromCloneableIntoIterator, Sig, SigVal, ToSig},
};
use super::ShardEdge;
#[test]
fn test_filter_func() -> anyhow::Result<()> {
_test_filter_func::<[u64; 1], FuseLge3NoShards>()?;
_test_filter_func::<[u64; 2], FuseLge3Shards>()?;
Ok(())
}
fn _test_filter_func<S: Sig + Send + Sync, E: ShardEdge<S, 3, LocalSig = [u64; 1]>>()
-> anyhow::Result<()>
where
usize: ToSig<S>,
u128: UpcastableFrom<usize>,
SigVal<S, EmptyVal>: RadixKey + BitXor + BitXorAssign,
SigVal<E::LocalSig, EmptyVal>: RadixKey + BitXor + BitXorAssign,
{
for n in [0_usize, 10, 1000, 100_000, 1_000_000] {
let filter = VBuilder::<u8, Box<[_]>, S, E>::default()
.log2_buckets(4)
.offline(false)
.try_build_filter(FromCloneableIntoIterator::from(0..n), no_logging![])?;
let shard_edge = &filter.func.shard_edge;
for i in 0..n {
let sig = ToSig::<S>::to_sig(i, filter.func.seed);
assert_eq!(
mix64(shard_edge.edge_hash(shard_edge.local_sig(sig))) & 0xFF,
filter.get(i) as u64
);
}
}
Ok(())
}
}