style: Refactor the custom properties map to have less temporary hashmap entries.

This commit is contained in:
Emilio Cobos Álvarez 2017-10-08 19:34:57 +02:00
parent 1ecd942384
commit c354f224ff
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C

View file

@ -57,7 +57,7 @@ pub struct BorrowedSpecifiedValue<'a> {
css: &'a str, css: &'a str,
first_token_type: TokenSerializationType, first_token_type: TokenSerializationType,
last_token_type: TokenSerializationType, last_token_type: TokenSerializationType,
references: Option<&'a PrecomputedHashSet<Name>>, references: &'a PrecomputedHashSet<Name>,
} }
/// A computed value is just a set of tokens as well, until we resolve variables /// A computed value is just a set of tokens as well, until we resolve variables
@ -155,6 +155,11 @@ where
self.values.len() self.values.len()
} }
/// Returns whether this map is empty.
pub fn is_empty(&self) -> bool {
self.len() == 0
}
/// Remove an item given its key. /// Remove an item given its key.
fn remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V> fn remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
where where
@ -461,7 +466,7 @@ fn parse_var_function<'i, 't>(
/// properties. /// properties.
pub struct CustomPropertiesBuilder<'a> { pub struct CustomPropertiesBuilder<'a> {
seen: PrecomputedHashSet<&'a Name>, seen: PrecomputedHashSet<&'a Name>,
specified_custom_properties: Option<OrderedMap<&'a Name, BorrowedSpecifiedValue<'a>>>, specified_custom_properties: OrderedMap<&'a Name, Option<BorrowedSpecifiedValue<'a>>>,
inherited: Option<&'a Arc<CustomPropertiesMap>>, inherited: Option<&'a Arc<CustomPropertiesMap>>,
} }
@ -470,7 +475,7 @@ impl<'a> CustomPropertiesBuilder<'a> {
pub fn new(inherited: Option<&'a Arc<CustomPropertiesMap>>) -> Self { pub fn new(inherited: Option<&'a Arc<CustomPropertiesMap>>) -> Self {
Self { Self {
seen: PrecomputedHashSet::default(), seen: PrecomputedHashSet::default(),
specified_custom_properties: None, specified_custom_properties: OrderedMap::new(),
inherited, inherited,
} }
} }
@ -486,38 +491,19 @@ impl<'a> CustomPropertiesBuilder<'a> {
return; return;
} }
let map = match self.specified_custom_properties {
Some(ref mut map) => map,
None => {
let mut map = OrderedMap::new();
if let Some(inherited) = self.inherited {
for (name, inherited_value) in inherited.iter() {
map.insert(name, BorrowedSpecifiedValue {
css: &inherited_value.css,
first_token_type: inherited_value.first_token_type,
last_token_type: inherited_value.last_token_type,
references: None
})
}
}
self.specified_custom_properties = Some(map);
self.specified_custom_properties.as_mut().unwrap()
}
};
match specified_value { match specified_value {
DeclaredValue::Value(ref specified_value) => { DeclaredValue::Value(ref specified_value) => {
map.insert(name, BorrowedSpecifiedValue { self.specified_custom_properties.insert(name, Some(BorrowedSpecifiedValue {
css: &specified_value.css, css: &specified_value.css,
first_token_type: specified_value.first_token_type, first_token_type: specified_value.first_token_type,
last_token_type: specified_value.last_token_type, last_token_type: specified_value.last_token_type,
references: Some(&specified_value.references), references: &specified_value.references,
}); }));
}, },
DeclaredValue::WithVariables(_) => unreachable!(), DeclaredValue::WithVariables(_) => unreachable!(),
DeclaredValue::CSSWideKeyword(keyword) => match keyword { DeclaredValue::CSSWideKeyword(keyword) => match keyword {
CSSWideKeyword::Initial => { CSSWideKeyword::Initial => {
map.remove(&name); self.specified_custom_properties.insert(name, None);
} }
CSSWideKeyword::Unset | // Custom properties are inherited by default. CSSWideKeyword::Unset | // Custom properties are inherited by default.
CSSWideKeyword::Inherit => {} // The inherited value is what we already have. CSSWideKeyword::Inherit => {} // The inherited value is what we already have.
@ -532,13 +518,12 @@ impl<'a> CustomPropertiesBuilder<'a> {
/// ///
/// Otherwise, just use the inherited custom properties map. /// Otherwise, just use the inherited custom properties map.
pub fn build(mut self) -> Option<Arc<CustomPropertiesMap>> { pub fn build(mut self) -> Option<Arc<CustomPropertiesMap>> {
let mut map = match self.specified_custom_properties.take() { if self.specified_custom_properties.is_empty() {
Some(map) => map, return self.inherited.cloned();
None => return self.inherited.cloned(), }
};
remove_cycles(&mut map); remove_cycles(&mut self.specified_custom_properties);
Some(Arc::new(substitute_all(map))) Some(Arc::new(substitute_all(self.specified_custom_properties, self.inherited)))
} }
} }
@ -546,7 +531,7 @@ impl<'a> CustomPropertiesBuilder<'a> {
/// ///
/// The initial value of a custom property is represented by this property not /// The initial value of a custom property is represented by this property not
/// being in the map. /// being in the map.
fn remove_cycles(map: &mut OrderedMap<&Name, BorrowedSpecifiedValue>) { fn remove_cycles(map: &mut OrderedMap<&Name, Option<BorrowedSpecifiedValue>>) {
let mut to_remove = PrecomputedHashSet::default(); let mut to_remove = PrecomputedHashSet::default();
{ {
let mut visited = PrecomputedHashSet::default(); let mut visited = PrecomputedHashSet::default();
@ -555,7 +540,7 @@ fn remove_cycles(map: &mut OrderedMap<&Name, BorrowedSpecifiedValue>) {
walk(map, name, &mut stack, &mut visited, &mut to_remove); walk(map, name, &mut stack, &mut visited, &mut to_remove);
fn walk<'a>( fn walk<'a>(
map: &OrderedMap<&'a Name, BorrowedSpecifiedValue<'a>>, map: &OrderedMap<&'a Name, Option<BorrowedSpecifiedValue<'a>>>,
name: &'a Name, name: &'a Name,
stack: &mut Vec<&'a Name>, stack: &mut Vec<&'a Name>,
visited: &mut PrecomputedHashSet<&'a Name>, visited: &mut PrecomputedHashSet<&'a Name>,
@ -565,10 +550,10 @@ fn remove_cycles(map: &mut OrderedMap<&Name, BorrowedSpecifiedValue>) {
if already_visited_before { if already_visited_before {
return return
} }
if let Some(value) = map.get(&name) { if let Some(&Some(ref value)) = map.get(&name) {
if let Some(references) = value.references { if !value.references.is_empty() {
stack.push(name); stack.push(name);
for next in references { for next in value.references {
if let Some(position) = stack.iter().position(|&x| x == next) { if let Some(position) = stack.iter().position(|&x| x == next) {
// Found a cycle // Found a cycle
for &in_cycle in &stack[position..] { for &in_cycle in &stack[position..] {
@ -591,16 +576,33 @@ fn remove_cycles(map: &mut OrderedMap<&Name, BorrowedSpecifiedValue>) {
/// Replace `var()` functions for all custom properties. /// Replace `var()` functions for all custom properties.
fn substitute_all( fn substitute_all(
specified_values_map: OrderedMap<&Name, BorrowedSpecifiedValue> specified_values_map: OrderedMap<&Name, Option<BorrowedSpecifiedValue>>,
inherited: Option<&Arc<CustomPropertiesMap>>,
) -> CustomPropertiesMap { ) -> CustomPropertiesMap {
let mut custom_properties_map = CustomPropertiesMap::new(); let mut custom_properties_map = match inherited {
None => CustomPropertiesMap::new(),
Some(inherited) => (**inherited).clone(),
};
let mut invalid = PrecomputedHashSet::default(); let mut invalid = PrecomputedHashSet::default();
for (name, value) in specified_values_map.iter() { for (name, value) in specified_values_map.iter() {
// If this value is invalid at computed-time it wont be inserted in computed_values_map. let value = match *value {
// Nothing else to do. Some(ref v) => v,
None => {
custom_properties_map.remove(*name);
continue;
}
};
let _ = substitute_one( let _ = substitute_one(
name, value, &specified_values_map, None, name,
&mut custom_properties_map, &mut invalid); value,
&specified_values_map,
None,
&mut custom_properties_map,
&mut invalid,
);
} }
custom_properties_map custom_properties_map
@ -613,22 +615,23 @@ fn substitute_all(
fn substitute_one( fn substitute_one(
name: &Name, name: &Name,
specified_value: &BorrowedSpecifiedValue, specified_value: &BorrowedSpecifiedValue,
specified_values_map: &OrderedMap<&Name, BorrowedSpecifiedValue>, specified_values_map: &OrderedMap<&Name, Option<BorrowedSpecifiedValue>>,
partial_computed_value: Option<&mut ComputedValue>, partial_computed_value: Option<&mut ComputedValue>,
custom_properties_map: &mut CustomPropertiesMap, custom_properties_map: &mut CustomPropertiesMap,
invalid: &mut PrecomputedHashSet<Name>, invalid: &mut PrecomputedHashSet<Name>,
) -> Result<TokenSerializationType, ()> { ) -> Result<TokenSerializationType, ()> {
if let Some(computed_value) = custom_properties_map.get(&name) {
if let Some(partial_computed_value) = partial_computed_value {
partial_computed_value.push_variable(computed_value)
}
return Ok(computed_value.last_token_type)
}
if invalid.contains(name) { if invalid.contains(name) {
return Err(()); return Err(());
} }
let computed_value = if specified_value.references.map_or(false, |set| !set.is_empty()) {
let computed_value = if specified_value.references.is_empty() {
// The specified value contains no var() reference
ComputedValue {
css: specified_value.css.to_owned(),
first_token_type: specified_value.first_token_type,
last_token_type: specified_value.last_token_type,
}
} else {
let mut partial_computed_value = ComputedValue::empty(); let mut partial_computed_value = ComputedValue::empty();
let mut input = ParserInput::new(&specified_value.css); let mut input = ParserInput::new(&specified_value.css);
let mut input = Parser::new(&mut input); let mut input = Parser::new(&mut input);
@ -636,9 +639,15 @@ fn substitute_one(
let result = substitute_block( let result = substitute_block(
&mut input, &mut position, &mut partial_computed_value, &mut input, &mut position, &mut partial_computed_value,
&mut |name, partial_computed_value| { &mut |name, partial_computed_value| {
if let Some(other_specified_value) = specified_values_map.get(&name) { if let Some(other_specified_value) = specified_values_map.get(&name).and_then(|v| v.as_ref()) {
substitute_one(name, other_specified_value, specified_values_map, substitute_one(
Some(partial_computed_value), custom_properties_map, invalid) name,
other_specified_value,
specified_values_map,
Some(partial_computed_value),
custom_properties_map,
invalid,
)
} else { } else {
Err(()) Err(())
} }
@ -651,13 +660,6 @@ fn substitute_one(
invalid.insert(name.clone()); invalid.insert(name.clone());
return Err(()) return Err(())
} }
} else {
// The specified value contains no var() reference
ComputedValue {
css: specified_value.css.to_owned(),
first_token_type: specified_value.first_token_type,
last_token_type: specified_value.last_token_type,
}
}; };
if let Some(partial_computed_value) = partial_computed_value { if let Some(partial_computed_value) = partial_computed_value {
partial_computed_value.push_variable(&computed_value) partial_computed_value.push_variable(&computed_value)