1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
open Core
type index_t = int array
let empty = [||]
let index ~source =
let total_len = String.length source in
let num_lines = List.length @@ String.split_on_chars source ~on:['\n'] in
let len = num_lines + 1 in
let a = Array.create ~len Int.max_value in
let line_index = ref 1 in
let offset = ref 0 in
let f char =
match char with
| '\n' ->
offset := !offset + 1;
a.(!line_index) <- !offset;
line_index := !line_index + 1;
| _ ->
if !offset = total_len then
a.(!line_index) <- !offset
else
offset := !offset + 1
in
String.iter source ~f;
a
let rec binary_search a value low high =
if high <= low then
(if value >= a.(low) && value < a.(low+1) then
low+1
else
low)
else let mid = (low + high) / 2 in
if a.(mid) > value then
binary_search a value low (mid - 1)
else if a.(mid) < value then
binary_search a value (mid + 1) high
else
mid + 1
let convert_fast ~offset index =
let line = binary_search index offset 1 (Array.length index) in
let col = if line = 0 || line = 1 then offset + 1 else offset - index.(line - 1) + 1 in
line, col
let convert_slow ~offset ~source =
let f (offset, line, col) char =
match offset, char with
| 0, _ -> (0, line, col)
| _, '\n' -> (offset - 1, line + 1, 1)
| _ -> (offset - 1, line, col + 1)
in
let _, line, col = String.fold ~init:(offset, 1, 1) ~f source in
line, col