mirror of
https://github.com/servo/servo.git
synced 2025-08-09 07:25:35 +01:00
Switch the bloom element list to a SmallVec and track pushed hashes.
This commit is contained in:
parent
0f0e0d81fb
commit
5d5c715152
1 changed files with 48 additions and 13 deletions
|
@ -46,8 +46,29 @@ pub struct StyleBloom<E: TElement> {
|
||||||
/// The bloom filter per se.
|
/// The bloom filter per se.
|
||||||
filter: Box<BloomFilter>,
|
filter: Box<BloomFilter>,
|
||||||
|
|
||||||
/// The stack of elements that this bloom filter contains.
|
/// The stack of elements that this bloom filter contains, along with the
|
||||||
elements: Vec<SendElement<E>>,
|
/// number of hashes pushed for each element.
|
||||||
|
elements: SmallVec<[PushedElement<E>; 16]>,
|
||||||
|
|
||||||
|
/// Stack of hashes that have been pushed onto this filter.
|
||||||
|
pushed_hashes: SmallVec<[u32; 64]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PushedElement<E: TElement> {
|
||||||
|
/// The element that was pushed.
|
||||||
|
element: SendElement<E>,
|
||||||
|
|
||||||
|
/// The number of hashes pushed for the element.
|
||||||
|
num_hashes: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: TElement> PushedElement<E> {
|
||||||
|
fn new(el: E, num_hashes: usize) -> Self {
|
||||||
|
PushedElement {
|
||||||
|
element: unsafe { SendElement::new(el) },
|
||||||
|
num_hashes: num_hashes,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn each_relevant_element_hash<E, F>(element: E, mut f: F)
|
fn each_relevant_element_hash<E, F>(element: E, mut f: F)
|
||||||
|
@ -75,7 +96,8 @@ impl<E: TElement> StyleBloom<E> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
StyleBloom {
|
StyleBloom {
|
||||||
filter: Box::new(BloomFilter::new()),
|
filter: Box::new(BloomFilter::new()),
|
||||||
elements: vec![],
|
elements: Default::default(),
|
||||||
|
pushed_hashes: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,23 +120,36 @@ impl<E: TElement> StyleBloom<E> {
|
||||||
/// Same as `push`, but without asserting, in order to use it from
|
/// Same as `push`, but without asserting, in order to use it from
|
||||||
/// `rebuild`.
|
/// `rebuild`.
|
||||||
fn push_internal(&mut self, element: E) {
|
fn push_internal(&mut self, element: E) {
|
||||||
|
let mut count = 0;
|
||||||
each_relevant_element_hash(element, |hash| {
|
each_relevant_element_hash(element, |hash| {
|
||||||
|
count += 1;
|
||||||
self.filter.insert_hash(hash);
|
self.filter.insert_hash(hash);
|
||||||
|
self.pushed_hashes.push(hash);
|
||||||
});
|
});
|
||||||
self.elements.push(unsafe { SendElement::new(element) });
|
self.elements.push(PushedElement::new(element, count));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pop the last element in the bloom filter and return it.
|
/// Pop the last element in the bloom filter and return it.
|
||||||
|
#[inline]
|
||||||
fn pop(&mut self) -> Option<E> {
|
fn pop(&mut self) -> Option<E> {
|
||||||
let popped = self.elements.pop().map(|el| *el);
|
let (popped_element, num_hashes) = match self.elements.pop() {
|
||||||
|
None => return None,
|
||||||
|
Some(x) => (*x.element, x.num_hashes),
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(popped) = popped {
|
// Verify that the pushed hashes match the ones we'd get from the element.
|
||||||
each_relevant_element_hash(popped, |hash| {
|
let mut expected_hashes = vec![];
|
||||||
self.filter.remove_hash(hash);
|
if cfg!(debug_assertions) {
|
||||||
})
|
each_relevant_element_hash(popped_element, |hash| expected_hashes.push(hash));
|
||||||
}
|
}
|
||||||
|
|
||||||
popped
|
for _ in 0..num_hashes {
|
||||||
|
let hash = self.pushed_hashes.pop().unwrap();
|
||||||
|
debug_assert_eq!(expected_hashes.pop().unwrap(), hash);
|
||||||
|
self.filter.remove_hash(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(popped_element)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the bloom filter is empty.
|
/// Returns true if the bloom filter is empty.
|
||||||
|
@ -158,7 +193,7 @@ impl<E: TElement> StyleBloom<E> {
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
let mut checked = 0;
|
let mut checked = 0;
|
||||||
while let Some(parent) = element.traversal_parent() {
|
while let Some(parent) = element.traversal_parent() {
|
||||||
assert_eq!(parent, *self.elements[self.elements.len() - 1 - checked]);
|
assert_eq!(parent, *(self.elements[self.elements.len() - 1 - checked].element));
|
||||||
element = parent;
|
element = parent;
|
||||||
checked += 1;
|
checked += 1;
|
||||||
}
|
}
|
||||||
|
@ -171,7 +206,7 @@ impl<E: TElement> StyleBloom<E> {
|
||||||
/// (if any) and its ancestors.
|
/// (if any) and its ancestors.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn current_parent(&self) -> Option<E> {
|
pub fn current_parent(&self) -> Option<E> {
|
||||||
self.elements.last().map(|el| **el)
|
self.elements.last().map(|ref el| *el.element)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert the parents of an element in the bloom filter, trying to recover
|
/// Insert the parents of an element in the bloom filter, trying to recover
|
||||||
|
@ -268,7 +303,7 @@ impl<E: TElement> StyleBloom<E> {
|
||||||
//
|
//
|
||||||
// Thus it's possible with Gecko that we do not find any common
|
// Thus it's possible with Gecko that we do not find any common
|
||||||
// ancestor.
|
// ancestor.
|
||||||
while **self.elements.last().unwrap() != common_parent {
|
while *(self.elements.last().unwrap().element) != common_parent {
|
||||||
parents_to_insert.push(common_parent);
|
parents_to_insert.push(common_parent);
|
||||||
self.pop().unwrap();
|
self.pop().unwrap();
|
||||||
common_parent = match common_parent.traversal_parent() {
|
common_parent = match common_parent.traversal_parent() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue