@@ -1258,6 +1258,8 @@ impl PikeVM {
1258
1258
Some ( config) => config,
1259
1259
} ;
1260
1260
1261
+ let maximum_look_behind_len = self . nfa . maximum_look_behind_len ( ) ;
1262
+
1261
1263
let pre =
1262
1264
if anchored { None } else { self . get_config ( ) . get_prefilter ( ) } ;
1263
1265
let Cache {
@@ -1274,7 +1276,14 @@ impl PikeVM {
1274
1276
if let Some ( active) = match_lookaround {
1275
1277
* curr_lookaround = active. clone ( ) ;
1276
1278
} else if self . lookaround_count ( ) > 0 {
1277
- // This initializes the look-behind threads from the start of the input
1279
+ // If we know the maximum look-behind length, we do not need to
1280
+ // start from 0.
1281
+ let start_position = usize:: saturating_sub (
1282
+ input. start ( ) ,
1283
+ maximum_look_behind_len. unwrap_or ( input. start ( ) ) ,
1284
+ ) ;
1285
+
1286
+ // This initializes the look-behind threads from the `start_position`
1278
1287
// Note: since capture groups are not allowed inside look-behinds,
1279
1288
// there won't be any Capture epsilon transitions and hence it is ok to
1280
1289
// use &mut [] for the slots parameter. We need to add the start states
@@ -1289,14 +1298,14 @@ impl PikeVM {
1289
1298
curr_lookaround,
1290
1299
lookaround,
1291
1300
input,
1292
- 0 ,
1301
+ start_position ,
1293
1302
* look_behind_start,
1294
1303
) ;
1295
1304
}
1296
1305
// This is necessary for look-behinds to be able to match outside of the
1297
1306
// input span.
1298
1307
self . fast_forward_lookbehinds (
1299
- Span { start : 0 , end : input. start ( ) } ,
1308
+ Span { start : start_position , end : input. start ( ) } ,
1300
1309
input,
1301
1310
stack,
1302
1311
curr_lookaround,
@@ -1346,10 +1355,46 @@ impl PikeVM {
1346
1355
None => break ,
1347
1356
Some ( ref span) => {
1348
1357
if self . lookaround_count ( ) > 0 {
1358
+ // If we know the maximum look-behind length,
1359
+ // we might be able to catch up the look-behind
1360
+ // threads later than starting at `at`.
1361
+ let start_position = usize:: max (
1362
+ at,
1363
+ usize:: saturating_sub (
1364
+ span. start ,
1365
+ maximum_look_behind_len
1366
+ . unwrap_or ( span. start ) ,
1367
+ ) ,
1368
+ ) ;
1369
+ // If we resume from later than `at`, we need
1370
+ // to reinitialize the look-behind threads.
1371
+ if start_position != at {
1372
+ curr_lookaround. set . clear ( ) ;
1373
+ for look_behind_start in self
1374
+ . nfa
1375
+ . look_behind_starts ( )
1376
+ . iter ( )
1377
+ . rev ( )
1378
+ {
1379
+ self . epsilon_closure (
1380
+ stack,
1381
+ & mut [ ] ,
1382
+ curr_lookaround,
1383
+ lookaround,
1384
+ input,
1385
+ start_position,
1386
+ * look_behind_start,
1387
+ ) ;
1388
+ }
1389
+ }
1390
+
1349
1391
// We are jumping ahead due to the pre-filter, thus we must bring
1350
1392
// the look-behind threads to the new position.
1351
1393
self . fast_forward_lookbehinds (
1352
- Span { start : at, end : span. start } ,
1394
+ Span {
1395
+ start : start_position,
1396
+ end : span. start ,
1397
+ } ,
1353
1398
input,
1354
1399
stack,
1355
1400
curr_lookaround,
0 commit comments