Skip to content

Instantly share code, notes, and snippets.

@dinosaure
Created July 12, 2016 12:11
Show Gist options
  • Save dinosaure/118f10188592a177387844757de71d0c to your computer and use it in GitHub Desktop.
Save dinosaure/118f10188592a177387844757de71d0c to your computer and use it in GitHub Desktop.
module type BLIT =
sig
type t
val blit : t -> int -> t -> int -> int -> unit
val blit_string : string -> int -> t -> int -> int -> unit
end
open Bigarray
type bigstring = (char, int8_unsigned_elt, c_layout) Array1.t
type normal = [ `Normal ]
type fast = [ `Fast ]
let memcpy_bytes src dst len src_idx dst_idx =
if len < 0 || src_idx < 0 || src_idx > Bytes.length src - len
|| dst_idx < 0 || dst_idx > Bytes.length dst - len
then raise (Invalid_argument "memcpy_bytes")
else Memcpy.memcpy_bytes src dst len src_idx dst_idx
module Bigstring =
struct
open Bigarray
type t = bigstring
let length = Array1.dim
let create = Array1.create Bigarray.Char c_layout
let get : t -> int -> char = Array1.get
let set : t -> int -> char -> unit = Array1.set
let sub : t -> int -> int -> t = Array1.sub
let fill : t -> char -> unit = Array1.fill
external get_u16 : t -> int -> int = "%caml_bigstring_get16u"
external get_u64 : t -> int -> int64 = "%caml_bigstring_get64u"
let to_string v =
let buf = Bytes.create (length v) in
for i = 0 to length v - 1
do Bytes.set buf i (get v i) done;
Bytes.unsafe_to_string buf
end
external string_get_u16 : string -> int -> int = "%caml_string_get16u"
external string_get_u64 : string -> int -> int64 = "%caml_string_get64u"
(* Read only module *)
module RO =
struct
type 'a t =
| String : string -> normal t
| Bigstring : bigstring -> fast t
let from_string v = String v
let from_bytes v = String (Bytes.to_string v)
let from_bigstring v = Bigstring v
let length (type a) (v : a t) = match v with
| String v -> String.length v
| Bigstring v -> Bigstring.length v
let get (type a) (v : a t) = match v with
| String v -> String.get v
| Bigstring v -> Bigstring.get v
let get_u16 (type a) (v : a t) = match v with
| String v -> string_get_u16 v
| Bigstring v -> Bigstring.get_u16 v
let get_u64 (type a) (v : a t) = match v with
| String v -> string_get_u64 v
| Bigstring v -> Bigstring.get_u64 v
let sub (type a) (v : a t) a b : a t = match v with
| String v -> from_string @@ String.sub v a b
| Bigstring v -> from_bigstring @@ Bigstring.sub v a b
let pp (type a) fmt (v : a t) = match v with
| String v -> Format.fprintf fmt "%S" v
| Bigstring v -> Format.fprintf fmt "%S" (Bigstring.to_string v)
end
(* Read and Write module *)
module RW =
struct
type 'a t =
| Bytes : bytes -> normal t
| Bigstring : bigstring -> fast t
let from_bytes v = Bytes v
let from_string v = Bytes (Bytes.of_string v)
let from_bigstring v = Bigstring v
let create_fast size =
Bigstring (Bigstring.create size)
let create_normal size =
Bytes (Bytes.create size)
let create_by (type a) (proof : a t) size : a t = match proof with
| Bytes _ -> Bytes (Bytes.create size)
| Bigstring _ -> Bigstring (Bigstring.create size)
let length (type a) (v : a t) = match v with
| Bytes v -> Bytes.length v
| Bigstring v -> Bigstring.length v
let get (type a) (v : a t) = match v with
| Bytes v -> Bytes.get v
| Bigstring v -> Bigstring.get v
let set (type a) (v : a t) = match v with
| Bytes v -> Bytes.set v
| Bigstring v -> Bigstring.set v
let get_u16 (type a) (v : a t) = match v with
| Bytes v -> string_get_u16 @@ Bytes.unsafe_to_string v
| Bigstring v -> Bigstring.get_u16 v
let get_u64 (type a) (v : a t) = match v with
| Bytes v -> string_get_u64 @@ Bytes.unsafe_to_string v
| Bigstring v -> Bigstring.get_u64 v
let sub_ro (type a) (v : a t) i l : a RO.t = match v with
| Bytes v -> RO.from_string @@ Bytes.sub_string v i l
| Bigstring v ->
let ro = Bigstring.create l in
Array1.blit (Bigstring.sub v i l) ro;
RO.from_bigstring ro
let fill (type a) (v : a t) off len chr = match v with
| Bytes v -> Bytes.fill v off len chr
| Bigstring v ->
let s = Bigstring.sub v off len in
Bigstring.fill s chr
end
module Make (Blit : BLIT with type t = bigstring) =
struct
include RW
let blit (type a) (src : a t) src_idx (dst : a t) dst_idx len =
match src, dst with
| Bytes src, Bytes dst ->
memcpy_bytes src dst len src_idx dst_idx
| Bigstring src, Bigstring dst ->
Blit.blit src src_idx dst dst_idx len
let blit_ro (type a) (src : a RO.t) src_idx (dst : a t) dst_idx len =
match src, dst with
| RO.String src, Bytes dst ->
(* XXX: not safe! *)
memcpy_bytes (Bytes.unsafe_of_string src) dst len src_idx dst_idx
| RO.Bigstring src, Bigstring dst ->
Blit.blit src src_idx dst dst_idx len
let blit_string (type a) src src_idx (dst : a t) dst_idx len =
match dst with
| Bytes dst ->
memcpy_bytes (Bytes.unsafe_of_string src) dst len src_idx dst_idx
| Bigstring dst ->
Blit.blit_string src src_idx dst dst_idx len
end
module Blit_bigstring =
struct
type t = bigstring
let blit src src_idx dst dst_idx len =
let src = Array1.sub src src_idx len in
let dst = Array1.sub dst dst_idx len in
Memcpy.memcpy_bigstring src dst len src_idx dst_idx
let blit_string src src_idx dst dst_idx len =
assert (src_idx + len <= String.length src);
assert (dst_idx + len <= Array1.dim dst);
let idx = ref 0 in
while !idx < len do
Array1.set dst (dst_idx + !idx) (String.get src (src_idx + !idx));
incr idx;
done
end
module RW_ext = Make(Blit_bigstring)
let to_rw (type a) (v : a RO.t) : a RW.t = match v with
| RO.String v -> RW.Bytes (Bytes.unsafe_of_string v)
| RO.Bigstring v -> RW.Bigstring v
let to_ro (type a) (v : a RW.t) : a RO.t = match v with
| RW.Bytes v -> RO.String (Bytes.unsafe_to_string v)
| RW.Bigstring v -> RO.Bigstring v
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment