diff options
author | Cameron McCormack <cam@mcc.id.au> | 2017-08-09 13:17:23 +0800 |
---|---|---|
committer | Cameron McCormack <cam@mcc.id.au> | 2017-08-09 19:27:48 +0800 |
commit | df2c8b2902523a02f5a51cbd47b797826a88d23e (patch) | |
tree | 9da2991d0fc34aeb658834175e8b3514b2769f65 /components/selectors/bloom.rs | |
parent | e294372a328ca9d3b308b2712b04232814eb7dfa (diff) | |
download | servo-df2c8b2902523a02f5a51cbd47b797826a88d23e.tar.gz servo-df2c8b2902523a02f5a51cbd47b797826a88d23e.zip |
selectors: Add a non-counting Bloom filter type.
Diffstat (limited to 'components/selectors/bloom.rs')
-rw-r--r-- | components/selectors/bloom.rs | 67 |
1 files changed, 65 insertions, 2 deletions
diff --git a/components/selectors/bloom.rs b/components/selectors/bloom.rs index 3d90dc0b943..9475676ec71 100644 --- a/components/selectors/bloom.rs +++ b/components/selectors/bloom.rs @@ -2,8 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -//! Counting Bloom filter tuned for use as an ancestor filter for selector -//! matching. +//! Counting and non-counting Bloom filters tuned for use as ancestor filters +//! for selector matching. use fnv::FnvHasher; use std::hash::{Hash, Hasher}; @@ -19,6 +19,11 @@ const KEY_MASK: u32 = (1 << KEY_SIZE) - 1; /// A counting Bloom filter with 8-bit counters. pub type BloomFilter = CountingBloomFilter<BloomStorageU8>; +/// A non-counting Bloom filter. +/// +/// Effectively a counting Bloom filter with 1-bit counters. +pub type NonCountingBloomFilter = CountingBloomFilter<BloomStorageBool>; + /// A counting Bloom filter with parameterized storage to handle /// counters of different sizes. For now we assume that having two hash /// functions is enough, but we may revisit that decision later. @@ -217,6 +222,56 @@ impl Clone for BloomStorageU8 { } } +/// Storage class for a CountingBloomFilter that has 1-bit counters. +pub struct BloomStorageBool { + counters: [u8; ARRAY_SIZE / 8], +} + +impl BloomStorage for BloomStorageBool { + #[inline] + fn adjust_slot(&mut self, index: usize, increment: bool) { + let bit = 1 << (index % 8); + let byte = &mut self.counters[index / 8]; + + // Since we have only one bit for storage, decrementing it + // should never do anything. Assert against an accidental + // decrementing of a bit that was never set. + assert!(increment || (*byte & bit) != 0, + "should not decrement if slot is already false"); + + if increment { + *byte |= bit; + } + } + + #[inline] + fn slot_is_empty(&self, index: usize) -> bool { + let bit = 1 << (index % 8); + (self.counters[index / 8] & bit) == 0 + } + + #[inline] + fn is_zeroed(&self) -> bool { + self.counters.iter().all(|x| *x == 0) + } +} + +impl Default for BloomStorageBool { + fn default() -> Self { + BloomStorageBool { + counters: [0; ARRAY_SIZE / 8], + } + } +} + +impl Clone for BloomStorageBool { + fn clone(&self) -> Self { + BloomStorageBool { + counters: self.counters, + } + } +} + fn hash<T: Hash>(elem: &T) -> u32 { let mut hasher = FnvHasher::default(); elem.hash(&mut hasher); @@ -236,8 +291,16 @@ fn hash2(hash: u32) -> u32 { #[test] fn create_and_insert_some_stuff() { + use std::mem::transmute; + let mut bf = BloomFilter::new(); + // Statically assert that ARRAY_SIZE is a multiple of 8, which + // BloomStorageBool relies on. + unsafe { + transmute::<[u8; ARRAY_SIZE % 8], [u8; 0]>([]); + } + for i in 0_usize .. 1000 { bf.insert(&i); } |