Module Bigstringaf
Bigstrings, but fast.
The OCaml compiler has a bunch of intrinsics for Bigstrings, but they're not widely-known, sometimes misused, and so programs that use Bigstrings are slower than they have to be. And even if a library got that part right and exposed the intrinsics properly, the compiler doesn't have any fast blits between Bigstrings and other string-like types.
So here they are. Go crazy.
type t
= (char, Bigarray_compat.int8_unsigned_elt, Bigarray_compat.c_layout) Bigarray_compat.Array1.t
Constructors
val create : int -> t
create n
returns a bigstring of lengthn
val empty : t
empty
is the empty bigstring. It has length0
and you can't really do much with it, but it's a good placeholder that only needs to be allocated once.
val of_string : off:int -> len:int -> string -> t
of_string ~off ~len s
returns a bigstring of lengthlen
that contains the contents of string from the range[off, len)
.
Memory-safe Operations
val length : t -> int
length t
is the length of the bigstring, in bytes.
val substring : t -> off:int -> len:int -> string
substring t ~off ~len
returns a string of lengthlen
containing the bytes oft
starting atoff
.
val to_string : t -> string
to_string t
is equivalent tosubstring t ~off:0 ~len:(length t)
val get : t -> int -> char
get t i
returns the character at offseti
int
.
val set : t -> int -> char -> unit
set t i c
sets the character at offseti
int
to bec
Little-endian Byte Order
The following operations assume a little-endian byte ordering of the bigstring. If the machine-native byte ordering differs, then the get operations will reorder the bytes so that they are in machine-native byte order before returning the result, and the set operations will reorder the bytes so that they are written out in the appropriate order.
Most modern processor architectures are little-endian, so more likely than not, these operations will not do any byte reordering.
val get_int16_le : t -> int -> int
get_int16_le t i
returns the two bytes int
starting at offseti
, interpreted as an unsigned integer.
val get_int16_sign_extended_le : t -> int -> int
get_int16_sign_extended_le t i
returns the two bytes int
starting at offseti
, interpreted as a signed integer and performing sign extension to the native word size before returning the result.
val set_int16_le : t -> int -> int -> unit
set_int16_le t i v
sets the two bytes int
starting at offseti
to the valuev
.
val get_int32_le : t -> int -> int32
get_int32_le t i
returns the four bytes int
starting at offseti
.
val set_int32_le : t -> int -> int32 -> unit
set_int32_le t i v
sets the four bytes int
starting at offseti
to the valuev
.
val get_int64_le : t -> int -> int64
get_int64_le t i
returns the eight bytes int
starting at offseti
.
val set_int64_le : t -> int -> int64 -> unit
set_int64_le t i v
sets the eight bytes int
starting at offseti
to the valuev
.
Big-endian Byte Order
The following operations assume a big-endian byte ordering of the bigstring. If the machine-native byte ordering differs, then the get operations will reorder the bytes so that they are in machine-native byte order before returning the result, and the set operations will reorder the bytes so that they are written out in the appropriate order.
Network byte order is big-endian, so you may need these operations when dealing with raw frames, for example, in a userland networking stack.
val get_int16_be : t -> int -> int
get_int16_be t i
returns the two bytes int
starting at offseti
, interpreted as an unsigned integer.
val get_int16_sign_extended_be : t -> int -> int
get_int16_sign_extended_be t i
returns the two bytes int
starting at offseti
, interpreted as a signed integer and performing sign extension to the native word size before returning the result.
val set_int16_be : t -> int -> int -> unit
set_int16_be t i v
sets the two bytes int
starting at offsetoff
to the valuev
.
val get_int32_be : t -> int -> int32
get_int32_be t i
returns the four bytes int
starting at offseti
.
val set_int32_be : t -> int -> int32 -> unit
set_int32_be t i v
sets the four bytes int
starting at offseti
to the valuev
.
val get_int64_be : t -> int -> int64
get_int64_be t i
returns the eight bytes int
starting at offseti
.
val set_int64_be : t -> int -> int64 -> unit
set_int64_be t i v
sets the eight bytes int
starting at offseti
to the valuev
.
Blits
All the following blit operations do the same thing. They copy a given number of bytes from a source starting at some offset to a destination starting at some other offset. Forgetting for a moment that OCaml is a memory-safe language, these are all equivalent to:
memcpy(dst + dst_off, src + src_off, len);
And in fact, that's how they're implemented. Except that bounds checking is performed before performing the blit.
val blit : t -> src_off:int -> t -> dst_off:int -> len:int -> unit
val blit_from_string : string -> src_off:int -> t -> dst_off:int -> len:int -> unit
val blit_from_bytes : Stdlib.Bytes.t -> src_off:int -> t -> dst_off:int -> len:int -> unit
val blit_to_bytes : t -> src_off:int -> Stdlib.Bytes.t -> dst_off:int -> len:int -> unit
memcmp
Fast comparisons based on memcmp
. Similar to the blits, these are implemented as C calls after performing bounds checks.
memcmp(buf1 + off1, buf2 + off2, len);
Memory-unsafe Operations
The following operations are not memory safe. However, they do compile down to just a couple instructions. Make sure when using them to perform your own bounds checking. Or don't. Just make sure you know what you're doing. You can do it, but only do it if you have to.
val unsafe_set : t -> int -> char -> unit
unsafe_set t i c
is likeset
except no bounds checking is performed.
val unsafe_get_int16_le : t -> int -> int
unsafe_get_int16_le t i
is likeget_int16_le
except no bounds checking is performed.
val unsafe_get_int16_be : t -> int -> int
unsafe_get_int16_be t i
is likeget_int16_be
except no bounds checking is performed.
val unsafe_get_int16_sign_extended_le : t -> int -> int
unsafe_get_int16_sign_extended_le t i
is likeget_int16_sign_extended_le
except no bounds checking is performed.
val unsafe_get_int16_sign_extended_be : t -> int -> int
unsafe_get_int16_sign_extended_be t i
is likeget_int16_sign_extended_be
except no bounds checking is performed.
val unsafe_set_int16_le : t -> int -> int -> unit
unsafe_set_int16_le t i v
is likeset_int16_le
except no bounds checking is performed.
val unsafe_set_int16_be : t -> int -> int -> unit
unsafe_set_int16_be t i v
is likeset_int16_be
except no bounds checking is performed.
val unsafe_get_int32_le : t -> int -> int32
unsafe_get_int32_le t i
is likeget_int32_le
except no bounds checking is performed.
val unsafe_get_int32_be : t -> int -> int32
unsafe_get_int32_be t i
is likeget_int32_be
except no bounds checking is performed.
val unsafe_set_int32_le : t -> int -> int32 -> unit
unsafe_set_int32_le t i v
is likeset_int32_le
except no bounds checking is performed.
val unsafe_set_int32_be : t -> int -> int32 -> unit
unsafe_set_int32_be t i v
is likeset_int32_be
except no bounds checking is performed.
val unsafe_get_int64_le : t -> int -> int64
unsafe_get_int64_le t i
is likeget_int64_le
except no bounds checking is performed.
val unsafe_get_int64_be : t -> int -> int64
unsafe_get_int64_be t i
is likeget_int64_be
except no bounds checking is performed.
val unsafe_set_int64_le : t -> int -> int64 -> unit
unsafe_set_int64_le t i v
is likeset_int64_le
except no bounds checking is performed.
val unsafe_set_int64_be : t -> int -> int64 -> unit
unsafe_set_int64_be t i v
is likeset_int64_be
except no bounds checking is performed.
Blits
All the following blit operations do the same thing. They copy a given number of bytes from a source starting at some offset to a destination starting at some other offset. Forgetting for a moment that OCaml is a memory-safe language, these are all equivalent to:
memcpy(dst + dst_off, src + src_off, len);
And in fact, that's how they're implemented. Except in the case of unsafe_blit
which uses a memmove
so that overlapping blits behave as expected. But in both cases, there's no bounds checking.
val unsafe_blit : t -> src_off:int -> t -> dst_off:int -> len:int -> unit
val unsafe_blit_from_string : string -> src_off:int -> t -> dst_off:int -> len:int -> unit
val unsafe_blit_from_bytes : Stdlib.Bytes.t -> src_off:int -> t -> dst_off:int -> len:int -> unit
val unsafe_blit_to_bytes : t -> src_off:int -> Stdlib.Bytes.t -> dst_off:int -> len:int -> unit
memcmp
Fast comparisons based on memcmp
. Similar to the blits, these are not memory safe and are implemented by the same C call:
memcmp(buf1 + off1, buf2 + off2, len);