183 lines
5.7 KiB
OCaml
183 lines
5.7 KiB
OCaml
|
|
open! Base
|
||
|
|
open Expect_test_helpers_core
|
||
|
|
|
||
|
|
let%expect_test _ =
|
||
|
|
let x = Sys.opaque_identity "one string" in
|
||
|
|
let y = Sys.opaque_identity "another" in
|
||
|
|
require_no_allocation [%here] (fun () ->
|
||
|
|
ignore (Sys.opaque_identity (String.Caseless.equal x y) : bool));
|
||
|
|
[%expect {| |}]
|
||
|
|
;;
|
||
|
|
|
||
|
|
let%expect_test "empty substring" =
|
||
|
|
let string = String.init 10 ~f:Char.of_int_exn in
|
||
|
|
let test here f =
|
||
|
|
let substring = require_no_allocation here f in
|
||
|
|
assert (String.is_empty substring)
|
||
|
|
in
|
||
|
|
test [%here] (fun () -> String.sub string ~pos:0 ~len:0);
|
||
|
|
test [%here] (fun () -> String.prefix string 0);
|
||
|
|
test [%here] (fun () -> String.suffix string 0);
|
||
|
|
test [%here] (fun () -> String.drop_prefix string 10);
|
||
|
|
test [%here] (fun () -> String.drop_suffix string 10);
|
||
|
|
[%expect {| |}]
|
||
|
|
;;
|
||
|
|
|
||
|
|
let%expect_test "mem does not allocate" =
|
||
|
|
let string = Sys.opaque_identity "abracadabra" in
|
||
|
|
let char = Sys.opaque_identity 'd' in
|
||
|
|
require_no_allocation [%here] (fun () -> ignore (String.mem string char : bool));
|
||
|
|
[%expect {| |}]
|
||
|
|
;;
|
||
|
|
|
||
|
|
let%expect_test "fold does not allocate" =
|
||
|
|
let string = Sys.opaque_identity "abracadabra" in
|
||
|
|
let char = Sys.opaque_identity 'd' in
|
||
|
|
let f acc c = if Char.equal c char then true else acc in
|
||
|
|
require_no_allocation [%here] (fun () ->
|
||
|
|
ignore (String.fold string ~init:false ~f : bool));
|
||
|
|
[%expect {| |}]
|
||
|
|
;;
|
||
|
|
|
||
|
|
let%expect_test "foldi does not allocate" =
|
||
|
|
let string = Sys.opaque_identity "abracadabra" in
|
||
|
|
let char = Sys.opaque_identity 'd' in
|
||
|
|
let f _i acc c = if Char.equal c char then true else acc in
|
||
|
|
require_no_allocation [%here] (fun () ->
|
||
|
|
ignore (String.foldi string ~init:false ~f : bool));
|
||
|
|
[%expect {| |}]
|
||
|
|
;;
|
||
|
|
|
||
|
|
let%test_module "common prefix and suffix" =
|
||
|
|
(module struct
|
||
|
|
let require_int_equal a b ~message = require_equal [%here] (module Int) a b ~message
|
||
|
|
|
||
|
|
let require_string_equal a b ~message =
|
||
|
|
require_equal [%here] (module String) a b ~message
|
||
|
|
;;
|
||
|
|
|
||
|
|
let simulate_common_length ~get_common2_length list =
|
||
|
|
let rec loop acc prev list ~get_common2_length =
|
||
|
|
match list with
|
||
|
|
| [] -> acc
|
||
|
|
| head :: tail ->
|
||
|
|
loop (Int.min acc (get_common2_length prev head)) head tail ~get_common2_length
|
||
|
|
in
|
||
|
|
match list with
|
||
|
|
| [] -> 0
|
||
|
|
| [ head ] -> String.length head
|
||
|
|
| head :: tail -> loop Int.max_value head tail ~get_common2_length
|
||
|
|
;;
|
||
|
|
|
||
|
|
let get_shortest_and_longest list =
|
||
|
|
let compare_by_length a b = Comparable.lift Int.compare ~f:String.length a b in
|
||
|
|
Option.both
|
||
|
|
(List.min_elt list ~compare:compare_by_length)
|
||
|
|
(List.max_elt list ~compare:compare_by_length)
|
||
|
|
;;
|
||
|
|
|
||
|
|
let test_generic get_common get_common2 get_common_length get_common2_length =
|
||
|
|
Staged.stage (fun list ->
|
||
|
|
let common = get_common list in
|
||
|
|
print_s [%sexp (common : string)];
|
||
|
|
let len = get_common_length list in
|
||
|
|
require_int_equal len (String.length common) ~message:"wrong length";
|
||
|
|
let common2 = List.reduce list ~f:get_common2 |> Option.value ~default:"" in
|
||
|
|
require_string_equal common common2 ~message:"pairwise result mismatch";
|
||
|
|
let len2 = simulate_common_length ~get_common2_length list in
|
||
|
|
require_int_equal len len2 ~message:"pairwise length mismatch";
|
||
|
|
if not (String.is_empty common || List.mem list common ~equal:String.equal)
|
||
|
|
then print_endline "(may allocate)"
|
||
|
|
else (
|
||
|
|
ignore (require_no_allocation [%here] (fun () -> get_common list) : string);
|
||
|
|
Option.iter (get_shortest_and_longest list) ~f:(fun (shortest, longest) ->
|
||
|
|
ignore
|
||
|
|
(require_no_allocation [%here] (fun () -> get_common2 shortest longest)
|
||
|
|
: string);
|
||
|
|
ignore
|
||
|
|
(require_no_allocation [%here] (fun () -> get_common2 longest shortest)
|
||
|
|
: string))))
|
||
|
|
;;
|
||
|
|
|
||
|
|
let test_prefix =
|
||
|
|
test_generic
|
||
|
|
String.common_prefix
|
||
|
|
String.common_prefix2
|
||
|
|
String.common_prefix_length
|
||
|
|
String.common_prefix2_length
|
||
|
|
|> Staged.unstage
|
||
|
|
;;
|
||
|
|
|
||
|
|
let test_suffix =
|
||
|
|
test_generic
|
||
|
|
String.common_suffix
|
||
|
|
String.common_suffix2
|
||
|
|
String.common_suffix_length
|
||
|
|
String.common_suffix2_length
|
||
|
|
|> Staged.unstage
|
||
|
|
;;
|
||
|
|
|
||
|
|
let%expect_test "empty" =
|
||
|
|
test_prefix [];
|
||
|
|
[%expect {| "" |}];
|
||
|
|
test_suffix [];
|
||
|
|
[%expect {| "" |}]
|
||
|
|
;;
|
||
|
|
|
||
|
|
let%expect_test "singleton" =
|
||
|
|
test_prefix [ "abut" ];
|
||
|
|
[%expect {| abut |}];
|
||
|
|
test_suffix [ "tuba" ];
|
||
|
|
[%expect {| tuba |}]
|
||
|
|
;;
|
||
|
|
|
||
|
|
let%expect_test "doubleton, alloc" =
|
||
|
|
test_prefix [ "hello"; "help"; "hex" ];
|
||
|
|
[%expect {|
|
||
|
|
he
|
||
|
|
(may allocate)
|
||
|
|
|}];
|
||
|
|
test_suffix [ "crest"; "zest"; "1st" ];
|
||
|
|
[%expect {|
|
||
|
|
st
|
||
|
|
(may allocate)
|
||
|
|
|}]
|
||
|
|
;;
|
||
|
|
|
||
|
|
let%expect_test "doubleton, no alloc" =
|
||
|
|
test_prefix [ "hello"; "help"; "he" ];
|
||
|
|
[%expect {| he |}];
|
||
|
|
test_suffix [ "crest"; "zest"; "st" ];
|
||
|
|
[%expect {| st |}]
|
||
|
|
;;
|
||
|
|
|
||
|
|
let%expect_test "many, alloc" =
|
||
|
|
test_prefix [ "this"; "that"; "the other"; "these"; "those"; "thy"; "thou" ];
|
||
|
|
[%expect {|
|
||
|
|
th
|
||
|
|
(may allocate)
|
||
|
|
|}];
|
||
|
|
test_suffix [ "fourth"; "fifth"; "sixth"; "seventh"; "eleventh"; "twelfth" ];
|
||
|
|
[%expect {|
|
||
|
|
th
|
||
|
|
(may allocate)
|
||
|
|
|}]
|
||
|
|
;;
|
||
|
|
|
||
|
|
let%expect_test "many, no alloc" =
|
||
|
|
test_prefix [ "inconsequential"; "invariant"; "in"; "inner"; "increment" ];
|
||
|
|
[%expect {| in |}];
|
||
|
|
test_suffix [ "fat"; "cat"; "sat"; "at"; "bat" ];
|
||
|
|
[%expect {| at |}]
|
||
|
|
;;
|
||
|
|
|
||
|
|
let%expect_test "many, nothing in common" =
|
||
|
|
let lorem_ipsum = [ "lorem"; "ipsum"; "dolor"; "sit"; "amet" ] in
|
||
|
|
test_prefix lorem_ipsum;
|
||
|
|
[%expect {| "" |}];
|
||
|
|
test_suffix lorem_ipsum;
|
||
|
|
[%expect {| "" |}]
|
||
|
|
;;
|
||
|
|
end)
|
||
|
|
;;
|