mirror of
https://github.com/c-cube/ocaml-containers.git
synced 2025-12-06 03:05:28 -05:00
Merge 3b10a14c93 into 02ac5bd78a
This commit is contained in:
commit
ecfc116de4
9 changed files with 1779 additions and 35 deletions
51
README.md
51
README.md
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
639
src/core/CCVec.ml
Normal 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
367
src/core/CCVec.mli
Normal 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 ",@ "). *)
|
||||||
|
|
@ -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 ]
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
733
tests/core/t_vec.ml
Normal 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)
|
||||||
|
|
@ -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;;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue