ocaml/stdlib/bytes.ml

270 lines
7.8 KiB
OCaml
Raw Normal View History

(***********************************************************************)
(* *)
(* OCaml *)
(* *)
(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
(* *)
(* Copyright 1996 Institut National de Recherche en Informatique et *)
(* en Automatique. All rights reserved. This file is distributed *)
(* under the terms of the GNU Library General Public License, with *)
(* the special exception on linking described in file ../LICENSE. *)
(* *)
(***********************************************************************)
(* Byte sequence operations *)
external length : bytes -> int = "%string_length"
external string_length : string -> int = "%string_length"
external get : bytes -> int -> char = "%string_safe_get"
external set : bytes -> int -> char -> unit = "%string_safe_set"
external create : int -> bytes = "caml_create_string"
external unsafe_get : bytes -> int -> char = "%string_unsafe_get"
external unsafe_set : bytes -> int -> char -> unit = "%string_unsafe_set"
external unsafe_fill : bytes -> int -> int -> char -> unit
= "caml_fill_string" "noalloc"
external unsafe_to_string : bytes -> string = "%identity"
external unsafe_of_string : string -> bytes = "%identity"
external unsafe_blit : bytes -> int -> bytes -> int -> int -> unit
= "caml_blit_string" "noalloc"
external unsafe_blit_string : string -> int -> bytes -> int -> int -> unit
= "caml_blit_string" "noalloc"
let make n c =
let s = create n in
unsafe_fill s 0 n c;
s
let init n f =
let s = create n in
for i = 0 to n - 1 do
unsafe_set s i (f i)
done;
s
let empty = create 0;;
let copy s =
let len = length s in
let r = create len in
unsafe_blit s 0 r 0 len;
r
let to_string b = unsafe_to_string (copy b)
let of_string s = copy (unsafe_of_string s)
let sub s ofs len =
if ofs < 0 || len < 0 || ofs > length s - len
then invalid_arg "String.sub / Bytes.sub"
else begin
let r = create len in
unsafe_blit s ofs r 0 len;
r
end
let sub_string b ofs len = unsafe_to_string (sub b ofs len)
let extend s left right =
let len = length s + left + right in
let r = create len in
let (srcoff, dstoff) = if left < 0 then -left, 0 else 0, left in
let cpylen = min (length s - srcoff) (len - dstoff) in
if cpylen > 0 then unsafe_blit s srcoff r dstoff cpylen;
r
let fill s ofs len c =
if ofs < 0 || len < 0 || ofs > length s - len
then invalid_arg "String.fill / Bytes.fill"
else unsafe_fill s ofs len c
let blit s1 ofs1 s2 ofs2 len =
if len < 0 || ofs1 < 0 || ofs1 > length s1 - len
|| ofs2 < 0 || ofs2 > length s2 - len
then invalid_arg "Bytes.blit"
else unsafe_blit s1 ofs1 s2 ofs2 len
let blit_string s1 ofs1 s2 ofs2 len =
if len < 0 || ofs1 < 0 || ofs1 > string_length s1 - len
|| ofs2 < 0 || ofs2 > length s2 - len
then invalid_arg "String.blit / Bytes.blit_string"
else unsafe_blit_string s1 ofs1 s2 ofs2 len
let iter f a =
for i = 0 to length a - 1 do f(unsafe_get a i) done
let iteri f a =
for i = 0 to length a - 1 do f i (unsafe_get a i) done
let concat sep l =
match l with
[] -> empty
| hd :: tl ->
let num = ref 0 and len = ref 0 in
List.iter (fun s -> incr num; len := !len + length s) l;
let r = create (!len + length sep * (!num - 1)) in
unsafe_blit hd 0 r 0 (length hd);
let pos = ref(length hd) in
List.iter
(fun s ->
unsafe_blit sep 0 r !pos (length sep);
pos := !pos + length sep;
unsafe_blit s 0 r !pos (length s);
pos := !pos + length s)
tl;
r
let cat s1 s2 =
let l1 = length s1 in
let l2 = length s2 in
let r = create (l1 + l2) in
unsafe_blit s1 0 r 0 l1;
unsafe_blit s2 0 r l1 l2;
r
;;
external is_printable: char -> bool = "caml_is_printable"
external char_code: char -> int = "%identity"
external char_chr: int -> char = "%identity"
let is_space = function
| ' ' | '\012' | '\n' | '\r' | '\t' -> true
| _ -> false
let trim s =
let len = length s in
let i = ref 0 in
while !i < len && is_space (unsafe_get s !i) do
incr i
done;
let j = ref (len - 1) in
while !j >= !i && is_space (unsafe_get s !j) do
decr j
done;
if !j >= !i then
sub s !i (!j - !i + 1)
else
empty
let escaped s =
let n = ref 0 in
for i = 0 to length s - 1 do
n := !n +
(match unsafe_get s i with
| '"' | '\\' | '\n' | '\t' | '\r' | '\b' -> 2
| c -> if is_printable c then 1 else 4)
done;
if !n = length s then copy s else begin
let s' = create !n in
n := 0;
for i = 0 to length s - 1 do
begin match unsafe_get s i with
| ('"' | '\\') as c ->
unsafe_set s' !n '\\'; incr n; unsafe_set s' !n c
| '\n' ->
unsafe_set s' !n '\\'; incr n; unsafe_set s' !n 'n'
| '\t' ->
unsafe_set s' !n '\\'; incr n; unsafe_set s' !n 't'
| '\r' ->
unsafe_set s' !n '\\'; incr n; unsafe_set s' !n 'r'
| '\b' ->
unsafe_set s' !n '\\'; incr n; unsafe_set s' !n 'b'
| c ->
if is_printable c then
unsafe_set s' !n c
else begin
let a = char_code c in
unsafe_set s' !n '\\';
incr n;
unsafe_set s' !n (char_chr (48 + a / 100));
incr n;
unsafe_set s' !n (char_chr (48 + (a / 10) mod 10));
incr n;
unsafe_set s' !n (char_chr (48 + a mod 10))
end
end;
incr n
done;
s'
end
let map f s =
let l = length s in
if l = 0 then s else begin
let r = create l in
for i = 0 to l - 1 do unsafe_set r i (f (unsafe_get s i)) done;
r
end
let mapi f s =
let l = length s in
if l = 0 then s else begin
let r = create l in
for i = 0 to l - 1 do unsafe_set r i (f i (unsafe_get s i)) done;
r
end
let uppercase s = map Char.uppercase s
let lowercase s = map Char.lowercase s
let uppercase_ascii s = map Char.uppercase_ascii s
let lowercase_ascii s = map Char.lowercase_ascii s
let apply1 f s =
if length s = 0 then s else begin
let r = copy s in
unsafe_set r 0 (f(unsafe_get s 0));
r
end
let capitalize s = apply1 Char.uppercase s
let uncapitalize s = apply1 Char.lowercase s
let capitalize_ascii s = apply1 Char.uppercase_ascii s
let uncapitalize_ascii s = apply1 Char.lowercase_ascii s
let rec index_rec s lim i c =
if i >= lim then raise Not_found else
if unsafe_get s i = c then i else index_rec s lim (i + 1) c;;
let index s c = index_rec s (length s) 0 c;;
let index_from s i c =
let l = length s in
if i < 0 || i > l then invalid_arg "String.index_from / Bytes.index_from" else
index_rec s l i c;;
let rec rindex_rec s i c =
if i < 0 then raise Not_found else
if unsafe_get s i = c then i else rindex_rec s (i - 1) c;;
let rindex s c = rindex_rec s (length s - 1) c;;
let rindex_from s i c =
if i < -1 || i >= length s then
invalid_arg "String.rindex_from / Bytes.rindex_from"
else
rindex_rec s i c
;;
let contains_from s i c =
let l = length s in
if i < 0 || i > l then
invalid_arg "String.contains_from / Bytes.contains_from"
else
try ignore (index_rec s l i c); true with Not_found -> false
;;
let contains s c = contains_from s 0 c;;
let rcontains_from s i c =
if i < 0 || i >= length s then
invalid_arg "String.rcontains_from / Bytes.rcontains_from"
else
try ignore (rindex_rec s i c); true with Not_found -> false
;;
type t = bytes
let compare (x: t) (y: t) = Pervasives.compare x y
external equal : t -> t -> bool = "caml_string_equal"