@@ -5,7 +5,7 @@ use std::hash::{BuildHasher, BuildHasherDefault, Hash, Hasher};
5
5
use std:: marker:: PhantomData ;
6
6
7
7
use rand:: Rng ;
8
- use succinct:: { IntVec , IntVecMut , IntVector } ;
8
+ use succinct:: { BitVec , BitVecMut , IntVec , IntVecMut , IntVector } ;
9
9
10
10
use crate :: filters:: Filter ;
11
11
use crate :: helpers:: all_zero_intvector;
@@ -186,6 +186,36 @@ where
186
186
Self :: with_params_and_hash ( rng, bucketsize, n_buckets, l_fingerprint, bh)
187
187
}
188
188
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
+
189
219
/// Construct new `bucketsize=4`-cuckoofilter with properties:
190
220
///
191
221
/// - `false_positive_rate`: false positive lookup rate
@@ -260,6 +290,28 @@ where
260
290
}
261
291
}
262
292
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
+
263
315
/// Construct new `bucketsize=4`-cuckoofilter with properties:
264
316
///
265
317
/// - `false_positive_rate`: false positive lookup rate
@@ -481,6 +533,35 @@ where
481
533
self . table . set ( pos as u64 , data) ;
482
534
}
483
535
}
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
+ }
484
565
}
485
566
486
567
impl < T , R , B > Filter < T > for CuckooFilter < T , R , B >
@@ -949,4 +1030,42 @@ mod tests {
949
1030
let cf = CuckooFilter :: < NotSend , _ > :: with_params ( ChaChaRng :: from_seed ( [ 0 ; 32 ] ) , 2 , 16 , 8 ) ;
950
1031
assert_send ( & cf) ;
951
1032
}
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
+ }
952
1071
}
0 commit comments