Commit f0b3b92e authored by POTTIER Francois's avatar POTTIER Francois
Browse files

CompactQueue: comments and stylistic improvements.

parent c83d9513
(** This module implements a mutable FIFO queue, like [Queue]. However it has a
more compact representation, storing elements contiguously in an array. *)
(* A queue [q] is represented as a circular array of elements, [q.buffer]. The
slots whose logical index lies between [q.first] (inclusive) and [q.first +
q.size] (exclusive) contain the elements of the queue. A logical index must
be normalized modulo [n], where [n] is the length of the array [buffer], to
obtain a physical index. *)
(* We maintain the following invariants:
- [n] is zero or a power of two, so as to speed up the [modulo] operation.
- [0 <= q.size <= n] holds. *)
type 'a t = {
(* The array that stores the elements (as well as empty slots). *)
mutable buffer: 'a array;
(* The array that stores all elements. *)
(* The logical index of the first element. *)
mutable first: int;
(* Index of the first element in the queue, if any (the one that will be
popped next). It has to be taken modulo (Array.length buffer). *)
(* The number of elements. *)
mutable size: int;
(* The number of elements in the queue. *)
(* Invariants:
- [Array.length q.buffer] is a power of 2, to speed up modulo
- [0 <= q.size <= Array.length q.buffer]
*)
}
(* The following code iterates on all queued elements:
(* The following code iterates on all queued elements:
for i = 0 to q.size - 1 do
f q.buffer.((q.first + i) mod (Array.length q.buffer))
done
let n = Array.length q.buffer in
for i = 0 to q.size - 1 do
f q.buffer.((q.first + i) mod n)
done
Since length is a power of 2, it is equivalent to:
Because [n] is a power of 2, this is equivalent to:
for i = 0 to q.size - 1 do
f q.buffer.((q.first + i) land (Array.length q.buffer - 1))
done
*)
}
let n = Array.length q.buffer in
for i = 0 to q.size - 1 do
f q.buffer.((q.first + i) land (n - 1))
done
*)
(* The buffer is initially an empty array. Another array is allocated when an
element is inserted. *)
let create () = {
(* The buffer is initially an empty array. It will be re-allocated when a
first element is pushed. *)
buffer = [||];
first = 0;
size = 0;
......@@ -45,26 +53,26 @@ let is_empty q =
let add x q =
let buffer = q.buffer in
let length = Array.length buffer in
if q.size < length then begin
(* Queue still has some room left *)
buffer.((q.first + q.size) land (length - 1)) <- x;
q.size <- q.size + 1
let n = Array.length buffer in
if q.size < n then begin
(* The queue still has room left. *)
buffer.((q.first + q.size) land (n - 1)) <- x;
q.size <- q.size + 1;
end
else if length > 0 then begin
(* Buffer is full *)
(* 1. Reallocate a buffer twice the size *)
let buffer' = Array.make (length * 2) x in
(* 2. Move existing elements *)
let first = q.first land (length - 1) in
Array.blit buffer first buffer' 0 (length - first);
Array.blit buffer 0 buffer' (length - first) first;
else if n > 0 then begin
(* The buffer is nonempty, and is full. *)
(* Allocate a new buffer that is twice larger. *)
let buffer' = Array.make (n * 2) x in
(* Move all existing elements. *)
let first = q.first land (n - 1) in
Array.blit buffer first buffer' 0 (n - first);
Array.blit buffer 0 buffer' (n - first) first;
q.buffer <- buffer';
q.first <- 0;
q.size <- length + 1;
q.size <- n + 1;
end
else begin
(* Queue has a buffer of size 0. Allocate an initial array. *)
(* The queue has a buffer of size 0. Allocate an array. *)
q.buffer <- Array.make 8 x;
q.size <- 1;
end
......@@ -74,9 +82,10 @@ exception Empty
let take q =
if q.size = 0 then
raise Empty
else (
else begin
q.size <- q.size - 1;
let result = q.buffer.(q.first land (Array.length q.buffer - 1)) in
let n = Array.length q.buffer in
let result = q.buffer.(q.first land (n - 1)) in
q.first <- q.first + 1;
result
)
end
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment