From 8b228ec8cbdc462c1a3ad2c6d30a56731cb9a953 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Sat, 19 Sep 2015 17:35:59 +0200 Subject: [PATCH] add `CCList.{take,drop}_while`; improve map performance --- src/core/CCList.ml | 58 ++++++++++++++++++++++++++++++++++++++++----- src/core/CCList.mli | 6 +++++ 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/src/core/CCList.ml b/src/core/CCList.ml index dc2b60da..2c6daaae 100644 --- a/src/core/CCList.ml +++ b/src/core/CCList.ml @@ -40,12 +40,16 @@ let direct_depth_default_ = 1000 let map f l = let rec direct f i l = match l with | [] -> [] - | _ when i=0 -> safe f l - | x::l' -> - let y = f x in - y :: direct f (i-1) l' - and safe f l = - List.rev (List.rev_map f l) + | [x] -> [f x] + | [x1;x2] -> let y1 = f x1 in [y1; f x2] + | [x1;x2;x3] -> let y1 = f x1 in let y2 = f x2 in [y1; y2; f x3] + | _ when i=0 -> List.rev (List.rev_map f l) + | x1::x2::x3::x4::l' -> + let y1 = f x1 in + let y2 = f x2 in + let y3 = f x3 in + let y4 = f x4 in + y1 :: y2 :: y3 :: y4 :: direct f (i-1) l' in direct f direct_depth_default_ l @@ -395,6 +399,13 @@ let take n l = take 300_000 (1 -- 400_000) = 1 -- 300_000 *) +(*$Q + (Q.pair (Q.list Q.small_int) Q.int) (fun (l,i) -> \ + let i = abs i in \ + let l1 = take i l in \ + List.length l1 <= i && ((List.length l1 = i) = (List.length l >= i))) +*) + let rec drop n l = match l with | [] -> [] | _ when n=0 -> l @@ -411,6 +422,41 @@ let split = take_drop l1 @ l2 = l ) *) +let take_while p l = + let rec direct i p l = match l with + | [] -> [] + | _ when i=0 -> safe p [] l + | x :: l' -> + if p x then x :: direct (i-1) p l' else [] + and safe p acc l = match l with + | [] -> List.rev acc + | x :: l' -> + if p x then safe p (x::acc) l' else List.rev acc + in + direct direct_depth_default_ p l + +(*$T + take_while (fun x->x<10) (1 -- 20) = (1--9) + take_while (fun x->x <> 0) [0;1;2;3] = [] + take_while (fun _ -> true) [] = [] + take_while (fun _ -> true) (1--10) = (1--10) +*) + +(*$Q + Q.(pair (fun1 small_int bool) (list small_int)) (fun (f,l) -> \ + let l1 = take_while f l in \ + List.for_all f l1) +*) + +let rec drop_while p l = match l with + | [] -> [] + | x :: l' -> if p x then drop_while p l' else l + +(*$Q + Q.(pair (fun1 small_int bool) (list small_int)) (fun (f,l) -> \ + take_while f l @ drop_while f l = l) +*) + let last n l = let len = List.length l in if len < n then l else drop (len-n) l diff --git a/src/core/CCList.mli b/src/core/CCList.mli index 90fb92ac..27d2757e 100644 --- a/src/core/CCList.mli +++ b/src/core/CCList.mli @@ -118,6 +118,12 @@ val take_drop : int -> 'a t -> 'a t * 'a t (** [take_drop n l] returns [l1, l2] such that [l1 @ l2 = l] and [length l1 = min (length l) n] *) +val take_while : ('a -> bool) -> 'a t -> 'a t +(** @since NEXT_RELEASE *) + +val drop_while : ('a -> bool) -> 'a t -> 'a t +(** @since NEXT_RELEASE *) + val split : int -> 'a t -> 'a t * 'a t (** synonym to {!take_drop} @deprecated since NEXT_RELEASE: conflict with the {!List.split} standard function *)