diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e8525909..8d0a0e036 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ TODO Bug fixes: +* [BUG #1116](https://github.com/rust-lang/regex/issues/1116): +Fixes a memory usage regression for large regexes (introduced in `regex 1.9`). * [BUG #1165](https://github.com/rust-lang/regex/issues/1083): Fixes a panic in the lazy DFA (can only occur for especially large regexes). diff --git a/regex-automata/src/meta/wrappers.rs b/regex-automata/src/meta/wrappers.rs index fd1d5a144..6651cb907 100644 --- a/regex-automata/src/meta/wrappers.rs +++ b/regex-automata/src/meta/wrappers.rs @@ -58,7 +58,7 @@ impl PikeVM { } pub(crate) fn create_cache(&self) -> PikeVMCache { - PikeVMCache::new(self) + PikeVMCache::none() } #[cfg_attr(feature = "perf-inline", inline(always))] @@ -93,7 +93,7 @@ impl PikeVMEngine { cache: &mut PikeVMCache, input: &Input<'_>, ) -> bool { - self.0.is_match(cache.0.as_mut().unwrap(), input.clone()) + self.0.is_match(cache.get(&self.0), input.clone()) } #[cfg_attr(feature = "perf-inline", inline(always))] @@ -103,7 +103,7 @@ impl PikeVMEngine { input: &Input<'_>, slots: &mut [Option], ) -> Option { - self.0.search_slots(cache.0.as_mut().unwrap(), input, slots) + self.0.search_slots(cache.get(&self.0), input, slots) } #[cfg_attr(feature = "perf-inline", inline(always))] @@ -113,11 +113,7 @@ impl PikeVMEngine { input: &Input<'_>, patset: &mut PatternSet, ) { - self.0.which_overlapping_matches( - cache.0.as_mut().unwrap(), - input, - patset, - ) + self.0.which_overlapping_matches(cache.get(&self.0), input, patset) } } @@ -129,17 +125,17 @@ impl PikeVMCache { PikeVMCache(None) } - pub(crate) fn new(builder: &PikeVM) -> PikeVMCache { - PikeVMCache(Some(builder.get().0.create_cache())) - } - pub(crate) fn reset(&mut self, builder: &PikeVM) { - self.0.as_mut().unwrap().reset(&builder.get().0); + self.get(&builder.get().0).reset(&builder.get().0); } pub(crate) fn memory_usage(&self) -> usize { self.0.as_ref().map_or(0, |c| c.memory_usage()) } + + fn get(&mut self, vm: &pikevm::PikeVM) -> &mut pikevm::Cache { + self.0.get_or_insert_with(|| vm.create_cache()) + } } #[derive(Debug)] @@ -155,7 +151,7 @@ impl BoundedBacktracker { } pub(crate) fn create_cache(&self) -> BoundedBacktrackerCache { - BoundedBacktrackerCache::new(self) + BoundedBacktrackerCache::none() } #[cfg_attr(feature = "perf-inline", inline(always))] @@ -235,9 +231,7 @@ impl BoundedBacktrackerEngine { // OK because we only permit access to this engine when we know // the haystack is short enough for the backtracker to run without // reporting an error. - self.0 - .try_is_match(cache.0.as_mut().unwrap(), input.clone()) - .unwrap() + self.0.try_is_match(cache.get(&self.0), input.clone()).unwrap() } #[cfg(not(feature = "nfa-backtrack"))] { @@ -259,9 +253,7 @@ impl BoundedBacktrackerEngine { // OK because we only permit access to this engine when we know // the haystack is short enough for the backtracker to run without // reporting an error. - self.0 - .try_search_slots(cache.0.as_mut().unwrap(), input, slots) - .unwrap() + self.0.try_search_slots(cache.get(&self.0), input, slots).unwrap() } #[cfg(not(feature = "nfa-backtrack"))] { @@ -304,25 +296,10 @@ impl BoundedBacktrackerCache { } } - pub(crate) fn new( - builder: &BoundedBacktracker, - ) -> BoundedBacktrackerCache { - #[cfg(feature = "nfa-backtrack")] - { - BoundedBacktrackerCache( - builder.0.as_ref().map(|e| e.0.create_cache()), - ) - } - #[cfg(not(feature = "nfa-backtrack"))] - { - BoundedBacktrackerCache(()) - } - } - pub(crate) fn reset(&mut self, builder: &BoundedBacktracker) { #[cfg(feature = "nfa-backtrack")] if let Some(ref e) = builder.0 { - self.0.as_mut().unwrap().reset(&e.0); + self.get(&e.0).reset(&e.0); } } @@ -336,6 +313,14 @@ impl BoundedBacktrackerCache { 0 } } + + #[cfg(feature = "nfa-backtrack")] + fn get( + &mut self, + bb: &backtrack::BoundedBacktracker, + ) -> &mut backtrack::Cache { + self.0.get_or_insert_with(|| bb.create_cache()) + } } #[derive(Debug)]