mirror of
https://github.com/servo/servo.git
synced 2025-08-02 20:20:14 +01:00
Move the ancestor hashes out of Selector.
MozReview-Commit-ID: 5mipXnjgSED
This commit is contained in:
parent
e3d3c5a7b2
commit
713c9a63f6
8 changed files with 153 additions and 79 deletions
|
@ -4,8 +4,8 @@
|
|||
|
||||
use attr::{ParsedAttrSelectorOperation, AttrSelectorOperation, NamespaceConstraint};
|
||||
use bloom::BloomFilter;
|
||||
use parser::{Combinator, ComplexSelector, Component, LocalName};
|
||||
use parser::{Selector, SelectorInner, SelectorIter};
|
||||
use parser::{AncestorHashes, Combinator, ComplexSelector, Component, LocalName};
|
||||
use parser::{SelectorInner, SelectorIter, SelectorList};
|
||||
use std::borrow::Borrow;
|
||||
use tree::Element;
|
||||
|
||||
|
@ -152,27 +152,29 @@ impl<'a> MatchingContext<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn matches_selector_list<E>(selector_list: &[Selector<E::Impl>],
|
||||
pub fn matches_selector_list<E>(selector_list: &SelectorList<E::Impl>,
|
||||
element: &E,
|
||||
context: &mut MatchingContext)
|
||||
-> bool
|
||||
where E: Element
|
||||
{
|
||||
selector_list.iter().any(|selector| {
|
||||
matches_selector(&selector.inner,
|
||||
selector_list.0.iter().any(|selector_and_hashes| {
|
||||
matches_selector(&selector_and_hashes.selector.inner,
|
||||
&selector_and_hashes.hashes,
|
||||
element,
|
||||
context,
|
||||
&mut |_, _| {})
|
||||
})
|
||||
}
|
||||
|
||||
fn may_match<E>(sel: &SelectorInner<E::Impl>,
|
||||
#[inline(always)]
|
||||
fn may_match<E>(hashes: &AncestorHashes,
|
||||
bf: &BloomFilter)
|
||||
-> bool
|
||||
where E: Element,
|
||||
{
|
||||
// Check against the list of precomputed hashes.
|
||||
for hash in sel.ancestor_hashes.iter() {
|
||||
for hash in hashes.0.iter() {
|
||||
// If we hit the 0 sentinel hash, that means the rest are zero as well.
|
||||
if *hash == 0 {
|
||||
break;
|
||||
|
@ -330,8 +332,10 @@ enum SelectorMatchingResult {
|
|||
NotMatchedGlobally,
|
||||
}
|
||||
|
||||
/// Matches an inner selector.
|
||||
/// Matches a selector, fast-rejecting against a bloom filter.
|
||||
#[inline(always)]
|
||||
pub fn matches_selector<E, F>(selector: &SelectorInner<E::Impl>,
|
||||
hashes: &AncestorHashes,
|
||||
element: &E,
|
||||
context: &mut MatchingContext,
|
||||
flags_setter: &mut F)
|
||||
|
@ -341,7 +345,7 @@ pub fn matches_selector<E, F>(selector: &SelectorInner<E::Impl>,
|
|||
{
|
||||
// Use the bloom filter to fast-reject.
|
||||
if let Some(filter) = context.bloom_filter {
|
||||
if !may_match::<E>(&selector, filter) {
|
||||
if !may_match::<E>(hashes, filter) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -130,7 +130,27 @@ pub trait Parser {
|
|||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
pub struct SelectorList<Impl: SelectorImpl>(pub Vec<Selector<Impl>>);
|
||||
pub struct SelectorAndHashes<Impl: SelectorImpl> {
|
||||
pub selector: Selector<Impl>,
|
||||
pub hashes: AncestorHashes,
|
||||
}
|
||||
|
||||
impl<Impl: SelectorImpl> SelectorAndHashes<Impl> {
|
||||
pub fn new(selector: Selector<Impl>) -> Self {
|
||||
let hashes = AncestorHashes::new(&selector);
|
||||
Self::new_with_hashes(selector, hashes)
|
||||
}
|
||||
|
||||
pub fn new_with_hashes(selector: Selector<Impl>, hashes: AncestorHashes) -> Self {
|
||||
SelectorAndHashes {
|
||||
selector: selector,
|
||||
hashes: hashes,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
pub struct SelectorList<Impl: SelectorImpl>(pub Vec<SelectorAndHashes<Impl>>);
|
||||
|
||||
impl<Impl: SelectorImpl> SelectorList<Impl> {
|
||||
/// Parse a comma-separated list of Selectors.
|
||||
|
@ -139,14 +159,41 @@ impl<Impl: SelectorImpl> SelectorList<Impl> {
|
|||
/// Return the Selectors or Err if there is an invalid selector.
|
||||
pub fn parse<P>(parser: &P, input: &mut CssParser) -> Result<Self, ()>
|
||||
where P: Parser<Impl=Impl> {
|
||||
input.parse_comma_separated(|input| parse_selector(parser, input))
|
||||
input.parse_comma_separated(|input| parse_selector(parser, input).map(SelectorAndHashes::new))
|
||||
.map(SelectorList)
|
||||
}
|
||||
}
|
||||
|
||||
/// Copied from Gecko, where it was noted to be unmeasured.
|
||||
/// Copied from Gecko, who copied it from WebKit. Note that increasing the
|
||||
/// number of hashes here will adversely affect the cache hit when fast-
|
||||
/// rejecting long lists of Rules with inline hashes.
|
||||
const NUM_ANCESTOR_HASHES: usize = 4;
|
||||
|
||||
/// Ancestor hashes for the bloom filter. We precompute these and store them
|
||||
/// inline with selectors to optimize cache performance during matching.
|
||||
/// This matters a lot.
|
||||
#[derive(Eq, PartialEq, Clone, Debug)]
|
||||
pub struct AncestorHashes(pub [u32; NUM_ANCESTOR_HASHES]);
|
||||
|
||||
impl AncestorHashes {
|
||||
pub fn new<Impl: SelectorImpl>(c: &Selector<Impl>) -> Self {
|
||||
let mut hashes = [0; NUM_ANCESTOR_HASHES];
|
||||
// Compute ancestor hashes for the bloom filter.
|
||||
let mut hash_iter = c.inner.complex.iter_ancestors()
|
||||
.map(|x| x.ancestor_hash())
|
||||
.filter(|x| x.is_some())
|
||||
.map(|x| x.unwrap());
|
||||
for i in 0..NUM_ANCESTOR_HASHES {
|
||||
hashes[i] = match hash_iter.next() {
|
||||
Some(x) => x,
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
|
||||
AncestorHashes(hashes)
|
||||
}
|
||||
}
|
||||
|
||||
/// The cores parts of a selector used for matching. This exists to make that
|
||||
/// information accessibly separately from the specificity and pseudo-element
|
||||
/// information that lives on |Selector| proper. We may want to refactor things
|
||||
|
@ -156,32 +203,12 @@ const NUM_ANCESTOR_HASHES: usize = 4;
|
|||
pub struct SelectorInner<Impl: SelectorImpl> {
|
||||
/// The selector data.
|
||||
pub complex: ComplexSelector<Impl>,
|
||||
/// Ancestor hashes for the bloom filter. We precompute these and store
|
||||
/// them inline to optimize cache performance during selector matching.
|
||||
/// This matters a lot.
|
||||
pub ancestor_hashes: [u32; NUM_ANCESTOR_HASHES],
|
||||
}
|
||||
|
||||
impl<Impl: SelectorImpl> SelectorInner<Impl> {
|
||||
pub fn new(c: ComplexSelector<Impl>) -> Self {
|
||||
let mut hashes = [0; NUM_ANCESTOR_HASHES];
|
||||
{
|
||||
// Compute ancestor hashes for the bloom filter.
|
||||
let mut hash_iter = c.iter_ancestors()
|
||||
.map(|x| x.ancestor_hash())
|
||||
.filter(|x| x.is_some())
|
||||
.map(|x| x.unwrap());
|
||||
for i in 0..NUM_ANCESTOR_HASHES {
|
||||
hashes[i] = match hash_iter.next() {
|
||||
Some(x) => x,
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SelectorInner {
|
||||
complex: c,
|
||||
ancestor_hashes: hashes,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -590,7 +617,7 @@ pub enum Component<Impl: SelectorImpl> {
|
|||
|
||||
impl<Impl: SelectorImpl> Component<Impl> {
|
||||
/// Compute the ancestor hash to check against the bloom filter.
|
||||
fn ancestor_hash(&self) -> Option<u32> {
|
||||
pub fn ancestor_hash(&self) -> Option<u32> {
|
||||
match *self {
|
||||
Component::LocalName(LocalName { ref name, ref lower_name }) => {
|
||||
// Only insert the local-name into the filter if it's all lowercase.
|
||||
|
@ -665,10 +692,10 @@ impl<Impl: SelectorImpl> ToCss for SelectorList<Impl> {
|
|||
let mut iter = self.0.iter();
|
||||
let first = iter.next()
|
||||
.expect("Empty SelectorList, should contain at least one selector");
|
||||
first.to_css(dest)?;
|
||||
for selector in iter {
|
||||
first.selector.to_css(dest)?;
|
||||
for selector_and_hashes in iter {
|
||||
dest.write_str(", ")?;
|
||||
selector.to_css(dest)?;
|
||||
selector_and_hashes.selector.to_css(dest)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue