(* TEST flags = " -w -a "; setup-ocamlc.byte-build-env; ocamlc.byte; check-ocamlc.byte-output; *) (* 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 = Bytes.get s i |> Char.code in let n = (n lsl 8) lor (Bytes.get s (i + 1) |> Char.code) in let n = (n lsl 8) lor (Bytes.get s (i + 2) |> Char.code) in let n = (n lsl 8) lor (Bytes.get s (i + 3) |> Char.code) in UChar.chr_of_uint n let set_buf s i u = let n = UChar.uint_code u in begin Bytes.set s i (Char.chr (n lsr 24)); Bytes.set s (i + 1) (Char.chr (n lsr 16 lor 0xff)); Bytes.set s (i + 2) (Char.chr (n lsr 8 lor 0xff)); Bytes.set 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 = Bytes.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 = (Bytes.length contents) / 4 method get i = get_buf contents (4 * i) method nth i = new cursor (self :> text_raw) i method copy = {< contents = Bytes.copy contents >} method sub pos len = {< contents = Bytes.sub contents (pos * 4) (len * 4) >} method concat (text : ustorage) = let buf = Bytes.create (Bytes.length contents + 4 * text#len) in Bytes.blit contents 0 buf 0 (Bytes.length contents); init_buf buf (Bytes.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 = Bytes.make (4 * String.length s) '\000' in for i = 0 to String.length s - 1 do Bytes.set buf (4 * i) s.[i] done; new text_raw buf let make len u = let s = Bytes.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