Use a bitmap to optimize adding to a PropertyDeclarationBlock.

This commit is contained in:
Simon Sapin 2017-03-07 20:12:06 +01:00
parent f70a49974a
commit 60f454d7c4
3 changed files with 61 additions and 18 deletions

View file

@ -41,7 +41,7 @@ impl Importance {
} }
/// Overridden declarations are skipped. /// Overridden declarations are skipped.
#[derive(Debug, PartialEq, Clone)] #[derive(Clone)]
pub struct PropertyDeclarationBlock { pub struct PropertyDeclarationBlock {
/// The group of declarations, along with their importance. /// The group of declarations, along with their importance.
/// ///
@ -50,6 +50,14 @@ pub struct PropertyDeclarationBlock {
/// The number of entries in `self.declaration` with `Importance::Important` /// The number of entries in `self.declaration` with `Importance::Important`
important_count: usize, important_count: usize,
longhands: LonghandIdSet,
}
impl fmt::Debug for PropertyDeclarationBlock {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.declarations.fmt(f)
}
} }
impl PropertyDeclarationBlock { impl PropertyDeclarationBlock {
@ -58,14 +66,20 @@ impl PropertyDeclarationBlock {
PropertyDeclarationBlock { PropertyDeclarationBlock {
declarations: Vec::new(), declarations: Vec::new(),
important_count: 0, important_count: 0,
longhands: LonghandIdSet::new(),
} }
} }
/// Create a block with a single declaration /// Create a block with a single declaration
pub fn with_one(declaration: PropertyDeclaration, importance: Importance) -> Self { pub fn with_one(declaration: PropertyDeclaration, importance: Importance) -> Self {
let mut longhands = LonghandIdSet::new();
if let PropertyDeclarationId::Longhand(id) = declaration.id() {
longhands.insert(id);
}
PropertyDeclarationBlock { PropertyDeclarationBlock {
declarations: vec![(declaration, importance)], declarations: vec![(declaration, importance)],
important_count: if importance.important() { 1 } else { 0 }, important_count: if importance.important() { 1 } else { 0 },
longhands: longhands,
} }
} }
@ -198,28 +212,39 @@ impl PropertyDeclarationBlock {
fn push_common(&mut self, declaration: PropertyDeclaration, importance: Importance, fn push_common(&mut self, declaration: PropertyDeclaration, importance: Importance,
overwrite_more_important: bool) -> bool { overwrite_more_important: bool) -> bool {
for slot in &mut *self.declarations { let definitely_new = if let PropertyDeclarationId::Longhand(id) = declaration.id() {
if slot.0.id() == declaration.id() { !self.longhands.contains(id)
match (slot.1, importance) { } else {
(Importance::Normal, Importance::Important) => { false // For custom properties, always scan
self.important_count += 1; };
}
(Importance::Important, Importance::Normal) => { if !definitely_new {
if overwrite_more_important { for slot in &mut *self.declarations {
self.important_count -= 1; if slot.0.id() == declaration.id() {
} else { match (slot.1, importance) {
return false (Importance::Normal, Importance::Important) => {
self.important_count += 1;
}
(Importance::Important, Importance::Normal) => {
if overwrite_more_important {
self.important_count -= 1;
} else {
return false
}
}
_ => if slot.0 == declaration {
return false;
} }
} }
_ => if slot.0 == declaration { *slot = (declaration, importance);
return false; return true
}
} }
*slot = (declaration, importance);
return true;
} }
} }
if let PropertyDeclarationId::Longhand(id) = declaration.id() {
self.longhands.insert(id);
}
self.declarations.push((declaration, importance)); self.declarations.push((declaration, importance));
if importance.important() { if importance.important() {
self.important_count += 1; self.important_count += 1;
@ -256,6 +281,11 @@ impl PropertyDeclarationBlock {
/// ///
/// Returns whether any declaration was actually removed. /// Returns whether any declaration was actually removed.
pub fn remove_property(&mut self, property: &PropertyId) -> bool { pub fn remove_property(&mut self, property: &PropertyId) -> bool {
if let PropertyId::Longhand(id) = *property {
if !self.longhands.contains(id) {
return false
}
}
let important_count = &mut self.important_count; let important_count = &mut self.important_count;
let mut removed_at_least_one = false; let mut removed_at_least_one = false;
self.declarations.retain(|&(ref declaration, importance)| { self.declarations.retain(|&(ref declaration, importance)| {
@ -269,6 +299,10 @@ impl PropertyDeclarationBlock {
!remove !remove
}); });
if let PropertyId::Longhand(id) = *property {
debug_assert!(removed_at_least_one);
self.longhands.remove(id);
}
removed_at_least_one removed_at_least_one
} }

View file

@ -177,6 +177,7 @@ pub mod animated_properties {
} }
/// A set of longhand properties /// A set of longhand properties
#[derive(Clone)]
pub struct LonghandIdSet { pub struct LonghandIdSet {
storage: [u32; (${len(data.longhands)} - 1 + 32) / 32] storage: [u32; (${len(data.longhands)} - 1 + 32) / 32]
} }
@ -202,6 +203,13 @@ impl LonghandIdSet {
self.storage[bit / 32] |= 1 << (bit % 32); self.storage[bit / 32] |= 1 << (bit % 32);
} }
/// Remove the given property from the set
#[inline]
pub fn remove(&mut self, id: LonghandId) {
let bit = id as usize;
self.storage[bit / 32] &= !(1 << (bit % 32));
}
/// Set the corresponding bit of TransitionProperty. /// Set the corresponding bit of TransitionProperty.
/// This function will panic if TransitionProperty::All is given. /// This function will panic if TransitionProperty::All is given.
pub fn set_transition_property_bit(&mut self, property: &TransitionProperty) { pub fn set_transition_property_bit(&mut self, property: &TransitionProperty) {

View file

@ -738,7 +738,8 @@ pub extern "C" fn Servo_DeclarationBlock_Clone(declarations: RawServoDeclaration
pub extern "C" fn Servo_DeclarationBlock_Equals(a: RawServoDeclarationBlockBorrowed, pub extern "C" fn Servo_DeclarationBlock_Equals(a: RawServoDeclarationBlockBorrowed,
b: RawServoDeclarationBlockBorrowed) b: RawServoDeclarationBlockBorrowed)
-> bool { -> bool {
*RwLock::<PropertyDeclarationBlock>::as_arc(&a).read() == *RwLock::<PropertyDeclarationBlock>::as_arc(&b).read() *RwLock::<PropertyDeclarationBlock>::as_arc(&a).read().declarations() ==
*RwLock::<PropertyDeclarationBlock>::as_arc(&b).read().declarations()
} }
#[no_mangle] #[no_mangle]