Bug 1397614 part 2. Avoid array overallocation when parsing background shorthand. r=xidorn draft
authorBoris Zbarsky <bzbarsky@mit.edu>
Sat, 09 Sep 2017 04:04:01 -0400
changeset 661896 356e1fcb871795306f851685b0377e1c67b7fc23
parent 661895 b6b65bad2dad97d71772b488d7cb349ae5c32979
child 661897 17bea77a2a7c0d2864eef89a870eed0bf7b480a8
push id78896
push userbzbarsky@mozilla.com
push dateSat, 09 Sep 2017 08:05:00 +0000
reviewersxidorn
bugs1397614
milestone57.0a1
Bug 1397614 part 2. Avoid array overallocation when parsing background shorthand. r=xidorn MozReview-Commit-ID: CX0hjjsSKXs
servo/components/style/properties/shorthand/background.mako.rs
servo/components/style/properties/shorthand/mask.mako.rs
--- a/servo/components/style/properties/shorthand/background.mako.rs
+++ b/servo/components/style/properties/shorthand/background.mako.rs
@@ -32,17 +32,21 @@
         }
     }
 
     pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
                                -> Result<Longhands, ParseError<'i>> {
         let mut background_color = None;
 
         % for name in "image position_x position_y repeat size attachment origin clip".split():
-            let mut background_${name} = background_${name}::SpecifiedValue(Vec::new());
+            // Vec grows from 0 to 4 by default on first push().  So allocate
+            // with capacity 1, so in the common case of only one item we don't
+            // way overallocate.  Note that we always push at least one item if
+            // parsing succeeds.
+            let mut background_${name} = background_${name}::SpecifiedValue(Vec::with_capacity(1));
         % endfor
         input.parse_comma_separated(|input| {
             // background-color can only be in the last element, so if it
             // is parsed anywhere before, the value is invalid.
             if background_color.is_some() {
                 return Err(StyleParseError::UnspecifiedError.into());
             }
 
@@ -192,18 +196,22 @@
                     sub_properties="background-position-x background-position-y"
                     spec="https://drafts.csswg.org/css-backgrounds-4/#the-background-position">
     use properties::longhands::{background_position_x, background_position_y};
     use values::specified::AllowQuirks;
     use values::specified::position::Position;
 
     pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
                                -> Result<Longhands, ParseError<'i>> {
-        let mut position_x = background_position_x::SpecifiedValue(Vec::new());
-        let mut position_y = background_position_y::SpecifiedValue(Vec::new());
+        // Vec grows from 0 to 4 by default on first push().  So allocate with
+        // capacity 1, so in the common case of only one item we don't way
+        // overallocate.  Note that we always push at least one item if parsing
+        // succeeds.
+        let mut position_x = background_position_x::SpecifiedValue(Vec::with_capacity(1));
+        let mut position_y = background_position_y::SpecifiedValue(Vec::with_capacity(1));
         let mut any = false;
 
         input.parse_comma_separated(|input| {
             let value = Position::parse_quirky(context, input, AllowQuirks::Yes)?;
             position_x.0.push(value.horizontal);
             position_y.0.push(value.vertical);
             any = true;
             Ok(())
--- a/servo/components/style/properties/shorthand/mask.mako.rs
+++ b/servo/components/style/properties/shorthand/mask.mako.rs
@@ -33,17 +33,21 @@
                 % endif
             }
         }
     }
 
     pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
                                -> Result<Longhands, ParseError<'i>> {
         % for name in "image mode position_x position_y size repeat origin clip composite".split():
-            let mut mask_${name} = mask_${name}::SpecifiedValue(Vec::new());
+            // Vec grows from 0 to 4 by default on first push().  So allocate
+            // with capacity 1, so in the common case of only one item we don't
+            // way overallocate.  Note that we always push at least one item if
+            // parsing succeeds.
+            let mut mask_${name} = mask_${name}::SpecifiedValue(Vec::with_capacity(1));
         % endfor
 
         input.parse_comma_separated(|input| {
             % for name in "image mode position size repeat origin clip composite".split():
                 let mut ${name} = None;
             % endfor
             loop {
                 if image.is_none() {
@@ -178,18 +182,22 @@
                     sub_properties="mask-position-x mask-position-y"
                     spec="https://drafts.csswg.org/css-masks-4/#the-mask-position">
     use properties::longhands::{mask_position_x,mask_position_y};
     use values::specified::position::Position;
     use parser::Parse;
 
     pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
                                -> Result<Longhands, ParseError<'i>> {
-        let mut position_x = mask_position_x::SpecifiedValue(Vec::new());
-        let mut position_y = mask_position_y::SpecifiedValue(Vec::new());
+        // Vec grows from 0 to 4 by default on first push().  So allocate with
+        // capacity 1, so in the common case of only one item we don't way
+        // overallocate.  Note that we always push at least one item if parsing
+        // succeeds.
+        let mut position_x = mask_position_x::SpecifiedValue(Vec::with_capacity(1));
+        let mut position_y = mask_position_y::SpecifiedValue(Vec::with_capacity(1));
         let mut any = false;
 
         input.parse_comma_separated(|input| {
             let value = Position::parse(context, input)?;
             position_x.0.push(value.horizontal);
             position_y.0.push(value.vertical);
             any = true;
             Ok(())