some optimizations in CCVector

This commit is contained in:
Simon Cruanes 2014-11-13 22:21:09 +01:00
parent 1a20df9393
commit b8d84de4dc
2 changed files with 48 additions and 27 deletions

View file

@ -92,36 +92,48 @@ let _resize v newcapacity =
()
(*$T
(let v = create_with ~capacity:10 1 in ensure v 200; capacity v >= 200)
let v = create_with ~capacity:10 1 in \
ensure v 200; capacity v >= 200
*)
(* grow the array, using [x] as a filler if required *)
let _grow v x =
if _empty_array v
then v.vec <- Array.make 32 x
else
else (
let n = Array.length v.vec in
let size = min (n + n/2 + 10) Sys.max_array_length in
let size = min (2 * n + 10) Sys.max_array_length in
if size = n then failwith "vec: can't grow any further";
_resize v size
)
(* resize so that capacity is at least size. Use a doubling-size
strategy so that calling many times [ensure] will
behave well *)
let ensure v size =
if Array.length v.vec = 0
then ()
else if v.size < size
then
let size' = min size Sys.max_array_length in
_resize v size'
else if size > Sys.max_array_length
then failwith "vec.ensure: size too big"
else (
let n = ref (max 16 (Array.length v.vec)) in
while !n < size do n := min Sys.max_array_length (2* !n) done;
_resize v !n
)
let clear v =
v.size <- 0
let is_empty v = v.size = 0
let push_unsafe v x =
Array.unsafe_set v.vec v.size x;
v.size <- v.size + 1
let push v x =
if v.size = Array.length v.vec
then _grow v x;
Array.unsafe_set v.vec v.size x;
v.size <- v.size + 1
push_unsafe v x
(** add all elements of b to a *)
let append a b =
@ -164,8 +176,10 @@ let append_seq a seq =
seq (fun x -> push a x)
let append_array a b =
ensure a (a.size + Array.length b);
Array.iter (push a) b
let len_b = Array.length b in
ensure a (a.size + len_b);
Array.blit b 0 a.vec a.size len_b;
a.size <- a.size + len_b
(*$T
let v1 = init 5 (fun i->i) and v2 = Array.init 5 (fun i->i+5) in \
@ -274,10 +288,7 @@ let map f v =
then create ()
else (
let vec = Array.init v.size (fun i -> f (Array.unsafe_get v.vec i)) in
{
size=v.size;
vec;
}
{ size=v.size; vec; }
)
(*$T
@ -286,17 +297,23 @@ let map f v =
*)
let filter' p v =
let i = ref (v.size - 1) in
while !i >= 0 do
if not (p v.vec.(! i))
(* remove i-th item! *)
then remove v !i;
decr i
done
let i = ref 0 in (* cur element *)
let j = ref 0 in (* cur insertion point *)
let n = v.size in
while !i < n do
if p v.vec.(! i) then (
(* move element i at the first empty slot.
invariant: i >= j*)
if !i > !j then v.vec.(!j) <- v.vec.(!i);
incr i;
incr j
) else incr i
done;
v.size <- !j
(*$T
let v = 1 -- 10 in filter' (fun x->x<4) v; \
to_list v |> List.sort Pervasives.compare = [1;2;3]
to_list v = [1;2;3]
*)
let filter p v =
@ -305,13 +322,14 @@ let filter p v =
else (
let v' = create_with ~capacity:v.size v.vec.(0) in
Array.iter
(fun x -> if p x then push v' x)
(fun x -> if p x then push_unsafe v' x)
v.vec;
v'
)
(*$T
filter (fun x-> x mod 2=0) (of_list [1;2;3;4;5]) |> to_list = [2;4]
filter (fun x-> x mod 2=0) (1 -- 1_000_000) |> length = 500_000
*)
let fold f acc v =
@ -463,9 +481,13 @@ let of_list l = match l with
| [] -> create()
| x::_ ->
let v = create_with ~capacity:(List.length l + 5) x in
List.iter (push v) l;
List.iter (push_unsafe v) l;
v
(*$T
of_list CCList.(1--300_000) |> to_list = CCList.(1--300_000)
*)
let to_array v =
Array.sub v.vec 0 v.size

View file

@ -134,8 +134,7 @@ val filter : ('a -> bool) -> ('a,_) t -> ('a, 'mut) t
returns a new vector that only contains elements of [v] satisfying [p]. *)
val filter' : ('a -> bool) -> ('a, rw) t -> unit
(** Filter elements in place. Does {b NOT} preserve the order
of the elements. *)
(** Filter elements in place. *)
val fold : ('b -> 'a -> 'b) -> 'b -> ('a,_) t -> 'b
(** fold on elements of the vector *)