mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
style: Document the bloom filter.
This commit is contained in:
parent
eb90004f5a
commit
30d010342a
1 changed files with 40 additions and 8 deletions
|
@ -5,10 +5,43 @@
|
||||||
//! The style bloom filter is used as an optimization when matching deep
|
//! The style bloom filter is used as an optimization when matching deep
|
||||||
//! descendant selectors.
|
//! descendant selectors.
|
||||||
|
|
||||||
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
use dom::{SendElement, TElement};
|
use dom::{SendElement, TElement};
|
||||||
use matching::MatchMethods;
|
use matching::MatchMethods;
|
||||||
use selectors::bloom::BloomFilter;
|
use selectors::bloom::BloomFilter;
|
||||||
|
|
||||||
|
/// A struct that allows us to fast-reject deep descendant selectors avoiding
|
||||||
|
/// selector-matching.
|
||||||
|
///
|
||||||
|
/// This is implemented using a counting bloom filter, and it's a standard
|
||||||
|
/// optimization. See Gecko's `AncestorFilter`, and Blink's and WebKit's
|
||||||
|
/// `SelectorFilter`.
|
||||||
|
///
|
||||||
|
/// The constraints for Servo's style system are a bit different compared to
|
||||||
|
/// traditional style systems given Servo does a parallel breadth-first
|
||||||
|
/// traversal instead of a sequential depth-first traversal.
|
||||||
|
///
|
||||||
|
/// This implies that we need to track a bit more state than other browsers to
|
||||||
|
/// ensure we're doing the correct thing during the traversal, and being able to
|
||||||
|
/// apply this optimization effectively.
|
||||||
|
///
|
||||||
|
/// Concretely, we have a bloom filter instance per worker thread, and we track
|
||||||
|
/// the current DOM depth in order to find a common ancestor when it doesn't
|
||||||
|
/// match the previous element we've styled.
|
||||||
|
///
|
||||||
|
/// This is usually a pretty fast operation (we use to be one level deeper than
|
||||||
|
/// the previous one), but in the case of work-stealing, we may needed to push
|
||||||
|
/// and pop multiple elements.
|
||||||
|
///
|
||||||
|
/// See the `insert_parents_recovering`, where most of the magic happens.
|
||||||
|
///
|
||||||
|
/// Regarding thread-safety, this struct is safe because:
|
||||||
|
///
|
||||||
|
/// * We clear this after a restyle.
|
||||||
|
/// * The DOM shape and attributes (and every other thing we access here) are
|
||||||
|
/// immutable during a restyle.
|
||||||
|
///
|
||||||
pub struct StyleBloom<E: TElement> {
|
pub struct StyleBloom<E: TElement> {
|
||||||
/// The bloom filter per se.
|
/// The bloom filter per se.
|
||||||
filter: Box<BloomFilter>,
|
filter: Box<BloomFilter>,
|
||||||
|
@ -18,6 +51,7 @@ pub struct StyleBloom<E: TElement> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: TElement> StyleBloom<E> {
|
impl<E: TElement> StyleBloom<E> {
|
||||||
|
/// Create an empty `StyleBloom`.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
StyleBloom {
|
StyleBloom {
|
||||||
filter: Box::new(BloomFilter::new()),
|
filter: Box::new(BloomFilter::new()),
|
||||||
|
@ -25,19 +59,14 @@ impl<E: TElement> StyleBloom<E> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the bloom filter used properly by the `selectors` crate.
|
||||||
pub fn filter(&self) -> &BloomFilter {
|
pub fn filter(&self) -> &BloomFilter {
|
||||||
&*self.filter
|
&*self.filter
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn maybe_pop(&mut self, element: E) {
|
|
||||||
if self.elements.last().map(|el| **el) == Some(element) {
|
|
||||||
self.pop().unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Push an element to the bloom filter, knowing that it's a child of the
|
/// Push an element to the bloom filter, knowing that it's a child of the
|
||||||
/// last element parent.
|
/// last element parent.
|
||||||
pub fn push(&mut self, element: E) {
|
fn push(&mut self, element: E) {
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
if self.elements.is_empty() {
|
if self.elements.is_empty() {
|
||||||
assert!(element.parent_element().is_none());
|
assert!(element.parent_element().is_none());
|
||||||
|
@ -78,6 +107,8 @@ impl<E: TElement> StyleBloom<E> {
|
||||||
|
|
||||||
/// In debug builds, asserts that all the parents of `element` are in the
|
/// In debug builds, asserts that all the parents of `element` are in the
|
||||||
/// bloom filter.
|
/// bloom filter.
|
||||||
|
///
|
||||||
|
/// Goes away in release builds.
|
||||||
pub fn assert_complete(&self, mut element: E) {
|
pub fn assert_complete(&self, mut element: E) {
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
let mut checked = 0;
|
let mut checked = 0;
|
||||||
|
@ -96,7 +127,8 @@ impl<E: TElement> StyleBloom<E> {
|
||||||
/// Gets the element depth in the dom, to make it efficient, or if not
|
/// Gets the element depth in the dom, to make it efficient, or if not
|
||||||
/// provided always rebuilds the filter from scratch.
|
/// provided always rebuilds the filter from scratch.
|
||||||
///
|
///
|
||||||
/// Returns the new bloom filter depth.
|
/// Returns the new bloom filter depth, that the traversal code is
|
||||||
|
/// responsible to keep around if it wants to get an effective filter.
|
||||||
pub fn insert_parents_recovering(&mut self,
|
pub fn insert_parents_recovering(&mut self,
|
||||||
element: E,
|
element: E,
|
||||||
element_depth: Option<usize>)
|
element_depth: Option<usize>)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue