open Base;;
type ring = {
buf: char Array.t; (* array serving as data store *)
mutable len: int; (* amount of characters currently retained *)
mutable pos: int; (* position in buffer of last character written *)
};;
let create size = {
buf = Array.create size '\x00';
len = 0;
pos = -1;
};;
let length r = r.len;;
let clear r =
r.len <- 0;
r.pos <- -1;
;;
let add_char r ch =
if r.len < Array.length r.buf then (
r.pos <- r.pos + 1;
Array.set r.buf r.pos ch;
r.len <- r.pos + 1;
None
) else (
r.pos <- (r.pos + 1) % (Array.length r.buf);
let prev_ch = Array.get r.buf r.pos in
Array.set r.buf r.pos ch;
Some prev_ch
)
;;
let rev_str s = Sequence.unfold_step ~init:(String.length s - 1) ~f:(
function n ->
if n < 0
then Sequence.Step.Done
else Sequence.Step.Yield (String.get s n, n - 1)
)
;;
let rev r = Sequence.unfold_step ~init:(r.len, r.pos) ~f:(
function (remaining, pos) ->
if remaining <= 0
then Sequence.Step.Done
else Sequence.Step.Yield (
Array.get r.buf pos,
(remaining - 1, (pos - 1) % (Array.length r.buf))
)
)
;;
let fwd r =
Sequence.unfold_step
~init:(
r.len,
if r.len < (Array.length r.buf) then 0 else (r.pos + 1) % (Array.length r.buf)
)
~f:(function (remaining, pos) ->
if remaining <= 0
then Sequence.Step.Done
else Sequence.Step.Yield (
Array.get r.buf pos,
(remaining - 1, (pos + 1) % (Array.length r.buf))
)
)
;;
let compare (r:ring) (s:string) =
let size_diff = r.len - (String.length s) in
if size_diff = 0 then (
Sequence.compare Char.compare (rev r) (rev_str s)
) else if size_diff < 0 then -1 else 1
;;