perf: reserve Vec capacities where appropriate

(cherry picked from commit 1e7d77c517)
This commit is contained in:
Will Lillis 2025-07-07 21:56:42 -04:00
parent bf4217f0ff
commit d7529c3265
12 changed files with 32 additions and 25 deletions

View file

@ -908,7 +908,7 @@ impl<'a> ParseTableBuilder<'a> {
let get_rule_names = |items: &[&ParseItem]| -> Vec<String> {
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;

View file

@ -272,12 +272,11 @@ pub(crate) fn parse_grammar(input: &str) -> ParseGrammarResult<InputGrammar> {
.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)?);
}

View file

@ -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());

View file

@ -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));

View file

@ -57,8 +57,9 @@ impl RuleFlattener {
}
fn flatten_variable(&mut self, variable: Variable) -> FlattenGrammarResult<SyntaxVariable> {
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<Rule> {
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<Rule> {
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);

View file

@ -65,7 +65,7 @@ pub(super) fn intern_symbols(grammar: &InputGrammar) -> InternSymbolsResult<Inte
let mut reserved_words = Vec::with_capacity(grammar.reserved_words.len());
for reserved_word_set in &grammar.reserved_words {
let mut interned_set = Vec::new();
let mut interned_set = Vec::with_capacity(reserved_word_set.reserved_words.len());
for rule in &reserved_word_set.reserved_words {
interned_set.push(interner.intern_rule(rule, None)?);
}
@ -75,7 +75,7 @@ pub(super) fn intern_symbols(grammar: &InputGrammar) -> InternSymbolsResult<Inte
});
}
let mut expected_conflicts = Vec::new();
let mut expected_conflicts = Vec::with_capacity(grammar.expected_conflicts.len());
for conflict in &grammar.expected_conflicts {
let mut interned_conflict = Vec::with_capacity(conflict.len());
for name in conflict {

View file

@ -678,12 +678,12 @@ impl Generator {
&mut next_flat_field_map_index,
);
let mut field_map_ids = Vec::new();
let mut field_map_ids = Vec::with_capacity(self.parse_table.production_infos.len());
for production_info in &self.parse_table.production_infos {
if production_info.field_map.is_empty() {
field_map_ids.push((0, 0));
} else {
let mut flat_field_map = Vec::new();
let mut flat_field_map = Vec::with_capacity(production_info.field_map.len());
for (field_name, locations) in &production_info.field_map {
for location in locations {
flat_field_map.push((field_name.clone(), *location));
@ -1350,7 +1350,12 @@ impl Generator {
indent!(self);
let mut next_table_index = 0;
let mut small_state_indices = Vec::new();
let mut small_state_indices = Vec::with_capacity(
self.parse_table
.states
.len()
.saturating_sub(self.large_state_count),
);
let mut symbols_by_value = HashMap::<(usize, SymbolType), Vec<Symbol>>::new();
for state in self.parse_table.states.iter().skip(self.large_state_count) {
small_state_indices.push(next_table_index);

View file

@ -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();

View file

@ -20,8 +20,8 @@ impl Rand {
}
pub fn words(&mut self, max_count: usize) -> Vec<u8> {
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 {

View file

@ -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::<String, Value>::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);

View file

@ -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();

View file

@ -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