Array.Sub: slice implementation

This commit is contained in:
Simon Cruanes 2014-06-15 18:58:32 +02:00
parent e2bb0e93cb
commit 9a9954c420
2 changed files with 406 additions and 96 deletions

View file

@ -25,26 +25,197 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
(** {1 Array utils} *) (** {1 Array utils} *)
type 'a sequence = ('a -> unit) -> unit
type 'a klist = unit -> [`Nil | `Cons of 'a * 'a klist]
type 'a gen = unit -> 'a option
type 'a equal = 'a -> 'a -> bool
type 'a ord = 'a -> 'a -> int
module type S = sig
type 'a t
(** Array, or sub-array, containing elements of type ['a] *)
val empty : 'a t
val equal : 'a equal -> 'a t equal
val compare : 'a ord -> 'a t ord
val get : 'a t -> int -> 'a
val set : 'a t -> int -> 'a -> unit
val length : _ t -> int
val fold : ('b -> 'a -> 'b) -> 'b -> 'a t -> 'b
val foldi : ('b -> int -> 'a -> 'b) -> 'b -> 'a t -> 'b
(** fold left on array, with index *)
val iter : ('a -> unit) -> 'a t -> unit
val iteri : (int -> 'a -> unit) -> 'a t -> unit
val reverse_in_place : 'a t -> unit
(** Reverse the array in place *)
val find : ('a -> 'b option) -> 'a t -> 'b option
(** [find f a] returns [Some y] if there is an element [x] such
that [f x = Some y], else it returns [None] *)
val for_all : ('a -> bool) -> 'a t -> bool
val for_all2 : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool
(** Forall on pairs of arrays.
@raise Invalid_argument if they have distinct lengths *)
val exists : ('a -> bool) -> 'a t -> bool
val exists2 : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool
(** Exists on pairs of arrays.
@raise Invalid_argument if they have distinct lengths *)
val shuffle : 'a t -> unit
(** shuffle randomly the array, in place *)
val shuffle_with : Random.State.t -> 'a t -> unit
(** Like shuffle but using a specialized random state *)
val to_seq : 'a t -> 'a sequence
val to_gen : 'a t -> 'a gen
val to_klist : 'a t -> 'a klist
(** {2 IO} *)
val pp: ?sep:string -> (Buffer.t -> 'a -> unit)
-> Buffer.t -> 'a t -> unit
(** print an array of items with printing function *)
val pp_i: ?sep:string -> (Buffer.t -> int -> 'a -> unit)
-> Buffer.t -> 'a t -> unit
(** print an array, giving the printing function both index and item *)
val print : ?sep:string -> (Format.formatter -> 'a -> unit)
-> Format.formatter -> 'a t -> unit
(** print an array of items with printing function *)
end
(** {2 General Implementation}
Most of those functions that a range [(i,j)] with
[i] included and [j] excluded *)
let rec _foldi f acc a i j =
if i = j then acc else _foldi f (f acc i a.(i)) a (i+1) j
let _reverse_in_place a i j =
if i=j then ()
else
for k = i to j/2 do
let t = a.(k) in
a.(k) <- a.(j-k);
a.(j-k) <- t;
done
let rec _equal eq a1 i1 j1 a2 i2 j2 =
if i1 = j1 || i2 = j2
then (assert (i1=j1 && i2=j2); true)
else
eq a1.(i1) a2.(i2) && _equal eq a1 (i1+1) j1 a2 (i2+2) j2
let rec _compare cmp a1 i1 j1 a2 i2 j2 =
if i1 = j1
then if i2=j2 then 0 else -1
else if i2=j2
then 1
else
let c = cmp a1.(i1) a2.(i2) in
if c = 0
then _compare cmp a1 (i1+1) j1 a2 (i2+2) j2
else c
let rec _find f a i j =
if i = j then None
else match f a.(i) with
| Some _ as res -> res
| None -> _find f a (i+1) j
let rec _for_all p a i j =
i = j || (p a.(i) && _for_all p a (i+1) j)
let rec _exists p a i j =
i <> j && (p a.(i) || _exists p a (i+1) j)
let rec _for_all2 p a1 a2 i1 i2 j1 =
i1 = j1 || (p a1.(i1) a2.(i2) && _for_all2 p a1 a2 (i1+1) (i2+1) j1)
let rec _exists2 p a1 a2 i1 i2 j1 =
i1 <> j1 && (p a1.(i1) a2.(i2) || _exists2 p a1 a2 (i1+1) (i2+1) j1)
(* shuffle a[i...j[ using the given int random generator
See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle *)
let _shuffle _rand_int a i j =
for k = i to j do
let l = _rand_int k in
let tmp = a.(l) in
a.(l) <- a.(k);
a.(l) <- tmp;
done
let _pp ~sep pp_item buf a i j =
for k = i to j - 1 do
if k > i then Buffer.add_string buf sep;
pp_item buf a.(k)
done
let _pp_i ~sep pp_item buf a i j =
for k = i to j - 1 do
if k > i then Buffer.add_string buf sep;
pp_item buf k a.(k)
done
let _print ~sep pp_item fmt a i j =
for k = i to j - 1 do
if k > i then Format.pp_print_string fmt sep;
pp_item fmt a.(k)
done
let _to_gen a i j =
let k = ref i in
fun () ->
if !k < j
then (
let x = a.(!k) in
incr k;
Some x
) else None
let rec _to_klist a i j () =
if i=j then `Nil else `Cons (a.(i), _to_klist a (i+1) j)
(** {2 Arrays} *)
type 'a t = 'a array type 'a t = 'a array
let empty = [| |] let empty = [| |]
let map = Array.map let map = Array.map
let foldi f acc a = let length = Array.length
let rec recurse acc i =
if i = Array.length a then acc else recurse (f acc i a.(i)) (i+1) let get = Array.get
in recurse acc 0
let set = Array.set
let fold = Array.fold_left
let foldi f acc a = _foldi f acc a 0 (Array.length a)
let iter = Array.iter
let iteri = Array.iteri
let reverse_in_place a = let reverse_in_place a =
if a = [| |] then () _reverse_in_place a 0 (Array.length a)
else
let n = Array.length a in
for i = 0 to (n-1)/2 do
let t = a.(i) in
a.(i) <- a.(n-i-1);
a.(n-i-1) <- t;
done
(*$T (*$T
reverse_in_place [| |]; true reverse_in_place [| |]; true
@ -58,12 +229,7 @@ let reverse_in_place a =
*) *)
let find f a = let find f a =
let rec find i = _find f a 0 (Array.length a)
if i = Array.length a then None
else match f a.(i) with
| Some _ as res -> res
| None -> find (i+1)
in find 0
let filter_map f a = let filter_map f a =
let rec aux acc i = let rec aux acc i =
@ -116,23 +282,19 @@ let flat_map f a =
let (>>=) a f = flat_map f a let (>>=) a f = flat_map f a
let for_all p a = let for_all p a = _for_all p a 0 (Array.length a)
let rec check i =
i = Array.length a || (p a.(i) && check (i+1))
in check 0
let for_all2 p a1 a2 = let exists p a = _exists p a 0 (Array.length a)
let rec check i =
i = Array.length a1 || (p a1.(i) a2.(i) && check (i+1))
in
if Array.length a1 <> Array.length a2
then raise (Invalid_argument "forall2")
else check 0
let exists p a = let for_all2 p a b =
let rec check i = Array.length a = Array.length b
i < Array.length a && (p a.(i) || check (i+1)) &&
in check 0 _for_all2 p a b 0 0 (Array.length a)
let exists2 p a b =
Array.length a = Array.length b
&&
_exists2 p a b 0 0 (Array.length a)
let (--) i j = let (--) i j =
if i<=j if i<=j
@ -147,37 +309,110 @@ let except_idx a i =
(fun acc j elt -> if i = j then acc else elt::acc) (fun acc j elt -> if i = j then acc else elt::acc)
[] a [] a
(* Randomly shuffle the array, in place. let equal eq a b =
See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle *) Array.length a = Array.length b
let _shuffle _rand_int a = &&
for i = 1 to Array.length a - 1 do _equal eq a 0 (Array.length a) b 0 (Array.length b)
let j = _rand_int i in
let tmp = a.(i) in
a.(i) <- a.(j);
a.(j) <- tmp;
done
let shuffle a = _shuffle Random.int a let compare cmp a b =
_compare cmp a 0 (Array.length a) b 0 (Array.length b)
let shuffle_with st a = _shuffle (Random.State.int st) a let shuffle a = _shuffle Random.int a 0 (Array.length a)
(** print an array of items using the printing function *) let shuffle_with st a = _shuffle (Random.State.int st) a 0 (Array.length a)
let pp ?(sep=", ") pp_item buf a =
for i = 0 to Array.length a - 1 do
(if i > 0 then Buffer.add_string buf sep);
pp_item buf a.(i)
done
(** print an array of items using the printing function *) let pp ?(sep=", ") pp_item buf a = _pp ~sep pp_item buf a 0 (Array.length a)
let pp_i ?(sep=", ") pp_item buf a =
for i = 0 to Array.length a - 1 do
(if i > 0 then Buffer.add_string buf sep);
pp_item buf i a.(i)
done
let print ?(sep=", ") pp_item fmt a = let pp_i ?(sep=", ") pp_item buf a = _pp_i ~sep pp_item buf a 0 (Array.length a)
Array.iteri
(fun i x -> let print ?(sep=", ") pp_item fmt a = _print ~sep pp_item fmt a 0 (Array.length a)
if i > 0 then Format.pp_print_string fmt sep;
pp_item fmt x let to_seq a k = iter k a
) a
let to_gen a = _to_gen a 0 (Array.length a)
let to_klist a = _to_klist a 0 (Array.length a)
module Sub = struct
type 'a t = {
arr : 'a array;
i : int; (** Start index (included) *)
j : int; (** Stop index (excluded) *)
}
let empty = {
arr = [||];
i = 0;
j = 0;
}
let make arr i ~len =
if i+len > Array.length arr then invalid_arg "Array.Sub.make";
{ arr; i; j=i+len; }
let full arr = { arr; i=0; j=Array.length arr; }
let underlying a = a.arr
let length a = a.j - a.i
let copy a = Array.sub a.arr a.i (length a)
let sub a i len = make a.arr (a.i + i) len
let equal eq a b =
length a = length b && _equal eq a.arr a.i a.j b.arr b.i b.j
let compare cmp a b =
_compare cmp a.arr a.i a.j b.arr b.i b.j
let fold f acc a =
let rec _fold acc i j =
if i=j then acc
else _fold (f acc a.arr.(i)) (i+1) j
in _fold acc a.i a.j
let foldi f acc a = _foldi f acc a.arr a.i a.j
let get a i = a.arr.(a.i+i)
let set a i x = a.arr.(a.i+i) <- x
let iter f a =
for k=a.i to a.j-1 do f a.arr.(k) done
let iteri f a =
for k=0 to length a-1 do f k a.arr.(a.i + k) done
let reverse_in_place a = _reverse_in_place a.arr a.i a.j
let find f a = _find f a.arr a.i a.j
let for_all p a = _for_all p a.arr a.i a.j
let exists p a = _exists p a.arr a.i a.j
let for_all2 p a b =
length a = length b && _for_all2 p a.arr b.arr a.i b.i b.j
let exists2 p a b =
length a = length b && _exists2 p a.arr b.arr a.i b.i a.j
let shuffle a =
_shuffle Random.int a.arr a.i a.j
let shuffle_with st a =
_shuffle (Random.State.int st) a.arr a.i a.j
let pp ?(sep=", ") pp_item buf a = _pp ~sep pp_item buf a.arr a.i a.j
let pp_i ?(sep=", ") pp_item buf a = _pp_i ~sep pp_item buf a.arr a.i a.j
let print ?(sep=", ") pp_item fmt a = _print ~sep pp_item fmt a.arr a.i a.j
let to_seq a k = iter k a
let to_gen a = _to_gen a.arr a.i a.j
let to_klist a = _to_klist a.arr a.i a.j
end

View file

@ -25,18 +25,38 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
(** {1 Array utils} *) (** {1 Array utils} *)
type 'a t = 'a array type 'a sequence = ('a -> unit) -> unit
type 'a klist = unit -> [`Nil | `Cons of 'a * 'a klist]
type 'a gen = unit -> 'a option
type 'a equal = 'a -> 'a -> bool
type 'a ord = 'a -> 'a -> int
(** {2 Abstract Signature} *)
module type S = sig
type 'a t
(** Array, or sub-array, containing elements of type ['a] *)
val empty : 'a t val empty : 'a t
val map : ('a -> 'b) -> 'a t -> 'b t val equal : 'a equal -> 'a t equal
val compare : 'a ord -> 'a t ord
val get : 'a t -> int -> 'a
val set : 'a t -> int -> 'a -> unit
val length : _ t -> int
val fold : ('b -> 'a -> 'b) -> 'b -> 'a t -> 'b
val foldi : ('b -> int -> 'a -> 'b) -> 'b -> 'a t -> 'b val foldi : ('b -> int -> 'a -> 'b) -> 'b -> 'a t -> 'b
(** fold left on array, with index *) (** fold left on array, with index *)
val filter : ('a -> bool) -> 'a t -> 'a t val iter : ('a -> unit) -> 'a t -> unit
(** Filter elements out of the array. Only the elements satisfying
the given predicate will be kept. *) val iteri : (int -> 'a -> unit) -> 'a t -> unit
val reverse_in_place : 'a t -> unit val reverse_in_place : 'a t -> unit
(** Reverse the array in place *) (** Reverse the array in place *)
@ -45,15 +65,6 @@ val find : ('a -> 'b option) -> 'a t -> 'b option
(** [find f a] returns [Some y] if there is an element [x] such (** [find f a] returns [Some y] if there is an element [x] such
that [f x = Some y], else it returns [None] *) that [f x = Some y], else it returns [None] *)
val filter_map : ('a -> 'b option) -> 'a t -> 'b t
(** Map each element into another value, or discard it *)
val flat_map : ('a -> 'b t) -> 'a t -> 'b t
(** transform each element into an array, then flatten *)
val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
(** Infix version of {!flat_map} *)
val for_all : ('a -> bool) -> 'a t -> bool val for_all : ('a -> bool) -> 'a t -> bool
val for_all2 : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool val for_all2 : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool
@ -62,11 +73,9 @@ val for_all2 : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool
val exists : ('a -> bool) -> 'a t -> bool val exists : ('a -> bool) -> 'a t -> bool
val (--) : int -> int -> int t val exists2 : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool
(** Range array *) (** Exists on pairs of arrays.
@raise Invalid_argument if they have distinct lengths *)
val except_idx : 'a t -> int -> 'a list
(** Remove given index *)
val shuffle : 'a t -> unit val shuffle : 'a t -> unit
(** shuffle randomly the array, in place *) (** shuffle randomly the array, in place *)
@ -74,6 +83,12 @@ val shuffle : 'a t -> unit
val shuffle_with : Random.State.t -> 'a t -> unit val shuffle_with : Random.State.t -> 'a t -> unit
(** Like shuffle but using a specialized random state *) (** Like shuffle but using a specialized random state *)
val to_seq : 'a t -> 'a sequence
val to_gen : 'a t -> 'a gen
val to_klist : 'a t -> 'a klist
(** {2 IO} *)
val pp: ?sep:string -> (Buffer.t -> 'a -> unit) val pp: ?sep:string -> (Buffer.t -> 'a -> unit)
-> Buffer.t -> 'a t -> unit -> Buffer.t -> 'a t -> unit
(** print an array of items with printing function *) (** print an array of items with printing function *)
@ -85,3 +100,63 @@ val pp_i: ?sep:string -> (Buffer.t -> int -> 'a -> unit)
val print : ?sep:string -> (Format.formatter -> 'a -> unit) val print : ?sep:string -> (Format.formatter -> 'a -> unit)
-> Format.formatter -> 'a t -> unit -> Format.formatter -> 'a t -> unit
(** print an array of items with printing function *) (** print an array of items with printing function *)
end
(** {2 Arrays} *)
type 'a t = 'a array
include S with type 'a t := 'a t
val map : ('a -> 'b) -> 'a t -> 'b t
val filter : ('a -> bool) -> 'a t -> 'a t
(** Filter elements out of the array. Only the elements satisfying
the given predicate will be kept. *)
val filter_map : ('a -> 'b option) -> 'a t -> 'b t
(** Map each element into another value, or discard it *)
val flat_map : ('a -> 'b t) -> 'a t -> 'b array
(** transform each element into an array, then flatten *)
val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
(** Infix version of {!flat_map} *)
val except_idx : 'a t -> int -> 'a list
(** Remove given index, obtaining the list of the other elements *)
val (--) : int -> int -> int t
(** Range array *)
(** {2 Slices}
A slice is a part of an array, that requires no copying and shares
its storage with the original array.
All indexing in a slice is relative to the beginning of a slice, not
to the underlying array (meaning a slice is effectively like
a regular array) *)
module Sub : sig
type 'a t
(** A slice is an array, an offset, and a length *)
val make : 'a array -> int -> len:int -> 'a t
(** Create a slice.
@raise Invalid_argument if the slice isn't valid *)
val full : 'a array -> 'a t
(** Slice that covers the full array *)
val underlying : 'a t -> 'a array
(** Underlying array (shared). Modifying this array will modify the slice *)
val copy : 'a t -> 'a array
(** Copy into a new array *)
val sub : 'a t -> int -> int -> 'a t
(** Sub-slice *)
include S with type 'a t := 'a t
end