59 lines
2.4 KiB
OCaml
59 lines
2.4 KiB
OCaml
let window_size = 32768
|
|
|
|
type t = { data : bytes; mutable write_pos : int; mutable size : int; mutable total : int64 }
|
|
|
|
let create () = { data = Bytes.make window_size '\000'; write_pos = 0; size = 0; total = 0L }
|
|
|
|
let current_size t = t.size
|
|
let total_processed t = t.total
|
|
|
|
let add_byte t b =
|
|
if b < 0 || b > 255 then invalid_arg "add_byte: byte out of range";
|
|
Bytes.set t.data t.write_pos (Char.chr b);
|
|
t.write_pos <- (t.write_pos + 1) mod window_size;
|
|
t.total <- Int64.succ t.total;
|
|
if t.size < window_size then t.size <- t.size + 1
|
|
|
|
let add_bytes t buf ofs len =
|
|
if ofs < 0 || ofs + len > Bytes.length buf then invalid_arg "add_bytes: out of bounds";
|
|
for i = 0 to len - 1 do
|
|
Bytes.set t.data t.write_pos (Bytes.get buf (ofs + i));
|
|
t.write_pos <- (t.write_pos + 1) mod window_size;
|
|
t.total <- Int64.succ t.total;
|
|
if t.size < window_size then t.size <- t.size + 1
|
|
done
|
|
|
|
let get_byte_at_distance t distance =
|
|
if distance <= 0 || distance > t.size || distance > window_size then
|
|
invalid_arg "get_byte_at_distance: invalid distance";
|
|
let pos = (t.write_pos - distance) mod window_size in
|
|
let pos = if pos < 0 then pos + window_size else pos in
|
|
Char.code (Bytes.get t.data pos)
|
|
|
|
let extract_slice t start len =
|
|
if start <= 0 || start > t.size then invalid_arg "extract_slice: invalid start";
|
|
if len < 0 then invalid_arg "extract_slice: negative len";
|
|
let out = Bytes.make len '\000' in
|
|
for i = 0 to len - 1 do
|
|
let dist = start + i in
|
|
if dist > t.size then invalid_arg "extract_slice: out of range";
|
|
let pos = (t.write_pos - dist) mod window_size in
|
|
let pos = if pos < 0 then pos + window_size else pos in
|
|
Bytes.set out i (Bytes.get t.data pos)
|
|
done;
|
|
out
|
|
|
|
let match_length_at_distance t distance lookahead ofs maxlen =
|
|
if distance <= 0 || distance > t.size then invalid_arg "match_length_at_distance: invalid distance";
|
|
let remaining = Bytes.length lookahead - ofs in
|
|
if remaining <= 0 || maxlen <= 0 then 0 else
|
|
let available_in_window = t.size - distance + 1 in
|
|
let max_cmp = min maxlen (min remaining available_in_window) in
|
|
let start_pos = (t.write_pos - distance) mod window_size in
|
|
let start_pos = if start_pos < 0 then start_pos + window_size else start_pos in
|
|
let rec cmp i =
|
|
if i >= max_cmp then i else
|
|
let pos = (start_pos + i) mod window_size in
|
|
if Bytes.get t.data pos = Bytes.get lookahead (ofs + i) then cmp (i + 1) else i
|
|
in cmp 0
|