Skip to content

Commit 3f5dd7c

Browse files
authored
Merge pull request #68 from CraigFe/extract-binary-codec
Extract primitive binary operations from generic derivation
2 parents 9234148 + 31734fd commit 3f5dd7c

File tree

4 files changed

+404
-246
lines changed

4 files changed

+404
-246
lines changed

src/repr/binary_codec.ml

+271
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
include Binary_codec_intf
2+
open Staging
3+
4+
let unsafe_add_bytes b k = k (Bytes.unsafe_to_string b)
5+
let str = Bytes.unsafe_of_string
6+
7+
let charstring_of_code : int -> string =
8+
let tbl =
9+
Array.init 256 (fun i -> Bytes.unsafe_to_string (Bytes.make 1 (Char.chr i)))
10+
in
11+
fun [@inline always] i ->
12+
assert (i < 256);
13+
Array.unsafe_get tbl i
14+
15+
module Unit = struct
16+
let encode () _k = ()
17+
let decode _ ofs = (ofs, ()) [@@inline always]
18+
end
19+
20+
module Char = struct
21+
let encode c k = k (charstring_of_code (Char.code c))
22+
let decode buf ofs = (ofs + 1, buf.[ofs]) [@@inline always]
23+
end
24+
25+
module Bool = struct
26+
let encode b = Char.encode (if b then '\255' else '\000')
27+
28+
let decode buf ofs =
29+
let ofs, c = Char.decode buf ofs in
30+
match c with '\000' -> (ofs, false) | _ -> (ofs, true)
31+
end
32+
33+
module Int8 = struct
34+
let encode i k = k (charstring_of_code i)
35+
36+
let decode buf ofs =
37+
let ofs, c = Char.decode buf ofs in
38+
(ofs, Stdlib.Char.code c)
39+
[@@inline always]
40+
end
41+
42+
module Int16 = struct
43+
let encode i =
44+
let b = Bytes.create 2 in
45+
Bytes.set_uint16_be b 0 i;
46+
unsafe_add_bytes b
47+
48+
let decode buf ofs = (ofs + 2, Bytes.get_uint16_be (str buf) ofs)
49+
end
50+
51+
module Int32 = struct
52+
let encode i =
53+
let b = Bytes.create 4 in
54+
Bytes.set_int32_be b 0 i;
55+
unsafe_add_bytes b
56+
57+
let decode buf ofs = (ofs + 4, Bytes.get_int32_be (str buf) ofs)
58+
end
59+
60+
module Int64 = struct
61+
let encode i =
62+
let b = Bytes.create 8 in
63+
Bytes.set_int64_be b 0 i;
64+
unsafe_add_bytes b
65+
66+
let decode buf ofs = (ofs + 8, Bytes.get_int64_be (str buf) ofs)
67+
end
68+
69+
module Float = struct
70+
let encode f = Int64.encode (Stdlib.Int64.bits_of_float f)
71+
72+
let decode buf ofs =
73+
let ofs, f = Int64.decode buf ofs in
74+
(ofs, Stdlib.Int64.float_of_bits f)
75+
end
76+
77+
module Int = struct
78+
let encode i k =
79+
let rec aux n k =
80+
if n >= 0 && n < 128 then k (charstring_of_code n)
81+
else
82+
let out = 128 lor (n land 127) in
83+
k (charstring_of_code out);
84+
aux (n lsr 7) k
85+
in
86+
aux i k
87+
88+
let decode buf ofs =
89+
let rec aux buf n p ofs =
90+
let ofs, i = Int8.decode buf ofs in
91+
let n = n + ((i land 127) lsl p) in
92+
if i >= 0 && i < 128 then (ofs, n) else aux buf n (p + 7) ofs
93+
in
94+
aux buf 0 0 ofs
95+
end
96+
97+
module Len = struct
98+
let encode n i =
99+
match n with
100+
| `Int -> Int.encode i
101+
| `Int8 -> Int8.encode i
102+
| `Int16 -> Int16.encode i
103+
| `Int32 -> Int32.encode (Stdlib.Int32.of_int i)
104+
| `Int64 -> Int64.encode (Stdlib.Int64.of_int i)
105+
| `Fixed _ -> Unit.encode ()
106+
| `Unboxed -> Unit.encode ()
107+
108+
let decode n buf ofs =
109+
match n with
110+
| `Int -> Int.decode buf ofs
111+
| `Int8 -> Int8.decode buf ofs
112+
| `Int16 -> Int16.decode buf ofs
113+
| `Int32 ->
114+
let ofs, i = Int32.decode buf ofs in
115+
(ofs, Stdlib.Int32.to_int i)
116+
| `Int64 ->
117+
let ofs, i = Int64.decode buf ofs in
118+
(ofs, Stdlib.Int64.to_int i)
119+
| `Fixed n -> (ofs, n)
120+
| `Unboxed -> (ofs, String.length buf - ofs)
121+
end
122+
123+
(* Helper functions generalising over [string] / [bytes]. *)
124+
module Mono_container = struct
125+
let decode_unboxed of_string of_bytes =
126+
stage @@ fun buf ofs ->
127+
let len = String.length buf - ofs in
128+
if ofs = 0 then (len, of_string buf)
129+
else
130+
let str = Bytes.create len in
131+
String.blit buf ofs str 0 len;
132+
(ofs + len, of_bytes str)
133+
134+
let decode of_string of_bytes =
135+
let sub len buf ofs =
136+
if ofs = 0 && len = String.length buf then (len, of_string buf)
137+
else
138+
let str = Bytes.create len in
139+
String.blit buf ofs str 0 len;
140+
(ofs + len, of_bytes str)
141+
in
142+
function
143+
| `Fixed n ->
144+
(* fixed-size strings are never boxed *)
145+
stage @@ fun buf ofs -> sub n buf ofs
146+
| n ->
147+
stage @@ fun buf ofs ->
148+
let ofs, len = Len.decode n buf ofs in
149+
sub len buf ofs
150+
end
151+
152+
module String_unboxed = struct
153+
let encode _ = stage (fun s k -> k s)
154+
155+
let decode _ =
156+
Mono_container.decode_unboxed (fun x -> x) Bytes.unsafe_to_string
157+
end
158+
159+
module Bytes_unboxed = struct
160+
(* NOTE: makes a copy of [b], since [k] may retain the string it's given *)
161+
let encode _ = stage (fun b k -> k (Bytes.to_string b))
162+
163+
let decode _ =
164+
Mono_container.decode_unboxed Bytes.unsafe_of_string (fun x -> x)
165+
end
166+
167+
module String = struct
168+
let encode len =
169+
stage (fun s k ->
170+
let i = String.length s in
171+
Len.encode len i k;
172+
k s)
173+
174+
let decode len = Mono_container.decode (fun x -> x) Bytes.unsafe_to_string len
175+
end
176+
177+
module Bytes = struct
178+
let encode len =
179+
stage (fun s k ->
180+
let i = Bytes.length s in
181+
Len.encode len i k;
182+
unsafe_add_bytes s k)
183+
184+
let decode len = Mono_container.decode Bytes.unsafe_of_string (fun x -> x) len
185+
end
186+
187+
module Option = struct
188+
let encode encode_elt v k =
189+
match v with
190+
| None -> Char.encode '\000' k
191+
| Some x ->
192+
Char.encode '\255' k;
193+
encode_elt x k
194+
195+
let decode decode_elt buf ofs =
196+
let ofs, c = Char.decode buf ofs in
197+
match c with
198+
| '\000' -> (ofs, None)
199+
| _ ->
200+
let ofs, x = decode_elt buf ofs in
201+
(ofs, Some x)
202+
end
203+
204+
module List = struct
205+
let encode =
206+
let rec encode_elements encode_elt k = function
207+
| [] -> ()
208+
| x :: xs ->
209+
encode_elt x k;
210+
(encode_elements [@tailcall]) encode_elt k xs
211+
in
212+
fun len encode_elt ->
213+
stage (fun x k ->
214+
Len.encode len (List.length x) k;
215+
encode_elements encode_elt k x)
216+
217+
let decode =
218+
let rec decode_elements decode_elt acc buf off = function
219+
| 0 -> (off, List.rev acc)
220+
| n ->
221+
let off, x = decode_elt buf off in
222+
decode_elements decode_elt (x :: acc) buf off (n - 1)
223+
in
224+
fun len decode_elt ->
225+
stage (fun buf ofs ->
226+
let ofs, len = Len.decode len buf ofs in
227+
decode_elements decode_elt [] buf ofs len)
228+
end
229+
230+
module Array = struct
231+
let encode =
232+
let encode_elements encode_elt k arr =
233+
for i = 0 to Array.length arr - 1 do
234+
encode_elt (Array.unsafe_get arr i) k
235+
done
236+
in
237+
fun n l ->
238+
stage (fun x k ->
239+
Len.encode n (Array.length x) k;
240+
encode_elements l k x)
241+
242+
let decode len decode_elt =
243+
let list_decode = unstage (List.decode len decode_elt) in
244+
stage (fun buf off ->
245+
let ofs, l = list_decode buf off in
246+
(ofs, Array.of_list l))
247+
end
248+
249+
module Pair = struct
250+
let encode a b (x, y) k =
251+
a x k;
252+
b y k
253+
254+
let decode a b buf off =
255+
let off, a = a buf off in
256+
let off, b = b buf off in
257+
(off, (a, b))
258+
end
259+
260+
module Triple = struct
261+
let encode a b c (x, y, z) k =
262+
a x k;
263+
b y k;
264+
c z k
265+
266+
let decode a b c buf off =
267+
let off, a = a buf off in
268+
let off, b = b buf off in
269+
let off, c = c buf off in
270+
(off, (a, b, c))
271+
end

src/repr/binary_codec.mli

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
include Binary_codec_intf.Intf
2+
(** @inline *)

src/repr/binary_codec_intf.ml

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
open Type_core
2+
open Staging
3+
4+
type 'a encoder = 'a -> (string -> unit) -> unit
5+
type 'a decoder = string -> int -> int * 'a
6+
7+
module type S = sig
8+
type t
9+
10+
val encode : t encoder
11+
val decode : t decoder
12+
end
13+
14+
module type S_with_length = sig
15+
type t
16+
17+
val encode : len -> t encoder staged
18+
val decode : len -> t decoder staged
19+
end
20+
21+
module type S1 = sig
22+
type 'a t
23+
24+
val encode : 'a encoder -> 'a t encoder
25+
val decode : 'a decoder -> 'a t decoder
26+
end
27+
28+
module type S1_with_length = sig
29+
type 'a t
30+
31+
val encode : len -> 'a encoder -> 'a t encoder staged
32+
val decode : len -> 'a decoder -> 'a t decoder staged
33+
end
34+
35+
module type S2 = sig
36+
type ('a, 'b) t
37+
38+
val encode : 'a encoder -> 'b encoder -> ('a, 'b) t encoder
39+
val decode : 'a decoder -> 'b decoder -> ('a, 'b) t decoder
40+
end
41+
42+
module type S3 = sig
43+
type ('a, 'b, 'c) t
44+
45+
val encode : 'a encoder -> 'b encoder -> 'c encoder -> ('a, 'b, 'c) t encoder
46+
val decode : 'a decoder -> 'b decoder -> 'c decoder -> ('a, 'b, 'c) t decoder
47+
end
48+
49+
module type Intf = sig
50+
module type S = S
51+
module type S1 = S1
52+
module type S2 = S2
53+
module type S3 = S3
54+
55+
module Unit : S with type t := unit
56+
module Bool : S with type t := bool
57+
module Char : S with type t := char
58+
module Int : S with type t := int
59+
module Int16 : S with type t := int
60+
module Int32 : S with type t := int32
61+
module Int64 : S with type t := int64
62+
module Float : S with type t := float
63+
module String : S_with_length with type t := string
64+
module String_unboxed : S_with_length with type t := string
65+
module Bytes : S_with_length with type t := bytes
66+
module Bytes_unboxed : S_with_length with type t := bytes
67+
module List : S1_with_length with type 'a t := 'a list
68+
module Array : S1_with_length with type 'a t := 'a array
69+
module Option : S1 with type 'a t := 'a option
70+
module Pair : S2 with type ('a, 'b) t := 'a * 'b
71+
module Triple : S3 with type ('a, 'b, 'c) t := 'a * 'b * 'c
72+
end

0 commit comments

Comments
 (0)