Deduplicate declarations when inserting each one, not at the end of parsing.

This will reduce the amount of re-allocations and copies.
It will be further optimized with a bit map.
This commit is contained in:
Simon Sapin 2017-03-07 19:38:25 +01:00
parent 4b4a873c3e
commit 460fd6eba8
3 changed files with 40 additions and 74 deletions

View file

@ -362,10 +362,10 @@ impl<'a> QualifiedRuleParser for KeyframeListParser<'a> {
context: self.context, context: self.context,
}; };
let mut iter = DeclarationListParser::new(input, parser); let mut iter = DeclarationListParser::new(input, parser);
let mut declarations = Vec::new(); let mut block = PropertyDeclarationBlock::new();
while let Some(declaration) = iter.next() { while let Some(declaration) = iter.next() {
match declaration { match declaration {
Ok(parsed) => parsed.expand(|d| declarations.push((d, Importance::Normal))), Ok(parsed) => parsed.expand(|d| block.push(d, Importance::Normal)),
Err(range) => { Err(range) => {
let pos = range.start; let pos = range.start;
let message = format!("Unsupported keyframe property declaration: '{}'", let message = format!("Unsupported keyframe property declaration: '{}'",
@ -377,10 +377,7 @@ impl<'a> QualifiedRuleParser for KeyframeListParser<'a> {
} }
Ok(Arc::new(RwLock::new(Keyframe { Ok(Arc::new(RwLock::new(Keyframe {
selector: prelude, selector: prelude,
block: Arc::new(RwLock::new(PropertyDeclarationBlock { block: Arc::new(RwLock::new(block)),
declarations: declarations,
important_count: 0,
})),
}))) })))
} }
} }

View file

@ -60,6 +60,14 @@ pub struct PropertyDeclarationBlock {
} }
impl PropertyDeclarationBlock { impl PropertyDeclarationBlock {
/// Create an empty block
pub fn new() -> Self {
PropertyDeclarationBlock {
declarations: Vec::new(),
important_count: 0,
}
}
/// Returns wheather this block contains any declaration with `!important`. /// Returns wheather this block contains any declaration with `!important`.
/// ///
/// This is based on the `important_count` counter, /// This is based on the `important_count` counter,
@ -169,11 +177,21 @@ impl PropertyDeclarationBlock {
} }
/// Adds or overrides the declaration for a given property in this block, /// Adds or overrides the declaration for a given property in this block,
/// without taking into account any kind of priority. Returns whether the /// except if an existing declaration for the same property is more important.
/// declaration block is actually changed. pub fn push(&mut self, declaration: PropertyDeclaration, importance: Importance) {
self.push_common(declaration, importance, false);
}
/// Adds or overrides the declaration for a given property in this block,
/// Returns whether the declaration block is actually changed.
pub fn set_parsed_declaration(&mut self, pub fn set_parsed_declaration(&mut self,
declaration: PropertyDeclaration, declaration: PropertyDeclaration,
importance: Importance) -> bool { importance: Importance) -> bool {
self.push_common(declaration, importance, true)
}
fn push_common(&mut self, declaration: PropertyDeclaration, importance: Importance,
overwrite_more_important: bool) -> bool {
for slot in &mut *self.declarations { for slot in &mut *self.declarations {
if slot.0.id() == declaration.id() { if slot.0.id() == declaration.id() {
match (slot.1, importance) { match (slot.1, importance) {
@ -181,7 +199,11 @@ impl PropertyDeclarationBlock {
self.important_count += 1; self.important_count += 1;
} }
(Importance::Important, Importance::Normal) => { (Importance::Important, Importance::Normal) => {
self.important_count -= 1; if overwrite_more_important {
self.important_count -= 1;
} else {
return false
}
} }
_ => if slot.0 == declaration { _ => if slot.0 == declaration {
return false; return false;
@ -276,39 +298,6 @@ impl PropertyDeclarationBlock {
} }
} }
} }
/// Only keep the "winning" declaration for any given property, by importance then source order.
pub fn deduplicate(&mut self) {
let mut deduplicated = Vec::with_capacity(self.declarations.len());
let mut seen_normal = PropertyDeclarationIdSet::new();
let mut seen_important = PropertyDeclarationIdSet::new();
for (declaration, importance) in self.declarations.drain(..).rev() {
if importance.important() {
let id = declaration.id();
if seen_important.contains(id) {
self.important_count -= 1;
continue
}
if seen_normal.contains(id) {
let previous_len = deduplicated.len();
deduplicated.retain(|&(ref d, _)| PropertyDeclaration::id(d) != id);
debug_assert_eq!(deduplicated.len(), previous_len - 1);
}
seen_important.insert(id);
} else {
let id = declaration.id();
if seen_normal.contains(id) ||
seen_important.contains(id) {
continue
}
seen_normal.insert(id)
}
deduplicated.push((declaration, importance))
}
deduplicated.reverse();
self.declarations = deduplicated;
}
} }
impl ToCss for PropertyDeclarationBlock { impl ToCss for PropertyDeclarationBlock {
@ -603,21 +592,14 @@ impl<'a, 'b> DeclarationParser for PropertyDeclarationParser<'a, 'b> {
pub fn parse_property_declaration_list(context: &ParserContext, pub fn parse_property_declaration_list(context: &ParserContext,
input: &mut Parser) input: &mut Parser)
-> PropertyDeclarationBlock { -> PropertyDeclarationBlock {
let mut declarations = Vec::new(); let mut block = PropertyDeclarationBlock::new();
let mut important_count = 0;
let parser = PropertyDeclarationParser { let parser = PropertyDeclarationParser {
context: context, context: context,
}; };
let mut iter = DeclarationListParser::new(input, parser); let mut iter = DeclarationListParser::new(input, parser);
while let Some(declaration) = iter.next() { while let Some(declaration) = iter.next() {
match declaration { match declaration {
Ok((parsed, importance)) => { Ok((parsed, importance)) => parsed.expand(|d| block.push(d, importance)),
let old_len = declarations.len();
parsed.expand(|d| declarations.push((d, importance)));
if importance.important() {
important_count += declarations.len() - old_len;
}
}
Err(range) => { Err(range) => {
let pos = range.start; let pos = range.start;
let message = format!("Unsupported property declaration: '{}'", let message = format!("Unsupported property declaration: '{}'",
@ -626,10 +608,5 @@ pub fn parse_property_declaration_list(context: &ParserContext,
} }
} }
} }
let mut block = PropertyDeclarationBlock {
declarations: declarations,
important_count: important_count,
};
block.deduplicate();
block block
} }

View file

@ -251,18 +251,13 @@ pub extern "C" fn Servo_AnimationValues_Uncompute(value: RawServoAnimationValueB
-> RawServoDeclarationBlockStrong -> RawServoDeclarationBlockStrong
{ {
let value = unsafe { value.as_ref().unwrap() }; let value = unsafe { value.as_ref().unwrap() };
let uncomputed_values = value.into_iter() let mut block = PropertyDeclarationBlock::new();
.map(|v| { for v in value.iter() {
let raw_anim = unsafe { v.as_ref().unwrap() }; let raw_anim = unsafe { v.as_ref().unwrap() };
let anim = AnimationValue::as_arc(&raw_anim); let anim = AnimationValue::as_arc(&raw_anim);
(anim.uncompute(), Importance::Normal) block.push(anim.uncompute(), Importance::Normal);
}) }
.collect(); Arc::new(RwLock::new(block)).into_strong()
Arc::new(RwLock::new(PropertyDeclarationBlock {
declarations: uncomputed_values,
important_count: 0,
})).into_strong()
} }
macro_rules! get_property_id_from_nscsspropertyid { macro_rules! get_property_id_from_nscsspropertyid {
@ -715,12 +710,9 @@ pub extern "C" fn Servo_ParseProperty(property: *const nsACString, value: *const
match ParsedDeclaration::parse(id, &context, &mut Parser::new(value), false) { match ParsedDeclaration::parse(id, &context, &mut Parser::new(value), false) {
Ok(parsed) => { Ok(parsed) => {
let mut declarations = Vec::new(); let mut block = PropertyDeclarationBlock::new();
parsed.expand(|d| declarations.push((d, Importance::Normal))); parsed.expand(|d| block.push(d, Importance::Normal));
Arc::new(RwLock::new(PropertyDeclarationBlock { Arc::new(RwLock::new(block)).into_strong()
declarations: declarations,
important_count: 0,
})).into_strong()
} }
Err(_) => RawServoDeclarationBlockStrong::null() Err(_) => RawServoDeclarationBlockStrong::null()
} }