This commit is contained in:
Simon Cruanes 2024-07-26 20:55:43 +02:00 committed by GitHub
commit ecfc116de4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 1779 additions and 35 deletions

View file

@ -65,7 +65,7 @@ changes in this release.
2. Another large change is the removal (at last!) of functions deprecated 2. Another large change is the removal (at last!) of functions deprecated
in 2.8, related to the spread of `Seq.t` as the standard iterator type. in 2.8, related to the spread of `Seq.t` as the standard iterator type.
Functions like `CCVector.of_seq` now operate on this standard `Seq.t` type, Functions like `CCVec.of_seq` now operate on this standard `Seq.t` type,
and old-time iteration based on [iter](https://github.com/c-cube/iter) and old-time iteration based on [iter](https://github.com/c-cube/iter)
is now named `of_iter`, `to_iter`, etc. is now named `of_iter`, `to_iter`, etc.
@ -438,18 +438,14 @@ map =
- : string option = Some "33" - : string option = Some "33"
``` ```
### New types: `CCVector`, `CCHeap`, `CCResult`, `CCSexp`, `CCByte_buffer` ### New types: `CCVec`, `CCHeap`, `CCResult`, `CCSexp`, `CCByte_buffer`
Containers also contains (!) a few datatypes that are not from the standard Containers also contains (!) a few datatypes that are not from the standard
library but that are useful in a lot of situations: library but that are useful in a lot of situations:
- `CCVector`: - `CCVec`:
A resizable array, with a mutability parameter. A value of type A simple and efficient dynamic array.
`('a, CCVector.ro) CCVector.t` is an immutable vector of values of type `'a`, This was called `CCVector` but the old module is deprecated now.
whereas a `('a, CCVector.rw) CCVector.t` is a mutable vector that
can be modified. This way, vectors can be used in a quite functional
way, using operations such as `map` or `flat_map`, or in a more
imperative way.
- `CCHeap`: - `CCHeap`:
A priority queue (currently, leftist heaps) functorized over A priority queue (currently, leftist heaps) functorized over
a module `sig val t val leq : t -> t -> bool` that provides a type `t` a module `sig val t val leq : t -> t -> bool` that provides a type `t`
@ -473,43 +469,42 @@ library but that are useful in a lot of situations:
Now for a few examples: Now for a few examples:
```ocaml ```ocaml
# (* create a new empty vector. It is mutable, for otherwise it would # (* create a new empty vector. *)
not be very useful. *) CCVec.create;;
CCVector.create;; - : unit -> 'a CCVec.t = <fun>
- : unit -> ('a, CCVector.rw) CCVector.t = <fun>
# (* init, similar to Array.init, can be used to produce a # (* init, similar to Array.init, can be used to produce a new vector
vector that is mutable OR immutable (see the 'mut parameter?) *) of given size *)
CCVector.init ;; CCVec.init ;;
- : int -> (int -> 'a) -> ('a, 'mut) CCVector.t = <fun> - : int -> (int -> 'a) -> 'a CCVec.t = <fun>
``` ```
```ocaml non-deterministic=output ```ocaml non-deterministic=output
# (* use the infix (--) operator for creating a range. Notice # (* use the infix (--) operator for creating a range. Notice
that v is a vector of integer but its mutability is not that v is a vector of integer but its mutability is not
decided yet. *) decided yet. *)
let v = CCVector.(1 -- 10);; let v = CCVec.(1 -- 10);;
val v : (int, '_a) CCVector.t = <abstr> val v : (int, '_a) CCVector.t = <abstr>
``` ```
```ocaml ```ocaml
# Format.printf "v = @[%a@]@." (CCVector.pp CCInt.pp) v;; # Format.printf "v = @[%a@]@." (CCVec.pp CCInt.pp) v;;
v = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 v = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
- : unit = () - : unit = ()
# CCVector.push v 42;; # CCVec.push v 42;;
- : unit = () - : unit = ()
# v (* now v is a mutable vector *);; # v (* now v is a mutable vector *);;
- : (int, CCVector.rw) CCVector.t = <abstr> - : int CCVec.t = <abstr>
# (* functional combinators! *) # (* functional combinators! *)
let v2 : _ CCVector.ro_vector = v let v2 : _ CCVec.t = v
|> CCVector.map (fun x-> x+1) |> CCVec.map (fun x-> x+1)
|> CCVector.filter (fun x-> x mod 2=0) |> CCVec.filter (fun x-> x mod 2=0)
|> CCVector.rev ;; |> CCVec.rev ;;
val v2 : int CCVector.ro_vector = <abstr> val v2 : int CCVec.t = <abstr>
# Format.printf "v2 = @[%a@]@." (CCVector.pp CCInt.pp) v2;; # Format.printf "v2 = @[%a@]@." (CCVec.pp CCInt.pp) v2;;
v2 = 10, 8, 6, 4, 2 v2 = 10, 8, 6, 4, 2
- : unit = () - : unit = ()
``` ```
@ -520,7 +515,7 @@ module IntHeap = CCHeap.Make(struct type t = int let leq = (<=) end);;
``` ```
```ocaml ```ocaml
# let h = v2 |> CCVector.to_iter |> IntHeap.of_iter ;; # let h = v2 |> CCVec.to_iter |> IntHeap.of_iter ;;
val h : IntHeap.t = <abstr> val h : IntHeap.t = <abstr>
# (* We can print the content of h # (* We can print the content of h

View file

@ -30,17 +30,17 @@ module Position = struct
type t = position type t = position
let compute_line_offsets_ (s : string) : int array = let compute_line_offsets_ (s : string) : int array =
let lines = CCVector.create () in let lines = CCVec.create () in
let i = ref 0 in let i = ref 0 in
CCVector.push lines 0; CCVec.push lines 0;
while !i < String.length s do while !i < String.length s do
match String.index_from s !i '\n' with match String.index_from s !i '\n' with
| exception Not_found -> i := String.length s | exception Not_found -> i := String.length s
| j -> | j ->
CCVector.push lines j; CCVec.push lines j;
i := j + 1 i := j + 1
done; done;
CCVector.to_array lines CCVec.to_array lines
let line_offsets_ cs = let line_offsets_ cs =
match cs.line_offsets with match cs.line_offsets with
@ -117,7 +117,7 @@ type state = {
where: where:
[type global = { [type global = {
mutable memo: Memo_state.t option; mutable memo: Memo_state.t option;
line_offsets: int CCVector.vector; line_offsets: int CCVec.vector;
} }
with line_offsets used to cache the offset where each line begins, with line_offsets used to cache the offset where each line begins,

639
src/core/CCVec.ml Normal file
View file

@ -0,0 +1,639 @@
(* This file is free software, part of containers. See file "license" for more details. *)
type 'a iter = ('a -> unit) -> unit
type 'a equal = 'a -> 'a -> bool
type 'a ord = 'a -> 'a -> int
type 'a printer = Format.formatter -> 'a -> unit
type 'a t = { mutable size: int; mutable vec: 'a array }
(** A vector of 'a. *)
external as_float_arr : 'a array -> float array = "%identity"
external as_obj_arr : 'a array -> Obj.t array = "%identity"
let fill_with_junk_ (a : _ array) i len : unit =
if Obj.(tag (repr a) = double_array_tag) then
Array.fill (as_float_arr a) i len 0.
else
Array.fill (as_obj_arr a) i len (Obj.repr ())
let create () = { size = 0; vec = [||] }
let create_with ?(capacity = 128) x =
let vec = Array.make capacity x in
fill_with_junk_ vec 0 capacity;
{ size = 0; vec }
let return x = { size = 1; vec = [| x |] }
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 array empty? *)
let[@inline] array_is_empty_ v = Array.length v.vec = 0
(* next capacity, if current one is [n] *)
let[@inline] next_grow_ n = min Sys.max_array_length (n + (n lsr 1) + 2)
(* resize the underlying array using x to temporarily fill the array *)
let resize_ v newcapacity x =
assert (newcapacity >= v.size);
assert (not (array_is_empty_ v));
let new_vec = Array.make newcapacity x in
Array.blit v.vec 0 new_vec 0 v.size;
fill_with_junk_ new_vec v.size (newcapacity - v.size);
v.vec <- new_vec;
()
(* grow the array, using [x] as a filler if required *)
let grow_with_ v ~filler:x =
if array_is_empty_ v then (
let len = 4 in
v.vec <- Array.make len x;
(* do not really use [x], it was just for knowing the type *)
fill_with_junk_ v.vec 0 len
) else (
let n = Array.length v.vec in
let size = next_grow_ n in
if size = n then invalid_arg "vec: can't grow any further";
resize_ v size v.vec.(0)
)
(* v is not empty; ensure it has at least [size] slots.
Use a doubling-size strategy so that calling many times [ensure] will
behave well *)
let ensure_assuming_not_empty_ v ~size =
if size > Sys.max_array_length then
invalid_arg "vec.ensure: size too big"
else if size < Array.length v.vec then
()
(* nothing to do *)
else (
let n = ref (Array.length v.vec) in
while !n < size do
n := next_grow_ !n
done;
resize_ v !n v.vec.(0)
)
let ensure_with ~init v size =
if array_is_empty_ v then (
v.vec <- Array.make size init;
fill_with_junk_ v.vec 0 size
) else
ensure_assuming_not_empty_ v ~size
let ensure v size =
if not (array_is_empty_ v) then ensure_assuming_not_empty_ v ~size
let[@inline] clear v = v.size <- 0
let clear_and_reset v =
v.size <- 0;
v.vec <- [||]
let[@inline] is_empty v = v.size = 0
let[@inline] 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_with_ v ~filler:x;
push_unsafe_ v x
let resize_with v f size =
if size < 0 then invalid_arg "Vec.resize_with";
if Array.length v.vec = 0 then (
let new_vec = Array.init size f in
v.vec <- new_vec;
v.size <- size
) else (
ensure_assuming_not_empty_ v size;
let { size = cur_size; vec } = v in
for i = cur_size to size - 1 do
Array.unsafe_set vec i (f i)
done;
assert (size <= Array.length v.vec);
v.size <- size
)
let resize_with_init v ~init size =
if size < 0 then invalid_arg "Vec.resize_with_init";
if Array.length v.vec = 0 then (
let vec = Array.make size init in
v.vec <- vec;
v.size <- size
) else (
ensure_assuming_not_empty_ v size;
(* nothing will change [v] *)
for i = v.size to size - 1 do
Array.unsafe_set v.vec i init
done;
v.size <- size
)
(** Add all elements of b to a *)
let append a b =
if array_is_empty_ a then
if array_is_empty_ b then
()
else (
a.vec <- Array.copy b.vec;
a.size <- b.size
)
else (
ensure_assuming_not_empty_ a ~size:(a.size + b.size);
assert (Array.length a.vec >= a.size + b.size);
Array.blit b.vec 0 a.vec a.size b.size;
a.size <- a.size + b.size
)
let[@inline] get v i =
if i < 0 || i >= v.size then invalid_arg "CCVector.get";
Array.unsafe_get v.vec i
let[@inline] set v i x =
if i < 0 || i >= v.size then invalid_arg "CCVector.set";
Array.unsafe_set v.vec i x
let remove_and_shift v i =
if i < 0 || i >= v.size then invalid_arg "CCVector.remove";
(* if v.(i) not the last element, then put last element at index i *)
if i < v.size - 1 then Array.blit v.vec (i + 1) v.vec i (v.size - i - 1);
(* remove one element *)
v.size <- v.size - 1;
fill_with_junk_ v.vec v.size 1
let remove_unordered v i =
if i < 0 || i >= v.size then invalid_arg "CCVector.remove_unordered";
(* if v.(i) not the last element, then put last element at index i *)
if i < v.size - 1 then v.vec.(i) <- v.vec.(v.size - 1);
(* remove one element *)
v.size <- v.size - 1;
fill_with_junk_ v.vec v.size 1
let insert v i x =
(* Note that we can insert at i=v.size *)
if i < 0 || i > v.size then invalid_arg "CCVector.insert";
if v.size = Array.length v.vec then grow_with_ v ~filler:x;
(* Shift the following elements, then put the element at i *)
if i < v.size then Array.blit v.vec i v.vec (i + 1) (v.size - i);
v.vec.(i) <- x;
v.size <- v.size + 1
let[@inline] append_iter a i = i (fun x -> push a x)
let append_seq a seq = Seq.iter (fun x -> push a x) seq
let append_array a b =
let len_b = Array.length b in
if array_is_empty_ a then (
a.vec <- Array.copy b;
a.size <- len_b
) else (
ensure_assuming_not_empty_ a ~size:(a.size + len_b);
Array.blit b 0 a.vec a.size len_b;
a.size <- a.size + len_b
)
let append_list a b =
match b with
| [] -> ()
| x :: _ ->
(* need to push at least one elem *)
let len_a = a.size in
let len_b = List.length b in
ensure_with ~init:x a (len_a + len_b);
List.iter (push_unsafe_ a) b;
()
let equal eq v1 v2 =
v1.size = v2.size
&&
let n = v1.size in
let rec check i = i = n || (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
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
exception Empty
let pop_exn v =
if v.size = 0 then raise Empty;
let new_size = v.size - 1 in
v.size <- new_size;
let x = v.vec.(new_size) in
(* free last element *)
fill_with_junk_ v.vec new_size 1;
x
let pop v = try Some (pop_exn v) with Empty -> None
let[@inline] top v =
if v.size = 0 then
None
else
Some (Array.unsafe_get v.vec (v.size - 1))
let[@inline] top_exn v =
if v.size = 0 then raise Empty;
Array.unsafe_get v.vec (v.size - 1)
let[@inline] copy v = { size = v.size; vec = Array.sub v.vec 0 v.size }
let truncate v n =
let old_size = v.size in
if n < old_size then (
v.size <- n;
(* free elements by erasing them *)
fill_with_junk_ v.vec n (old_size - n)
)
let shrink_to_fit v : unit =
if v.size = 0 then
v.vec <- [||]
else if v.size < Array.length v.vec then
v.vec <- Array.sub v.vec 0 v.size
let sort cmp v =
(* possibly copy array (to avoid junk at its end), then sort the array *)
let a =
if Array.length v.vec = v.size then
v.vec
else
Array.sub v.vec 0 v.size
in
Array.fast_sort cmp a;
v.vec <- a
let sorted cmp v =
let v' = { size = v.size; vec = Array.sub v.vec 0 v.size } in
Array.sort cmp v'.vec;
v'
let uniq_sort cmp v =
sort cmp v;
let n = v.size in
(* traverse to remove duplicates. i= current index,
j=current append index, j<=i. new_size is the size
the vector will have after removing duplicates. *)
let rec traverse prev i j =
if i >= n then
()
(* done traversing *)
else if cmp prev v.vec.(i) = 0 then (
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
if v.size > 0 then traverse v.vec.(0) 1 1
(* start at 1, to get the first element in hand *)
let iter k v =
let { vec; size = n } = v in
for i = 0 to n - 1 do
k (Array.unsafe_get vec i)
done
let iteri k v =
let { vec; size = n } = v in
for i = 0 to n - 1 do
k i (Array.unsafe_get vec i)
done
let map f v =
if array_is_empty_ v then
create ()
else (
let { vec; size } = v in
let vec = Array.init size (fun i -> f (Array.unsafe_get vec i)) in
{ size; vec }
)
let mapi f v =
if array_is_empty_ v then
create ()
else (
let { vec; size } = v in
let vec = Array.init size (fun i -> f i (Array.unsafe_get vec i)) in
{ size; vec }
)
let map_in_place f v =
let { vec; size = n } = v in
for i = 0 to n - 1 do
Array.unsafe_set vec i (f (Array.unsafe_get vec i))
done
let filter_in_place p v =
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;
(* free elements *)
fill_with_junk_ v.vec !j (v.size - !j);
v.size <- !j
let filter p v =
if array_is_empty_ v then
create ()
else (
let v' = create_with ~capacity:v.size v.vec.(0) in
iter (fun x -> if p x then push_unsafe_ v' x) v;
v'
)
let fold_left f acc v =
let { vec; size } = v in
let rec fold acc i =
if i = size then
acc
else (
let x = Array.unsafe_get vec i in
fold (f acc x) (i + 1)
)
in
fold acc 0
let fold = fold_left
let exists p v =
let n = v.size in
let rec check i =
if i = n then
false
else
p v.vec.(i) || check (i + 1)
in
check 0
let for_all p v =
let n = v.size in
let rec check i =
if i = n then
true
else
p v.vec.(i) && check (i + 1)
in
check 0
let member ~eq x v = exists (eq x) v
let find_internal_ p v =
let n = v.size in
let rec check i =
if i = n then
raise_notrace Not_found
else (
let x = v.vec.(i) in
if p x then
x
else
check (i + 1)
)
in
check 0
let find_exn p v = try find_internal_ p v with Not_found -> raise Not_found
let find p v = try Some (find_internal_ p v) with Not_found -> None
let find_map f v =
let n = v.size in
let rec search i =
if i = n then
None
else (
match f v.vec.(i) with
| None -> search (i + 1)
| Some _ as res -> res
)
in
search 0
let filter_map f v =
let v' = create () in
iter
(fun x ->
match f x with
| None -> ()
| Some y -> push v' y)
v;
v'
let filter_map_in_place f v =
let i = ref 0 in
(* cur element *)
let j = ref 0 in
(* cur insertion point *)
let n = v.size in
while !i < n do
match f v.vec.(!i) with
| None -> incr i (* drop *)
| Some y ->
(* move element i at the first empty slot.
invariant: i >= j*)
v.vec.(!j) <- y;
incr i;
incr j
done;
(* free elements *)
fill_with_junk_ v.vec !j (v.size - !j);
v.size <- !j
let flat_map f v =
let v' = create () in
iter (fun x -> iter (push v') (f x)) v;
v'
let flat_map_seq f v =
let v' = create () in
iter
(fun x ->
let seq = f x in
append_seq v' seq)
v;
v'
let flat_map_list f v =
let v' = create () in
iter
(fun x ->
let l = f x in
append_list v' l)
v;
v'
let cartesian_product f a1 a2 : _ t =
let na1 = a1.size in
init (na1 * a2.size) (fun i_prod ->
let i = i_prod mod na1 in
let j = i_prod / na1 in
f a1.vec.(i) a2.vec.(j))
let rev_in_place v =
if v.size > 0 then (
let n = v.size in
let vec = v.vec in
for i = 0 to (n - 1) / 2 do
let x = Array.unsafe_get vec i in
let y = Array.unsafe_get vec (n - i - 1) in
Array.unsafe_set vec i y;
Array.unsafe_set vec (n - i - 1) x
done
)
let rev v =
let v' = copy v in
rev_in_place v';
v'
let rev_iter f v =
let { vec; size = n } = v in
for i = n - 1 downto 0 do
f (Array.unsafe_get vec i)
done
let size v = v.size
let length v = v.size
let capacity v = Array.length v.vec
let unsafe_get_array v = v.vec
let of_iter ?(init = create ()) seq =
append_iter init seq;
init
let of_seq ?(init = create ()) seq =
append_seq init seq;
init
let to_iter v k = iter k v
let to_iter_rev v k =
let { vec; size = n } = v in
for i = n - 1 downto 0 do
k (Array.unsafe_get vec i)
done
let to_seq v =
let { size; vec } = v in
let rec aux i () =
if i >= size then
Seq.Nil
else
Seq.Cons (vec.(i), aux (i + 1))
in
aux 0
let to_seq_rev v =
let { size; vec } = v in
let rec aux i () =
if i < 0 then
Seq.Nil
else
Seq.Cons (vec.(i), aux (i - 1))
in
aux (size - 1)
let slice_iter v start len =
assert (start >= 0 && len >= 0);
fun k ->
let { size; vec } = v in
assert (start + len <= size);
for i = start to start + len - 1 do
let x = Array.unsafe_get vec i in
k x
done
let range_inclusive i j =
if i > j then
init (i - j + 1) (fun k -> i - k)
else
init (j - i + 1) (fun k -> i + k)
let range_exclusive i j =
if i = j then
create ()
else if i > j then
init (i - j) (fun k -> i - k)
else
init (j - i) (fun k -> i + k)
let unsafe_slice v = v.vec, 0, v.size
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 ] -> return x
| [ x; y ] -> { size = 2; vec = [| x; y |] }
| x :: _ ->
let v = create_with ~capacity:(List.length l) x in
List.iter (push_unsafe_ v) l;
v
let to_array v = Array.sub v.vec 0 v.size
let to_list v = List.rev (fold (fun acc x -> x :: acc) [] v)
let to_string ?(start = "") ?(stop = "") ?(sep = ", ") item_to_string v =
start ^ (to_list v |> List.map item_to_string |> String.concat sep) ^ stop
let pp ?(pp_start = fun _ () -> ()) ?(pp_stop = fun _ () -> ())
?(pp_sep = fun fmt () -> Format.fprintf fmt ",@ ") pp_item fmt v =
pp_start fmt ();
iteri
(fun i x ->
if i > 0 then pp_sep fmt ();
pp_item fmt x)
v;
pp_stop fmt ()
module Infix = struct
let ( -- ) = range_inclusive
let ( --^ ) = range_exclusive
let ( >>= ) x f = flat_map f x
let ( >|= ) x f = map f x
[@@@ifge 4.8]
let ( let+ ) = ( >|= )
let ( let* ) = ( >>= )
let[@inline] ( and+ ) a1 a2 = cartesian_product (fun x y -> x, y) a1 a2
let ( and* ) = ( and+ )
[@@@endif]
end
include Infix

367
src/core/CCVec.mli Normal file
View file

@ -0,0 +1,367 @@
(* This file is free software, part of containers. See file "license" for more details. *)
(** Growable, mutable vector.
This replaces {!CCVector}, removing permissions, and re-vamping the API overall.
@since NEXT_RELEASE
*)
type 'a t
(** The type of a vector of elements of type ['a], with *)
type 'a iter = ('a -> unit) -> unit
(** Fast internal iterator. *)
type 'a equal = 'a -> 'a -> bool
type 'a ord = 'a -> 'a -> int
type 'a printer = Format.formatter -> 'a -> unit
val create : unit -> 'a t
(** Create a new, empty vector. *)
val create_with : ?capacity:int -> 'a -> 'a t
(** Create a new vector, the value is used to enforce the type the new vector.
@param capacity the size of the underlying array. *)
val return : 'a -> 'a t
(** Singleton vector.
@since 0.14 *)
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 : _ t -> unit
(** Clear the content of the vector.
This ensures that [length v = 0] but the underlying array is kept,
and possibly references to former elements, which are therefore
not garbage collectible. *)
val clear_and_reset : _ t -> unit
(** Clear the content of the vector, and deallocate the underlying array,
removing references to all the elements. The elements can be collected. *)
val ensure_with : init:'a -> 'a t -> int -> unit
(** Hint to the vector that it should have at least the given capacity.
This does not affect [length v].
@param init if [capacity v = 0], used to enforce the type of the vector
(see {!create_with}).
@raise Invalid_arg if the size is not suitable (negative, or too big for OCaml arrays) *)
val ensure : _ t -> int -> unit
(** Hint to the vector that it should have at least the given capacity.
Just a hint, will not be enforced if the vector is empty and [init]
is not provided.
@raise Invalid_arg if the size is not suitable (negative, or too big for OCaml arrays)
*)
val is_empty : _ t -> bool
(** Is the vector empty? *)
val push : 'a t -> 'a -> unit
(** Add an element at the end of the vector. *)
val resize_with : 'a t -> (int -> 'a) -> int -> unit
(** [resize_with vec f size] resizes vector [vec] up to [size], fills vector
with calls to [f] on indexes [[vec.size-1.. size - 1]].
The contents and size of vec are untouched if [size] is inferior or equal
to [length vec].
@raise Invalid_argument if the size is too big *)
val resize_with_init : 'a t -> init:'a -> int -> unit
(** [resize_with_init vec init size] resizes vector [vec] up to [size],
fills vector with calls to [init] on indexes [[length vec -1.. size - 1]].
The contents and size of vec are untouched if [size] is inferior or equal
to [length vec].
@raise Invalid_argument if the size is too big *)
val append : 'a t -> 'a t -> unit
(** [append a b] adds all elements of [b] to [a]. *)
val append_array : 'a t -> 'a array -> unit
(** Like {!append}, with an array. *)
val append_iter : 'a t -> 'a iter -> unit
(** Append content of iterator. *)
val append_seq : 'a t -> 'a Seq.t -> unit
(** Append content of iterator.
Renamed from [append_std_seq] since 3.0. *)
val append_list : 'a t -> 'a list -> unit
(** Append content of list. *)
val equal : 'a equal -> 'a t equal
(** Content-wise equality *)
val compare : 'a ord -> 'a t ord
(** Total ordering on vectors. Lexicographic comparison. *)
exception Empty
(** Raised on empty stack/vector. *)
val pop : 'a t -> 'a option
(** Remove last element, or [None]. *)
val pop_exn : 'a t -> 'a
(** Remove last element, or raise an exception if empty.
@raise Empty on an empty vector. *)
val top : 'a t -> 'a option
(** Top element, if present. *)
val top_exn : 'a t -> 'a
(** Top element, if present.
@raise Empty on an empty vector. *)
val copy : 'a t -> 'a t
(** Shallow copy. *)
val truncate : _ t -> int -> unit
(** Truncate to the given size (remove elements above this size).
Does nothing if the parameter is bigger than the current size. *)
val shrink_to_fit : _ t -> unit
(** Shrink internal array to fit the size of the vector. This will
most likely reallocate the internal array. *)
val member : ('a -> 'a -> bool) -> 'a -> 'a t -> bool
(** Is the element a member of the vector? *)
val sorted : ('a -> 'a -> int) -> 'a t -> 'a t
(** Sort the vector, returning a copy of it that is sorted
w.r.t the given ordering. The vector itself is unchanged.
The underlying array of the new vector can be smaller than
the original one. *)
val sort : ('a -> 'a -> int) -> 'a t -> unit
(** Sort the vector in place (modifying it).
This function change the size of the underlying array. *)
val uniq_sort : ('a -> 'a -> int) -> 'a t -> unit
(** Sort the array and remove duplicates, in place (e.g. modifying
the vector itself). *)
val iter : ('a -> unit) -> 'a t -> unit
(** Iterate on the vector's content. *)
val iteri : (int -> 'a -> unit) -> 'a t -> unit
(** Iterate on the vector, with indexes. *)
val map : ('a -> 'b) -> 'a t -> 'b t
(** Map elements of the vector, yielding a new vector. *)
val mapi : (int -> 'a -> 'b) -> 'a t -> 'b t
(** [map f v] is just like {!map}, but it also passes in the index
of each element as the first argument to the function [f]. *)
val map_in_place : ('a -> 'a) -> 'a t -> unit
(** Map elements of the vector in place. *)
val filter : ('a -> bool) -> 'a t -> 'a t
(** Filter elements from the vector. [filter p v] leaves [v] unchanged but
returns a new vector that only contains elements of [v] satisfying [p]. *)
val filter_in_place : ('a -> bool) -> 'a t -> unit
(** Filter elements from the vector in place. *)
val fold_left : ('b -> 'a -> 'b) -> 'b -> 'a t -> 'b
(** Fold on elements of the vector *)
val fold : ('b -> 'a -> 'b) -> 'b -> 'a t -> 'b
(** Fold on elements of the vector. Alias for {!fold_left}. *)
val exists : ('a -> bool) -> 'a t -> bool
(** Existential test (is there an element that satisfies the predicate?). *)
val for_all : ('a -> bool) -> 'a t -> bool
(** Universal test (do all the elements satisfy the predicate?). *)
val find : ('a -> bool) -> 'a t -> 'a option
(** 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 find_map : ('a -> 'b option) -> 'a t -> 'b option
(** [find_map f v] returns the first [Some y = f x] for [x] in [v],
or [None] if [f x = None] for each [x] in [v]. *)
val filter_map : ('a -> 'b option) -> 'a t -> 'b t
(** Map elements with a function, possibly filtering some of them out. *)
val filter_map_in_place : ('a -> 'a option) -> 'a t -> unit
(** Filter-map elements of the vector in place. *)
val flat_map : ('a -> 'b t) -> 'a t -> 'b t
(** Map each element to a sub-vector. *)
val flat_map_seq : ('a -> 'b Seq.t) -> 'a t -> 'b t
(** Like {!flat_map}, but using [Seq] for intermediate collections. *)
val flat_map_list : ('a -> 'b list) -> 'a t -> 'b t
(** Like {!flat_map}, but using {!list} for
intermediate collections. *)
val cartesian_product : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t
(** All combinaisons of tuples from the two vectors are passed to the function. *)
val range_inclusive : int -> int -> int t
(** Range of integers, either ascending or descending, where both
bounds are included, therefore the result is never empty).
Example: [1 -- 10] returns the vector [[1;2;3;4;5;6;7;8;9;10]]. *)
val range_exclusive : int -> int -> int t
(** Range of integers, either ascending or descending, but excluding the second argument.
Example: [1 --^ 10] returns the vector [[1;2;3;4;5;6;7;8;9]]. *)
module Infix : sig
val ( >>= ) : 'a t -> ('a -> 'b t) -> 'b t
(** Infix version of {!flat_map}. *)
val ( >|= ) : 'a t -> ('a -> 'b) -> 'b t
(** Infix version of {!map}. *)
val ( -- ) : int -> int -> int t
(** Alias for {!range_inclusive} *)
val ( --^ ) : int -> int -> int t
(** Alias for {!range_exclusive} *)
[@@@ifge 4.08]
val ( let+ ) : 'a t -> ('a -> 'b) -> 'b t
(** @since 2.8 *)
val ( and+ ) : 'a t -> 'b t -> ('a * 'b) t
(** @since 2.8 *)
val ( let* ) : 'a t -> ('a -> 'b t) -> 'b t
(** @since 2.8 *)
val ( and* ) : 'a t -> 'b t -> ('a * 'b) t
(** @since 2.8 *)
[@@@endif]
end
include module type of Infix
val get : 'a t -> int -> 'a
(** Access element by its index, or
@raise Invalid_argument if bad index. *)
val set : 'a t -> int -> 'a -> unit
(** Modify element at given index, or
@raise Invalid_argument if the index is
invalid (i.e. not in [[0.. length v-1]]). *)
val remove_and_shift : 'a t -> int -> unit
(** [remove_and_shift v i] remove the [i-th] element from [v].
Move elements that are after the [i-th] in [v], in linear time.
Preserve the order of the elements in [v].
See {!remove_unordered} for constant time removal function that doesn't
preserve the order of elements. *)
val remove_unordered : 'a t -> int -> unit
(** [remove_unordered v i] remove the [i-th] element from [v].
Does {b NOT} preserve the order of the elements in [v]
(might swap with the last element).
See {!remove_and_shift} if you want to keep the ordering. *)
val insert : 'a t -> int -> 'a -> unit
(** [insert v i x] insert the given element at index i.
Elements at location [i] and later are first shifted over in linear time before inserting [x].
Preserve the order of elements in [v]. *)
val rev : 'a t -> 'a t
(** Reverse the vector. *)
val rev_in_place : 'a t -> unit
(** Reverse the vector in place. *)
val rev_iter : ('a -> unit) -> 'a t -> unit
(** [rev_iter f a] is the same as [iter f (rev a)], only more efficient. *)
val size : _ t -> int
(** Number of elements in the vector. *)
val length : _ t -> int
(** 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
(** Access the underlying {b shared} array (do not modify!).
[unsafe_get_array v] is longer than [size v], but elements at higher
index than [size v] are undefined (do not access!). *)
val of_array : 'a array -> 'a t
(** [of_array a] returns a vector corresponding to the array [a]. Operates in [O(n)] time. *)
val of_list : 'a list -> 'a t
val to_array : 'a t -> 'a array
(** [to_array v] returns an array corresponding to the vector [v].
This allocates a new array. *)
val to_list : 'a t -> 'a list
(** Return a list with the elements contained in the vector. *)
val of_iter : ?init:'a t -> 'a iter -> 'a t
(** Convert an Iterator to a vector. *)
val of_seq : ?init:'a t -> 'a Seq.t -> 'a t
(** Convert an Iterator to a vector. *)
val to_iter : 'a t -> 'a iter
(** Return a [iter] with the elements contained in the vector. *)
val to_iter_rev : 'a t -> 'a iter
(** [to_iter_rev v] returns the sequence of elements of [v] in reverse order,
that is, the last elements of [v] are iterated on first.
*)
val to_seq : 'a t -> 'a Seq.t
(** Return an iterator with the elements contained in the vector.
Renamed from [to_std_seq] since 3.0.
*)
val to_seq_rev : 'a t -> 'a Seq.t
(** [to_seq v] returns the sequence of elements of [v] in reverse order,
that is, the last elements of [v] are iterated on first.
*)
val unsafe_slice : 'a t -> 'a array * int * int
(** Vector as an array slice. By doing it we expose the internal array, so
be careful!. *)
val slice_iter : 'a t -> int -> int -> 'a iter
(** [slice_iter v start len] is the sequence of elements from [v.(start)]
to [v.(start+len-1)].
*)
val to_string :
?start:string ->
?stop:string ->
?sep:string ->
('a -> string) ->
'a t ->
string
(** Print the vector in a string. *)
val pp :
?pp_start:unit printer ->
?pp_stop:unit printer ->
?pp_sep:unit printer ->
'a printer ->
'a t printer
(** [pp ~pp_start ~pp_stop ~pp_sep pp_item ppf v] formats the vector [v] on [ppf].
Each element is formatted with [pp_item], [pp_start] is called at the beginning,
[pp_stop] is called at the end, [pp_sep] is called between each elements.
By defaults [pp_start] and [pp_stop] does nothing and [pp_sep] defaults to
(fun out -> Format.fprintf out ",@ "). *)

View file

@ -1,6 +1,11 @@
(* This file is free software, part of containers. See file "license" for more details. *) (* This file is free software, part of containers. See file "license" for more details. *)
(** Growable, mutable vector *) (** Growable, mutable vector
@deprecated since NEXT_RELEASE , see {!CCVec} instead *)
[@@@deprecated "use CCVec"]
type ro = [ `RO ] type ro = [ `RO ]
type rw = [ `RW ] type rw = [ `RW ]

View file

@ -50,7 +50,8 @@ module Result = CCResult
module Seq = CCSeq module Seq = CCSeq
module Set = CCSet module Set = CCSet
module String = CCString module String = CCString
module Vector = CCVector module Vec = CCVec
module Vector = CCVector [@@deprecated "use Vec"]
module Monomorphic = CCMonomorphic module Monomorphic = CCMonomorphic
module Utf8_string = CCUtf8_string module Utf8_string = CCUtf8_string
module Unit = CCUnit module Unit = CCUnit

View file

@ -31,6 +31,7 @@ Containers_testlib.run_all ~descr:"containers"
T_sexp.get (); T_sexp.get ();
T_string.get (); T_string.get ();
T_utf8string.get (); T_utf8string.get ();
T_vec.get ();
T_vector.get (); T_vector.get ();
T_bencode.get (); T_bencode.get ();
T_cbor.get (); T_cbor.get ();

733
tests/core/t_vec.ml Normal file
View file

@ -0,0 +1,733 @@
module T = (val Containers_testlib.make ~__FILE__ ())
include T
open CCVec;;
t ~name:__LOC__ @@ fun () -> create_with ~capacity:200 1 |> capacity >= 200;;
t ~name:__LOC__ @@ fun () -> return 42 |> to_list = [ 42 ];;
t ~name:__LOC__ @@ fun () -> return 42 |> length = 1;;
t ~name:__LOC__ @@ fun () ->
let v = create_with ~capacity:10 1 in
ensure v 200;
capacity v >= 200
;;
t ~name:__LOC__ @@ fun () ->
let v = create () in
push v 0.;
push v 1.;
push v 2.;
3 = length v
;;
t ~name:__LOC__ @@ fun () ->
let v = create () in
push v 1.;
push v 2.;
push v 3.;
6. = get v 0 +. get v 1 +. get v 2
;;
t ~name:__LOC__ @@ fun () ->
let v = create () in
push v 0;
push v 1;
push v 2;
3 = length v
;;
t ~name:__LOC__ @@ fun () ->
let v = create () in
push v 1;
push v 2;
push v 3;
6 = get v 0 + get v 1 + get v 2
;;
t ~name:__LOC__ @@ fun () ->
let v = create () in
push v "a";
push v "b";
push v "c";
3 = length v
;;
t ~name:__LOC__ @@ fun () ->
let v = create () in
push v "a";
push v "b";
push v "c";
"abc" = String.concat "" (to_list v)
;;
t ~name:__LOC__ @@ fun () ->
let v = create () in
push v 0.;
push v 1.;
clear v;
push v 0.;
push v 1.;
push v 7.;
push v 10.;
push v 12.;
truncate v 2;
assert_equal 1. (fold ( +. ) 0. v);
clear v;
assert_equal 0 (size v);
push v 0.;
push v 1.;
push v 7.;
push v 10.;
push v 12.;
assert_equal (1. +. 7. +. 10. +. 12.) (fold ( +. ) 0. v);
true
;;
t ~name:__LOC__ @@ fun () ->
let v = of_iter Iter.(1 -- 10) in
assert_equal 10 (size v);
clear v;
assert_equal 0 (size v);
assert (Iter.is_empty (to_iter v));
true
;;
t ~name:__LOC__ (fun () ->
let v = of_iter Iter.(1 -- 10) in
assert_equal CCList.(1 -- 10) (to_seq v |> CCList.of_seq);
(* test that we capture the length *)
let seq = to_seq v in
push v 11;
assert_equal CCList.(1 -- 10) (seq |> CCList.of_seq);
assert_equal CCList.(1 -- 11) (to_seq v |> CCList.of_seq);
clear v;
assert_equal 0 (size v);
assert (CCSeq.is_empty (to_seq v));
true)
;;
t ~name:__LOC__ (fun () ->
let v = of_iter Iter.(1 -- 10) in
assert_equal CCList.(1 -- 10 |> rev) (to_seq_rev v |> CCList.of_seq);
clear v;
assert_equal 0 (size v);
assert (CCSeq.is_empty (to_seq v));
true)
;;
t ~name:__LOC__ @@ fun () ->
let v = create () in
push v 1;
to_list v = [ 1 ]
;;
t ~name:__LOC__ @@ fun () ->
let v = of_list [ 1; 2; 3 ] in
push v 4;
to_list v = [ 1; 2; 3; 4 ]
;;
t ~name:__LOC__ @@ fun () ->
let v = make 1 0 in
resize_with v (fun i -> i) 5;
to_list v = [ 0; 1; 2; 3; 4 ]
;;
t ~name:__LOC__ @@ fun () ->
let v = make 1 0 in
resize_with v (fun i -> i) 5;
CCList.length (to_list v) = 5
;;
t ~name:__LOC__ @@ fun () ->
let v = create_with ~capacity:2 0 in
resize_with v (fun i -> i) 5;
to_list v = [ 0; 1; 2; 3; 4 ]
;;
t ~name:__LOC__ @@ fun () ->
let v = make 5 0 in
resize_with v (fun i -> i) 5;
to_list v = [ 0; 0; 0; 0; 0 ]
;;
t ~name:__LOC__ @@ fun () ->
let v = make 5 0 in
resize_with v (fun i -> i) 6;
to_list v = [ 0; 0; 0; 0; 0; 5 ]
;;
t ~name:__LOC__ @@ fun () ->
let v = make 5 0 in
try
resize_with v (fun i -> i) (-1);
false
with Invalid_argument _ -> true
;;
t ~name:__LOC__ @@ fun () ->
let v = make 5 0 in
resize_with v (fun i -> i) 5;
List.length (to_list v) = 5
;;
t ~name:__LOC__ @@ fun () ->
let v = make 1 0 in
resize_with_init v ~init:1 5;
to_list v = [ 0; 1; 1; 1; 1 ]
;;
t ~name:__LOC__ @@ fun () ->
let v = make 1 0 in
resize_with_init v ~init:1 5;
List.length (to_list v) = 5
;;
t ~name:__LOC__ @@ fun () ->
let v = create_with ~capacity:2 0 in
resize_with_init v ~init:1 5;
to_list v = [ 1; 1; 1; 1; 1 ]
;;
t ~name:__LOC__ @@ fun () ->
let v = make 5 0 in
resize_with_init v ~init:1 5;
to_list v = [ 0; 0; 0; 0; 0 ]
;;
t ~name:__LOC__ @@ fun () ->
let v = make 3 0 in
resize_with_init v ~init:1 5;
to_list v = [ 0; 0; 0; 1; 1 ]
;;
t ~name:__LOC__ @@ fun () ->
let v = make 5 0 in
try
resize_with_init v ~init:1 (-1);
false
with Invalid_argument _ -> true
;;
t ~name:__LOC__ @@ fun () ->
let v = make 5 0 in
resize_with_init v ~init:1 5;
List.length (to_list v) = 5
;;
(* test for asymptotic behavior *)
t ~name:__LOC__ @@ fun () ->
let v = make 1 0 in
for i = 0 to 100_000 do
resize_with_init v ~init:10 i
done;
true
;;
t ~name:__LOC__ @@ fun () ->
let v1 = init 5 (fun i -> i) and v2 = init 5 (fun i -> i + 5) in
append v1 v2;
to_list v1 = CCList.(0 -- 9)
;;
t ~name:__LOC__ @@ fun () ->
let empty = create () and v2 = init 5 (fun i -> i) in
append empty v2;
to_list empty = CCList.(0 -- 4)
;;
t ~name:__LOC__ @@ fun () ->
let v1 = init 5 (fun i -> i) and empty = create () in
append v1 empty;
to_list v1 = CCList.(0 -- 4)
;;
t ~name:__LOC__ @@ fun () ->
let v = init 3 (fun i -> i) in
append v v;
to_list v = [ 0; 1; 2; 0; 1; 2 ]
;;
t ~name:__LOC__ @@ fun () ->
let empty = create () in
append empty empty;
to_list empty = []
;;
t ~name:__LOC__ @@ fun () ->
let a = of_iter Iter.(1 -- 5) in
let b = of_iter Iter.(6 -- 10) in
append a b;
assert_equal 10 (size a);
assert_equal (Iter.to_array Iter.(1 -- 10)) (to_array a);
assert_equal (Iter.to_array Iter.(6 -- 10)) (to_array b);
true
;;
q
Q.(list_of_size (Gen.int_range 10 10) small_int)
(fun l ->
let v1 = of_list l and v2 = of_list l in
remove_and_shift v1 9;
remove_unordered v2 9;
to_list v1 = to_list v2)
;;
q
Q.(list_of_size (Gen.int_range 10 10) small_int)
(fun l ->
let l = List.sort CCInt.compare l in
let v = of_list l in
remove_and_shift v 3;
to_list v = List.sort CCInt.compare (to_list v))
;;
q
Q.(list_of_size (Gen.int_range 10 10) small_int)
(fun l ->
let l = List.sort CCInt.compare l in
let v1 = of_list l and v2 = of_list l in
remove_and_shift v1 3;
remove_unordered v2 3;
to_list v1 = List.sort CCInt.compare (to_list v2))
;;
t ~name:__LOC__ @@ fun () ->
let v = 1 -- 5 in
insert v 3 9;
to_list v = [ 1; 2; 3; 9; 4; 5 ]
;;
t ~name:__LOC__ @@ fun () ->
let v = create () in
insert v 0 2;
to_list v = [ 2 ]
;;
t ~name:__LOC__ @@ fun () ->
let v = 1 -- 3 in
remove_and_shift v 1;
insert v 1 5;
to_list v = [ 1; 5; 3 ]
;;
t ~name:__LOC__ @@ fun () ->
let v = 1 -- 3 in
remove_and_shift v 0;
insert v 2 5;
to_list v = [ 2; 3; 5 ]
;;
t ~name:__LOC__ @@ fun () ->
let v = 1 -- 3 in
insert v 3 5;
to_list v = [ 1; 2; 3; 5 ]
;;
t ~name:__LOC__ @@ fun () ->
let v1 = init 5 (fun i -> i) and v2 = Array.init 5 (fun i -> i + 5) in
append_array v1 v2;
to_list v1 = CCList.(0 -- 9)
;;
t ~name:__LOC__ @@ fun () ->
let empty = create () in
append_array empty CCArray.(0 -- 5);
to_list empty = CCList.(0 -- 5)
;;
t ~name:__LOC__ @@ fun () ->
let v1 = init 5 (fun i -> i) in
append_array v1 [||];
to_list v1 = CCList.(0 -- 4)
;;
t ~name:__LOC__ @@ fun () ->
let empty = create () in
append_array empty [||];
to_list empty = []
;;
q
Q.(pair (list int) (list int))
(fun (l1, l2) ->
let v = of_list l1 in
append_list v l2;
to_list v = l1 @ l2)
;;
q
Q.(pair (list int) (list int))
(fun (l1, l2) ->
let v = of_list l1 in
append_list v l2;
length v = List.length l1 + List.length l2)
let gen x =
let small = length in
let print =
CCOption.map (fun p x -> Q.Print.list p (CCVec.to_list x)) x.Q.print
in
Q.make ?print ~small Q.Gen.(list x.Q.gen >|= of_list)
;;
q
(Q.pair (gen Q.int) (gen Q.int))
(fun (v1, v2) ->
let l1 = to_list v1 in
append v1 v2;
Iter.to_list (to_iter v1)
= Iter.(to_list (append (of_list l1) (to_iter v2))))
;;
t ~name:__LOC__ @@ fun () -> equal ( = ) (create ()) (create ());;
t ~name:__LOC__ @@ fun () -> equal ( = ) (return 42) (return 42);;
t ~name:__LOC__ @@ fun () -> not (equal ( = ) (create ()) (return 42));;
t ~name:__LOC__ @@ fun () -> not (equal ( = ) (return 42) (create ()));;
q
Q.(
let g = list_of_size Gen.(0 -- 10) small_int in
pair g g)
(fun (l1, l2) -> equal ( = ) (of_list l1) (of_list l2) = (l1 = l2))
;;
q
Q.(pair (small_list small_int) (small_list small_int))
(fun (l1, l2) ->
let v1 = of_list l1 in
let v2 = of_list l2 in
equal ( = ) v1 v2 = (l1 = l2))
;;
q
Q.(pair (small_list small_int) (small_list small_int))
(fun (l1, l2) ->
let v1 = of_list l1 in
let v2 = of_list l2 in
compare Stdlib.compare v1 v2 = CCList.compare Stdlib.compare l1 l2)
;;
t ~name:__LOC__ @@ fun () -> 1 -- 10 |> top = Some 10;;
t ~name:__LOC__ @@ fun () -> create () |> top = None;;
t ~name:__LOC__ @@ fun () -> 1 -- 10 |> top_exn = 10;;
t ~name:__LOC__ @@ fun () ->
let v = of_list [ 1; 2; 3 ] in
let v' = copy v in
to_list v' = [ 1; 2; 3 ]
;;
t ~name:__LOC__ @@ fun () -> create () |> copy |> is_empty;;
t ~name:__LOC__ @@ fun () ->
let v = of_iter Iter.(1 -- 100) in
assert_equal 100 (size v);
let v' = copy v in
assert_equal 100 (size v');
clear v';
assert (is_empty v');
assert (not (is_empty v));
true
;;
q
Q.(small_list small_int)
(fun l ->
let v = of_list l in
let v' = copy v in
equal ( = ) v v')
;;
t ~name:__LOC__ @@ fun () ->
let v = of_iter Iter.(1 -- 10) in
truncate v 5;
assert_equal [ 1; 2; 3; 4; 5 ] (to_list v);
true
;;
q (gen Q.small_int) (fun v ->
let n = size v / 2 in
let l = to_list v in
let h = Iter.(to_list (take n (of_list l))) in
let v' = copy v in
truncate v' n;
h = to_list v')
;;
q (gen Q.small_int) (fun v ->
let v' = copy v in
shrink_to_fit v;
to_list v = to_list v')
;;
q (gen Q.small_int) (fun v ->
let v' = sorted Stdlib.compare v in
let l = to_list v' in
List.sort Stdlib.compare l = l)
;;
q (gen Q.small_int) (fun v ->
let v' = copy v in
sort Stdlib.compare v';
let l = to_list v' in
List.sort Stdlib.compare l = l)
;;
t ~name:__LOC__ @@ fun () ->
let v = of_list [ 1; 4; 5; 3; 2; 4; 1 ] in
uniq_sort Stdlib.compare v;
to_list v = [ 1; 2; 3; 4; 5 ]
;;
q ~long_factor:10
Q.(small_list small_int)
(fun l ->
let v = of_list l in
uniq_sort Stdlib.compare v;
to_list v = CCList.sort_uniq ~cmp:Stdlib.compare l)
;;
t ~name:__LOC__ @@ fun () ->
let v = 0 -- 6 in
iteri (fun i _ -> if i = 3 then remove_unordered v i) v;
length v = 6
;;
t ~name:__LOC__ @@ fun () ->
let v = create () in
push v 1;
push v 2;
push v 3;
to_list (map string_of_int v) = [ "1"; "2"; "3" ]
;;
q
Q.(pair (fun1 Observable.int small_int) (small_list small_int))
(fun (Q.Fun (_, f), l) ->
let v = of_list l in
to_list (map f v) = List.map f l)
;;
t ~name:__LOC__ @@ fun () ->
let v = create () in
push v 1;
push v 2;
push v 3;
to_list (mapi (fun i e -> Printf.sprintf "%i %i" i e) v)
= [ "0 1"; "1 2"; "2 3" ]
;;
q
Q.(pair (fun2 Observable.int Observable.int small_int) (small_list small_int))
(fun (Q.Fun (_, f), l) ->
let v = of_list l in
to_list (mapi f v) = List.mapi f l)
;;
q
Q.(pair (fun1 Observable.int small_int) (small_list small_int))
(fun (Q.Fun (_, f), l) ->
let v = of_list l in
map_in_place f v;
to_list v = List.map f l)
;;
t ~name:__LOC__ @@ fun () ->
let v = 1 -- 10 in
filter_in_place (fun x -> x < 4) v;
to_list v = [ 1; 2; 3 ]
;;
q
Q.(pair (fun1 Observable.int bool) (small_list small_int))
(fun (Q.Fun (_, f), l) ->
let v = of_list l in
filter_in_place f v;
to_list v = List.filter f l)
;;
t ~name:__LOC__ @@ fun () ->
filter (fun x -> x mod 2 = 0) (of_list [ 1; 2; 3; 4; 5 ]) |> to_list = [ 2; 4 ]
;;
t ~name:__LOC__ @@ fun () ->
filter (fun x -> x mod 2 = 0) (1 -- 1_000_000) |> length = 500_000
;;
q
Q.(pair (fun1 Observable.int bool) (small_list small_int))
(fun (Q.Fun (_, f), l) ->
let v = of_list l in
to_list (filter f v) = List.filter f l)
;;
t ~name:__LOC__ @@ fun () -> fold ( + ) 0 (of_list [ 1; 2; 3; 4; 5 ]) = 15;;
t ~name:__LOC__ @@ fun () -> fold ( + ) 0 (create ()) = 0;;
q
Q.(pair (fun2 Observable.int Observable.int small_int) (small_list small_int))
(fun (Q.Fun (_, f), l) ->
let v = of_list l in
fold f 0 v = List.fold_left f 0 l)
;;
q
Q.(pair (fun1 Observable.int bool) (small_list small_int))
(fun (Q.Fun (_, f), l) ->
let v = of_list l in
exists f v = List.exists f l)
;;
q
Q.(pair (fun1 Observable.int bool) (small_list small_int))
(fun (Q.Fun (_, f), l) ->
let v = of_list l in
for_all f v = List.for_all f l)
;;
q
Q.(pair (fun1 Observable.int bool) (small_list small_int))
(fun (Q.Fun (_, f), l) ->
let v = of_list l in
find f v = CCList.find_pred f l)
;;
q
Q.(list small_int)
(fun l ->
let v = of_list l in
let f x = x > 30 && x < 35 in
find_map
(fun x ->
if f x then
Some x
else
None)
v
= find f v)
;;
q
Q.(pair (fun1 Observable.int (option bool)) (small_list small_int))
(fun (Q.Fun (_, f), l) ->
let v = of_list l in
to_list (filter_map f v) = CCList.filter_map f l)
;;
q
Q.(pair (fun1 Observable.int (option small_int)) (small_list small_int))
(fun (Q.Fun (_, f), l) ->
let v = of_list l in
filter_map_in_place f v;
to_list v = CCList.filter_map f l)
;;
(* check it frees memory properly *)
t ~name:__LOC__ @@ fun () ->
let w = Weak.create 1 in
let v =
let s = "coucou" ^ "lol" in
Weak.set w 0 (Some s);
of_list [ "a"; s ]
in
filter_in_place (fun s -> String.length s <= 1) v;
assert_equal 1 (length v);
assert_equal "a" (get v 0);
Gc.full_major ();
assert_equal None (Weak.get w 0);
true
;;
eq ~cmp:( = )
~printer:Q.Print.(list int)
[ 11; 12; 21; 22 ]
(List.sort CCInt.compare @@ to_list
@@ cartesian_product ( + ) (of_list [ 10; 20 ]) (of_list [ 1; 2 ]))
;;
eq ~cmp:( = )
~printer:Q.Print.(list int)
[ 11; 12; 13; 14 ]
(List.sort CCInt.compare @@ to_list
@@ cartesian_product ( + ) (of_list [ 10 ]) (of_list [ 1; 2; 3; 4 ]))
;;
q
Q.(small_list small_int)
(fun l ->
let v = of_list l in
rev_in_place v;
to_list v = List.rev l)
;;
t ~name:__LOC__ @@ fun () ->
rev (of_list [ 1; 2; 3; 4 ]) |> to_list = [ 4; 3; 2; 1 ]
;;
t ~name:__LOC__ @@ fun () ->
rev (of_list [ 1; 2; 3; 4; 5 ]) |> to_list = [ 5; 4; 3; 2; 1 ]
;;
t ~name:__LOC__ @@ fun () -> rev (create ()) |> to_list = [];;
q
Q.(small_list small_int)
(fun l ->
let v = of_list l in
to_list (rev v) = List.rev l)
;;
t ~name:__LOC__ @@ fun () ->
let v = of_list [ 1; 2; 3 ] in
(fun f -> rev_iter f v) |> Iter.to_list = [ 3; 2; 1 ]
;;
q
Q.(list int)
(fun l ->
let v = of_list l in
(fun f -> rev_iter f v) |> Iter.to_list = List.rev l)
;;
t ~name:__LOC__ @@ fun () ->
of_iter Iter.(1 -- 10) |> to_list = CCList.(1 -- 10)
;;
q
Q.(list int)
(fun l ->
let v = of_list l in
v |> to_iter_rev |> Iter.to_rev_list = l)
;;
t ~name:__LOC__ @@ fun () ->
slice_iter (of_list [ 0; 1; 2; 3; 4 ]) 1 3 |> CCList.of_iter = [ 1; 2; 3 ]
;;
t ~name:__LOC__ @@ fun () ->
slice_iter (of_list [ 0; 1; 2; 3; 4 ]) 1 4 |> CCList.of_iter = [ 1; 2; 3; 4 ]
;;
t ~name:__LOC__ @@ fun () ->
slice_iter (of_list [ 0; 1; 2; 3; 4 ]) 0 5 |> CCList.of_iter = [ 0; 1; 2; 3; 4 ]
;;
t ~name:__LOC__ @@ fun () -> 1 -- 4 |> to_list = [ 1; 2; 3; 4 ];;
t ~name:__LOC__ @@ fun () -> 4 -- 1 |> to_list = [ 4; 3; 2; 1 ];;
t ~name:__LOC__ @@ fun () -> 0 -- 0 |> to_list = [ 0 ];;
q
Q.(pair small_int small_int)
(fun (a, b) -> a -- b |> to_list = CCList.(a -- b))
;;
q
Q.(pair small_int small_int)
(fun (a, b) -> a --^ b |> to_list = CCList.(a --^ b))
;;
t ~name:__LOC__ @@ fun () ->
of_list CCList.(1 -- 300_000) |> to_list = CCList.(1 -- 300_000)

View file

@ -1,5 +1,8 @@
module T = (val Containers_testlib.make ~__FILE__ ()) module T = (val Containers_testlib.make ~__FILE__ ())
include T include T
[@@@ocaml.alert "-deprecated"]
open CCVector;; open CCVector;;
t @@ fun () -> create_with ~capacity:200 1 |> capacity >= 200;; t @@ fun () -> create_with ~capacity:200 1 |> capacity >= 200;;