I am delighted to announce the release of bstr.0.1.0, as well as bin.0.1.0 and slice.0.1.0. These releases are the result of a synthetic work between several libraries, aimed at bringing together everything that might be useful to us in implementing formats and protocols within our cooperative. In particular, these libraries offer:
- a comprehensive module for manipulating what are known as bigstrings (replacing bigstringaf - because the name of that library is too long)
- a library providing access to bigstrings and bytes (in short, an abstraction of ocaml-cstruct)
- finally, a library for describing binary formats from which one can derive an encoder and a decoder (in the spirit of what repr can offer)
For those who want to understand the benefits of bigstrings, I’ve previously shared my thoughts on the subject here. Although we’ve since backtracked on the use of ocaml-cstruct, particularly for performance reasons (see this article), bigstrings remain useful in certain cases: they should, fundamentally, be used wisely.
Particular attention has been paid to performance using bechamel (for micro-benchmarking), and we can draw a few conclusions from this:
bstrhas the edge overbigstringafas it uses tags that did not exist at the timebigstringafwas developed
| bstr | bigstringaf | |
|---|---|---|
| blit | 4.4ns | 4.8ns |
| sub | 15.4ns | 18.9ns |
slice.bstrperforms likeocaml-cstruct(which was to be expected)binchallenges hand-written code in terms of decoding
| bin | hand-written (ocaml-cstruct) |
repr |
angstrom |
|
|---|---|---|---|---|
| ipv4 | 11.9ns | 11.9ns | 93.9ns | 136ns |
let bin =
let fn vihl tos total_length id ff ttl protocol checksum src dst =
{ version= vihl lsr 4; ihl= vihl land 0x0f; tos; total_length; id
; flags= ff lsr 13; frag_offset= ff land 0x1fff; ttl; protocol; checksum
; src; dst }
in
let open Bin in
record ~name:"ipv4" fn
|+ field ~name:"vihl" uint8 (fun t -> (t.version lsl 4) lor t.ihl)
|+ field ~name:"tos" uint8 (fun t -> t.tos)
|+ field ~name:"total_length" beuint16 (fun t -> t.total_length)
|+ field ~name:"id" beuint16 (fun t -> t.id)
|+ field ~name:"flags_frag" beuint16 (fun t ->
(t.flags lsl 13) lor t.frag_offset)
|+ field ~name:"ttl" uint8 (fun t -> t.ttl)
|+ field ~name:"protocol" uint8 (fun t -> t.protocol)
|+ field ~name:"checksum" beuint16 (fun t -> t.checksum)
|+ field ~name:"src" beint32 (fun t -> t.src)
|+ field ~name:"dst" beint32 (fun t -> t.dst)
|> sealr
let cstruct cs =
let vihl = Cstruct.get_uint8 cs 0 in
let tos = Cstruct.get_uint8 cs 1 in
let total_length = Cstruct.BE.get_uint16 cs 2 in
let id = Cstruct.BE.get_uint16 cs 4 in
let ff = Cstruct.BE.get_uint16 cs 6 in
let ttl = Cstruct.get_uint8 cs 8 in
let protocol = Cstruct.get_uint8 cs 9 in
let checksum = Cstruct.BE.get_uint16 cs 10 in
let src = Cstruct.BE.get_uint32 cs 12 in
let dst = Cstruct.BE.get_uint32 cs 16 in
{ version= vihl lsr 4; ihl= vihl land 0x0f; tos; total_length; id
; flags= ff lsr 13; frag_offset= ff land 0x1fff; ttl; protocol; checksum
; src; dst }
These libraries were driven by the ambition to provide a coherent and consistent set of libraries, particularly for working with bigarrays, whilst making few compromises in terms of performance. Several attempts were made to experiment with functors, GADTs, ADTs and even higher-kinded polymorphism… (even with capabilities).
The result is that a poor man’s functor appears to be sufficient, along with a few tweaks (notably to avoid a few caml_apply2 calls), to achieve something that is fairly competitive compared to hand-written code.
These libraries also encapsulate what may have been missing and/or emerged within the community when it came to working with bigstrings. I have personally contributed to improving these libraries without being entirely satisfied with them: hence the emergence of bstr in particular. A considerable amount of effort has been put into documenting these libraries and into testing them. Fuzzers are also available to verify certain assertions regarding bin (such as isomorphism).
These libraries are currently in use, and this version is certainly not the final one. Indeed, we will continue to improve them as we use them (particularly with regard to the implementation of protocols and formats in OCaml).
If you appreciate our work, you can make a donation via GitHub or directly to our charity. Bighappy hacking!