big refactoring of CCVector, to fit the recent coding style;

safe functions with _exn versions, iterators, printers, comparison
and other monadic operators
This commit is contained in:
Simon Cruanes 2014-06-13 23:51:34 +02:00
parent e7dbdeff2e
commit 043003cf3b
4 changed files with 415 additions and 140 deletions

View file

@ -162,3 +162,10 @@ let pp_i ?(sep=", ") pp_item buf a =
(if i > 0 then Buffer.add_string buf sep); (if i > 0 then Buffer.add_string buf sep);
pp_item buf i a.(i) pp_item buf i a.(i)
done done
let print ?(sep=", ") pp_item fmt a =
Array.iteri
(fun i x ->
if i > 0 then Format.pp_print_string fmt sep;
pp_item fmt x
) a

View file

@ -68,9 +68,13 @@ val shuffle : 'a t -> unit
(** shuffle randomly the array, in place *) (** shuffle randomly the array, in place *)
val pp: ?sep:string -> (Buffer.t -> 'a -> unit) val pp: ?sep:string -> (Buffer.t -> 'a -> unit)
-> Buffer.t -> 'a array -> unit -> Buffer.t -> 'a t -> unit
(** print an array of items with printing function *) (** print an array of items with printing function *)
val pp_i: ?sep:string -> (Buffer.t -> int -> 'a -> unit) val pp_i: ?sep:string -> (Buffer.t -> int -> 'a -> unit)
-> Buffer.t -> 'a array -> unit -> Buffer.t -> 'a t -> unit
(** print an array, giving the printing function both index and item *) (** print an array, giving the printing function both index and item *)
val print : ?sep:string -> (Format.formatter -> 'a -> unit)
-> Format.formatter -> 'a t -> unit
(** print an array of items with printing function *)

View file

@ -25,30 +25,76 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
(** {1 Growable, mutable vector} *) (** {1 Growable, mutable vector} *)
type 'a sequence = ('a -> unit) -> unit
type 'a klist = unit -> [`Nil | `Cons of 'a * 'a klist]
type 'a gen = unit -> 'a option
type 'a equal = 'a -> 'a -> bool
type 'a ord = 'a -> 'a -> int
type 'a printer = Buffer.t -> 'a -> unit
type 'a formatter = Format.formatter -> 'a -> unit
(** a vector of 'a. *) (** a vector of 'a. *)
type 'a t = { type 'a t = {
mutable size : int; mutable size : int;
mutable vec : 'a array; mutable vec : 'a array;
} }
let create i = let create () = {
let i = max i 3 in size = 0;
{ size = 0; vec = [| |];
vec = Array.create i (Obj.magic None); }
}
let resize v newcapacity = let create_with ?(capacity=128) x = {
size = 0;
vec = Array.make capacity x;
}
(*$T
(create_with ~capacity:200 1 |> capacity) >= 200
*)
let make n x = {
size=n;
vec=Array.make n x;
}
let init n f = {
size=n;
vec=Array.init n f;
}
(* is the underlying empty? *)
let _empty_array v =
Array.length v.vec = 0
(* assuming the underlying array isn't empty, resize it *)
let _resize v newcapacity =
assert (newcapacity >= v.size); assert (newcapacity >= v.size);
let new_vec = Array.create newcapacity (Obj.magic None) in assert (not (_empty_array v));
let new_vec = Array.create newcapacity v.vec.(0) in
Array.blit v.vec 0 new_vec 0 v.size; Array.blit v.vec 0 new_vec 0 v.size;
v.vec <- new_vec; v.vec <- new_vec;
() ()
(*$T
(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
let size = min (2 * Array.length v.vec + 10) Sys.max_array_length in
_resize v size
let ensure v size = let ensure v size =
if v.size < size if Array.length v.vec = 0
then ()
else if v.size < size
then then
let size' = min (2 * v.size) Sys.max_array_length in let size' = min size Sys.max_array_length in
resize v size' _resize v size'
let clear v = let clear v =
v.size <- 0 v.size <- 0
@ -56,59 +102,92 @@ let clear v =
let is_empty v = v.size = 0 let is_empty v = v.size = 0
let push v x = let push v x =
(if v.size = Array.length v.vec then resize v (2 * v.size)); if v.size = Array.length v.vec
then _grow v x;
Array.unsafe_set v.vec v.size x; Array.unsafe_set v.vec v.size x;
v.size <- v.size + 1 v.size <- v.size + 1
(** add all elements of b to a *) (** add all elements of b to a *)
let append a b = let append a b =
(if Array.length a.vec < a.size + b.size if _empty_array a
then resize a (2 * (a.size + b.size))); then if _empty_array b
then ()
else (
a.vec <- Array.copy b.vec;
a.size <- b.size
)
else (
ensure a (a.size + b.size);
assert (Array.length a.vec >= a.size + b.size);
Array.blit b.vec 0 a.vec a.size b.size; Array.blit b.vec 0 a.vec a.size b.size;
a.size <- a.size + b.size a.size <- a.size + b.size
)
let append_array a b = let get v i =
(if Array.length a.vec < a.size + Array.length b if i < 0 || i >= v.size then failwith "Vector.get";
then resize a (2 * (a.size + Array.length b))); Array.unsafe_get v.vec i
Array.blit b 0 a.vec a.size (Array.length b);
a.size <- a.size + Array.length b let set v i x =
if i < 0 || i >= v.size then failwith "Vector.set";
Array.unsafe_set v.vec i x
let append_seq a seq = let append_seq a seq =
seq (fun x -> push a x) seq (fun x -> push a x)
let pop v = let append_array a b =
(if v.size = 0 then failwith "Vector.pop on empty vector"); Array.iter (push a) b
let equal eq v1 v2 =
let n = min v1.size v2.size in
let rec check i =
if i = n
then v1.size = v2.size
else eq (get v1 i) (get v2 i) && check (i+1)
in check 0
let compare cmp v1 v2 =
let n = min v1.size v2.size in
let rec check i =
if i = n
then Pervasives.compare v1.size v2.size
else
let c = cmp (get v1 i) (get v2 i) in
if c = 0 then check (i+1) else c
in check 0
let pop_exn v =
if v.size = 0
then failwith "Vector.pop on empty vector";
v.size <- v.size - 1; v.size <- v.size - 1;
let x = v.vec.(v.size) in let x = v.vec.(v.size) in
x x
let copy v = let pop v =
let v' = create v.size in try Some (pop_exn v)
Array.blit v.vec 0 v'.vec 0 v.size; with Failure _ -> None
v'.size <- v.size;
v' let copy v = {
size = v.size;
vec = Array.sub v.vec 0 v.size;
}
(*$T
(let v = of_list [1;2;3] in let v' = copy v in \
to_list v' = [1;2;3])
create () |> copy |> is_empty
*)
let shrink v n = let shrink v n =
if n > v.size if n < v.size then v.size <- n
then failwith "cannot shrink to bigger size"
else v.size <- n
let member ?(eq=(=)) v x = let sort cmp v =
let n = v.size in
let rec check i =
if i = n then false
else if eq x v.vec.(i) then true
else check (i+1)
in check 0
let sort ?(cmp=compare) v =
(* copy array (to avoid junk in it), then sort the array *) (* copy array (to avoid junk in it), then sort the array *)
let a = Array.sub v.vec 0 v.size in let a = Array.sub v.vec 0 v.size in
Array.fast_sort cmp a; Array.fast_sort cmp a;
v.vec <- a v.vec <- a
let uniq_sort ?(cmp=compare) v = let uniq_sort cmp v =
sort ~cmp v; sort cmp v;
let n = v.size in let n = v.size in
(* traverse to remove duplicates. i= current index, (* traverse to remove duplicates. i= current index,
j=current append index, j<=i. new_size is the size j=current append index, j<=i. new_size is the size
@ -116,64 +195,83 @@ let uniq_sort ?(cmp=compare) v =
let rec traverse prev i j = let rec traverse prev i j =
if i >= n then () (* done traversing *) if i >= n then () (* done traversing *)
else if cmp prev v.vec.(i) = 0 else if cmp prev v.vec.(i) = 0
then (v.size <- v.size - 1; traverse prev (i+1) j) (* duplicate, remove it *) then (
else (v.vec.(j) <- v.vec.(i); traverse v.vec.(i) (i+1) (j+1)) (* keep it *) v.size <- v.size - 1;
traverse prev (i+1) j
) (* duplicate, remove it *)
else (
v.vec.(j) <- v.vec.(i);
traverse v.vec.(i) (i+1) (j+1)
) (* keep it *)
in in
if v.size > 0 if v.size > 0
then traverse v.vec.(0) 1 1 (* start at 1, to get the first element in hand *) then traverse v.vec.(0) 1 1
(* start at 1, to get the first element in hand *)
let iter v k = let iter k v =
for i = 0 to v.size -1 do for i = 0 to v.size -1 do
k (Array.unsafe_get v.vec i) k (Array.unsafe_get v.vec i)
done done
let iteri v k = let iteri k v =
for i = 0 to v.size -1 do for i = 0 to v.size -1 do
k i (Array.unsafe_get v.vec i) k i (Array.unsafe_get v.vec i)
done done
let map v f = let map f v =
let v' = create v.size in if _empty_array v
for i = 0 to v.size - 1 do then create ()
let x = f (Array.unsafe_get v.vec i) in else {
Array.unsafe_set v'.vec i x size=v.size;
done; vec=Array.map f v.vec
v'.size <- v.size; }
let filter p v =
if _empty_array v
then create ()
else (
let v' = create_with ~capacity:v.size v.vec.(0) in
Array.iter
(fun x -> if p x then push v' x)
v.vec;
v' v'
)
let filter v f = (*$T
let v' = create v.size in filter (fun x-> x mod 2=0) (of_list [1;2;3;4;5]) |> to_list = [2;4]
for i = 0 to v.size - 1 do *)
let fold f acc v =
let rec fold acc i =
if i = v.size then acc
else
let x = Array.unsafe_get v.vec i in let x = Array.unsafe_get v.vec i in
if f x then push v' x; fold (f acc x) (i+1)
done; in fold acc 0
v'
let fold v acc f = (*$T
let acc = ref acc in fold (+) 0 (of_list [1;2;3;4;5]) = 15
for i = 0 to v.size - 1 do fold (+) 0 (create ()) = 0
let x = Array.unsafe_get v.vec i in *)
acc := f !acc x;
done;
!acc
let exists v p = let exists p v =
let n = v.size in let n = v.size in
let rec check i = let rec check i =
if i = n then false if i = n then false
else if p v.vec.(i) then true else p v.vec.(i) || check (i+1)
else check (i+1)
in check 0 in check 0
let for_all v p = let for_all p v =
let n = v.size in let n = v.size in
let rec check i = let rec check i =
if i = n then true if i = n then true
else if not (p v.vec.(i)) then false else p v.vec.(i) && check (i+1)
else check (i+1)
in check 0 in check 0
let find v p = let member ?(eq=(=)) x v =
exists (eq x) v
let find_exn p v =
let n = v.size in let n = v.size in
let rec check i = let rec check i =
if i = n then raise Not_found if i = n then raise Not_found
@ -181,15 +279,40 @@ let find v p =
else check (i+1) else check (i+1)
in check 0 in check 0
let get v i = let find p v =
(if i < 0 || i >= v.size then failwith "Vector.get"); try Some (find_exn p v)
Array.unsafe_get v.vec i with Not_found -> None
let set v i x = let filter_map f v =
(if i < 0 || i >= v.size then failwith "Vector.set"); let v' = create () in
Array.unsafe_set v.vec i x iter
(fun x -> match f x with
| None -> ()
| Some y -> push v' y
) v;
v'
let rev v = let flat_map f v =
let v' = create () in
iter (fun x -> iter (push v') (f x)) v;
v'
let flat_map' f v =
let v' = create () in
iter
(fun x ->
let seq = f x in
seq (fun y -> push v' y)
) v;
v'
let (>>=) x f = flat_map f x
let (>|=) x f = map f x
let rev' v =
if v.size > 0
then (
let n = v.size in let n = v.size in
let vec = v.vec in let vec = v.vec in
for i = 0 to (n-1)/2 do for i = 0 to (n-1)/2 do
@ -198,39 +321,73 @@ let rev v =
Array.unsafe_set vec i y; Array.unsafe_set vec i y;
Array.unsafe_set vec (n-i-1) x; Array.unsafe_set vec (n-i-1) x;
done done
)
let rev v =
let v' = copy v in
rev' v';
v'
(*$T
rev (of_list [1;2;3;4]) |> to_list = [4;3;2;1]
rev (of_list [1;2;3;4;5]) |> to_list = [5;4;3;2;1]
rev (create ()) |> to_list = []
*)
let size v = v.size let size v = v.size
let length v = v.size let length v = v.size
let capacity v = Array.length v.vec
let unsafe_get_array v = v.vec let unsafe_get_array v = v.vec
type 'a sequence = ('a -> unit) -> unit let of_seq ?(init=create ()) seq =
let of_seq ?(init=create 10) seq =
append_seq init seq; append_seq init seq;
init init
let to_seq = iter (*$T
of_seq CCSequence.(1 -- 10) |> to_list = CCList.(1 -- 10)
*)
let to_seq v k = iter k v
let slice v start len = let slice v start len =
assert (start >= 0 && len >= 0); assert (start >= 0 && len >= 0);
fun k -> fun k ->
assert (start+len < v.size); assert (start+len < v.size);
for i = start to start+len do for i = start to start+len-1 do
let x = Array.unsafe_get v.vec i in let x = Array.unsafe_get v.vec i in
k x k x
done done
let from_array a = (*$T
let c = Array.length a in slice (of_list [0;1;2;3;4]) 1 3 |> CCList.of_seq = [1;2;3]
let v = create c in *)
Array.blit a 0 v.vec 0 c;
v.size <- c;
v
let from_list l = let (--) i j =
let v = create 10 in if i>j
then init (i-j+1) (fun k -> i-k)
else init (j-i+1) (fun k -> i+k)
(*$T
(1 -- 4) |> to_list = [1;2;3;4]
(4 -- 1) |> to_list = [4;3;2;1]
(0 -- 0) |> to_list = [0]
*)
let of_array a =
if Array.length a = 0
then create ()
else {
size=Array.length a;
vec=Array.copy a;
}
let of_list l = match l with
| [] -> create()
| x::l' ->
let v = create_with ~capacity:(List.length l + 5) x in
List.iter (push v) l; List.iter (push v) l;
v v
@ -238,8 +395,50 @@ let to_array v =
Array.sub v.vec 0 v.size Array.sub v.vec 0 v.size
let to_list v = let to_list v =
let l = ref [] in List.rev (fold (fun acc x -> x::acc) [] v)
for i = 0 to v.size - 1 do
l := get v i :: !l; let of_gen ?(init=create ()) g =
done; let rec aux g = match g() with
List.rev !l | None -> init
| Some x -> push init x; aux g
in aux g
let to_gen v =
let i = ref 0 in
fun () ->
if !i < v.size
then (
let x = v.vec.( !i ) in
incr i;
Some x
) else None
let of_klist ?(init=create ()) l =
let rec aux l = match l() with
| `Nil -> init
| `Cons (x,l') -> push init x; aux l'
in aux l
let to_klist v =
let rec aux i () =
if i=v.size then `Nil
else `Cons (v.vec.(i), aux (i+1))
in aux 0
let pp ?(start="[") ?(stop="]") ?(sep=", ") pp_item buf v =
Buffer.add_string buf start;
iteri
(fun i x ->
if i > 0 then Buffer.add_string buf sep;
pp_item buf x
) v;
Buffer.add_string buf stop
let print ?(start="[") ?(stop="]") ?(sep=", ") pp_item fmt v =
Format.fprintf fmt "@[%s" start;
iteri
(fun i x ->
if i > 0 then Format.pp_print_string fmt sep;
pp_item fmt x
) v;
Format.fprintf fmt "%s@]" stop

View file

@ -29,16 +29,33 @@ type 'a t
(** the type of a vector of 'a *) (** the type of a vector of 'a *)
type 'a sequence = ('a -> unit) -> unit type 'a sequence = ('a -> unit) -> unit
type 'a klist = unit -> [`Nil | `Cons of 'a * 'a klist]
type 'a gen = unit -> 'a option
type 'a equal = 'a -> 'a -> bool
type 'a ord = 'a -> 'a -> int
type 'a printer = Buffer.t -> 'a -> unit
type 'a formatter = Format.formatter -> 'a -> unit
val create : int -> 'a t val create : unit -> 'a t
(** create a vector of given initial capacity *) (** Create a new, empty vector *)
val create_with : ?capacity:int -> 'a -> 'a t
(** Create a new vector, using the given value as a filler.
@param capacity the size of the underlying array
{b caution}: the value will likely not be GC'd before the vector is. *)
val make : int -> 'a -> 'a t
(** [make n x] makes a vector of size [n], filled with [x] *)
val init : int -> (int -> 'a) -> 'a t
(** Init the vector with the given function and size *)
val clear : 'a t -> unit val clear : 'a t -> unit
(** clear the content of the vector *) (** clear the content of the vector *)
val ensure : 'a t -> int -> unit val ensure : 'a t -> int -> unit
(** Ensure that the vector can contain that much elements, resizing it (** Hint to the vector that it should have at least the given capacity.
if required *) Just a hint, will not be enforced if the vector is empty. *)
val is_empty : 'a t -> bool val is_empty : 'a t -> bool
(** is the vector empty? *) (** is the vector empty? *)
@ -55,56 +72,88 @@ val append_array : 'a t -> 'a array -> unit
val append_seq : 'a t -> 'a sequence -> unit val append_seq : 'a t -> 'a sequence -> unit
(** Append content of sequence *) (** Append content of sequence *)
val pop : 'a t -> 'a val equal : 'a equal -> 'a t equal
(** remove last element, or raise a Failure if empty *)
val compare : 'a ord -> 'a t ord
(** Lexicographic comparison *)
val pop : 'a t -> 'a option
(** Remove last element, or [None] *)
val pop_exn : 'a t -> 'a
(** remove last element, or raise a Failure if empty
@raise Failure on an empty vector *)
val copy : 'a t -> 'a t val copy : 'a t -> 'a t
(** shallow copy *) (** shallow copy *)
val shrink : 'a t -> int -> unit val shrink : 'a t -> int -> unit
(** shrink to the given size (remove elements above this size) *) (** shrink to the given size (remove elements above this size).
Does nothing if the parameter is bigger than the current size. *)
val member : ?eq:('a -> 'a -> bool) -> 'a t -> 'a -> bool val member : ?eq:('a -> 'a -> bool) -> 'a -> 'a t -> bool
(** is the element a member of the vector? *) (** is the element a member of the vector? *)
val sort : ?cmp:('a -> 'a -> int) -> 'a t -> unit val sort : ('a -> 'a -> int) -> 'a t -> unit
(** sort the array in place*) (** sort the array in place*)
val uniq_sort : ?cmp:('a -> 'a -> int) -> 'a t -> unit val uniq_sort : ('a -> 'a -> int) -> 'a t -> unit
(** sort the array and remove duplicates in place*) (** sort the array and remove duplicates in place*)
val iter : 'a t -> ('a -> unit) -> unit val iter : ('a -> unit) -> 'a t -> unit
(** iterate on the vector *) (** iterate on the vector *)
val iteri : 'a t -> (int -> 'a -> unit) -> unit val iteri : (int -> 'a -> unit) -> 'a t -> unit
(** iterate on the vector with indexes *) (** iterate on the vector with indexes *)
val map : 'a t -> ('a -> 'b) -> 'b t val map : ('a -> 'b) -> 'a t -> 'b t
(** map elements of the vector *) (** map elements of the vector *)
val filter : 'a t -> ('a -> bool) -> 'a t val filter : ('a -> bool) -> 'a t -> 'a t
(** filter elements from vector *) (** filter elements from vector *)
val fold : 'a t -> 'b -> ('b -> 'a -> 'b) -> 'b val fold : ('b -> 'a -> 'b) -> 'b -> 'a t -> 'b
(** fold on elements of the vector *) (** fold on elements of the vector *)
val exists : 'a t -> ('a -> bool) -> bool val exists : ('a -> bool) -> 'a t -> bool
(** existential test *) (** existential test *)
val for_all : 'a t -> ('a -> bool) -> bool val for_all : ('a -> bool) -> 'a t -> bool
(** universal test *) (** universal test *)
val find : 'a t -> ('a -> bool) -> 'a val find : ('a -> bool) -> 'a t -> 'a option
(** find an element that satisfies the predicate, or Not_found *) (** Find an element that satisfies the predicate *)
val find_exn : ('a -> bool) -> 'a t -> 'a
(** find an element that satisfies the predicate, or
@raise Not_found if no element does *)
val filter_map : ('a -> 'b option) -> 'a t -> 'b t
(** Map elements with a function, possibly filtering some of them out *)
val flat_map : ('a -> 'b t) -> 'a t -> 'b t
(** Map each element to a sub-vector *)
val flat_map' : ('a -> 'b sequence) -> 'a t -> 'b t
(** Like {!flat_map}, but using {!sequence} for intermediate collections *)
val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
val (>|=) : 'a t -> ('a -> 'b) -> 'b t
val get : 'a t -> int -> 'a val get : 'a t -> int -> 'a
(** access element, or Failure if bad index *) (** access element, or
@raise Failure if bad index *)
val set : 'a t -> int -> 'a -> unit val set : 'a t -> int -> 'a -> unit
(** access element, or Failure if bad index *) (** access element, or
@raise Failure if bad index *)
val rev : 'a t -> unit val rev : 'a t -> 'a t
(** Reverse array in place *) (** Reverse the vector *)
val rev' : 'a t -> unit
(** Reverse the vector in place *)
val size : 'a t -> int val size : 'a t -> int
(** number of elements in vector *) (** number of elements in vector *)
@ -112,21 +161,37 @@ val size : 'a t -> int
val length : _ t -> int val length : _ t -> int
(** Synonym for {! size} *) (** Synonym for {! size} *)
val capacity : _ t -> int
(** Number of elements the vector can contain without being resized *)
val unsafe_get_array : 'a t -> 'a array val unsafe_get_array : 'a t -> 'a array
(** Access the underlying *shared* array (do not modify!). (** Access the underlying {b shared} array (do not modify!).
[unsafe_get_array v] is longer than [size v], but elements at higher [unsafe_get_array v] is longer than [size v], but elements at higher
index than [size v] are undefined (do not access!). *) index than [size v] are undefined (do not access!). *)
val (--) : int -> int -> int t
(** Range of integers (both included) *)
val of_array : 'a array -> 'a t
val of_list : 'a list -> 'a t
val to_array : 'a t -> 'a array
val to_list : 'a t -> 'a list
val of_seq : ?init:'a t -> 'a sequence -> 'a t val of_seq : ?init:'a t -> 'a sequence -> 'a t
val to_seq : 'a t -> 'a sequence val to_seq : 'a t -> 'a sequence
val slice : 'a t -> int -> int -> 'a sequence val slice : 'a t -> int -> int -> 'a sequence
(** [slice v start len] is the sequence of elements from [v.(start)] (** [slice v start len] is the sequence of elements from [v.(start)]
to [v.(start+len)] included. *) to [v.(start+len-1)]. *)
val from_array : 'a array -> 'a t val of_klist : ?init:'a t -> 'a klist -> 'a t
val from_list : 'a list -> 'a t val to_klist : 'a t -> 'a klist
val to_array : 'a t -> 'a array val of_gen : ?init:'a t -> 'a gen -> 'a t
val to_list : 'a t -> 'a list val to_gen : 'a t -> 'a gen
val pp : ?start:string -> ?stop:string -> ?sep:string ->
'a printer -> 'a t printer
val print : ?start:string -> ?stop:string -> ?sep:string ->
'a formatter -> 'a t formatter