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
type 'a raw =
| Empty of int
| Inited of {
data : 'a array;
mutable size : int ;
mutable pos : int
}
type 'a t = 'a raw ref
let create capacity =
if capacity <= 0 then invalid_arg "Ring.create: capacity must be positive"
else ref (Empty capacity)
let capacity r =
match !r with
| Empty capacity -> capacity
| Inited {data; _} -> Array.length data
let length r =
match !r with
| Empty _ -> 0
| Inited {data; size; pos = _} ->
assert (size <= Array.length data) ;
size
let add r v =
match !r with
| Empty size -> r := Inited {data = Array.make size v; size = 1; pos = 0}
| Inited ({data; size; pos} as s) ->
let capacity = Array.length data in
let new_size = min (size + 1) capacity in
let new_pos = (pos + 1) mod capacity in
s.data.(new_pos) <- v ;
s.pos <- new_pos ;
s.size <- new_size
let add_and_return_erased r v =
let replaced =
match !r with
| Empty _ -> None
| Inited s ->
let capacity = Array.length s.data in
if s.size = capacity then Some s.data.((s.pos + 1) mod capacity)
else None
in
add r v ;
replaced
let clear r =
match !r with
| Empty _ -> ()
| Inited {data; _} -> r := Empty (Array.length data)
let add_list r l = List.iter (add r) l
let fold r ~init ~f =
match !r with
| Empty _ -> init
| Inited {data; size; pos} ->
let acc = ref init in
let capacity = Array.length data in
for i = 0 to size - 1 do
acc := f !acc data.((pos - i + capacity) mod capacity)
done ;
!acc
let fold_oldest_first r ~init ~f =
match !r with
| Empty _ -> init
| Inited {data; size; pos} ->
let acc = ref init in
let capacity = Array.length data in
for i = size - 1 downto 0 do
acc := f !acc data.((pos - i + capacity) mod capacity)
done ;
!acc
let newest_element t =
match !t with Empty _ -> None | Inited {data; pos; _} -> Some data.(pos)
let oldest_element t =
match !t with
| Empty _ -> None
| Inited {data; size; pos; _} ->
let capacity = Array.length data in
let oldest_pos = (pos - (size - 1) + capacity) mod capacity in
Some data.(oldest_pos)
let elements t = fold t ~init:[] ~f:(fun acc elt -> elt :: acc)
let remove_newest r =
match !r with
| Empty _ -> None
| Inited {data = _; size = 0; pos = _} -> assert false
| Inited {data; size = 1; pos} ->
r := Empty (Array.length data);
Some data.(pos)
| Inited ({data; size; pos} as s) ->
let capacity = Array.length data in
let removed = data.(pos) in
s.pos <- (pos - 1 + capacity) mod capacity ;
data.(pos) <- data.(s.pos) ;
s.size <- size - 1 ;
Some removed
let remove_oldest r =
match !r with
| Empty _ -> None
| Inited {data = _; size = 0; pos = _} -> assert false
| Inited {data; size = 1; pos} ->
r := Empty (Array.length data);
Some data.(pos)
| Inited ({data; size; pos} as s) ->
let capacity = Array.length data in
let removed_pos = (pos - (size - 1) + capacity) mod capacity in
let removed = data.(removed_pos) in
data.(removed_pos) <- data.(s.pos) ;
s.size <- size - 1 ;
Some removed