Skip to content

Commit b2e8905

Browse files
committed
Make line search logic in SourcePositions generally available.
Create an object Util for utility methods that are used in several places.
1 parent 9641b2a commit b2e8905

File tree

2 files changed

+36
-6
lines changed

2 files changed

+36
-6
lines changed

src/dotty/tools/dotc/util/SourceFile.scala

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,7 @@ case class SourceFile(file: AbstractFile, content: Array[Char]) {
9999
* Lines are numbered from 0
100100
*/
101101
def offsetToLine(offset: Int): Int = {
102-
val lines = lineIndices
103-
def findLine(lo: Int, hi: Int, mid: Int): Int =
104-
if (offset < lines(mid)) findLine(lo, mid - 1, (lo + mid - 1) / 2)
105-
else if (offset >= lines(mid + 1)) findLine(mid + 1, hi, (mid + 1 + hi) / 2)
106-
else mid
107-
lastLine = findLine(0, lines.length, lastLine)
102+
lastLine = Util.bestFit(lineIndices, offset, lastLine)
108103
lastLine
109104
}
110105

src/dotty/tools/dotc/util/Util.scala

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package dotty.tools.dotc.util
2+
import reflect.ClassTag
3+
4+
object Util {
5+
6+
/** The index `i` in `candidates.indices` such that `candidates(i) <= x` and
7+
* `candidates(i)` is closest to `x`, determined by binary search, or -1
8+
* if `x < candidates(0)`.
9+
* @param hint If between 0 and `candidates.length` use this
10+
* as the first search point, otherwise use
11+
* `candidates.length/2`.
12+
* @pre candidates is sorted
13+
* @pre candidates(0) <= x
14+
*/
15+
def bestFit(candidates: Array[Int], x: Int, hint: Int = -1): Int = {
16+
def recur(lo: Int, hi: Int, mid: Int): Int =
17+
if (x < candidates(mid))
18+
recur(lo, mid - 1, (lo + mid - 1) / 2)
19+
else if (mid + 1 < candidates.length && x >= candidates(mid + 1))
20+
recur(mid + 1, hi, (mid + 1 + hi) / 2)
21+
else mid
22+
val initMid =
23+
if (0 <= hint && hint < candidates.length) hint
24+
else candidates.length / 2
25+
if (candidates.isEmpty || x < candidates(0)) -1
26+
else recur(0, candidates.length, initMid)
27+
}
28+
29+
/** An array twice the size of given array, with existing elements copied over */
30+
def dble[T: ClassTag](arr: Array[T]) = {
31+
val arr1 = new Array[T](arr.length * 2)
32+
Array.copy(arr, 0, arr1, 0, arr.length)
33+
arr1
34+
}
35+
}

0 commit comments

Comments
 (0)