custom_properties_map.rs (7230B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ 4 5 //! The structure that contains the custom properties of a given element. 6 7 use crate::custom_properties::Name; 8 use crate::properties_and_values::value::ComputedValue as ComputedRegisteredValue; 9 use crate::selector_map::PrecomputedHasher; 10 use indexmap::IndexMap; 11 use servo_arc::Arc; 12 use std::hash::BuildHasherDefault; 13 use std::sync::LazyLock; 14 15 /// A map for a set of custom properties, which implements copy-on-write behavior on insertion with 16 /// cheap copying. 17 #[derive(Clone, Debug, PartialEq)] 18 pub struct CustomPropertiesMap(Arc<Inner>); 19 20 impl Default for CustomPropertiesMap { 21 fn default() -> Self { 22 Self(EMPTY.clone()) 23 } 24 } 25 26 /// We use None in the value to represent a removed entry. 27 type OwnMap = 28 IndexMap<Name, Option<ComputedRegisteredValue>, BuildHasherDefault<PrecomputedHasher>>; 29 30 static EMPTY: LazyLock<Arc<Inner>> = LazyLock::new(|| { 31 Arc::new_leaked(Inner { 32 own_properties: Default::default(), 33 parent: None, 34 len: 0, 35 ancestor_count: 0, 36 }) 37 }); 38 39 #[derive(Debug, Clone)] 40 struct Inner { 41 own_properties: OwnMap, 42 parent: Option<Arc<Inner>>, 43 /// The number of custom properties we store. Note that this is different from the sum of our 44 /// own and our parent's length, since we might store duplicate entries. 45 len: usize, 46 /// The number of ancestors we have. 47 ancestor_count: u8, 48 } 49 50 /// A not-too-large, not too small ancestor limit, to prevent creating too-big chains. 51 const ANCESTOR_COUNT_LIMIT: usize = 4; 52 53 /// An iterator over the custom properties. 54 pub struct Iter<'a> { 55 current: &'a Inner, 56 current_iter: indexmap::map::Iter<'a, Name, Option<ComputedRegisteredValue>>, 57 descendants: smallvec::SmallVec<[&'a Inner; ANCESTOR_COUNT_LIMIT]>, 58 } 59 60 impl<'a> Iterator for Iter<'a> { 61 type Item = (&'a Name, &'a Option<ComputedRegisteredValue>); 62 63 fn next(&mut self) -> Option<Self::Item> { 64 loop { 65 let (name, value) = match self.current_iter.next() { 66 Some(v) => v, 67 None => { 68 let parent = self.current.parent.as_deref()?; 69 self.descendants.push(self.current); 70 self.current = parent; 71 self.current_iter = parent.own_properties.iter(); 72 continue; 73 }, 74 }; 75 // If the property is overridden by a descendant we've already visited it. 76 for descendant in &self.descendants { 77 if descendant.own_properties.contains_key(name) { 78 continue; 79 } 80 } 81 return Some((name, value)); 82 } 83 } 84 } 85 86 impl PartialEq for Inner { 87 fn eq(&self, other: &Self) -> bool { 88 if self.len != other.len { 89 return false; 90 } 91 // NOTE(emilio): In order to speed up custom property comparison when tons of custom 92 // properties are involved, we return false in some cases where the ordering might be 93 // different, but the computed values end up being the same. 94 // 95 // This is a performance trade-off, on the assumption that if the ordering is different, 96 // there's likely a different value as well, but might over-invalidate. 97 // 98 // Doing the slow thing (checking all the keys) shows up a lot in profiles, see 99 // bug 1926423. 100 // 101 // Note that self.own_properties != other.own_properties is not the same, as by default 102 // IndexMap comparison is not order-aware. 103 if self.own_properties.as_slice() != other.own_properties.as_slice() { 104 return false; 105 } 106 self.parent == other.parent 107 } 108 } 109 110 impl Inner { 111 fn iter(&self) -> Iter<'_> { 112 Iter { 113 current: self, 114 current_iter: self.own_properties.iter(), 115 descendants: Default::default(), 116 } 117 } 118 119 fn is_empty(&self) -> bool { 120 self.len == 0 121 } 122 123 fn len(&self) -> usize { 124 self.len 125 } 126 127 fn get(&self, name: &Name) -> Option<&ComputedRegisteredValue> { 128 if let Some(p) = self.own_properties.get(name) { 129 return p.as_ref(); 130 } 131 self.parent.as_ref()?.get(name) 132 } 133 134 fn insert(&mut self, name: &Name, value: Option<ComputedRegisteredValue>) { 135 let new = self.own_properties.insert(name.clone(), value).is_none(); 136 if new && self.parent.as_ref().map_or(true, |p| p.get(name).is_none()) { 137 self.len += 1; 138 } 139 } 140 141 /// Whether we should expand the chain, or just copy-on-write. 142 fn should_expand_chain(&self) -> bool { 143 const SMALL_THRESHOLD: usize = 8; 144 if self.own_properties.len() <= SMALL_THRESHOLD { 145 return false; // Just copy, to avoid very long chains. 146 } 147 self.ancestor_count < ANCESTOR_COUNT_LIMIT as u8 148 } 149 } 150 151 impl CustomPropertiesMap { 152 /// Returns whether the map has no properties in it. 153 pub fn is_empty(&self) -> bool { 154 self.0.is_empty() 155 } 156 157 /// Returns the amount of different properties in the map. 158 pub fn len(&self) -> usize { 159 self.0.len() 160 } 161 162 /// Returns the property name and value at a given index. 163 pub fn get_index(&self, index: usize) -> Option<(&Name, &Option<ComputedRegisteredValue>)> { 164 if index >= self.len() { 165 return None; 166 } 167 // FIXME: This is O(n) which is a bit unfortunate. 168 self.0.iter().nth(index) 169 } 170 171 /// Returns a given property value by name. 172 pub fn get(&self, name: &Name) -> Option<&ComputedRegisteredValue> { 173 self.0.get(name) 174 } 175 176 fn do_insert(&mut self, name: &Name, value: Option<ComputedRegisteredValue>) { 177 if let Some(inner) = Arc::get_mut(&mut self.0) { 178 return inner.insert(name, value); 179 } 180 if self.get(name) == value.as_ref() { 181 return; 182 } 183 if !self.0.should_expand_chain() { 184 return Arc::make_mut(&mut self.0).insert(name, value); 185 } 186 let len = self.0.len; 187 let ancestor_count = self.0.ancestor_count + 1; 188 let mut new_inner = Inner { 189 own_properties: Default::default(), 190 // FIXME: Would be nice to avoid this clone. 191 parent: Some(self.0.clone()), 192 len, 193 ancestor_count, 194 }; 195 new_inner.insert(name, value); 196 self.0 = Arc::new(new_inner); 197 } 198 199 /// Inserts an element in the map. 200 pub fn insert(&mut self, name: &Name, value: ComputedRegisteredValue) { 201 self.do_insert(name, Some(value)) 202 } 203 204 /// Removes an element from the map. 205 pub fn remove(&mut self, name: &Name) { 206 self.do_insert(name, None) 207 } 208 209 /// Shrinks the map as much as possible. 210 pub fn shrink_to_fit(&mut self) { 211 if let Some(inner) = Arc::get_mut(&mut self.0) { 212 inner.own_properties.shrink_to_fit() 213 } 214 } 215 216 /// Return iterator to go through all properties. 217 pub fn iter(&self) -> Iter<'_> { 218 self.0.iter() 219 } 220 }