Commit a0b9c010 authored by POTTIER Francois's avatar POTTIER Francois

Moved [ResizableArray] back from the attic. Added optimized [push] and [pop]....

Moved [ResizableArray] back from the attic. Added optimized [push] and [pop]. Added auto-initialization of newly created logical slots.
parent e9a5a3cc
(* This module implements resizable arrays, that is, arrays that can
grow upon explicit request. *)
type 'a t = {
(* The default element is used to fill empty slots. *)
default: 'a;
(* The logical size of this array. *)
mutable size: int;
(* The physical array, whose length is at least [size]. *)
mutable table: 'a array
}
let make capacity default =
(* [capacity] must be nonzero, so that doubling it actually
enlarges the array. *)
assert (capacity >= 0);
let capacity = if capacity = 0 then 1 else capacity in
let table = Array.make capacity default in
{ default; size = 0; table }
let length a =
a.size
let get a i =
assert (0 <= i && i < a.size);
Array.unsafe_get a.table (i)
let set a i x =
assert (0 <= i && i < a.size);
Array.unsafe_set a.table (i) x
let resize a s =
assert (s >= 0);
if s < a.size then begin
(* The logical size of the array decreases. *)
Array.fill a.table s (a.size - s) a.default;
a.size <- s
end
else if s > a.size then begin
(* The logical size of the array increases. *)
let n = Array.length a.table in
if s > n then begin
(* The physical size of the array must increase. The new size is at
least double of the previous size, and larger if requested. *)
let table = Array.make (max (2 * n) s) a.default in
Array.blit a.table 0 table 0 n;
a.table <- table
end;
a.size <- s
end;
assert (a.size <= Array.length a.table)
(* This module implements resizable arrays, that is, arrays that can
grow upon explicit request. *)
type 'a t = {
(* The default element is used to fill empty slots when growing or shrinking
the physical array. *)
default: 'a;
(* The init function is used to initialize newly allocated slots when
growing the logical array. *)
init: int -> 'a;
(* The logical size of this array. *)
mutable size: int;
(* The physical array, whose length is at least [size]. *)
mutable table: 'a array
}
let make capacity default init =
(* [capacity] must be nonzero, so that doubling it actually
enlarges the array. *)
assert (capacity >= 0);
let capacity = if capacity = 0 then 1 else capacity in
let table = Array.make capacity default in
{ default; init; size = 0; table }
let make_ capacity default =
make capacity default (fun _ -> default)
let length a =
a.size
let get a i =
assert (0 <= i && i < a.size);
Array.unsafe_get a.table (i)
let set a i x =
assert (0 <= i && i < a.size);
Array.unsafe_set a.table (i) x
let shrink a s =
(* This is [resize a s], assuming [0 <= s < a.size]. *)
Array.fill a.table s (a.size - s) a.default;
a.size <- s
let grow a s =
(* This is [resize a s], assuming [0 <= s && a.size < s]. *)
let n = Array.length a.table in
if s > n then begin
(* The physical size of the array must increase. The new size is at
least double of the previous size, and larger if requested. *)
let table = Array.make (max (2 * n) s) a.default in
Array.blit a.table 0 table 0 n;
a.table <- table
end;
(* From [a.size] to [s], we have new logical slots. Initialize them. *)
let init = a.init
and table = a.table in
for i = a.size to s - 1 do
Array.unsafe_set table i (init i)
done;
(* Update the array's logical size. *)
a.size <- s
let resize a s =
assert (0 <= s);
if s < a.size then
shrink a s
else if s > a.size then
grow a s
let push a x =
let s = a.size in (* equivalent to: [length a] *)
begin (* equivalent to: [resize a (s + 1)] *)
let s = s + 1 in
let n = Array.length a.table in
if s > n then begin
(* assert (s = n + 1); *)
(* assert (max (2 * n) s = 2 * n); *)
let table = Array.make (2 * n) a.default in
Array.blit a.table 0 table 0 n;
a.table <- table
end;
(* No need to call [init], since there is just one new logical slot
and we are about to write it anyway. *)
a.size <- s
end;
Array.unsafe_set a.table (s) x (* equivalent to: [set a s x] *)
let pop a =
let s = a.size in (* equivalent to: [length a] *)
assert (s > 0);
let s = s - 1 in
a.size <- s;
let table = a.table in
let x = Array.unsafe_get table (s) in (* equivalent to: [get a s] *)
Array.unsafe_set table (s) a.default; (* equivalent to: [resize a s] *)
x
let default a =
a.default
......@@ -3,11 +3,20 @@
type 'a t
(* [make capacity x] creates a resizable array of logical length 0, whose
physical length is initially [capacity], and whose default element is [x].
The default element is used to fill empty slots in the physical array. *)
(* [make capacity default init] creates a resizable array of logical length 0,
whose physical length is initially [capacity], and whose default element is
[default]. The default element is used to fill empty slots in the physical
array; it is otherwise irrelevant. The [init] function is used to
initialize new logical slots when the logical size of the array grows, so,
unlike [default], it is semantically meaningful. *)
val make: int -> 'a -> 'a t
val make: int -> 'a -> (int -> 'a) -> 'a t
(* [make_] is a simplified variant of [make] where the [init] function always
returns [default], i.e., where new logical slots are initialized with
[default] when the array is grown. *)
val make_: int -> 'a -> 'a t
(* [length a] returns the current logical length of the array [a]. *)
......@@ -34,3 +43,18 @@ val get: 'a t -> int -> 'a
val set: 'a t -> int -> 'a -> unit
(* [push a x] appends the element [x] at the end of the array [a], whose
length increases by one. *)
val push: 'a t -> 'a -> unit
(* [pop a] removes the element [x] found at the end of the array [a], whose
length decreases by one. The array must have nonzero length. *)
val pop: 'a t -> 'a
(* [default a] returns the default value that was used when the array [a]
was created. This should be seldom useful, but can be convenient. *)
val default: 'a t -> 'a
Markdown is supported
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