forked from ahrefs/devkit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
extEnum.ml
173 lines (158 loc) · 4.79 KB
/
extEnum.ml
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
(** Extensions to Enum *)
include Enum
let rec find_peek f e =
match peek e with
| Some x when f x ->
x
| None ->
raise Not_found
| _ ->
junk e;
find_peek f e
let list_loop l =
assert (l <> []);
let r = ref l in
let rec next () =
match !r with
| x :: xs -> r := xs; x
| [] -> r := l; next ()
in
from next
let of_dynarray ?(start=0) ?n d =
let last =
match n with
| None -> DynArray.length d
| Some n -> start + n
in
let rec make start =
let idxref = ref start in
let next () =
if !idxref >= last then
raise Enum.No_more_elements;
let retval = DynArray.get d !idxref in
incr idxref;
retval
and count () =
if !idxref >= last then 0 else last - !idxref
and clone () =
make !idxref
in
Enum.make ~next ~count ~clone
in
make start
let take limit e =
let limit = ref limit in
from begin fun () ->
if 0 = !limit then raise Enum.No_more_elements;
let x = next e in
decr limit;
x
end
let align f e1 e2 =
let next () =
match peek e1, peek e2 with
| None, None -> raise No_more_elements
| Some x, None -> junk e1; x
| None, Some y -> junk e2; y
| Some x, Some y when f x y < 0 -> junk e1; x
| Some _, Some y -> junk e2; y
in
from next
let join ?(left=false) ?(right=false) ?(multi=true) f e1 e2 =
let found = ref false in
let rec next () =
let found' = !found in
found := false;
match peek e1, peek e2 with
| None, None -> raise No_more_elements
| Some _, None as res -> junk e1; if left && not found' then res else next ()
| None, Some _ as res -> junk e2; if right then res else raise No_more_elements
| Some x, Some y as res ->
match f x y with
| n when n < 0 -> junk e1; if left && not found' then Some x, None else next ()
| n when n > 0 -> junk e2; if right then None, Some y else next ()
| _ -> if not multi then junk e1; junk e2; found := multi; res
in
from next
let join_assoc ?(left=false) ?(right=false) ?(multi=true) f e1 e2 =
let found = ref false in
let rec next () =
let found' = !found in
found := false;
match peek e1, peek e2 with
| None, None -> raise No_more_elements
| Some (k, x), None -> junk e1; if left && not found' then k, Some x, None else next ()
| None, Some (k, y) -> junk e2; if right then k, None, Some y else raise No_more_elements
| Some (kx, x), Some (ky, y) ->
match f kx ky with
| n when n < 0 -> junk e1; if left && not found' then kx, Some x, None else next ()
| n when n > 0 -> junk e2; if right then ky, None, Some y else next ()
| _ -> if not multi then junk e1; junk e2; found := multi; kx, Some x, Some y
in
from next
include ExtEnum_merge
let group equal fold zero e =
let current = ref None in
let rec next () =
match get e, !current with
| None, None -> raise No_more_elements
| None, Some x -> current := None; x
| Some v, None -> current := Some (fold zero v); next ()
| Some v, Some x when equal x v -> current := Some (fold x v); next ()
| Some v, Some x -> current := Some (fold zero v); x
in
from next
let group_assoc equal fold zero e =
let current = ref None in
let rec next () =
match get e, !current with
| None, None -> raise No_more_elements
| None, Some x -> current := None; x
| Some (k,v), None -> current := Some (k, fold zero v); next ()
| Some (k,v), Some (g,acc) when equal k g -> current := Some (g, fold acc v); next ()
| Some (k,v), Some cur -> current := Some (k, fold zero v); cur
in
from next
let uniq equal e =
let current = ref None in
let rec next () =
match get e, !current with
| None, None -> raise No_more_elements
| None, Some x -> current := None; x
| Some v, None -> current := Some v; next ()
| Some v, Some x when equal x v -> next ()
| Some v, Some x -> current := Some v; x
in
from next
let count_unique equal e =
let current = ref None in
let n = ref 0 in
let rec next () =
match get e, !current with
| None, None -> raise No_more_elements
| None, Some x -> current := None; x, !n
| Some v, None -> current := Some v; n := 1; next ()
| Some v, Some x when equal x v -> incr n; next ()
| Some v, Some x -> let count = !n in current := Some v; n := 1; x, count
in
from next
let sub ?(eq=(=)) e f =
match peek e with
| None -> None
| Some x ->
let current = f x in
let next () =
match peek e with
| Some x when eq (f x) current -> junk e; x
| None | Some _ -> raise No_more_elements
in
Some (current, from next)
let rec iter_while f e =
match peek e with
| Some x when f x ->
begin match peek e with
| Some y when x == y -> junk e (* "support" recursive invocations *)
| _ -> ()
end;
iter_while f e
| _ -> ()