[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[Libguestfs] [PATCH v8 06/42] common/mlstdutils: Implement ‘Char.mem’, ‘String.span ’ and ‘String.cspan’.



Char.mem tells you if a byte is a member of a string.

String.span and String.cspan are like the C functions strspn and
strcspn.
---
 common/mlstdutils/std_utils.ml       | 20 ++++++++++++++++++++
 common/mlstdutils/std_utils.mli      | 15 +++++++++++++++
 common/mlstdutils/std_utils_tests.ml | 21 +++++++++++++++++++++
 3 files changed, 56 insertions(+)

diff --git a/common/mlstdutils/std_utils.ml b/common/mlstdutils/std_utils.ml
index 363b761ce..374507662 100644
--- a/common/mlstdutils/std_utils.ml
+++ b/common/mlstdutils/std_utils.ml
@@ -74,6 +74,8 @@ module Char = struct
       | 'e' | 'E' -> 14
       | 'f' | 'F' -> 15
       | _ -> -1
+
+    let mem c str = String.contains str c
 end
 
 module String = struct
@@ -246,6 +248,24 @@ module String = struct
       List.map f (explode str)
 
     let spaces n = String.make n ' '
+
+    let span str accept =
+      let len = String.length str in
+      let rec loop i =
+        if i >= len then len
+        else if Char.mem (String.unsafe_get str i) accept then loop (i+1)
+        else i
+      in
+      loop 0
+
+    let cspan str reject =
+      let len = String.length str in
+      let rec loop i =
+        if i >= len then len
+        else if Char.mem (String.unsafe_get str i) reject then i
+        else loop (i+1)
+      in
+      loop 0
 end
 
 let (//) = Filename.concat
diff --git a/common/mlstdutils/std_utils.mli b/common/mlstdutils/std_utils.mli
index a07c1e6dc..0b7d90736 100644
--- a/common/mlstdutils/std_utils.mli
+++ b/common/mlstdutils/std_utils.mli
@@ -41,6 +41,12 @@ module Char : sig
     val hexdigit : char -> int
     (** Return the value of a hex digit.  If the char is not in
         the set [[0-9a-fA-F]] then this returns [-1]. *)
+
+    val mem : char -> string -> bool
+    (** [mem c str] returns true if the byte [c] is contained in [str].
+
+        This is actually the same as {!String.contains} with the
+        parameters reversed. *)
 end
 (** Override the Char module from stdlib. *)
 
@@ -109,6 +115,15 @@ module String : sig
     (** Explode string, then map function over the characters. *)
     val spaces : int -> string
     (** [spaces n] creates a string of n spaces. *)
+    val span : string -> string -> int
+    val cspan : string -> string -> int
+    (** [span str accept] returns the length in bytes of the initial
+        segment of [str] which contains only bytes in [accept].
+
+        [cspan str reject] returns the length in bytes of the initial
+        segment of [str] which contains only bytes {!i not} in [reject].
+
+        These work exactly like the C functions [strspn] and [strcspn]. *)
 end
 (** Override the String module from stdlib. *)
 
diff --git a/common/mlstdutils/std_utils_tests.ml b/common/mlstdutils/std_utils_tests.ml
index 6bc74fb63..2789766c6 100644
--- a/common/mlstdutils/std_utils_tests.ml
+++ b/common/mlstdutils/std_utils_tests.ml
@@ -50,6 +50,14 @@ and test_swap int_of_x x_of_int i s =
   assert_equal_int64 i (int_of_x s);
   assert_equal_string s (x_of_int i)
 
+(* Test Std_utils.Char.mem. *)
+let test_char_mem ctx =
+  assert_bool "Char.mem" (Char.mem 'a' "abc");
+  assert_bool "Char.mem" (Char.mem 'b' "abc");
+  assert_bool "Char.mem" (Char.mem 'c' "abc");
+  assert_bool "Char.mem" (not (Char.mem 'd' "abc"));
+  assert_bool "Char.mem" (not (Char.mem 'a' ""))
+
 (* Test Std_utils.String.is_prefix. *)
 let test_string_is_prefix ctx =
   assert_bool "String.is_prefix,," (String.is_prefix "" "");
@@ -91,16 +99,29 @@ let test_string_lines_split ctx =
   assert_equal_stringlist ["A\nB"; ""] (String.lines_split "A\\\nB\n");
   assert_equal_stringlist ["A\nB\n"] (String.lines_split "A\\\nB\\\n")
 
+(* Test Std_utils.String.span and cspan. *)
+let test_string_span ctx =
+  assert_equal_int 3 (String.span "aaabb" "a");
+  assert_equal_int 3 (String.span "aaaba" "a");
+  assert_equal_int 3 (String.span "aba" "ab");
+  assert_equal_int 0 (String.span "" "ab");
+  assert_equal_int 3 (String.cspan "defab" "ab");
+  assert_equal_int 3 (String.cspan "defba" "ab");
+  assert_equal_int 3 (String.cspan "def" "ab");
+  assert_equal_int 0 (String.cspan "" "ab")
+
 (* Suites declaration. *)
 let suite =
   "mllib Std_utils" >:::
     [
       "subdirectory" >:: test_subdirectory;
       "numeric.byteswap" >:: test_byteswap;
+      "char.mem" >:: test_char_mem;
       "strings.is_prefix" >:: test_string_is_prefix;
       "strings.is_suffix" >:: test_string_is_suffix;
       "strings.find" >:: test_string_find;
       "strings.lines_split" >:: test_string_lines_split;
+      "strings.span" >:: test_string_span;
     ]
 
 let () =
-- 
2.13.0


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]