diff --git a/src/core/CCArray.ml b/src/core/CCArray.ml index bf783639..eb6b283b 100644 --- a/src/core/CCArray.ml +++ b/src/core/CCArray.ml @@ -89,6 +89,25 @@ module type S = sig (** Same as {!lookup_exn}, but @raise Not_found if the key is not present *) + val bsearch : ?cmp:('a -> 'a -> int) -> 'a -> 'a t -> + [ `All_lower | `All_bigger | `Just_after of int | `Empty | `At of int ] + (** [bsearch ?cmp x arr] finds the index of the object [x] in the array [arr], + provided [arr] is {b sorted} using [cmp]. If the array is not sorted, + the result is not specified (may raise Invalid_argument). + + Complexity: O(log n) where n is the length of the array + (dichotomic search). + + @return + - [`At i] if [cmp arr.(i) x = 0] (for some i) + - [`All_lower] if all elements of [arr] are lower than [x] + - [`All_bigger] if all elements of [arr] are bigger than [x] + - [`Just_after i] if [arr.(i) < x < arr.(i+1)] + - [`Empty] if the array is empty + + @raise Invalid_argument if the array is found to be unsorted w.r.t [cmp] + @since NEXT_RELEASE *) + val for_all : ('a -> bool) -> 'a t -> bool val for_all2 : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool @@ -201,6 +220,23 @@ let _lookup_exn ~cmp k a i j = | n when n<0 -> _lookup_rec ~cmp k a (i+1) (j-1) | _ -> raise Not_found (* too high *) +let bsearch_ ~cmp x arr i j = + let rec aux i j = + if i > j + then `Just_after j + else + let middle = i + (j - i) / 2 in (* avoid overflow *) + match cmp x arr.(middle) with + | 0 -> `At middle + | n when n<0 -> aux i (middle - 1) + | _ -> aux (middle + 1) j + in + if i>=j then `Empty + else match cmp arr.(i) x, cmp arr.(j) x with + | n, _ when n>0 -> `All_bigger + | _, n when n<0 -> `All_lower + | _ -> aux i j + let rec _for_all p a i j = i = j || (p a.(i) && _for_all p a (i+1) j) @@ -390,6 +426,18 @@ let lookup ?(cmp=Pervasives.compare) k a = lookup 2 [| 1 |] = None *) +let bsearch ?(cmp=Pervasives.compare) k a = bsearch_ ~cmp k a 0 (Array.length a-1) + +(*$T bsearch + bsearch 3 [|1; 2; 2; 3; 4; 10|] = `At 3 + bsearch 5 [|1; 2; 2; 3; 4; 10|] = `Just_after 4 + bsearch 1 [|1; 2; 5; 5; 11; 12|] = `At 0 + bsearch 12 [|1; 2; 5; 5; 11; 12|] = `At 5 + bsearch 10 [|1; 2; 2; 3; 4; 9|] = `All_lower + bsearch 0 [|1; 2; 2; 3; 4; 9|] = `All_bigger + bsearch 3 [| |] = `Empty +*) + let (>>=) a f = flat_map f a let (>>|) a f = map f a @@ -554,6 +602,9 @@ module Sub = struct try Some (_lookup_exn ~cmp k a.arr a.i (a.j-1)) with Not_found -> None + let bsearch ?(cmp=Pervasives.compare) k a = + bsearch_ ~cmp k a.arr a.i (a.j - 1) + 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 diff --git a/src/core/CCArray.mli b/src/core/CCArray.mli index 403578e6..c40b1131 100644 --- a/src/core/CCArray.mli +++ b/src/core/CCArray.mli @@ -93,6 +93,25 @@ module type S = sig (** Same as {!lookup_exn}, but @raise Not_found if the key is not present *) + val bsearch : ?cmp:('a -> 'a -> int) -> 'a -> 'a t -> + [ `All_lower | `All_bigger | `Just_after of int | `Empty | `At of int ] + (** [bsearch ?cmp x arr] finds the index of the object [x] in the array [arr], + provided [arr] is {b sorted} using [cmp]. If the array is not sorted, + the result is not specified (may raise Invalid_argument). + + Complexity: O(log n) where n is the length of the array + (dichotomic search). + + @return + - [`At i] if [cmp arr.(i) x = 0] (for some i) + - [`All_lower] if all elements of [arr] are lower than [x] + - [`All_bigger] if all elements of [arr] are bigger than [x] + - [`Just_after i] if [arr.(i) < x < arr.(i+1)] + - [`Empty] if the array is empty + + @raise Invalid_argument if the array is found to be unsorted w.r.t [cmp] + @since NEXT_RELEASE *) + val for_all : ('a -> bool) -> 'a t -> bool val for_all2 : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool