mirror of
https://github.com/servo/servo.git
synced 2025-08-04 21:20:23 +01:00
style: Stop allocating when lowercasing element names for lookup in the
hash. 31% win on selector matching.
This commit is contained in:
parent
78e0545918
commit
c6fed026ac
1 changed files with 53 additions and 6 deletions
|
@ -6,6 +6,7 @@ use extra::arc::Arc;
|
||||||
use std::ascii::StrAsciiExt;
|
use std::ascii::StrAsciiExt;
|
||||||
use std::hashmap::HashMap;
|
use std::hashmap::HashMap;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
use std::to_bytes;
|
||||||
|
|
||||||
use servo_util::namespace;
|
use servo_util::namespace;
|
||||||
|
|
||||||
|
@ -24,6 +25,36 @@ pub enum StylesheetOrigin {
|
||||||
/// The definition of whitespace per CSS Selectors Level 3 § 4.
|
/// The definition of whitespace per CSS Selectors Level 3 § 4.
|
||||||
static SELECTOR_WHITESPACE: &'static [char] = &'static [' ', '\t', '\n', '\r', '\x0C'];
|
static SELECTOR_WHITESPACE: &'static [char] = &'static [' ', '\t', '\n', '\r', '\x0C'];
|
||||||
|
|
||||||
|
/// A newtype struct used to perform lowercase ASCII comparisons without allocating a whole new
|
||||||
|
/// string.
|
||||||
|
struct LowercaseAsciiString<'a>(&'a str);
|
||||||
|
|
||||||
|
impl<'a> Equiv<~str> for LowercaseAsciiString<'a> {
|
||||||
|
fn equiv(&self, other: &~str) -> bool {
|
||||||
|
let LowercaseAsciiString(this) = *self;
|
||||||
|
this.eq_ignore_ascii_case(*other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> IterBytes for LowercaseAsciiString<'a> {
|
||||||
|
#[inline]
|
||||||
|
fn iter_bytes(&self, _: bool, f: to_bytes::Cb) -> bool {
|
||||||
|
for b in self.bytes() {
|
||||||
|
// FIXME(pcwalton): This is a nasty hack for performance. We temporarily violate the
|
||||||
|
// `Ascii` type's invariants by using `to_ascii_nocheck`, but it's OK as we simply
|
||||||
|
// convert to a byte afterward.
|
||||||
|
unsafe {
|
||||||
|
if !f([ b.to_ascii_nocheck().to_lower().to_byte() ]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Terminate the string with a non-UTF-8 character, to match what the built-in string
|
||||||
|
// `ToBytes` implementation does. (See `libstd/to_bytes.rs`.)
|
||||||
|
f([ 0xff ])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Map node attributes to Rules whose last simple selector starts with them.
|
/// Map node attributes to Rules whose last simple selector starts with them.
|
||||||
///
|
///
|
||||||
/// e.g.,
|
/// e.g.,
|
||||||
|
@ -88,8 +119,10 @@ impl SelectorMap {
|
||||||
match element.get_attr(&namespace::Null, "class") {
|
match element.get_attr(&namespace::Null, "class") {
|
||||||
Some(ref class_attr) => {
|
Some(ref class_attr) => {
|
||||||
for class in class_attr.split(SELECTOR_WHITESPACE) {
|
for class in class_attr.split(SELECTOR_WHITESPACE) {
|
||||||
SelectorMap::get_matching_rules_from_hash(
|
SelectorMap::get_matching_rules_from_hash(node,
|
||||||
node, &self.class_hash, class, matching_rules_list);
|
&self.class_hash,
|
||||||
|
class,
|
||||||
|
matching_rules_list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
|
@ -97,10 +130,10 @@ impl SelectorMap {
|
||||||
|
|
||||||
// HTML elements in HTML documents must be matched case-insensitively.
|
// HTML elements in HTML documents must be matched case-insensitively.
|
||||||
// TODO(pradeep): Case-sensitivity depends on the document type.
|
// TODO(pradeep): Case-sensitivity depends on the document type.
|
||||||
SelectorMap::get_matching_rules_from_hash(node,
|
SelectorMap::get_matching_rules_from_hash_ignoring_case(node,
|
||||||
&self.element_hash,
|
&self.element_hash,
|
||||||
element.get_local_name().to_ascii_lower(),
|
element.get_local_name(),
|
||||||
matching_rules_list);
|
matching_rules_list);
|
||||||
SelectorMap::get_matching_rules(node,
|
SelectorMap::get_matching_rules(node,
|
||||||
self.universal_rules,
|
self.universal_rules,
|
||||||
matching_rules_list);
|
matching_rules_list);
|
||||||
|
@ -130,6 +163,20 @@ impl SelectorMap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_matching_rules_from_hash_ignoring_case<E:TElement,
|
||||||
|
N:TNode<E>>(
|
||||||
|
node: &N,
|
||||||
|
hash: &HashMap<~str,~[Rule]>,
|
||||||
|
key: &str,
|
||||||
|
matching_rules: &mut ~[Rule]) {
|
||||||
|
match hash.find_equiv(&LowercaseAsciiString(key)) {
|
||||||
|
Some(rules) => {
|
||||||
|
SelectorMap::get_matching_rules(node, *rules, matching_rules)
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Adds rules in `rules` that match `node` to the `matching_rules` list.
|
/// Adds rules in `rules` that match `node` to the `matching_rules` list.
|
||||||
fn get_matching_rules<E:TElement,
|
fn get_matching_rules<E:TElement,
|
||||||
N:TNode<E>>(
|
N:TNode<E>>(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue