From d7529c32650b5f5c2d3c238e3eb17c8a3d750785 Mon Sep 17 00:00:00 2001 From: Will Lillis Date: Mon, 7 Jul 2025 21:56:42 -0400 Subject: [PATCH] perf: reserve `Vec` capacities where appropriate (cherry picked from commit 1e7d77c5177cc79c4b4d781698cd245499671c53) --- cli/generate/src/build_tables/build_parse_table.rs | 2 +- cli/generate/src/parse_grammar.rs | 3 +-- cli/generate/src/prepare_grammar/expand_tokens.rs | 6 +++--- cli/generate/src/prepare_grammar/extract_tokens.rs | 6 +++--- cli/generate/src/prepare_grammar/flatten_grammar.rs | 9 +++++---- cli/generate/src/prepare_grammar/intern_symbols.rs | 4 ++-- cli/generate/src/render.rs | 11 ++++++++--- cli/src/fuzz/mod.rs | 5 +++-- cli/src/fuzz/random.rs | 2 +- cli/src/highlight.rs | 2 +- cli/src/tests/corpus_test.rs | 5 +++-- cli/src/tests/highlight_test.rs | 2 +- 12 files changed, 32 insertions(+), 25 deletions(-) diff --git a/cli/generate/src/build_tables/build_parse_table.rs b/cli/generate/src/build_tables/build_parse_table.rs index c41c4838..67f84df0 100644 --- a/cli/generate/src/build_tables/build_parse_table.rs +++ b/cli/generate/src/build_tables/build_parse_table.rs @@ -908,7 +908,7 @@ impl<'a> ParseTableBuilder<'a> { let get_rule_names = |items: &[&ParseItem]| -> Vec { let mut last_rule_id = None; - let mut result = Vec::new(); + let mut result = Vec::with_capacity(items.len()); for item in items { if last_rule_id == Some(item.variable_index) { continue; diff --git a/cli/generate/src/parse_grammar.rs b/cli/generate/src/parse_grammar.rs index 0b8de958..3448ed30 100644 --- a/cli/generate/src/parse_grammar.rs +++ b/cli/generate/src/parse_grammar.rs @@ -272,12 +272,11 @@ pub(crate) fn parse_grammar(input: &str) -> ParseGrammarResult { .reserved .into_iter() .map(|(name, rule_values)| { - let mut reserved_words = Vec::new(); - let Value::Array(rule_values) = rule_values else { Err(ParseGrammarError::InvalidReservedWordSet)? }; + let mut reserved_words = Vec::with_capacity(rule_values.len()); for value in rule_values { reserved_words.push(parse_rule(serde_json::from_value(value)?, false)?); } diff --git a/cli/generate/src/prepare_grammar/expand_tokens.rs b/cli/generate/src/prepare_grammar/expand_tokens.rs index ed4774d4..2762b41c 100644 --- a/cli/generate/src/prepare_grammar/expand_tokens.rs +++ b/cli/generate/src/prepare_grammar/expand_tokens.rs @@ -90,7 +90,7 @@ pub fn expand_tokens(mut grammar: ExtractedLexicalGrammar) -> ExpandTokensResult Rule::repeat(Rule::choice(grammar.separators)) }; - let mut variables = Vec::new(); + let mut variables = Vec::with_capacity(grammar.variables.len()); for (i, variable) in grammar.variables.into_iter().enumerate() { if variable.rule.is_empty() { Err(ExpandTokensError::EmptyString(variable.name.clone()))?; @@ -195,7 +195,7 @@ impl NfaBuilder { Ok(!s.is_empty()) } Rule::Choice(elements) => { - let mut alternative_state_ids = Vec::new(); + let mut alternative_state_ids = Vec::with_capacity(elements.len()); for element in elements { if self.expand_rule(element, next_state_id)? { alternative_state_ids.push(self.nfa.last_state_id()); @@ -338,7 +338,7 @@ impl NfaBuilder { Ok(result) } HirKind::Alternation(alternations) => { - let mut alternative_state_ids = Vec::new(); + let mut alternative_state_ids = Vec::with_capacity(alternations.len()); for hir in alternations { if self.expand_regex(hir, next_state_id)? { alternative_state_ids.push(self.nfa.last_state_id()); diff --git a/cli/generate/src/prepare_grammar/extract_tokens.rs b/cli/generate/src/prepare_grammar/extract_tokens.rs index c66b7029..579ded06 100644 --- a/cli/generate/src/prepare_grammar/extract_tokens.rs +++ b/cli/generate/src/prepare_grammar/extract_tokens.rs @@ -86,7 +86,7 @@ pub(super) fn extract_tokens( // that pointed to that variable will need to be updated to point to the // variable in the lexical grammar. Symbols that pointed to later variables // will need to have their indices decremented. - let mut variables = Vec::new(); + let mut variables = Vec::with_capacity(grammar.variables.len()); let mut symbol_replacer = SymbolReplacer { replacements: HashMap::new(), }; @@ -200,9 +200,9 @@ pub(super) fn extract_tokens( word_token = Some(token); } - let mut reserved_word_contexts = Vec::new(); + let mut reserved_word_contexts = Vec::with_capacity(grammar.reserved_word_sets.len()); for reserved_word_context in grammar.reserved_word_sets { - let mut reserved_words = Vec::new(); + let mut reserved_words = Vec::with_capacity(reserved_word_contexts.len()); for reserved_rule in reserved_word_context.reserved_words { if let Rule::Symbol(symbol) = reserved_rule { reserved_words.push(symbol_replacer.replace_symbol(symbol)); diff --git a/cli/generate/src/prepare_grammar/flatten_grammar.rs b/cli/generate/src/prepare_grammar/flatten_grammar.rs index bffd3ef9..954902e3 100644 --- a/cli/generate/src/prepare_grammar/flatten_grammar.rs +++ b/cli/generate/src/prepare_grammar/flatten_grammar.rs @@ -57,8 +57,9 @@ impl RuleFlattener { } fn flatten_variable(&mut self, variable: Variable) -> FlattenGrammarResult { - let mut productions = Vec::new(); - for rule in extract_choices(variable.rule) { + let choices = extract_choices(variable.rule); + let mut productions = Vec::with_capacity(choices.len()); + for rule in choices { let production = self.flatten_rule(rule)?; if !productions.contains(&production) { productions.push(production); @@ -195,7 +196,7 @@ fn extract_choices(rule: Rule) -> Vec { let mut result = vec![Rule::Blank]; for element in elements { let extraction = extract_choices(element); - let mut next_result = Vec::new(); + let mut next_result = Vec::with_capacity(result.len()); for entry in result { for extraction_entry in &extraction { next_result.push(Rule::Seq(vec![entry.clone(), extraction_entry.clone()])); @@ -206,7 +207,7 @@ fn extract_choices(rule: Rule) -> Vec { result } Rule::Choice(elements) => { - let mut result = Vec::new(); + let mut result = Vec::with_capacity(elements.len()); for element in elements { for rule in extract_choices(element) { result.push(rule); diff --git a/cli/generate/src/prepare_grammar/intern_symbols.rs b/cli/generate/src/prepare_grammar/intern_symbols.rs index 6301e462..41a5b56e 100644 --- a/cli/generate/src/prepare_grammar/intern_symbols.rs +++ b/cli/generate/src/prepare_grammar/intern_symbols.rs @@ -65,7 +65,7 @@ pub(super) fn intern_symbols(grammar: &InputGrammar) -> InternSymbolsResult InternSymbolsResult>::new(); for state in self.parse_table.states.iter().skip(self.large_state_count) { small_state_indices.push(next_table_index); diff --git a/cli/src/fuzz/mod.rs b/cli/src/fuzz/mod.rs index efa07d3b..04b4910d 100644 --- a/cli/src/fuzz/mod.rs +++ b/cli/src/fuzz/mod.rs @@ -215,8 +215,9 @@ pub fn fuzz_language_corpus( } // Perform a random series of edits and reparse. - let mut undo_stack = Vec::new(); - for _ in 0..=rand.unsigned(*EDIT_COUNT) { + let edit_count = rand.unsigned(*EDIT_COUNT); + let mut undo_stack = Vec::with_capacity(edit_count); + for _ in 0..=edit_count { let edit = get_random_edit(&mut rand, &input); undo_stack.push(invert_edit(&input, &edit)); perform_edit(&mut tree, &mut input, &edit).unwrap(); diff --git a/cli/src/fuzz/random.rs b/cli/src/fuzz/random.rs index 8a8410f4..7b2ede62 100644 --- a/cli/src/fuzz/random.rs +++ b/cli/src/fuzz/random.rs @@ -20,8 +20,8 @@ impl Rand { } pub fn words(&mut self, max_count: usize) -> Vec { - let mut result = Vec::new(); let word_count = self.unsigned(max_count); + let mut result = Vec::with_capacity(2 * word_count); for i in 0..word_count { if i > 0 { if self.unsigned(5) == 0 { diff --git a/cli/src/highlight.rs b/cli/src/highlight.rs index 13cf932e..abb64020 100644 --- a/cli/src/highlight.rs +++ b/cli/src/highlight.rs @@ -83,8 +83,8 @@ impl<'de> Deserialize<'de> for Theme { let mut styles = Vec::new(); let mut highlight_names = Vec::new(); if let Ok(colors) = BTreeMap::::deserialize(deserializer) { - highlight_names.reserve(colors.len()); styles.reserve(colors.len()); + highlight_names.reserve(colors.len()); for (name, style_value) in colors { let mut style = Style::default(); parse_style(&mut style, style_value); diff --git a/cli/src/tests/corpus_test.rs b/cli/src/tests/corpus_test.rs index 9b0ea8ba..9e557945 100644 --- a/cli/src/tests/corpus_test.rs +++ b/cli/src/tests/corpus_test.rs @@ -243,8 +243,9 @@ pub fn test_language_corpus( } // Perform a random series of edits and reparse. - let mut undo_stack = Vec::new(); - for _ in 0..=rand.unsigned(*EDIT_COUNT) { + let edit_count = rand.unsigned(*EDIT_COUNT); + let mut undo_stack = Vec::with_capacity(edit_count); + for _ in 0..=edit_count { let edit = get_random_edit(&mut rand, &input); undo_stack.push(invert_edit(&input, &edit)); perform_edit(&mut tree, &mut input, &edit).unwrap(); diff --git a/cli/src/tests/highlight_test.rs b/cli/src/tests/highlight_test.rs index 8a9c1ffa..76c43f43 100644 --- a/cli/src/tests/highlight_test.rs +++ b/cli/src/tests/highlight_test.rs @@ -597,7 +597,7 @@ fn test_highlighting_via_c_api() { let output_line_offsets = unsafe { slice::from_raw_parts(output_line_offsets, output_line_count as usize) }; - let mut lines = Vec::new(); + let mut lines = Vec::with_capacity(output_line_count as usize); for i in 0..(output_line_count as usize) { let line_start = output_line_offsets[i] as usize; let line_end = output_line_offsets