@@ -48,7 +48,7 @@ use core::fmt;
48
48
use core:: hash;
49
49
#[ cfg( not( no_global_oom_handling) ) ]
50
50
use core:: iter:: FromIterator ;
51
- use core:: iter:: FusedIterator ;
51
+ use core:: iter:: { from_fn , FusedIterator } ;
52
52
#[ cfg( not( no_global_oom_handling) ) ]
53
53
use core:: ops:: Add ;
54
54
#[ cfg( not( no_global_oom_handling) ) ]
@@ -1290,32 +1290,49 @@ impl String {
1290
1290
{
1291
1291
use core:: str:: pattern:: Searcher ;
1292
1292
1293
- let matches = {
1293
+ let rejections = {
1294
1294
let mut searcher = pat. into_searcher ( self ) ;
1295
- let mut matches = Vec :: new ( ) ;
1296
-
1297
- while let Some ( m) = searcher. next_match ( ) {
1298
- matches. push ( m) ;
1299
- }
1300
-
1301
- matches
1295
+ // Per Searcher::next:
1296
+ //
1297
+ // A Match result needs to contain the whole matched pattern,
1298
+ // however Reject results may be split up into arbitrary many
1299
+ // adjacent fragments. Both ranges may have zero length.
1300
+ //
1301
+ // In practice the implementation of Searcher::next_match tends to
1302
+ // be more efficient, so we use it here and do some work to invert
1303
+ // matches into rejections since that's what we want to copy below.
1304
+ let mut front = 0 ;
1305
+ let rejections: Vec < _ > = from_fn ( || {
1306
+ let ( start, end) = searcher. next_match ( ) ?;
1307
+ let prev_front = front;
1308
+ front = end;
1309
+ Some ( ( prev_front, start) )
1310
+ } )
1311
+ . collect ( ) ;
1312
+ rejections. into_iter ( ) . chain ( core:: iter:: once ( ( front, self . len ( ) ) ) )
1302
1313
} ;
1303
1314
1304
- let len = self . len ( ) ;
1305
- let mut shrunk_by = 0 ;
1315
+ let mut len = 0 ;
1316
+ let ptr = self . vec . as_mut_ptr ( ) ;
1317
+
1318
+ for ( start, end) in rejections {
1319
+ let count = end - start;
1320
+ if start != len {
1321
+ // SAFETY: per Searcher::next:
1322
+ //
1323
+ // The stream of Match and Reject values up to a Done will
1324
+ // contain index ranges that are adjacent, non-overlapping,
1325
+ // covering the whole haystack, and laying on utf8
1326
+ // boundaries.
1327
+ unsafe {
1328
+ ptr:: copy ( ptr. add ( start) , ptr. add ( len) , count) ;
1329
+ }
1330
+ }
1331
+ len += count;
1332
+ }
1306
1333
1307
- // SAFETY: start and end will be on utf8 byte boundaries per
1308
- // the Searcher docs
1309
1334
unsafe {
1310
- for ( start, end) in matches {
1311
- ptr:: copy (
1312
- self . vec . as_mut_ptr ( ) . add ( end - shrunk_by) ,
1313
- self . vec . as_mut_ptr ( ) . add ( start - shrunk_by) ,
1314
- len - end,
1315
- ) ;
1316
- shrunk_by += end - start;
1317
- }
1318
- self . vec . set_len ( len - shrunk_by) ;
1335
+ self . vec . set_len ( len) ;
1319
1336
}
1320
1337
}
1321
1338
0 commit comments