Stop slicing selectors when noting dependencies, and match with an offset instead.

MozReview-Commit-ID: KLqmdRKygO0
This commit is contained in:
Bobby Holley 2017-06-01 16:47:41 -07:00
parent 5ddabef636
commit 1281fd9353
6 changed files with 76 additions and 55 deletions

View file

@ -160,6 +160,7 @@ pub fn matches_selector_list<E>(selector_list: &SelectorList<E::Impl>,
{
selector_list.0.iter().any(|selector_and_hashes| {
matches_selector(&selector_and_hashes.selector,
0,
&selector_and_hashes.hashes,
element,
context,
@ -333,8 +334,16 @@ enum SelectorMatchingResult {
}
/// Matches a selector, fast-rejecting against a bloom filter.
///
/// We accept an offset to allow consumers to represent and match against partial
/// selectors (indexed from the right). We use this API design, rather than
/// having the callers pass a SelectorIter, because creating a SelectorIter
/// requires dereferencing the selector to get the length, which adds an
/// unncessary cache miss for cases when we can fast-reject with AncestorHashes
/// (which the caller can store inline with the selector pointer).
#[inline(always)]
pub fn matches_selector<E, F>(selector: &Selector<E::Impl>,
offset: usize,
hashes: &AncestorHashes,
element: &E,
context: &mut MatchingContext,
@ -350,11 +359,12 @@ pub fn matches_selector<E, F>(selector: &Selector<E::Impl>,
}
}
matches_complex_selector(selector, element, context, flags_setter)
matches_complex_selector(selector, offset, element, context, flags_setter)
}
/// Matches a complex selector.
pub fn matches_complex_selector<E, F>(complex_selector: &Selector<E::Impl>,
offset: usize,
element: &E,
context: &mut MatchingContext,
flags_setter: &mut F)
@ -362,11 +372,15 @@ pub fn matches_complex_selector<E, F>(complex_selector: &Selector<E::Impl>,
where E: Element,
F: FnMut(&E, ElementSelectorFlags),
{
let mut iter = complex_selector.iter();
let mut iter = if offset == 0 {
complex_selector.iter()
} else {
complex_selector.iter_from(offset)
};
if cfg!(debug_assertions) {
if context.matching_mode == MatchingMode::ForStatelessPseudoElement {
assert!(complex_selector.iter().any(|c| {
assert!(iter.clone().any(|c| {
matches!(*c, Component::PseudoElement(..))
}));
}

View file

@ -177,9 +177,13 @@ pub struct AncestorHashes(pub [u32; NUM_ANCESTOR_HASHES]);
impl AncestorHashes {
pub fn new<Impl: SelectorImpl>(s: &Selector<Impl>) -> Self {
Self::from_iter(s.iter())
}
pub fn from_iter<Impl: SelectorImpl>(iter: SelectorIter<Impl>) -> Self {
let mut hashes = [0; NUM_ANCESTOR_HASHES];
// Compute ancestor hashes for the bloom filter.
let mut hash_iter = s.iter_ancestors()
let mut hash_iter = AncestorIter::new(iter)
.map(|x| x.ancestor_hash())
.filter(|x| x.is_some())
.map(|x| x.unwrap());
@ -356,6 +360,16 @@ impl<Impl: SelectorImpl> Selector<Impl> {
}
}
pub fn iter_from(&self, offset: usize) -> SelectorIter<Impl> {
// Note: selectors are stored left-to-right but logical order is right-to-left.
let slice = self.0.as_ref();
let iter = slice[..(slice.len() - offset)].iter().rev();
SelectorIter {
iter: iter,
next_combinator: None,
}
}
/// Returns an iterator over the entire sequence of simple selectors and combinators,
/// from right to left.
pub fn iter_raw(&self) -> Rev<slice::Iter<Component<Impl>>> {
@ -368,28 +382,6 @@ impl<Impl: SelectorImpl> Selector<Impl> {
self.0.iter()
}
/// Returns an iterator over ancestor simple selectors. All combinators and
/// non-ancestor simple selectors will be skipped.
pub fn iter_ancestors(&self) -> AncestorIter<Impl> {
AncestorIter::new(self.iter())
}
/// Returns a Selector identical to |self| but with the rightmost |index| entries
/// removed.
pub fn slice_from(&self, index: usize) -> Self {
// Note that we convert the slice_from to slice_to because selectors are
// stored left-to-right but logical order is right-to-left.
Selector(self.0.clone().slice_to(self.0.len() - index), self.1)
}
/// Returns a Selector identical to |self| but with the leftmost |len() - index|
/// entries removed.
pub fn slice_to(&self, index: usize) -> Self {
// Note that we convert the slice_to to slice_from because selectors are
// stored left-to-right but logical order is right-to-left.
Selector(self.0.clone().slice_from(self.0.len() - index), self.1)
}
/// Creates a Selector from a vec of Components. Used in tests.
pub fn from_vec(vec: Vec<Component<Impl>>, specificity_and_flags: u32) -> Self {
Selector(ArcSlice::new(vec.into_boxed_slice()), specificity_and_flags)