/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! The structure that contains the custom properties of a given element.
usecrate::custom_properties::Name; usecrate::properties_and_values::value::ComputedValue as ComputedRegisteredValue; usecrate::selector_map::PrecomputedHasher; use indexmap::IndexMap; use servo_arc::Arc; use std::hash::BuildHasherDefault;
/// A map for a set of custom properties, which implements copy-on-write behavior on insertion with /// cheap copying. #[derive(Clone, Debug, PartialEq)] pubstruct CustomPropertiesMap(Arc<Inner>);
/// We use None in the value to represent a removed entry. type OwnMap =
IndexMap<Name, Option<ComputedRegisteredValue>, BuildHasherDefault<PrecomputedHasher>>;
#[derive(Debug, Clone)] struct Inner {
own_properties: OwnMap,
parent: Option<Arc<Inner>>, /// The number of custom properties we store. Note that this is different from the sum of our /// own and our parent's length, since we might store duplicate entries.
len: usize, /// The number of ancestors we have.
ancestor_count: u8,
}
/// A not-too-large, not too small ancestor limit, to prevent creating too-big chains. const ANCESTOR_COUNT_LIMIT: usize = 4;
/// An iterator over the custom properties. pubstruct Iter<'a> {
current: &'a Inner,
current_iter: indexmap::map::Iter<'a, Name, Option<ComputedRegisteredValue>>,
descendants: smallvec::SmallVec<[&'a Inner; ANCESTOR_COUNT_LIMIT]>,
}
impl<'a> Iterator for Iter<'a> { type Item = (&'a Name, &'a Option<ComputedRegisteredValue>);
fn next(&mutself) -> Option<Self::Item> { loop { let (name, value) = matchself.current_iter.next() {
Some(v) => v,
None => { let parent = self.current.parent.as_deref()?; self.descendants.push(self.current); self.current = parent; self.current_iter = parent.own_properties.iter(); continue;
},
}; // If the property is overridden by a descendant we've already visited it. for descendant in &self.descendants { if descendant.own_properties.contains_key(name) { continue;
}
} return Some((name, value));
}
}
}
impl PartialEq for Inner { fn eq(&self, other: &Self) -> bool { ifself.len != other.len { returnfalse;
} // NOTE(emilio): In order to speed up custom property comparison when tons of custom // properties are involved, we return false in some cases where the ordering might be // different, but the computed values end up being the same. // // This is a performance trade-off, on the assumption that if the ordering is different, // there's likely a different value as well, but might over-invalidate. // // Doing the slow thing (checking all the keys) shows up a lot in profiles, see // bug 1926423. // // Note that self.own_properties != other.own_properties is not the same, as by default // IndexMap comparison is not order-aware. ifself.own_properties.as_slice() != other.own_properties.as_slice() { returnfalse;
} self.parent == other.parent
}
}
impl Inner { fn iter(&self) -> Iter {
Iter {
current: self,
current_iter: self.own_properties.iter(),
descendants: Default::default(),
}
}
fn insert(&mutself, name: &Name, value: Option<ComputedRegisteredValue>) { let new = self.own_properties.insert(name.clone(), value).is_none(); if new && self.parent.as_ref().map_or(true, |p| p.get(name).is_none()) { self.len += 1;
}
}
/// Whether we should expand the chain, or just copy-on-write. fn should_expand_chain(&self) -> bool { const SMALL_THRESHOLD: usize = 8; ifself.own_properties.len() <= SMALL_THRESHOLD { returnfalse; // Just copy, to avoid very long chains.
} self.ancestor_count < ANCESTOR_COUNT_LIMIT as u8
}
}
impl CustomPropertiesMap { /// Returns whether the map has no properties in it. pubfn is_empty(&self) -> bool { self.0.is_empty()
}
/// Returns the amount of different properties in the map. pubfn len(&self) -> usize { self.0.len()
}
/// Returns the property name and value at a given index. pubfn get_index(&self, index: usize) -> Option<(&Name, &Option<ComputedRegisteredValue>)> { if index >= self.len() { return None;
} // FIXME: This is O(n) which is a bit unfortunate. self.0.iter().nth(index)
}
/// Returns a given property value by name. pubfn get(&self, name: &Name) -> Option<&ComputedRegisteredValue> { self.0.get(name)
}
fn do_insert(&mutself, name: &Name, value: Option<ComputedRegisteredValue>) { iflet Some(inner) = Arc::get_mut(&mutself.0) { return inner.insert(name, value);
} ifself.get(name) == value.as_ref() { return;
} if !self.0.should_expand_chain() { return Arc::make_mut(&mutself.0).insert(name, value);
} let len = self.0.len; let ancestor_count = self.0.ancestor_count + 1; letmut new_inner = Inner {
own_properties: Default::default(), // FIXME: Would be nice to avoid this clone.
parent: Some(self.0.clone()),
len,
ancestor_count,
};
new_inner.insert(name, value); self.0 = Arc::new(new_inner);
}
/// Inserts an element in the map. pubfn insert(&mutself, name: &Name, value: ComputedRegisteredValue) { self.do_insert(name, Some(value))
}
/// Removes an element from the map. pubfn remove(&mutself, name: &Name) { self.do_insert(name, None)
}
/// Shrinks the map as much as possible. pubfn shrink_to_fit(&mutself) { iflet Some(inner) = Arc::get_mut(&mutself.0) {
inner.own_properties.shrink_to_fit()
}
}
/// Return iterator to go through all properties. pubfn iter(&self) -> Iter { self.0.iter()
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-06-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.