@@ -189,7 +189,7 @@ STRINGLIB(_lex_search)(const STRINGLIB_CHAR *needle, Py_ssize_t len_needle,
189
189
Py_ssize_t period = 1 ;
190
190
191
191
while (candidate + k < len_needle ) {
192
- // loop increases candidate + k by 1 at each step
192
+ // each loop increases candidate + k + max_suffix
193
193
STRINGLIB_CHAR a = needle [candidate + k ];
194
194
STRINGLIB_CHAR b = needle [max_suffix + k ];
195
195
// check if the suffix at candidate is better than max_suffix
@@ -286,11 +286,11 @@ STRINGLIB(_factorize)(const STRINGLIB_CHAR *needle,
286
286
return cut ;
287
287
}
288
288
289
- #define SHIFT_TYPE uint16_t
289
+ #define SHIFT_TYPE uint8_t
290
290
#define NOT_FOUND ((1U<<(8*sizeof(SHIFT_TYPE))) - 1U)
291
291
#define SHIFT_OVERFLOW (NOT_FOUND - 1U)
292
292
293
- #define TABLE_SIZE_BITS 7
293
+ #define TABLE_SIZE_BITS 6
294
294
#define TABLE_SIZE (1U << TABLE_SIZE_BITS)
295
295
#define TABLE_MASK (TABLE_SIZE - 1U)
296
296
@@ -315,8 +315,14 @@ STRINGLIB(_preprocess)(const STRINGLIB_CHAR *needle, Py_ssize_t len_needle,
315
315
p -> is_periodic = (0 == memcmp (needle ,
316
316
needle + p -> period ,
317
317
p -> cut * STRINGLIB_SIZEOF_CHAR ));
318
- assert (!p -> is_periodic || (p -> cut <= len_needle /2
319
- && p -> cut < p -> period ));
318
+ if (p -> is_periodic ) {
319
+ assert (p -> cut <= len_needle /2 );
320
+ assert (p -> cut < p -> period );
321
+ }
322
+ else {
323
+ // A lower bound on the period
324
+ p -> period = Py_MAX (p -> cut , len_needle - p -> cut ) + 1 ;
325
+ }
320
326
// Now fill up a table
321
327
memset (& (p -> table [0 ]), 0xff , TABLE_SIZE * sizeof (SHIFT_TYPE ));
322
328
assert (p -> table [0 ] == NOT_FOUND );
@@ -344,11 +350,13 @@ STRINGLIB(_two_way)(const STRINGLIB_CHAR *haystack, Py_ssize_t len_haystack,
344
350
const STRINGLIB_CHAR * needle = p -> needle ;
345
351
const STRINGLIB_CHAR * window = haystack ;
346
352
const STRINGLIB_CHAR * last_window = haystack + len_haystack - len_needle ;
353
+ SHIFT_TYPE * table = p -> table ;
347
354
LOG ("===== Two-way: \"%s\" in \"%s\". =====\n" , needle , haystack );
348
355
349
356
if (p -> is_periodic ) {
350
357
LOG ("Needle is periodic.\n" );
351
358
Py_ssize_t memory = 0 ;
359
+ periodicwindowloop :
352
360
while (window <= last_window ) {
353
361
Py_ssize_t i = Py_MAX (cut , memory );
354
362
@@ -364,7 +372,7 @@ STRINGLIB(_two_way)(const STRINGLIB_CHAR *haystack, Py_ssize_t len_haystack,
364
372
// as well jump to line up the character *after* the
365
373
// current window.
366
374
STRINGLIB_CHAR first_outside = window [len_needle ];
367
- SHIFT_TYPE shift = p -> table [first_outside & TABLE_MASK ];
375
+ SHIFT_TYPE shift = table [first_outside & TABLE_MASK ];
368
376
if (shift == NOT_FOUND ) {
369
377
LOG ("\"%c\" not found. Skipping entirely.\n" ,
370
378
first_outside );
@@ -376,42 +384,36 @@ STRINGLIB(_two_way)(const STRINGLIB_CHAR *haystack, Py_ssize_t len_haystack,
376
384
window += Py_MAX (shift , memory_shift );
377
385
}
378
386
memory = 0 ;
379
- continue ;
387
+ goto periodicwindowloop ;
380
388
}
381
-
382
- i ++ ;
383
- while (i < len_needle && needle [i ] == window [i ]) {
384
- i ++ ;
385
- }
386
- if (i >= len_needle ) {
387
- LOG ("Right half matches.\n" );
388
- i = cut - 1 ;
389
- while (i >= memory && needle [i ] == window [i ]) {
390
- i -- ;
389
+ for (i = i + 1 ; i < len_needle ; i ++ ) {
390
+ if (needle [i ] != window [i ]) {
391
+ LOG ("Right half does not match. Jump ahead by %d.\n" ,
392
+ i - cut + 1 );
393
+ window += i - cut + 1 ;
394
+ memory = 0 ;
395
+ goto periodicwindowloop ;
391
396
}
392
- if (i < memory ) {
393
- LOG ("Left half matches. Returning %d.\n" ,
394
- window - haystack );
395
- return window - haystack ;
396
- }
397
- LOG ("Left half does not match. Jump ahead by period %d.\n" ,
398
- period );
399
- window += period ;
400
- memory = len_needle - period ;
401
397
}
402
- else {
403
- LOG ("Right half does not match. Jump ahead by %d.\n" ,
404
- i - cut + 1 );
405
- window += i - cut + 1 ;
406
- memory = 0 ;
398
+ for (i = memory ; i < cut ; i ++ ) {
399
+ if (needle [i ] != window [i ]) {
400
+ LOG ("Left half does not match. Jump ahead by period %d.\n" ,
401
+ period );
402
+ window += period ;
403
+ memory = len_needle - period ;
404
+ goto periodicwindowloop ;
405
+ }
407
406
}
407
+ LOG ("Left half matches. Returning %d.\n" ,
408
+ window - haystack );
409
+ return window - haystack ;
408
410
}
409
411
}
410
412
else {
411
- period = Py_MAX (cut , len_needle - cut ) + 1 ;
412
413
LOG ("Needle is not periodic.\n" );
413
414
assert (cut < len_needle );
414
415
STRINGLIB_CHAR needle_cut = needle [cut ];
416
+ windowloop :
415
417
while (window <= last_window ) {
416
418
417
419
// Visualize the line-up:
@@ -426,7 +428,7 @@ STRINGLIB(_two_way)(const STRINGLIB_CHAR *haystack, Py_ssize_t len_haystack,
426
428
// as well jump to line up the character *after* the
427
429
// current window.
428
430
STRINGLIB_CHAR first_outside = window [len_needle ];
429
- SHIFT_TYPE shift = p -> table [first_outside & TABLE_MASK ];
431
+ SHIFT_TYPE shift = table [first_outside & TABLE_MASK ];
430
432
if (shift == NOT_FOUND ) {
431
433
LOG ("\"%c\" not found. Skipping entirely.\n" ,
432
434
first_outside );
@@ -436,33 +438,26 @@ STRINGLIB(_two_way)(const STRINGLIB_CHAR *haystack, Py_ssize_t len_haystack,
436
438
LOG ("Shifting to line up \"%c\".\n" , first_outside );
437
439
window += shift ;
438
440
}
439
- continue ;
440
- }
441
-
442
- Py_ssize_t i = cut + 1 ;
443
- while (i < len_needle && needle [i ] == window [i ]) {
444
- i ++ ;
441
+ goto windowloop ;
445
442
}
446
- if (i >= len_needle ) {
447
- LOG ("Right half matches.\n" );
448
- i = cut - 1 ;
449
- while (i >= 0 && needle [i ] == window [i ]) {
450
- i -- ;
443
+ for (Py_ssize_t i = cut + 1 ; i < len_needle ; i ++ ) {
444
+ if (needle [i ] != window [i ]) {
445
+ LOG ("Right half does not match. Advance by %d.\n" ,
446
+ i - cut + 1 );
447
+ window += i - cut + 1 ;
448
+ goto windowloop ;
451
449
}
452
- if (i < 0 ){
453
- LOG ("Left half matches. Returning %d.\n" ,
454
- window - haystack );
455
- return window - haystack ;
456
- }
457
- LOG ("Left half does not match. Advance by period %d.\n" ,
458
- period );
459
- window += period ;
460
450
}
461
- else {
462
- LOG ("Right half does not match. Advance by %d.\n" ,
463
- i - cut + 1 );
464
- window += i - cut + 1 ;
451
+ for (Py_ssize_t i = 0 ; i < cut ; i ++ ) {
452
+ if (needle [i ] != window [i ]) {
453
+ LOG ("Left half does not match. Advance by period %d.\n" ,
454
+ period );
455
+ window += period ;
456
+ goto windowloop ;
457
+ }
465
458
}
459
+ LOG ("Left half matches. Returning %d.\n" , window - haystack );
460
+ return window - haystack ;
466
461
}
467
462
}
468
463
LOG ("Not found. Returning -1.\n" );
0 commit comments