@@ -16,6 +16,7 @@ use std::{
1616 fs:: File ,
1717 io:: { self , BufRead , BufReader , StdoutLock , Write } ,
1818 path:: { Path , PathBuf } ,
19+ ptr,
1920} ;
2021
2122/// grep - search a file for a pattern.
@@ -303,13 +304,13 @@ impl Patterns {
303304 /// # Returns
304305 ///
305306 /// Returns [bool](bool) - `true` if input matches present patterns, else `false`.
306- fn matches (
307- & self ,
308- input : impl AsRef < str > ,
309- collect_matching_substrings : bool ,
310- ) -> ( bool , Vec < Vec < u8 > > ) {
307+ fn matches ( & self , input : impl AsRef < str > , collect_matching_substrings : bool ) -> MatchesResult {
311308 let input = input. as_ref ( ) ;
312309
310+ let mut matching_substrings = Vec :: < Vec < u8 > > :: new ( ) ;
311+
312+ let mut any_pattern_matched = false ;
313+
313314 match self {
314315 Patterns :: Fixed ( patterns, ignore_case, line_regexp) => {
315316 let input = if * ignore_case {
@@ -318,18 +319,14 @@ impl Patterns {
318319 input. to_string ( )
319320 } ;
320321
321- let mut matching_substrings = Vec :: < Vec < u8 > > :: new ( ) ;
322-
323- let mut any_pattern_matched = false ;
324-
325322 for pattern in patterns {
326323 if * line_regexp {
327324 if input != * pattern {
328325 continue ;
329326 }
330327
331328 if !collect_matching_substrings {
332- return ( true , Vec :: < Vec < u8 > > :: new ( ) ) ;
329+ return MatchesResult :: fast_path_match ( ) ;
333330 }
334331
335332 any_pattern_matched = true ;
@@ -338,7 +335,7 @@ impl Patterns {
338335 } else {
339336 for st in input. matches ( pattern) {
340337 if !collect_matching_substrings {
341- return ( true , Vec :: < Vec < u8 > > :: new ( ) ) ;
338+ return MatchesResult :: fast_path_match ( ) ;
342339 }
343340
344341 any_pattern_matched = true ;
@@ -347,45 +344,45 @@ impl Patterns {
347344 }
348345 }
349346 }
350-
351- ( any_pattern_matched, matching_substrings)
352347 }
353348 Patterns :: Regex ( patterns) => {
354- let nmatch_to_use = if collect_matching_substrings { 1 } else { 0 } ;
349+ const SINGLE_ELEMENT_ARRAY_SIZE : usize = 1_usize ;
355350
356351 let input_slice = input. as_bytes ( ) ;
357352
358- let mut matching_substrings = Vec :: < Vec < u8 > > :: new ( ) ;
353+ let mut regmatch_t_array = [ const {
354+ regmatch_t {
355+ rm_so : -1 ,
356+ rm_eo : -1 ,
357+ }
358+ } ; SINGLE_ELEMENT_ARRAY_SIZE ] ;
359359
360- let mut any_pattern_matched = false ;
360+ let ( nmatch, pmatch) = if collect_matching_substrings {
361+ ( SINGLE_ELEMENT_ARRAY_SIZE , regmatch_t_array. as_mut_ptr ( ) )
362+ } else {
363+ ( 0_usize , ptr:: null_mut ( ) )
364+ } ;
361365
362- for p in patterns {
366+ for pattern in patterns {
363367 let mut current_string_index = 0_usize ;
364368
365369 loop {
370+ // Clear values from the last iteration
371+ if collect_matching_substrings {
372+ let [ ref mut regmatch_t] = regmatch_t_array;
373+
374+ regmatch_t. rm_so = -1 ;
375+ regmatch_t. rm_eo = -1 ;
376+ }
377+
366378 let current_string_slice = & input_slice[ current_string_index..] ;
367379
368380 let current_string_c_string = CString :: new ( current_string_slice) . unwrap ( ) ;
369381
370- let mut regmatch_t_vec = vec ! [
371- regmatch_t {
372- rm_so: -1 ,
373- rm_eo: -1 ,
374- } ;
375- nmatch_to_use
376- ] ;
377-
378- let regmatch_vec_pointer = regmatch_t_vec. as_mut_ptr ( ) ;
379-
380- let regexec_return_value = unsafe {
381- regexec (
382- p,
383- current_string_c_string. as_ptr ( ) ,
384- nmatch_to_use,
385- regmatch_vec_pointer,
386- 0 ,
387- )
388- } ;
382+ let current_string_pointer = current_string_c_string. as_ptr ( ) ;
383+
384+ let regexec_return_value =
385+ unsafe { regexec ( pattern, current_string_pointer, nmatch, pmatch, 0 ) } ;
389386
390387 if regexec_return_value != 0 {
391388 debug_assert ! ( regexec_return_value == REG_NOMATCH ) ;
@@ -394,15 +391,20 @@ impl Patterns {
394391 }
395392
396393 if !collect_matching_substrings {
397- return ( true , Vec :: < Vec < u8 > > :: new ( ) ) ;
394+ return MatchesResult :: fast_path_match ( ) ;
398395 }
399396
400397 any_pattern_matched = true ;
401398
402- let regmatch_t = regmatch_t_vec . first ( ) . unwrap ( ) ;
399+ let [ regmatch_t] = regmatch_t_array ;
403400
404- let start = usize:: try_from ( regmatch_t. rm_so ) . unwrap ( ) ;
405- let end = usize:: try_from ( regmatch_t. rm_eo ) . unwrap ( ) ;
401+ let regmatch_t { rm_so, rm_eo } = regmatch_t;
402+
403+ debug_assert ! ( rm_so != -1 ) ;
404+ debug_assert ! ( rm_eo != -1 ) ;
405+
406+ let start = usize:: try_from ( rm_so) . unwrap ( ) ;
407+ let end = usize:: try_from ( rm_eo) . unwrap ( ) ;
406408
407409 // TODO
408410 // Is this the right fix?
@@ -418,10 +420,13 @@ impl Patterns {
418420 current_string_index += end;
419421 }
420422 }
421-
422- ( any_pattern_matched, matching_substrings)
423423 }
424424 }
425+
426+ MatchesResult {
427+ any_pattern_matched,
428+ matching_substrings,
429+ }
425430 }
426431}
427432
@@ -462,6 +467,21 @@ struct GrepModel {
462467 only_matching : bool ,
463468}
464469
470+ struct MatchesResult {
471+ any_pattern_matched : bool ,
472+ /// Will always be empty if the -o option is not being used
473+ matching_substrings : Vec < Vec < u8 > > ,
474+ }
475+
476+ impl MatchesResult {
477+ pub fn fast_path_match ( ) -> MatchesResult {
478+ MatchesResult {
479+ any_pattern_matched : true ,
480+ matching_substrings : Vec :: < Vec < u8 > > :: new ( ) ,
481+ }
482+ }
483+ }
484+
465485impl GrepModel {
466486 /// Processes input files or STDIN content.
467487 ///
@@ -542,15 +562,20 @@ impl GrepModel {
542562 _ => line. as_str ( ) ,
543563 } ;
544564
545- let ( line_matches_any_pattern , matching_substrings ) = self . patterns . matches (
565+ let matches_result = self . patterns . matches (
546566 line_without_newline,
547567 self . only_matching && matches ! ( self . output_mode, OutputMode :: Default ) ,
548568 ) ;
549569
570+ let MatchesResult {
571+ any_pattern_matched,
572+ matching_substrings,
573+ } = matches_result;
574+
550575 let matches = if self . invert_match {
551- !line_matches_any_pattern
576+ !any_pattern_matched
552577 } else {
553- line_matches_any_pattern
578+ any_pattern_matched
554579 } ;
555580
556581 if matches {
0 commit comments