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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
type t =
| Str of string * int * int
| App of t * t * int * int
let length = function
| Str (_, _, len)
| App (_, _, len, _) -> len
let empty = Str (String.empty, 0, 0)
let height = function
| Str _ -> 0
| App (_, _, _, h) -> h
let append = function
| Str (_,_,0), t | t, Str (_,_,0) -> t
| t1, t2 ->
App (t1, t2, length t1 + length t2, 1 + Int.max (height t1) (height t2))
let rec unsafe_sub t start stop =
if start == 0 && stop = length t
then t else match t with
| Str (str, off, _) ->
Str (str, off + start, stop - start)
| App (l, r, _, _) ->
let len = length l in
if stop <= len then unsafe_sub l start stop
else if start >= len then unsafe_sub r (start - len) (stop - len)
else append (unsafe_sub l start len, unsafe_sub r 0 (stop - len))
let chop t len =
if len < 0 || len > length t
then invalid_arg "Rope.chop";
if len == 0 then empty else unsafe_sub t 0 len
let shift t len =
if len < 0 then t
else if len == 0 then t
else
let max = length t in
let len = Int.min max len in
unsafe_sub t len (len + (max - len))
let rec into_bytes buf dst_off = function
| Str (str, src_off, len) -> Bytes.blit_string str src_off buf dst_off len
| App (l, r, _, _) ->
into_bytes buf dst_off l;
into_bytes buf (dst_off + length l) r
let to_strings t =
let rec go acc = function
| Str (_, _, 0) -> acc
| Str (str, 0, len) when String.length str == len -> str :: acc
| Str (str, off, len) -> String.sub str off len :: acc
| App (l, r, _, _) -> go (go acc r) l in
go [] t
let to_string t =
let len = length t in
let buf = Bytes.create len in
into_bytes buf 0 t;
Bytes.unsafe_to_string buf
let concat a b = append (a, b)
let prepend str t = append (Str (str, 0, String.length str), t)
let append t ?(off = 0) ?len str =
let len = match len with
| Some len -> len
| None -> String.length str - off
in
append (t, (Str (str, off, len)))
let of_string str = Str (str, 0, String.length str)
let of_strings strs = List.fold_left (fun t str -> append t str) empty strs
let equal a b = String.equal (to_string a) (to_string b)