Skip to content

Commit e489fd5

Browse files
committed
Add associated functions/methods for exposing/loading table data in CuckooFilter
1 parent 0ef1a11 commit e489fd5

File tree

1 file changed

+120
-1
lines changed

1 file changed

+120
-1
lines changed

src/filters/cuckoofilter.rs

Lines changed: 120 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::hash::{BuildHasher, BuildHasherDefault, Hash, Hasher};
55
use std::marker::PhantomData;
66

77
use rand::Rng;
8-
use succinct::{IntVec, IntVecMut, IntVector};
8+
use succinct::{BitVec, BitVecMut, IntVec, IntVecMut, IntVector};
99

1010
use crate::filters::Filter;
1111
use crate::helpers::all_zero_intvector;
@@ -186,6 +186,36 @@ where
186186
Self::with_params_and_hash(rng, bucketsize, n_buckets, l_fingerprint, bh)
187187
}
188188

189+
/// Create CuckooFilter with existing filter table data:
190+
///
191+
/// - `rng`: random number generator used for certain random actions
192+
/// - `bucketsize`: number of elements per bucket, must be at least 2
193+
/// - `n_buckets`: number of buckets, must be a power of 2 and at least 2
194+
/// - `l_fingerprint`: size of the fingerprint in bits
195+
/// - `n_elements`: number of elements in existing filter
196+
/// - `table_succinct_blocks`: filter table block data
197+
///
198+
/// The BuildHasher is set to the `DefaultHasher`.
199+
pub fn with_existing_filter<I: IntoIterator<Item = u64>>(
200+
rng: R,
201+
bucketsize: usize,
202+
n_buckets: usize,
203+
l_fingerprint: usize,
204+
n_elements: usize,
205+
table_succinct_blocks: I,
206+
) -> Self {
207+
let bh = BuildHasherDefault::<DefaultHasher>::default();
208+
Self::with_existing_filter_and_hash(
209+
rng,
210+
bucketsize,
211+
n_buckets,
212+
l_fingerprint,
213+
n_elements,
214+
table_succinct_blocks,
215+
bh,
216+
)
217+
}
218+
189219
/// Construct new `bucketsize=4`-cuckoofilter with properties:
190220
///
191221
/// - `false_positive_rate`: false positive lookup rate
@@ -260,6 +290,28 @@ where
260290
}
261291
}
262292

293+
/// Same as `with_existing_filter` but with specific `BuildHasher`.
294+
pub fn with_existing_filter_and_hash<I: IntoIterator<Item = u64>>(
295+
rng: R,
296+
bucketsize: usize,
297+
n_buckets: usize,
298+
l_fingerprint: usize,
299+
n_elements: usize,
300+
table_succinct_blocks: I,
301+
bh: B,
302+
) -> Self {
303+
let mut filter = Self::with_params_and_hash(rng, bucketsize, n_buckets, l_fingerprint, bh);
304+
for (i, block) in table_succinct_blocks.into_iter().enumerate() {
305+
assert!(
306+
i < filter.table.block_len(),
307+
"existing input table block length must not exceed filter table block length"
308+
);
309+
filter.table.set_block(i, block);
310+
}
311+
filter.n_elements = n_elements;
312+
filter
313+
}
314+
263315
/// Construct new `bucketsize=4`-cuckoofilter with properties:
264316
///
265317
/// - `false_positive_rate`: false positive lookup rate
@@ -481,6 +533,35 @@ where
481533
self.table.set(pos as u64, data);
482534
}
483535
}
536+
537+
/// Clear and load filter table with individual filter table elements
538+
/// and existing element count.
539+
pub fn load_table<I: IntoIterator<Item = u64>>(&mut self, table: I, n_elements: usize) {
540+
self.clear();
541+
for (i, value) in table.into_iter().enumerate() {
542+
let i = i as u64;
543+
assert!(
544+
i < self.table.len(),
545+
"input table length must not exceed filter table length"
546+
);
547+
self.table.set(i, value);
548+
}
549+
self.n_elements = n_elements;
550+
}
551+
552+
/// Return the individual filter table elements.
553+
pub fn table(&self) -> Vec<u64> {
554+
self.table.iter().collect()
555+
}
556+
557+
/// Return the filter table succinct block data.
558+
pub fn table_succinct_blocks(&self) -> Vec<u64> {
559+
let mut result = Vec::with_capacity(self.table.block_len());
560+
for i in 0..self.table.block_len() {
561+
result.push(self.table.get_block(i));
562+
}
563+
result
564+
}
484565
}
485566

486567
impl<T, R, B> Filter<T> for CuckooFilter<T, R, B>
@@ -949,4 +1030,42 @@ mod tests {
9491030
let cf = CuckooFilter::<NotSend, _>::with_params(ChaChaRng::from_seed([0; 32]), 2, 16, 8);
9501031
assert_send(&cf);
9511032
}
1033+
1034+
#[test]
1035+
fn succinct_table_save_load() {
1036+
let mut cf = CuckooFilter::with_params(ChaChaRng::from_seed([0; 32]), 2, 16, 8);
1037+
assert!(cf.insert(&10).unwrap());
1038+
assert!(cf.insert(&51).unwrap());
1039+
assert_eq!(cf.len(), 2);
1040+
1041+
let loaded_cf = CuckooFilter::with_existing_filter(
1042+
ChaChaRng::from_seed([0; 32]),
1043+
2,
1044+
16,
1045+
8,
1046+
cf.len(),
1047+
cf.table_succinct_blocks(),
1048+
);
1049+
1050+
assert!(loaded_cf.query(&10));
1051+
assert!(loaded_cf.query(&51));
1052+
assert!(!loaded_cf.query(&33));
1053+
assert_eq!(loaded_cf.len(), 2);
1054+
}
1055+
1056+
#[test]
1057+
fn table_save_load() {
1058+
let mut cf = CuckooFilter::with_params(ChaChaRng::from_seed([0; 32]), 2, 16, 8);
1059+
assert!(cf.insert(&10).unwrap());
1060+
assert!(cf.insert(&51).unwrap());
1061+
assert_eq!(cf.len(), 2);
1062+
1063+
let mut loaded_cf = CuckooFilter::with_params(ChaChaRng::from_seed([0; 32]), 2, 16, 8);
1064+
loaded_cf.load_table(cf.table(), cf.len());
1065+
1066+
assert!(loaded_cf.query(&10));
1067+
assert!(loaded_cf.query(&51));
1068+
assert!(!loaded_cf.query(&33));
1069+
assert_eq!(loaded_cf.len(), 2);
1070+
}
9521071
}

0 commit comments

Comments
 (0)