tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }