From d61d9e371515e4672efb8c0b683680cd63ce2086 Mon Sep 17 00:00:00 2001 From: Will Lillis Date: Sun, 1 Mar 2026 15:39:08 -0500 Subject: [PATCH] pointers to map, small perf gain, scales w grammar --- .../src/build_tables/minimize_parse_table.rs | 27 ++++++++++--------- .../src/build_tables/token_conflicts.rs | 4 ++- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/crates/generate/src/build_tables/minimize_parse_table.rs b/crates/generate/src/build_tables/minimize_parse_table.rs index d12bedabe..5a7f407e6 100644 --- a/crates/generate/src/build_tables/minimize_parse_table.rs +++ b/crates/generate/src/build_tables/minimize_parse_table.rs @@ -194,19 +194,22 @@ impl Minimizer<'_> { group_ids_by_state_id.push(state.core_id); } - // Precompute sorted terminal entry indices for merge-join in states_conflict. - // entry_maps[state_id][i] = (symbol_key, index_into_terminal_entries) + // Precompute sorted terminal entry pointers for merge-join in states_conflict. + // entry_maps[state_id][i] = (symbol_key, *const ParseTableEntry) // Keys are packed u64s (symbol_key) for single-instruction comparison. - let entry_maps: Vec> = self + // Storing a raw pointer avoids the IndexMap::get_index call in states_conflict. + // + // Safety invariant: parse_table.states are not mutated during the grouping phase, + // so all pointers remain valid for the lifetime of entry_maps. + let entry_maps: Vec> = self .parse_table .states .iter() .map(|state| { - let mut entries: Vec<(SymbolKey, usize)> = state + let mut entries: Vec<(SymbolKey, *const ParseTableEntry)> = state .terminal_entries .iter() - .enumerate() - .map(|(idx, (sym, _))| (symbol_key(*sym), idx)) + .map(|(sym, entry)| (symbol_key(*sym), entry as *const ParseTableEntry)) .collect(); entries.sort_unstable_by_key(|&(key, _)| key); entries @@ -328,7 +331,7 @@ impl Minimizer<'_> { state1: &ParseState, state2: &ParseState, group_ids_by_state_id: &[ParseStateId], - entry_maps: &[Vec<(SymbolKey, usize)>], + entry_maps: &[Vec<(SymbolKey, *const ParseTableEntry)>], ) -> bool { let entries1 = &entry_maps[state1.id]; let entries2 = &entry_maps[state2.id]; @@ -347,10 +350,10 @@ impl Minimizer<'_> { match ord { Ordering::Equal => { let token = key_symbol(entries1[i].0); - let (_, left_entry) = - state1.terminal_entries.get_index(entries1[i].1).unwrap(); - let (_, right_entry) = - state2.terminal_entries.get_index(entries2[j].1).unwrap(); + // Safety: pointers were taken from the same parse_table.states that + // is not mutated during the grouping phase (see entry_maps comment). + let left_entry = unsafe { &*entries1[i].1 }; + let right_entry = unsafe { &*entries2[j].1 }; if self.entries_conflict( state1.id, state2.id, @@ -517,7 +520,7 @@ impl Minimizer<'_> { left_id: ParseStateId, right_id: ParseStateId, right_state: &ParseState, - right_entry_map: &[(SymbolKey, usize)], + right_entry_map: &[(SymbolKey, *const ParseTableEntry)], new_token: Symbol, ) -> bool { if new_token == Symbol::end_of_nonterminal_extra() { diff --git a/crates/generate/src/build_tables/token_conflicts.rs b/crates/generate/src/build_tables/token_conflicts.rs index 35445ad2b..95d260a95 100644 --- a/crates/generate/src/build_tables/token_conflicts.rs +++ b/crates/generate/src/build_tables/token_conflicts.rs @@ -80,7 +80,9 @@ impl<'a> TokenConflictMap<'a> { #[inline] pub fn does_conflict(&self, i: usize, j: usize) -> bool { - let entry = &self.status_matrix[matrix_index(self.n, i, j)]; + debug_assert!(i < self.n && j < self.n, "token indices out of bounds"); + // Safety: i < n and j < n, so n*i+j < n*n == status_matrix.len(). + let entry = unsafe { self.status_matrix.get_unchecked(matrix_index(self.n, i, j)) }; entry.does_match_valid_continuation || entry.does_match_separators || entry.matches_same_string