From 10bec85d49e6e299d1bacf4ef32da426bdc50488 Mon Sep 17 00:00:00 2001 From: favonia Date: Thu, 19 Oct 2023 21:22:00 -0500 Subject: [PATCH] feat: add is_empty, find_index, find_mapi (#21) These functions were introduced in OCaml 5.1. --- src/BwdLabels.ml | 6 ++++++ src/BwdLabels.mli | 3 +++ src/BwdNoLabels.ml | 22 +++++++++++++++++++++- src/BwdNoLabels.mli | 3 +++ test/ListAsBwdLabels.ml | 6 ++++++ test/TestBwdLabels.ml | 18 ++++++++++++++++++ 6 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/BwdLabels.ml b/src/BwdLabels.ml index 4996a81..6effb71 100644 --- a/src/BwdLabels.ml +++ b/src/BwdLabels.ml @@ -8,6 +8,8 @@ let compare_lengths = BwdNoLabels.compare_lengths let[@inline] compare_length_with xs ~len = BwdNoLabels.compare_length_with xs len +let is_empty = BwdNoLabels.is_empty + let snoc = BwdNoLabels.snoc let nth = BwdNoLabels.nth @@ -64,8 +66,12 @@ let[@inline] find ~f = BwdNoLabels.find f let[@inline] find_opt ~f = BwdNoLabels.find_opt f +let[@inline] find_index ~f = BwdNoLabels.find_index f + let[@inline] find_map ~f = BwdNoLabels.find_map f +let[@inline] find_mapi ~f = BwdNoLabels.find_mapi f + let[@inline] filter ~f = BwdNoLabels.filter f let[@inline] find_all ~f = BwdNoLabels.find_all f diff --git a/src/BwdLabels.mli b/src/BwdLabels.mli index 4615f00..f8f07f5 100644 --- a/src/BwdLabels.mli +++ b/src/BwdLabels.mli @@ -38,6 +38,7 @@ type 'a t = 'a BwdDef.bwd = val length : 'a t -> int val compare_lengths : 'a t -> 'a t -> int val compare_length_with : 'a t -> len:int -> int +val is_empty : 'a t -> bool val snoc : 'a t -> 'a -> 'a t val nth : 'a t -> int -> 'a val nth_opt : 'a t -> int -> 'a option @@ -97,7 +98,9 @@ val memq : 'a -> set:'a t -> bool val find : f:('a -> bool) -> 'a t -> 'a val find_opt : f:('a -> bool) -> 'a t -> 'a option +val find_index : f:('a -> bool) -> 'a t -> int option val find_map : f:('a -> 'b option) -> 'a t -> 'b option +val find_mapi : f:(int -> 'a -> 'b option) -> 'a t -> 'b option val filter : f:('a -> bool) -> 'a t -> 'a t val find_all : f:('a -> bool) -> 'a t -> 'a t val filteri : f:(int -> 'a -> bool) -> 'a t -> 'a t diff --git a/src/BwdNoLabels.ml b/src/BwdNoLabels.ml index 73a299c..b277ee4 100644 --- a/src/BwdNoLabels.ml +++ b/src/BwdNoLabels.ml @@ -28,6 +28,8 @@ let compare_length_with xs len = (go[@tailcall]) (len-1) xs in go len xs +let is_empty = function Emp -> true | _ -> false + let snoc l x = Snoc (l, x) let nth xs i = @@ -270,16 +272,34 @@ let find_opt f = if f x then Some x else go xs in go +let find_index f = + let rec go i = + function + | Emp -> None + | Snoc (xs, x) -> + if f x then Some i else go (i+1) xs + in go 0 + let find_map f = let rec go = function | Emp -> None | Snoc (xs, x) -> match f x with - | Some y -> Some y + | Some _ as r -> r | None -> go xs in go +let find_mapi f = + let rec go i = + function + | Emp -> None + | Snoc (xs, x) -> + match f i x with + | Some _ as r -> r + | None -> go (i+1) xs + in go 0 + let filter f = let[@tail_mod_cons] rec go = function diff --git a/src/BwdNoLabels.mli b/src/BwdNoLabels.mli index 4831359..3738fb0 100644 --- a/src/BwdNoLabels.mli +++ b/src/BwdNoLabels.mli @@ -38,6 +38,7 @@ type 'a t = 'a BwdDef.bwd = val length : 'a t -> int val compare_lengths : 'a t -> 'a t -> int val compare_length_with : 'a t -> int -> int +val is_empty : 'a t -> bool val snoc : 'a t -> 'a -> 'a t val nth : 'a t -> int -> 'a val nth_opt : 'a t -> int -> 'a option @@ -97,7 +98,9 @@ val memq : 'a -> 'a t -> bool val find : ('a -> bool) -> 'a t -> 'a val find_opt : ('a -> bool) -> 'a t -> 'a option +val find_index : ('a -> bool) -> 'a t -> int option val find_map : ('a -> 'b option) -> 'a t -> 'b option +val find_mapi : (int -> 'a -> 'b option) -> 'a t -> 'b option val filter : ('a -> bool) -> 'a t -> 'a t val find_all : ('a -> bool) -> 'a t -> 'a t val filteri : (int -> 'a -> bool) -> 'a t -> 'a t diff --git a/test/ListAsBwdLabels.ml b/test/ListAsBwdLabels.ml index 0b745df..a0a5ecc 100644 --- a/test/ListAsBwdLabels.ml +++ b/test/ListAsBwdLabels.ml @@ -6,6 +6,8 @@ let compare_lengths = L.compare_lengths let compare_length_with = L.compare_length_with +let is_empty l = l = [] + let snoc l x = l @ [x] let nth xs i = @@ -83,8 +85,12 @@ let find ~f xs = L.find ~f (L.rev xs) let find_opt ~f xs = L.find_opt ~f (L.rev xs) +let find_index ~f xs = L.find_map ~f:Fun.id (L.mapi ~f:(fun i x -> if f x then Some i else None) (L.rev xs)) + let find_map ~f xs = L.find_map ~f (L.rev xs) +let find_mapi ~f xs = L.find_map ~f:Fun.id (L.mapi ~f (L.rev xs)) + let filter ~f xs = L.rev (L.filter ~f (L.rev xs)) let find_all ~f xs = L.rev (L.find_all ~f (L.rev xs)) diff --git a/test/TestBwdLabels.ml b/test/TestBwdLabels.ml index 446039e..090dbd9 100644 --- a/test/TestBwdLabels.ml +++ b/test/TestBwdLabels.ml @@ -34,6 +34,11 @@ let test_compare_length_with = Q.Gen.(pair (small_list unit) (small_signed_int)) ~print:Q.Print.(pair (list unit) int) (fun (xs, len) -> B.compare_length_with (of_list xs) ~len = L.compare_length_with xs ~len) +let test_is_empty = + Q.Test.make ~count ~name:"is_empty" + Q.Gen.(small_list unit) + ~print:Q.Print.(list unit) + (fun xs -> B.is_empty (of_list xs) = L.is_empty xs) let test_snoc = Q.Test.make ~count ~name:"snoc" Q.Gen.(pair (small_list int) int) ~print:Q.Print.(pair (list int) int) (fun (xs, x) -> to_list (B.snoc (of_list xs) x) = L.snoc xs x) @@ -208,11 +213,21 @@ let test_find_opt = Q.Gen.(pair (Q.fun1 Q.Observable.int bool) (small_list int)) ~print:Q.Print.(pair Q.Fn.print (list int)) (fun (Fun (_, f), xs) -> B.find_opt ~f (of_list xs) = L.find_opt ~f xs) +let test_find_index = + Q.Test.make ~count ~name:"find_index" + Q.Gen.(pair (Q.fun1 Q.Observable.int bool) (small_list int)) + ~print:Q.Print.(pair Q.Fn.print (list int)) + (fun (Fun (_, f), xs) -> B.find_index ~f (of_list xs) = L.find_index ~f xs) let test_find_map = Q.Test.make ~count ~name:"find_map" Q.Gen.(pair (Q.fun1 Q.Observable.int (opt int)) (small_list int)) ~print:Q.Print.(pair Q.Fn.print (list int)) (fun (Fun (_, f), xs) -> B.find_map ~f (of_list xs) = L.find_map ~f xs) +let test_find_mapi = + Q.Test.make ~count ~name:"find_mapi" + Q.Gen.(pair (Q.fun2 Q.Observable.int Q.Observable.int (opt int)) (small_list int)) + ~print:Q.Print.(pair Q.Fn.print (list int)) + (fun (Fun (_, f), xs) -> B.find_mapi ~f (of_list xs) = L.find_mapi ~f xs) let test_filter = Q.Test.make ~count ~name:"filter" Q.Gen.(pair (Q.fun1 Q.Observable.int bool) (small_list int)) @@ -301,6 +316,7 @@ let () = test_length; test_compare_lengths; test_compare_length_with; + test_is_empty; test_snoc; test_nth; test_nth_opt; @@ -329,7 +345,9 @@ let () = test_memq; test_find; test_find_opt; + test_find_index; test_find_map; + test_find_mapi; test_filter; test_find_all; test_filteri;