cache.rs (2743B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ 4 5 use rustc_hash::FxHashMap; 6 /// Relative selector cache. This is useful for following cases. 7 /// First case is non-subject relative selector: Imagine `.anchor:has(<..>) ~ .foo`, with DOM 8 /// `.anchor + .foo + .. + .foo`. Each match on `.foo` triggers `:has()` traversal that 9 /// yields the same result. This is simple enough, since we just need to store 10 /// the exact match on that anchor pass/fail. 11 /// Second case is `querySelectorAll`: Imagine `querySelectorAll(':has(.a)')`, with DOM 12 /// `div > .. > div > .a`. When the we perform the traversal at the top div, 13 /// we basically end up evaluating `:has(.a)` for all anchors, which could be reused. 14 /// Also consider the sibling version: `querySelectorAll(':has(~ .a)')` with DOM 15 /// `div + .. + div + .a`. 16 /// TODO(dshin): Second case is not yet handled. That is tracked in Bug 1845291. 17 use std::hash::Hash; 18 19 use crate::parser::{RelativeSelector, SelectorKey}; 20 use crate::{tree::OpaqueElement, SelectorImpl}; 21 22 /// Match data for a given element and a selector. 23 #[derive(Clone, Copy)] 24 pub enum RelativeSelectorCachedMatch { 25 /// This selector matches this element. 26 Matched, 27 /// This selector does not match this element. 28 NotMatched, 29 } 30 31 impl RelativeSelectorCachedMatch { 32 /// Is the cached result a match? 33 pub fn matched(&self) -> bool { 34 matches!(*self, Self::Matched) 35 } 36 } 37 38 #[derive(Clone, Copy, Hash, Eq, PartialEq)] 39 struct Key { 40 element: OpaqueElement, 41 selector: SelectorKey, 42 } 43 44 impl Key { 45 pub fn new<Impl: SelectorImpl>( 46 element: OpaqueElement, 47 selector: &RelativeSelector<Impl>, 48 ) -> Self { 49 Key { 50 element, 51 selector: SelectorKey::new(&selector.selector), 52 } 53 } 54 } 55 56 /// Cache to speed up matching of relative selectors. 57 #[derive(Default)] 58 pub struct RelativeSelectorCache { 59 cache: FxHashMap<Key, RelativeSelectorCachedMatch>, 60 } 61 62 impl RelativeSelectorCache { 63 /// Add a relative selector match into the cache. 64 pub fn add<Impl: SelectorImpl>( 65 &mut self, 66 anchor: OpaqueElement, 67 selector: &RelativeSelector<Impl>, 68 matched: RelativeSelectorCachedMatch, 69 ) { 70 self.cache.insert(Key::new(anchor, selector), matched); 71 } 72 73 /// Check if we have a cache entry for the element. 74 pub fn lookup<Impl: SelectorImpl>( 75 &mut self, 76 element: OpaqueElement, 77 selector: &RelativeSelector<Impl>, 78 ) -> Option<RelativeSelectorCachedMatch> { 79 self.cache.get(&Key::new(element, selector)).copied() 80 } 81 }