194 lines
4.7 KiB
OCaml
194 lines
4.7 KiB
OCaml
(* The module begins *)
|
|
exception Out_of_range
|
|
|
|
class type ['a] cursor =
|
|
object
|
|
method get : 'a
|
|
method incr : unit -> unit
|
|
method is_last : bool
|
|
end
|
|
|
|
class type ['a] storage =
|
|
object ('self)
|
|
method first : 'a cursor
|
|
method len : int
|
|
method nth : int -> 'a cursor
|
|
method copy : 'self
|
|
method sub : int -> int -> 'self
|
|
method concat : 'a storage -> 'self
|
|
method fold : 'b. ('a -> int -> 'b -> 'b) -> 'b -> 'b
|
|
method iter : ('a -> unit) -> unit
|
|
end
|
|
|
|
class virtual ['a, 'cursor] storage_base =
|
|
object (self : 'self)
|
|
constraint 'cursor = 'a #cursor
|
|
method virtual first : 'cursor
|
|
method virtual len : int
|
|
method virtual copy : 'self
|
|
method virtual sub : int -> int -> 'self
|
|
method virtual concat : 'a storage -> 'self
|
|
method fold : 'b. ('a -> int -> 'b -> 'b) -> 'b -> 'b = fun f a0 ->
|
|
let cur = self#first in
|
|
let rec loop count a =
|
|
if count >= self#len then a else
|
|
let a' = f cur#get count a in
|
|
cur#incr (); loop (count + 1) a'
|
|
in
|
|
loop 0 a0
|
|
method iter proc =
|
|
let p = self#first in
|
|
for i = 0 to self#len - 2 do proc p#get; p#incr () done;
|
|
if self#len > 0 then proc p#get else ()
|
|
end
|
|
|
|
class type ['a] obj_input_channel =
|
|
object
|
|
method get : unit -> 'a
|
|
method close : unit -> unit
|
|
end
|
|
|
|
class type ['a] obj_output_channel =
|
|
object
|
|
method put : 'a -> unit
|
|
method flush : unit -> unit
|
|
method close : unit -> unit
|
|
end
|
|
|
|
module UChar =
|
|
struct
|
|
|
|
type t = int
|
|
|
|
let highest_bit = 1 lsl 30
|
|
let lower_bits = highest_bit - 1
|
|
|
|
let char_of c =
|
|
try Char.chr c with Invalid_argument _ -> raise Out_of_range
|
|
|
|
let of_char = Char.code
|
|
|
|
let code c =
|
|
if c lsr 30 = 0
|
|
then c
|
|
else raise Out_of_range
|
|
|
|
let chr n =
|
|
if n >= 0 && (n lsr 31 = 0) then n else raise Out_of_range
|
|
|
|
let uint_code c = c
|
|
let chr_of_uint n = n
|
|
|
|
end
|
|
|
|
type uchar = UChar.t
|
|
|
|
let int_of_uchar u = UChar.uint_code u
|
|
let uchar_of_int n = UChar.chr_of_uint n
|
|
|
|
class type ucursor = [uchar] cursor
|
|
|
|
class type ustorage = [uchar] storage
|
|
|
|
class virtual ['ucursor] ustorage_base = [uchar, 'ucursor] storage_base
|
|
|
|
module UText =
|
|
struct
|
|
|
|
(* the internal representation is UCS4 with big endian*)
|
|
(* The most significant digit appears first. *)
|
|
let get_buf s i =
|
|
let n = Char.code s.[i] in
|
|
let n = (n lsl 8) lor (Char.code s.[i + 1]) in
|
|
let n = (n lsl 8) lor (Char.code s.[i + 2]) in
|
|
let n = (n lsl 8) lor (Char.code s.[i + 3]) in
|
|
UChar.chr_of_uint n
|
|
|
|
let set_buf s i u =
|
|
let n = UChar.uint_code u in
|
|
begin
|
|
s.[i] <- Char.chr (n lsr 24);
|
|
s.[i + 1] <- Char.chr (n lsr 16 lor 0xff);
|
|
s.[i + 2] <- Char.chr (n lsr 8 lor 0xff);
|
|
s.[i + 3] <- Char.chr (n lor 0xff);
|
|
end
|
|
|
|
let init_buf buf pos init =
|
|
if init#len = 0 then () else
|
|
let cur = init#first in
|
|
for i = 0 to init#len - 2 do
|
|
set_buf buf (pos + i lsl 2) (cur#get); cur#incr ()
|
|
done;
|
|
set_buf buf (pos + (init#len - 1) lsl 2) (cur#get)
|
|
|
|
let make_buf init =
|
|
let s = String.create (init#len lsl 2) in
|
|
init_buf s 0 init; s
|
|
|
|
class text_raw buf =
|
|
object (self : 'self)
|
|
inherit [cursor] ustorage_base
|
|
val contents = buf
|
|
method first = new cursor (self :> text_raw) 0
|
|
method len = (String.length contents) / 4
|
|
method get i = get_buf contents (4 * i)
|
|
method nth i = new cursor (self :> text_raw) i
|
|
method copy = {< contents = String.copy contents >}
|
|
method sub pos len =
|
|
{< contents = String.sub contents (pos * 4) (len * 4) >}
|
|
method concat (text : ustorage) =
|
|
let buf = String.create (String.length contents + 4 * text#len) in
|
|
String.blit contents 0 buf 0 (String.length contents);
|
|
init_buf buf (String.length contents) text;
|
|
{< contents = buf >}
|
|
end
|
|
and cursor text i =
|
|
object
|
|
val contents = text
|
|
val mutable pos = i
|
|
method get = contents#get pos
|
|
method incr () = pos <- pos + 1
|
|
method is_last = (pos + 1 >= contents#len)
|
|
end
|
|
|
|
class string_raw buf =
|
|
object
|
|
inherit text_raw buf
|
|
method set i u = set_buf contents (4 * i) u
|
|
end
|
|
|
|
class text init = text_raw (make_buf init)
|
|
class string init = string_raw (make_buf init)
|
|
|
|
let of_string s =
|
|
let buf = String.make (4 * String.length s) '\000' in
|
|
for i = 0 to String.length s - 1 do
|
|
buf.[4 * i] <- s.[i]
|
|
done;
|
|
new text_raw buf
|
|
|
|
let make len u =
|
|
let s = String.create (4 * len) in
|
|
for i = 0 to len - 1 do set_buf s (4 * i) u done;
|
|
new string_raw s
|
|
|
|
let create len = make len (UChar.chr 0)
|
|
|
|
let copy s = s#copy
|
|
|
|
let sub s start len = s#sub start len
|
|
|
|
let fill s start len u =
|
|
for i = start to start + len - 1 do s#set i u done
|
|
|
|
let blit src srcoff dst dstoff len =
|
|
for i = 0 to len - 1 do
|
|
let u = src#get (srcoff + i) in
|
|
dst#set (dstoff + i) u
|
|
done
|
|
|
|
let concat s1 s2 = s1#concat (s2 (* : #ustorage *) :> uchar storage)
|
|
|
|
let iter proc s = s#iter proc
|
|
end
|