(* Flots d'entiers / Flots binaires*)
(* A bit can be represented either as a Boolean or as an integer. *)
let b2i (b : bool) : int =
if b then 1 else 0
let i2b (i : int) : bool =
assert (i = 0 || i = 1);
i = 1
(* [unpack_int k i bs] is a producer. It constructs the concatenation of the
[k] least significant bits of the integer [i] in front of the bit t
[bs]. It is not lazy; [k] memory cells are allocated immediately. The bits
are written from left to right, i.e., the most significant bit comes
first. Note that bits may be lost if [k] exceeds [Sys.word_size - 1].*)
let rec push_int_as_bits (k : int) (i : int) (bs : bool MyStream.t) : bool MyStream.t =
if k = 0 then
bs
else
(* Among the [k] rightmost bits of [i], compute the most significant one.
This can be done by shifting [i] to the right by [k - 1] and reading
the rightmost bit. *)
let bit = (i lsr (k - 1)) land 1 in
(* Continue. *)
lazy (MyStream.Cons (
(i2b bit) ,
(push_int_as_bits (k - 1) i bs) ))
(* [pack_int k accu bs] is a consumer. It reads up to [k] bits from the bit
t [bs] and inserts them at the right end of the accumulator, which is
shifted towards the left. If the end of the t [bs] is reached before
[k] bits have been read, an appropriate number of zero bits are inserted at
the end as padding. The function returns the updated accumulator and the
remainder of the t. *)
let rec pop_bits_as_int (k : int) (accu : int) (bs : bool MyStream.t) : int * bool MyStream.t =
if k = 0 then
accu, bs
else
let b, bs =
match Lazy.force bs with
| MyStream.Nil ->
0, bs (* padding *)
| MyStream.Cons (b, bs) ->
b2i b, bs
in
pop_bits_as_int (k - 1) (accu lsl 1 + b) bs
let pop_bits_as_int k bs = pop_bits_as_int k 0 bs
(* Remark that (unpack_int k) o (pack_int k) = id provided k ≤ (Sys.word_size) - 1
and (pack_int k) o (unpack_int k) = id provided k ≥ (Sys.word_size) -1 *)