Skip to content

Commit ce91ddc

Browse files
authored
Optimize Loc Lookups (dlang#21088)
1 parent 13b0745 commit ce91ddc

File tree

1 file changed

+107
-2
lines changed

1 file changed

+107
-2
lines changed

compiler/src/dmd/location.d

Lines changed: 107 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,11 @@ struct BaseLoc
366366
uint[] lines; /// For each line, the file offset at which it starts. At index 0 there's always a 0 entry.
367367
BaseLoc[] substitutions; /// Substitutions from #line / #file directives
368368

369+
/// Cache for the last line lookup
370+
private size_t lastLineIndex = 0;
371+
/// Cache for the last substitution lookup
372+
private size_t lastSubstIndex = 0;
373+
369374
/// Register that a new line starts at `offset` bytes from the start of the source file
370375
void newLine(uint offset)
371376
{
@@ -421,16 +426,72 @@ struct BaseLoc
421426

422427
private size_t getSubstitutionIndex(uint offset) @nogc
423428
{
429+
if (substitutions.length <= 1)
430+
return 0;
431+
432+
// Check if the offset falls within the current cached substitution or the next one
433+
if (lastSubstIndex < substitutions.length - 1)
434+
{
435+
// For the current substitution's range
436+
if (substitutions[lastSubstIndex].startIndex <= offset &&
437+
(lastSubstIndex == substitutions.length - 1 ||
438+
substitutions[lastSubstIndex + 1].startIndex > offset))
439+
return lastSubstIndex;
440+
441+
// For the next substitution's range
442+
if (lastSubstIndex + 1 < substitutions.length - 1 &&
443+
substitutions[lastSubstIndex + 1].startIndex <= offset &&
444+
substitutions[lastSubstIndex + 2].startIndex > offset)
445+
{
446+
lastSubstIndex++;
447+
return lastSubstIndex;
448+
}
449+
450+
// For the previous substitution's range
451+
if (lastSubstIndex > 0 &&
452+
substitutions[lastSubstIndex - 1].startIndex <= offset &&
453+
substitutions[lastSubstIndex].startIndex > offset)
454+
{
455+
lastSubstIndex--;
456+
return lastSubstIndex;
457+
}
458+
}
459+
else if (lastSubstIndex == substitutions.length - 1 &&
460+
substitutions[lastSubstIndex].startIndex <= offset)
461+
{
462+
// Last substitution case
463+
return lastSubstIndex;
464+
}
465+
466+
// Fall back to binary search, but start near
424467
size_t lo = 0;
425-
size_t hi = substitutions.length + -1;
468+
size_t hi = substitutions.length - 1;
469+
470+
// Adjust the range based on the offset relative to lastSubstIndex
471+
if (offset < substitutions[lastSubstIndex].startIndex)
472+
{
473+
// Search backward
474+
lo = 0;
475+
hi = lastSubstIndex;
476+
}
477+
else
478+
{
479+
// Search forward
480+
lo = lastSubstIndex;
481+
hi = substitutions.length - 1;
482+
}
483+
426484
size_t mid = 0;
427485
while (lo <= hi)
428486
{
429487
mid = lo + (hi - lo) / 2;
430488
if (substitutions[mid].startIndex <= offset)
431489
{
432490
if (mid == substitutions.length - 1 || substitutions[mid + 1].startIndex > offset)
491+
{
492+
lastSubstIndex = mid; // Update cache
433493
return mid;
494+
}
434495

435496
lo = mid + 1;
436497
}
@@ -443,18 +504,62 @@ struct BaseLoc
443504
}
444505

445506
/// Binary search the index in `this.lines` corresponding to `offset`
507+
/// lastLineIndex cache to avoid full binary search when possible
446508
private size_t getLineIndex(uint offset) @nogc
447509
{
510+
if (lines.length <= 1)
511+
return 0;
512+
513+
if (lastLineIndex < lines.length - 1)
514+
{
515+
if (lines[lastLineIndex] <= offset && offset < lines[lastLineIndex + 1])
516+
return lastLineIndex;
517+
518+
if (lastLineIndex + 1 < lines.length - 1 &&
519+
lines[lastLineIndex + 1] <= offset && offset < lines[lastLineIndex + 2])
520+
{
521+
lastLineIndex++;
522+
return lastLineIndex;
523+
}
524+
525+
if (lastLineIndex > 0 &&
526+
lines[lastLineIndex - 1] <= offset && offset < lines[lastLineIndex])
527+
{
528+
lastLineIndex--;
529+
return lastLineIndex;
530+
}
531+
}
532+
else if (lastLineIndex == lines.length - 1 && lines[lastLineIndex] <= offset)
533+
{
534+
return lastLineIndex;
535+
}
536+
537+
// Fall back to binary search
448538
size_t lo = 0;
449-
size_t hi = lines.length + -1;
539+
size_t hi = lines.length - 1;
540+
541+
if (offset < lines[lastLineIndex])
542+
{
543+
lo = 0;
544+
hi = lastLineIndex;
545+
}
546+
else
547+
{
548+
lo = lastLineIndex;
549+
hi = lines.length - 1;
550+
}
551+
450552
size_t mid = 0;
451553
while (lo <= hi)
452554
{
453555
mid = lo + (hi - lo) / 2;
454556
if (lines[mid] <= offset)
455557
{
456558
if (mid == lines.length - 1 || lines[mid + 1] > offset)
559+
{
560+
lastLineIndex = mid; // Update cache
457561
return mid;
562+
}
458563

459564
lo = mid + 1;
460565
}

0 commit comments

Comments
 (0)