lz77/lib/window.ml

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