Store selectors and combinators inline in a single sequence.

This improves cache locality and reduces allocations during parsing.

Note that this reverses the iteration order within a sequence of simple selectors,
but that shouldn't matter.
This commit is contained in:
Bobby Holley 2017-04-18 23:43:39 -07:00
parent 93fa0ae1e3
commit 6d66ec5e11
10 changed files with 703 additions and 330 deletions

View file

@ -84,27 +84,24 @@ fn test_parse_stylesheet() {
CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule {
selectors: SelectorList(vec![
Selector {
inner: SelectorInner::new(Arc::new(ComplexSelector {
compound_selector: vec![
SimpleSelector::Namespace(Namespace {
inner: SelectorInner::from_vec(vec![
SimpleSelector::Namespace(Namespace {
prefix: None,
url: NsAtom::from("http://www.w3.org/1999/xhtml")
}),
SimpleSelector::LocalName(LocalName {
name: local_name!("input"),
lower_name: local_name!("input"),
}),
SimpleSelector::AttrEqual(AttrSelector {
name: local_name!("type"),
lower_name: local_name!("type"),
namespace: NamespaceConstraint::Specific(Namespace {
prefix: None,
url: NsAtom::from("http://www.w3.org/1999/xhtml")
url: ns!()
}),
SimpleSelector::LocalName(LocalName {
name: local_name!("input"),
lower_name: local_name!("input"),
}),
SimpleSelector::AttrEqual(AttrSelector {
name: local_name!("type"),
lower_name: local_name!("type"),
namespace: NamespaceConstraint::Specific(Namespace {
prefix: None,
url: ns!()
}),
}, "hidden".to_owned(), CaseSensitivity::CaseInsensitive)
],
next: None,
})),
}, "hidden".to_owned(), CaseSensitivity::CaseInsensitive)
]),
pseudo_element: None,
specificity: (0 << 20) + (1 << 10) + (1 << 0),
},
@ -120,36 +117,30 @@ fn test_parse_stylesheet() {
CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule {
selectors: SelectorList(vec![
Selector {
inner: SelectorInner::new(Arc::new(ComplexSelector {
compound_selector: vec![
SimpleSelector::Namespace(Namespace {
prefix: None,
url: NsAtom::from("http://www.w3.org/1999/xhtml")
}),
SimpleSelector::LocalName(LocalName {
name: local_name!("html"),
lower_name: local_name!("html"),
}),
],
next: None,
})),
inner: SelectorInner::from_vec(vec![
SimpleSelector::Namespace(Namespace {
prefix: None,
url: NsAtom::from("http://www.w3.org/1999/xhtml")
}),
SimpleSelector::LocalName(LocalName {
name: local_name!("html"),
lower_name: local_name!("html"),
}),
]),
pseudo_element: None,
specificity: (0 << 20) + (0 << 10) + (1 << 0),
},
Selector {
inner: SelectorInner::new(Arc::new(ComplexSelector {
compound_selector: vec![
SimpleSelector::Namespace(Namespace {
prefix: None,
url: NsAtom::from("http://www.w3.org/1999/xhtml")
}),
SimpleSelector::LocalName(LocalName {
name: local_name!("body"),
lower_name: local_name!("body"),
}),
],
next: None,
})),
inner: SelectorInner::from_vec(vec![
SimpleSelector::Namespace(Namespace {
prefix: None,
url: NsAtom::from("http://www.w3.org/1999/xhtml")
}),
SimpleSelector::LocalName(LocalName {
name: local_name!("body"),
lower_name: local_name!("body"),
}),
]),
pseudo_element: None,
specificity: (0 << 20) + (0 << 10) + (1 << 0),
},
@ -162,25 +153,19 @@ fn test_parse_stylesheet() {
CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule {
selectors: SelectorList(vec![
Selector {
inner: SelectorInner::new(Arc::new(ComplexSelector {
compound_selector: vec![
SimpleSelector::Namespace(Namespace {
prefix: None,
url: NsAtom::from("http://www.w3.org/1999/xhtml")
}),
SimpleSelector::Class(Atom::from("ok")),
],
next: Some((Arc::new(ComplexSelector {
compound_selector: vec![
SimpleSelector::Namespace(Namespace {
prefix: None,
url: NsAtom::from("http://www.w3.org/1999/xhtml")
}),
SimpleSelector::ID(Atom::from("d1")),
],
next: None,
}), Combinator::Child)),
})),
inner: SelectorInner::from_vec(vec![
SimpleSelector::Namespace(Namespace {
prefix: None,
url: NsAtom::from("http://www.w3.org/1999/xhtml")
}),
SimpleSelector::ID(Atom::from("d1")),
SimpleSelector::Combinator(Combinator::Child),
SimpleSelector::Namespace(Namespace {
prefix: None,
url: NsAtom::from("http://www.w3.org/1999/xhtml")
}),
SimpleSelector::Class(Atom::from("ok")),
]),
pseudo_element: None,
specificity: (1 << 20) + (1 << 10) + (0 << 0),
},

View file

@ -77,7 +77,7 @@ fn test_get_id_name() {
#[test]
fn test_get_class_name() {
let (rules_list, _) = get_mock_rules(&[".intro.foo", "#top"]);
assert_eq!(SelectorMap::get_class_name(&rules_list[0][0]), Some(Atom::from("intro")));
assert_eq!(SelectorMap::get_class_name(&rules_list[0][0]), Some(Atom::from("foo")));
assert_eq!(SelectorMap::get_class_name(&rules_list[1][0]), None);
}
@ -103,8 +103,8 @@ fn test_insert() {
selector_map.insert(rules_list[1][0].clone());
assert_eq!(1, selector_map.id_hash.get(&Atom::from("top")).unwrap()[0].source_order);
selector_map.insert(rules_list[0][0].clone());
assert_eq!(0, selector_map.class_hash.get(&Atom::from("intro")).unwrap()[0].source_order);
assert!(selector_map.class_hash.get(&Atom::from("foo")).is_none());
assert_eq!(0, selector_map.class_hash.get(&Atom::from("foo")).unwrap()[0].source_order);
assert!(selector_map.class_hash.get(&Atom::from("intro")).is_none());
}
#[test]