: NATIVE_STRING = struct
include StringLabels
type character = char
let empty = ""
let is_empty t = (compare "" t = 0)
let of_character = String.make 1
let of_character_list cl =
let length = List.length cl in
let buf = String.make length '\x00' in
List.iteri cl ~f:(fun i c -> buf.[i] <- c);
buf
let to_character_list s =
let res = ref [] in
for i = length s - 1 downto 0 do
res := s.[i] :: !res
done;
!res
let get s ~index =
try Some (s.[index])
with _ -> None
let set s ~index ~v =
if index > String.length s - 1
then None
else begin
let cop = String.copy s in
cop.[index] <- v;
Some cop
end
let get_exn s ~index = s.[index]
let set_exn s ~index ~v =
match set s ~index ~v with None -> failwith "set_exn" | Some s -> s
let compare_substring (a, idxa, lena) (b, idxb, lenb) =
let module With_exns = struct
exception Return of int
exception Left_out of int
exception Right_out of int
let f () =
try
let shortest = min lena lenb in
for i = 0 to shortest - 1 do
let ca = try a.[idxa + i] with _ -> raise (Left_out i) in
let cb = try b.[idxb + i] with _ -> raise (Right_out i) in
let c = Char.compare ca cb in
if c <> 0
then raise (Return c)
else ()
done;
(Pervasives.compare (lena : int) lenb)
with
| Return c -> c
| Left_out c -> (* a went out of bounds at 'c + idxa' *) -1
| Right_out _ -> (* b went out of bounds at 'c + idxb' *)
(* so, a is “longer” *) 1
end in
With_exns.f ()
type s = t
module T_length_and_compsub = struct
type t = s let length = length let compare_substring = compare_substring
end
include Compare_substring_strict_of_loose(T_length_and_compsub)
include Make_index_of_string(T_length_and_compsub)
let to_native_string x = String.copy x
let of_native_string x = return (String.copy x)
let of_native_substring x ~offset ~length =
if length = 0 then return ""
else
try return (String.sub x offset length)
with e -> fail `out_of_bounds
let to_string_hum x = sprintf "%S" x
let concat ?(sep="") sl = concat ~sep sl
let fold t ~init ~f =
let res = ref init in
for i = 0 to String.length t - 1 do
res := f !res t.[i];
done;
!res
let foldi t ~init ~f =
let res = ref init in
for i = 0 to String.length t - 1 do
res := f i !res t.[i];
done;
!res
let fold2_exn t1 t2 ~init ~f =
let lgth1 = (length t1) in
let lgth2 = (length t2) in
match lgth1, lgth2 with
| 0, 0 -> init
| _, _ when lgth1 <> lgth2 -> failwith "fold2_exn"
| lgth1, lgth2 ->
let res = ref init in
for i = 0 to lgth1 - 1 do
res := f !res t1.[i] t2.[i];
done;
!res
let sub_exn t ~index ~length =
if length = 0 then empty else String.sub t index length
let sub t ~index ~length =
if length = 0 then Some empty else
try Some (String.sub t index length)
with e -> None
let slice_exn ?(start=0) ?finish t =
let length_of_t = String.length t in
let bound_check strict m x =
let out_of_ub = if strict then x > length_of_t else x >= length_of_t in
if x < 0 || (not (is_empty t) && out_of_ub) then
ksprintf failwith "slice_exn: invalid %s %d" m x
else x
in
let _ = bound_check false "start" start
and finish =
match finish with
| None -> length_of_t
| Some f -> bound_check true "finish" f
in
sub_exn t ~index:start ~length:(finish - start)
let slice ?start ?finish t =
try Some (slice_exn ?start ?finish t)
with _ -> None
let mutate_exn t ~index c = String.set t index c
let mutate t ~index c =
try String.set t index c; return () with _ -> fail `out_of_bounds
let blit_exn ~src ~src_index ~dst ~dst_index ~length =
blit ~src ~src_pos:src_index ~dst ~dst_pos:dst_index ~len:length
let blit ~src ~src_index ~dst ~dst_index ~length =
try blit_exn ~src ~src_index ~dst ~dst_index ~length; return ()
with _ -> fail `out_of_bounds
let iter t ~f = String.iter t ~f
let iteri t ~f = String.iteri t ~f
let iter_reverse t ~f =
for i = length t -1 downto 0 do
f (get_exn t i)
done
let rev t =
let lgth = length t in
match lgth with
| 0 -> empty
| lgth ->
let res = make lgth (String.get t 0) in
for i = 0 to lgth - 1 do
String.set res i (String.get t (lgth - 1 - i))
done;
res
let map t ~f = String.map t ~f
let map2_exn t1 t2 ~f =
let lgth1 = (length t1) in
let lgth2 = (length t2) in
match lgth1, lgth2 with
| 0, 0 -> empty
| _, _ when lgth1 <> lgth2 -> failwith "map2_exn"
| lgth1, lgth2 ->
let res = make lgth1 (String.get t1 0) in
for i = 0 to lgth1 - 1 do
String.set res i (f (String.get t1 i) (String.get t2 i))
done;
res
let mapi t ~f =
let buffer = String.create (String.length t) in
let () = String.iteri t ~f:(fun i c -> String.set buffer i (f i c)) in
buffer
(* TODO: Change this to
let mapi t ~f = String.mapi t ~f
once we switch to 4.02 *)
let for_all t ~f =
try (iter t (fun x -> if not (f x) then raise Not_found else ()); true)
with Not_found -> false
let exists t ~f =
try (iter t (fun x -> if f x then raise Not_found else ()); false)
with Not_found -> true
let index_of_character t ?(from=0) c =
let from = if from <= 0 then 0 else min (length t) from in
try Some (String.index_from t from c)
with _ -> None
let index_of_character_reverse t ?from c =
let from =
let length_of_t = length t in
match from with
| None -> length_of_t - 1
| Some s when s < 0 -> -1
| Some s when s > length_of_t - 1 -> length_of_t - 1
| Some s -> s
in
try Some (String.rindex_from t from c)
with _ -> None
let resize_from_length ~from ?length ~length_of_s =
let from = if from <= 0 then 0 else min length_of_s from in
let length =
match length with
| None -> length_of_s - from
| Some lg when lg <= 0 -> 0
| Some lg -> min (length_of_s - from) lg
in
(from, length)
let find ?(from=0) ?length s ~f =
let length_of_s = String.length s in
let from, length = resize_from_length ~from ?length ~length_of_s in
let found = ref None in
let i = ref 0 in
while !found = None && !i < length do
if f (get_exn s (!i + from))
then found := Some (!i + from)
else incr i
done;
!found
let find_reverse ?from ?length s ~f =
let length_of_s = String.length s in
if length_of_s = 0 then None
else begin
let from =
match from with
| None -> length_of_s - 1
| Some s when s < 0 -> -1
| Some s when s >= length_of_s - 1 -> length_of_s - 1
| Some s -> s
in
let length =
match length with
| None -> from + 1
| Some l when l <= 0 -> 0
| Some l when l >= from + 1 -> from + 1
| Some l -> l
in
let found = ref None in
let i = ref from in
while !found = None && !i >= from - length + 1 do
(* dbg "i: %d from: %d length: %d" !i from length; *)
if f (get_exn s !i)
then found := Some (!i)
else decr i
done;
!found
end
let filter_map ?(from=0) ?length s ~f =
let length_of_s = String.length s in
let from, length = resize_from_length ~from ?length ~length_of_s in
if length = 0 then empty
else begin
let b = Buffer.create length in
for i = 0 to length - 1 do
match f (get_exn s (i + from)) with
| Some c -> Buffer.add_char b c
| None -> ()
done;
Buffer.contents b
end
let filter ?from ?length s ~f =
filter_map ?from ?length s ~f:(fun c -> if f c then Some c else None)
include Make_strip_function (struct
type t = string
type character = char
let empty = empty
let length = length
let sub_exn = sub_exn
let find = find
let find_reverse = find_reverse
let is_whitespace = Native_character.is_whitespace
end)
include Make_split_function(struct
type t = string
type character = char
let length = length
let sub_exn = sub_exn
let index_of_string = index_of_string
let index_of_character = index_of_character
end)
include Make_prefix_suffix_array (struct
type t = string
type character = char
let length = length
let get = (fun s i -> s.[i])
let sub_exn = sub_exn
end)
include Make_split_at_index_functions(struct
type t = string
type character = char
let empty = empty
let length = length
let sub_exn = sub_exn
end)
module Make_output (Model: OUTPUT_MODEL) = Model
let take_while_with_index t ~f =
let buf = Buffer.create (length t) in
let rec loop idx =
match get t idx with
| Some c when f idx c -> Buffer.add_char buf c; loop (idx + 1)
| _ -> ()
in
loop 0;
Buffer.contents buf
let take_while t ~f = take_while_with_index t ~f:(fun _ c -> f c)
end