Source file fragmentBuffer.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
type fragment = {
data : string;
mutable next : fragment option;
}
type t = {
(** String fragments stored in FIFO order *)
mutable ends : (fragment * fragment) option;
(** Total byte count of the fragments *)
mutable fragments_size : int;
}
let empty () = {
ends = None;
fragments_size = 0;
}
let add_fragment stream data =
let len = String.length data in
if len > 0 then (
let fragment = { data; next = None } in
begin match stream.ends with
| Some (old_front, old_back) ->
old_back.next <- Some fragment;
stream.ends <- Some (old_front, fragment)
| None ->
stream.ends <- Some (fragment, fragment)
end;
stream.fragments_size <- stream.fragments_size + len
)
let enqueue_front stream data =
match stream.ends with
| None ->
let fragment = { data; next = None } in
stream.ends <- Some (fragment, fragment)
| Some (old_front, old_back) ->
let fragment = { data; next = Some old_front } in
stream.ends <- Some (fragment, old_back)
let pop stream =
match stream.ends with
| None ->
assert (stream.fragments_size = 0);
assert false
| Some (fragment, old_back) ->
begin match fragment.next with
| None -> stream.ends <- None
| Some new_front -> stream.ends <- Some (new_front, old_back)
end;
fragment.data
let of_string s =
let stream = empty () in
let () = add_fragment stream s in
stream
let byte_count stream = stream.fragments_size
let remove_exact stream size =
if stream.fragments_size < size then
None
else
let buf = Bytes.create size in
let () =
let ofs = ref 0 in
while !ofs < size do
let bytes_remaining = size - !ofs in
let fragment = pop stream in
let bytes_from_fragment = min bytes_remaining (String.length fragment) in
Bytes.blit
(Bytes.unsafe_of_string fragment) 0
buf !ofs
bytes_from_fragment;
begin if bytes_from_fragment < String.length fragment then
let remainder = Util.str_slice ~start:bytes_from_fragment fragment in
enqueue_front stream remainder
end;
ofs := !ofs + bytes_from_fragment;
done;
stream.fragments_size <- stream.fragments_size - size;
in
Some (Bytes.unsafe_to_string buf)
let remove_at_least stream size =
if stream.fragments_size < size then
None
else begin
let buffer = Buffer.create size in
while Buffer.length buffer < size do
Buffer.add_string buffer (pop stream)
done;
stream.fragments_size <- stream.fragments_size - (Buffer.length buffer);
Some (Buffer.contents buffer)
end
let unremove stream data =
let len = String.length data in
if len > 0 then (
enqueue_front stream data;
stream.fragments_size <- stream.fragments_size + len;
)
let peek_exact stream size =
match remove_exact stream size with
| Some bytes ->
unremove stream bytes;
Some bytes
| None -> None