Sorting and shuffling

val sort : cmp:('a -> 'a -> int) -> 'a array -> unit

Sort an array in increasing order according to a comparison function. The comparison function must return 0 if its arguments compare as equal, a positive integer if the first is greater, and a negative integer if the first is smaller (see below for a complete specification). For example, compare[28.2] is a suitable comparison function. After calling sort, the array is sorted in place in increasing order. sort is guaranteed to run in constant heap space and (at most) logarithmic stack space.

The current implementation uses Heap Sort. It runs in constant stack space.

Specification of the comparison function: Let `a` be the array and `cmp` the comparison function. The following must be true for all `x`, `y`, `z` in `a`:

* `cmp x y > 0` if and only if `cmp y x < 0`

* if `cmp x y ≥ 0` and `cmp y z ≥ 0` then `cmp x z ≥ 0`

When `sort` returns, `a` contains the same elements as before, reordered in such a way that for all `i` and `j` valid indices of `a`:

* `cmp a.(i) a.(j) ≥ 0` if `i ≥ j`

val stable_sort : cmp:('a -> 'a -> int) -> 'a array -> unit

Same as `ArrayLabels.sort[29.3]`, but the sorting algorithm is stable (i.e. elements that compare equal are kept in their original order) and not guaranteed to run in constant heap space.

The current implementation uses Merge Sort. It uses a temporary array of length `n/2`, where `n` is the length of the array. It is usually faster than the current implementation of `ArrayLabels.sort[29.3]`.

val fast_sort : cmp:('a -> 'a -> int) -> 'a array -> unit

Same as `ArrayLabels.sort[29.3]` or `ArrayLabels.stable_sort[29.3]`, whichever is faster on typical input.

val shuffle : rand:(int -> int) -> 'a array -> unit

`shuffle ~rand` a randomly permutes `a`'s element using `rand` for randomness. The distribution of permutations is uniform.

`rand` must be such that a call to `rand n` returns a uniformly distributed random number in the range `[0;n-1]`. `Random.int[29.49]` can be used for this (do not forget to initialize[29.49] the generator).

**Since:** 5.2
Binary encoding of integers

The functions in this section append binary encodings of integers to buffers.

Little-endian (resp. big-endian) encoding means that least (resp. most) significant bytes are
stored first. Big-endian is also known as network byte order. Native-endian encoding is either
little-endian or big-endian depending on Sys.big_endian[28.55].

32-bit and 64-bit integers are represented by the `int32` and `int64` types, which can be interpreted either as signed or unsigned numbers.

8-bit and 16-bit integers are represented by the `int` type, which has more bits than the binary encoding. Functions that encode these values truncate their inputs to their least significant bytes.

val add_uint8 : t -> int -> unit
add_uint8 b i appends a binary unsigned 8-bit integer i to b.

Since: 4.08

val add_int8 : t -> int -> unit
add_int8 b i appends a binary signed 8-bit integer i to b.

Since: 4.08

val add_uint16_ne : t -> int -> unit
add_uint16_ne b i appends a binary native-endian unsigned 16-bit integer i to b.

Since: 4.08

val add_uint16_be : t -> int -> unit
add_uint16_be b i appends a binary big-endian unsigned 16-bit integer i to b.

Since: 4.08

val add_uint16_le : t -> int -> unit
add_uint16_le b i appends a binary little-endian unsigned 16-bit integer i to b.

Since: 4.08

val add_int16_ne : t -> int -> unit
add_int16_ne b i appends a binary native-endian signed 16-bit integer i to b.

Since: 4.08

val add_int16_be : t -> int -> unit
add_int16_be b i appends a binary big-endian signed 16-bit integer i to b.

Since: 4.08

val add_int16_le : t -> int -> unit
add_int16_le b i appends a binary little-endian signed 16-bit integer i to b.

Since: 4.08

val add_int32_ne : t -> int32 -> unit
## Arrays and Sequences

val to_seq : 'a array -> 'a Seq.t

Iterate on the array, in increasing order. Modifications of the array during iteration will be reflected in the sequence.

**Since:** 4.07

val to_seqi : 'a array -> (int * 'a) Seq.t

Iterate on the array, in increasing order, yielding indices along elements. Modifications of the array during iteration will be reflected in the sequence.

**Since:** 4.07

val of_seq : 'a Seq.t -> 'a array

Create an array from the generator

**Since:** 4.07

## Arrays and concurrency safety

Care must be taken when concurrently accessing arrays from multiple domains: accessing an array will never crash a program, but unsynchronized accesses might yield surprising (non-sequentially-consistent) results.

## Atomicity

Every array operation that accesses more than one array element is not atomic. This includes iteration, scanning, sorting, splitting and combining arrays.

For example, consider the following program:

let size = 100_000_000
let a = ArrayLabels.make size 1
let d1 = Domain spawn (fun () ->
  ArrayLabels.iteri ~f:(fun i x -> a.(i) <- x + 1) a
)
let d2 = Domain spawn (fun () ->
  ArrayLabels.iteri ~f:(fun i x -> a.(i) <- 2 * x + 1) a
)
let () = Domain.join d1; Domain.join d2

After executing this code, each field of the array `a` is either 2, 3, 4 or 5. If atomicity is required, then the user must implement their own synchronization (for example, using `Mutex.t[29.38]`).

## Data races

If two domains only access disjoint parts of the array, then the observed behaviour is the equivalent to some sequential interleaving of the operations from the two domains.
`add_int32_ne b i` appends a binary native-endian 32-bit integer `i` to `b`.

Since: 4.08

`val add_int32_be : t -> int32 -> unit`

`add_int32_be b i` appends a binary big-endian 32-bit integer `i` to `b`.

Since: 4.08

`val add_int32_le : t -> int32 -> unit`

`add_int32_le b i` appends a binary little-endian 32-bit integer `i` to `b`.

Since: 4.08

`val add_int64_ne : t -> int64 -> unit`

`add_int64_ne b i` appends a binary native-endian 64-bit integer `i` to `b`.

Since: 4.08

`val add_int64_be : t -> int64 -> unit`

`add_int64_be b i` appends a binary big-endian 64-bit integer `i` to `b`.

Since: 4.08

`val add_int64_le : t -> int64 -> unit`

`add_int64_ne b i` appends a binary little-endian 64-bit integer `i` to `b`.

Since: 4.08

## 28.8 Module Bytes: Byte sequence operations.

A byte sequence is a mutable data structure that contains a fixed-length sequence of bytes. Each byte can be indexed in constant time for reading or writing.

Given a byte sequence `s` of length `l`, we can access each of the `l` bytes of `s` via its index in the sequence. Indexes start at 0, and we will call an index valid in `s` if it falls within the range `[0...(l-1)]` (inclusive). A position is the point between two bytes or at the beginning or end of the sequence. We call a position valid in `s` if it falls within the range `[0...(l-1)]` (inclusive). Note that the byte at index `n` is between positions `n` and `n+1`.

Two parameters `start` and `len` are said to designate a valid range of `s` if `len >= 0` and `start` and `start+len` are valid positions in `s`.

Byte sequences can be modified in place, for instance via the `set` and `blit` functions described below. See also strings (module `String` [28.53]), which are almost the same data structure, but cannot be modified in place.

Bytes are represented by the OCaml type `char`.

The labeled version of this module can be used as described in the `StdLabels` [28.52] module.

Since: 4.02

`val length : bytes -> int`
A data race is said to occur when two domains access the same array element without synchronization and at least one of the accesses is a write. In the absence of data races, the observed behaviour is equivalent to some sequential interleaving of the operations from different domains.

Whenever possible, data races should be avoided by using synchronization to mediate the accesses to the array elements.

Indeed, in the presence of data races, programs will not crash but the observed behaviour may not be equivalent to any sequential interleaving of operations from different domains. Nevertheless, even in the presence of data races, a read operation will return the value of some prior write to that location (with a few exceptions for float arrays).

## Float arrays

Float arrays have two supplementary caveats in the presence of data races.

First, the blit operation might copy an array byte-by-byte. Data races between such a blit operation and another operation might produce surprising values due to tearing: partial writes interleaved with other operations can create float values that would not exist with a sequential execution.

For instance, at the end of

```javascript
let zeros = Array.make size 0.
let max_floats = Array.make size Float.max_float
let res = Array.copy zeros
let d1 = Domain spawn (fun () -> Array.blit zeros 0 res 0 size)
let d2 = Domain spawn (fun () -> Array.blit max_floats 0 res 0 size)
let () = Domain.join d1; Domain.join d2
```

the `res` array might contain values that are neither 0. nor `max_float`.

Second, on 32-bit architectures, getting or setting a field involves two separate memory accesses. In the presence of data races, the user may observe tearing on any operation.

## 29.4 Module Atomic : Atomic references.

See the examples[29.48] below. See 'Memory model: The hard bits' chapter in the manual.

**Since:** 4.12

### type !'a t

An atomic (mutable) reference to a value of type `'a`.

### val make : 'a -> 'a t

Create an atomic reference.

### val make_contended : 'a -> 'a t

Create an atomic reference that is alone on a cache line. It occupies 4-16x the memory of one allocated with `make v`.
Return the length (number of bytes) of the argument.

`val get : bytes -> int -> char`

`get s n` returns the byte at index `n` in argument `s`.

**Raises** `Invalid_argument` if `n` is not a valid index in `s`.

`val set : bytes -> int -> char -> unit`

`set s n c` modifies `s` in place, replacing the byte at index `n` with `c`.

**Raises** `Invalid_argument` if `n` is not a valid index in `s`.

`val create : int -> bytes`

`create n` returns a new byte sequence of length `n`. The sequence is uninitialized and contains arbitrary bytes.

**Raises** `Invalid_argument` if `n < 0` or `n > Sys.max_string_length[28.55]`.

`val make : int -> char -> bytes`

`make n c` returns a new byte sequence of length `n`, filled with the byte `c`.

**Raises** `Invalid_argument` if `n < 0` or `n > Sys.max_string_length[28.55]`.

`val init : int -> (int -> char) -> bytes`

`init n f` returns a fresh byte sequence of length `n`, with character `i` initialized to the result of `f i` (in increasing index order).

**Raises** `Invalid_argument` if `n < 0` or `n > Sys.max_string_length[28.55]`.

`val empty : bytes`

A byte sequence of size 0.

`val copy : bytes -> bytes`

Return a new byte sequence that contains the same bytes as the argument.

`val of_string : string -> bytes`

Return a new byte sequence that contains the same bytes as the given string.

`val to_string : bytes -> string`

Return a new string that contains the same bytes as the given byte sequence.

`val sub : bytes -> int -> int -> bytes`

`sub s pos len` returns a new byte sequence of length `len`, containing the subsequence of `s` that starts at position `pos` and has length `len`.

**Raises** `Invalid_argument` if `pos` and `len` do not designate a valid range of `s`.

`val sub_string : bytes -> int -> int -> string`

Same as `Bytes.sub[28.8]` but return a string instead of a byte sequence.
The primary purpose is to prevent false-sharing and the resulting performance degradation. When a CPU performs an atomic operation, it temporarily takes ownership of an entire cache line that contains the atomic reference. If multiple atomic references share the same cache line, modifying these disjoint memory regions simultaneously becomes impossible, which can create a bottleneck. Hence, as a general guideline, if an atomic reference is experiencing contention, assigning it its own cache line may enhance performance.

val get : 'a t -> 'a

Get the current value of the atomic reference.

val set : 'a t -> 'a -> unit

Set a new value for the atomic reference.

val exchange : 'a t -> 'a -> 'a

Set a new value for the atomic reference, and return the current value.

val compare_and_set : 'a t -> 'a -> 'a -> bool

compare_and_set r seen v sets the new value of r to v only if its current value is physically equal to seen – the comparison and the set occur atomically. Returns true if the comparison succeeded (so the set happened) and false otherwise.

val fetch_and_add : int t -> int -> int

fetch_and_add r n atomically increments the value of r by n, and returns the current value (before the increment).

val incr : int t -> unit

incr r atomically increments the value of r by 1.

val decr : int t -> unit

decr r atomically decrements the value of r by 1.

module Loc :

sig

type 'a t = 'a atomic_loc

This module exposes a dedicated type 'a Atomic.Loc.t for atomic locations (storing a value of type 'a) inside objects that may not be atomic references. It is used in particular for atomic record fields: if a record r has an atomic field f of type foo, then [%atomic.loc r.f] has type foo Atomic.Loc.t.

The API below mirrors the API to access atomic references[29.4], see the documentation above for more information.

val get : 'a t -> 'a

val set : 'a t -> 'a -> unit
val extend : bytes -> int -> int -> bytes

extend s left right returns a new byte sequence that contains the bytes of s, with left uninitialized bytes prepended and right uninitialized bytes appended to it. If left or right is negative, then bytes are removed (instead of appended) from the corresponding side of s.

**Since:** 4.05 in BytesLabels

**Raises:** Invalid_argument if the result length is negative or longer than Sys.max_string_length[28.55] bytes.

val fill : bytes -> int -> int -> char -> unit

fill s pos len c modifies s in place, replacing len characters with c, starting at pos.

**Raises:** Invalid_argument if pos and len do not designate a valid range of s.

val blit : bytes -> int -> bytes -> int -> int -> unit

blit src src_pos dst dst_pos len copies len bytes from byte sequence src, starting at index src_pos, to byte sequence dst, starting at index dst_pos. It works correctly even if src and dst are the same byte sequence, and the source and destination intervals overlap.

**Raises:** Invalid_argument if src_pos and len do not designate a valid range of src, or if dst_pos and len do not designate a valid range of dst.

val blit_string : string -> int -> bytes -> int -> int -> unit

blit_string src src_pos dst dst_pos len copies len bytes from string src, starting at index src_pos, to byte sequence dst, starting at index dst_pos.

**Since:** 4.05 in BytesLabels

**Raises:** Invalid_argument if src_pos and len do not designate a valid range of src, or if dst_pos and len do not designate a valid range of dst.

val concat : bytes -> bytes list -> bytes

concat sep s1 concatenates the list of byte sequences s1, inserting the separator byte sequence sep between each, and returns the result as a new byte sequence.

**Raises:** Invalid_argument if the result is longer than Sys.max_string_length[28.55] bytes.

val cat : bytes -> bytes -> bytes

cat s1 s2 concatenates s1 and s2 and returns the result as a new byte sequence.

**Since:** 4.05 in BytesLabels

**Raises:** Invalid_argument if the result is longer than Sys.max_string_length[28.55] bytes.

val iter : (char -> unit) -> bytes -> unit

iter f s applies function f in turn to all the bytes of s. It is equivalent to f (get s 0); f (get s 1); ...; f (get s (length s - 1)); ().

val iteri : (int -> char -> unit) -> bytes -> unit
```kotlin
val exchange: 'a t -> 'a -> 'a
val compare_and_set: 'a t -> 'a -> 'a -> bool
val fetch_and_add: int t -> int -> int
val incr: int t -> unit
val decr: int t -> unit
end
```

Atomic "locations", such as record fields.

## Examples

### Basic Thread Coordination

A basic use case is to have global counters that are updated in a thread-safe way, for example to keep some sorts of metrics over IOs performed by the program. Another basic use case is to coordinate the termination of threads in a given program, for example when one thread finds an answer, or when the program is shut down by the user.

Here, for example, we're going to try to find a number whose hash satisfies a basic property. To do that, we'll run multiple threads which will try random numbers until they find one that works. Of course the output below is a sample run and will change every time the program is run.

```kotlin
(* use for termination *)
let stop_all_threads = Atomic.make false

(* total number of individual attempts to find a number *)
let num_attempts = Atomic.make 0

(* find a number that satisfies [p], by... trying random numbers
until one fits. *)
let find_number_where (p:int -> bool) =
    let rand = Random.State.make self_init() in
    while not (Atomic.get stop_all_threads) do
        let n = Random.State.full_int rand max_int in
        ignore (Atomic.fetch_and_add num_attempts 1 : int);
        if p (Hashtbl.hash n) then (
            Printfformat "found %d (hash=%d)\n!" n (Hashtbl.hash n);
            Atomic.set stop_all_threads true; (* signal all threads to stop *)
        )
    done;;
```

```kotlin
(* run multiple domains to search for a [n] where [hash n <= 100] *)
```
Same as `Bytes.iter` [28.8], but the function is applied to the index of the byte as first argument and the byte itself as second argument.

`val map : (char -> char) -> bytes -> bytes`

`map f s` applies function `f` in turn to all the bytes of `s` (in increasing index order) and stores the resulting bytes in a new sequence that is returned as the result.

`val mapi : (int -> char -> char) -> bytes -> bytes`

`mapi f s` calls `f` with each character of `s` and its index (in increasing index order) and stores the resulting bytes in a new sequence that is returned as the result.

`val fold_left : ('acc -> char -> 'acc) -> 'acc -> bytes -> 'acc`

`fold_left f x s` computes `f(... (f (f x (get s 0)) (get s 1)) ...) (get s (n-1)))`, where `n` is the length of `s`.

**Since:** 4.13

`val fold_right : (char -> 'acc -> 'acc) -> bytes -> 'acc -> 'acc`

`fold_right f s x` computes `f(get s 0) (f(get s 1) (... (f(get s (n-1)) x) ...))`, where `n` is the length of `s`.

**Since:** 4.13

`val for_all : (char -> bool) -> bytes -> bool`

`for_all p s` checks if all characters in `s` satisfy the predicate `p`.

**Since:** 4.13

`val exists : (char -> bool) -> bytes -> bool`

`exists p s` checks if at least one character of `s` satisfies the predicate `p`.

**Since:** 4.13

`val trim : bytes -> bytes`

Return a copy of the argument, without leading and trailing whitespace. The bytes regarded as whitespace are the ASCII characters ' ', '\012', '\n', '\r', and '\t'.

`val escaped : bytes -> bytes`

Return a copy of the argument, with special characters represented by escape sequences, following the lexical conventions of OCaml. All characters outside the ASCII printable range (32..126) are escaped, as well as backslash and double-quote.

**Raises** `Invalid_argument` if the result is longer than `Sys.max_string_length` [28.55] bytes.

`val index : bytes -> char -> int`

`index s c` returns the index of the first occurrence of byte `c` in `s`.

**Raises** `Not_found` if `c` does not occur in `s`.
```python
let () =
    let criterion n = n <= 100 in
    let threads =
        Array.init 8
        (fun _ -> Domain spawn (fun () -> find_number_where criterion))
    in
    Array.iter Domain.join threads;
    Printf printf "total number of attempts: %d\n!" (Atomic.get num_attempts) ;;

- : unit = ()
found 1651745641680046833 (hash=33)
total number of attempts: 30230350
```

## Treiber Stack

Another example is a basic Treiber stack[https://en.wikipedia.org/wiki/Treiber_stack] (a thread-safe stack) that can be safely shared between threads.

Note how both `push` and `pop` are recursive, because they attempt to swap the new stack (with one more, or one fewer, element) with the old stack. This is optimistic concurrency: each iteration of, say, `push stack x` gets the old stack `l`, and hopes that by the time it tries to replace `l` with `x::l`, nobody else has had time to modify the list. If the `compare_and_set` fails it means we were too optimistic, and must try again.

```python
type 'a stack = 'a list Atomic.t

let rec push (stack: _ stack) elt : unit =
    let cur = Atomic.get stack in
    let success = Atomic compare_and_set stack cur (elt :: cur) in
    if not success then
        push stack elt

let rec pop (stack: _ stack) : _ option =
    let cur = Atomic.get stack in
    match cur with
    | [] -> None
    | x :: tail ->
        let success = Atomic compare_and_set stack cur tail in
        if success then Some x
        else pop stack

# let st = Atomic.make []
# push st 1
- : unit = ()
```
val index_opt : bytes -> char -> int option

index_opt s c returns the index of the first occurrence of byte c in s or None if c does not occur in s.

Since: 4.05

val rindex : bytes -> char -> int

rindex s c returns the index of the last occurrence of byte c in s.

Raises Not_found if c does not occur in s.

val rindex_opt : bytes -> char -> int option

rindex_opt s c returns the index of the last occurrence of byte c in s or None if c does not occur in s.

Since: 4.05

val index_from : bytes -> int -> char -> int

index_from s i c returns the index of the first occurrence of byte c in s after position i.

index s c is equivalent to index_from s 0 c.

Raises

• Invalid_argument if i is not a valid position in s.

• Not_found if c does not occur in s after position i.

val index_from_opt : bytes -> int -> char -> int option

index_from_opt s i c returns the index of the first occurrence of byte c in s after position i or None if c does not occur in s after position i. index_opt s c is equivalent to index_from_opt s 0 c.

Since: 4.05

Raises Invalid_argument if i is not a valid position in s.

val rindex_from : bytes -> int -> char -> int

rindex_from s i c returns the index of the last occurrence of byte c in s before position i+1. rindex s c is equivalent to rindex_from s (length s - 1) c.

Raises

• Invalid_argument if i+1 is not a valid position in s.

• Not_found if c does not occur in s before position i+1.

val rindex_from_opt : bytes -> int -> char -> int option

rindex_from_opt s i c returns the index of the last occurrence of byte c in s before position i+1 or None if c does not occur in s before position i+1. rindex_opt s c is equivalent to rindex_from s (length s - 1) c.

Since: 4.05

Raises Invalid_argument if i+1 is not a valid position in s.
```h
# push st 2
- : unit = ()
# pop st
- : int option = Some 2
# pop st
- : int option = Some 1
# pop st
- : int option = None
```

## 29.5 Module Bigarray : Large, multi-dimensional, numerical arrays.

This module implements multi-dimensional arrays of integers and floating-point numbers, thereafter referred to as 'Bigarrays', to distinguish them from the standard OCaml arrays described in Array[29.2].

The implementation allows efficient sharing of large numerical arrays between OCaml code and C or Fortran numerical libraries.

The main differences between 'Bigarrays' and standard OCaml arrays are as follows:

* Bigarrays are not limited in size, unlike OCaml arrays. (Normal float arrays are limited to 2,097,151 elements on a 32-bit platform, and normal arrays of other types to 4,194,303 elements.)

* Bigarrays are multi-dimensional. Any number of dimensions between 0 and 16 is supported. In contrast, OCaml arrays are mono-dimensional and require encoding multi-dimensional arrays as arrays of arrays.

* Bigarrays can only contain integers and floating-point numbers, while OCaml arrays can contain arbitrary OCaml data types.

* Bigarrays provide more space-efficient storage of integer and floating-point elements than normal OCaml arrays, in particular because they support 'small' types such as single-precision floats and 8 and 16-bit integers, in addition to the standard OCaml types of double-precision floats and 32 and 64-bit integers.

* The memory layout of Bigarrays is entirely compatible with that of arrays in C and Fortran, allowing large arrays to be passed back and forth between OCaml code and C / Fortran code with no data copying at all.

* Bigarrays support interesting high-level operations that normal arrays do not provide efficiently, such as extracting sub-arrays and 'slicing' a multi-dimensional array along certain dimensions, all without any copying.

Users of this module are encouraged to do `open Bigarray` in their source, then refer to array types and operations via short dot notation, e.g. `Array1.t` or `Array2.sub`.

Bigarrays support all the OCaml ad-hoc polymorphic operations:
`val contains : bytes -> char -> bool`

contains `s c` tests if byte `c` appears in `s`.

`val contains_from : bytes -> int -> char -> bool`

contains_from `s start c` tests if byte `c` appears in `s` after position `start`. contains `s c` is equivalent to contains_from `s 0 c`.

**Raises** Invalid_argument if `start` is not a valid position in `s`.

`val rcontains_from : bytes -> int -> char -> bool`

rcontains_from `s stop c` tests if byte `c` appears in `s` before position `stop+1`.

**Raises** Invalid_argument if `stop < 0` or `stop+1` is not a valid position in `s`.

`val uppercase波cii : bytes -> bytes`

Return a copy of the argument, with all lowercase letters translated to uppercase, using the US-ASCII character set.

**Since:** 4.03 (4.05 in BytesLabels)

`val lowercase波cii : bytes -> bytes`

Return a copy of the argument, with all uppercase letters translated to lowercase, using the US-ASCII character set.

**Since:** 4.03 (4.05 in BytesLabels)

`val capitalize波cii : bytes -> bytes`

Return a copy of the argument, with the first character set to uppercase, using the US-ASCII character set.

**Since:** 4.03 (4.05 in BytesLabels)

`val un capitalize波cii : bytes -> bytes`

Return a copy of the argument, with the first character set to lowercase, using the US-ASCII character set.

**Since:** 4.03 (4.05 in BytesLabels)

`type t = bytes`

An alias for the type of byte sequences.

`val compare : t -> t -> int`

The comparison function for byte sequences, with the same specification as `compare` [27.2]. Along with the type `t`, this function `compare` allows the module `Bytes` to be passed as argument to the functors `Set.Make` [28.49] and `Map.Make` [28.33].

`val equal : t -> t -> bool`

The equality function for byte sequences.

**Since:** 4.03 (4.05 in BytesLabels)
* comparisons (`=`, `<>`, `<=`, etc, as well as `compare[28.2]`);

* hashing (module `Hash`);

* and structured input-output (the functions from the ` Marshal[29.36] ` module, as well as ` output_value[28.2] ` and ` input_value[28.2] `).

Element kinds

Bigarrays can contain elements of the following kinds:

* IEEE half precision (16 bits) floating-point numbers (`Bigarray.float16_elt[29.5]`),

* IEEE single precision (32 bits) floating-point numbers (`Bigarray.float32_elt[29.5]`),

* IEEE double precision (64 bits) floating-point numbers (`Bigarray.float64_elt[29.5]`),

* IEEE single precision (2 * 32 bits) floating-point complex numbers (`Bigarray.complex32_elt[29.5]`),

* IEEE double precision (2 * 64 bits) floating-point complex numbers (`Bigarray.complex64_elt[29.5]`),

* 8-bit integers (signed or unsigned) (`Bigarray.int8 BIGarray.int8_elt[29.5]`),

* 16-bit integers (signed or unsigned) (`Bigarray.int16Signed_elt[29.5]` or `Bigarray.int16_elt[29.5]`),

* OCaml integers (signed, 31 bits on 32-bit architectures, 63 bits on 64-bit architectures) (`Bigarray.int_elt[29.5]`),

* 32-bit signed integers (`Bigarray.int32_elt[29.5]`),

* 64-bit signed integers (`Bigarray.int64_elt[29.5]`),

* platform-native signed integers (32 bits on 32-bit architectures, 64 bits on 64-bit architectures) (`Bigarray.nativeint_elt[29.5]`).

Each element kind is represented at the type level by one of the `*_elt` types defined below
(defined with a single constructor instead of abstract types for technical injectivity reasons).

type float16_elt =
  | Float16_elt

type float32_elt =
  | Float32_elt

type float64_elt =
  | Float64_elt
type int8_signed_elt =
val starts_with : prefix:bytes -> bytes -> bool
    starts_with ~prefix s is true if and only if s starts with prefix.

Since: 4.13

val ends_with : suffix:bytes -> bytes -> bool
    ends_with ~suffix s is true if and only if s ends with suffix.

Since: 4.13

## Unsafe conversions (for advanced users)

This section describes unsafe, low-level conversion functions between `bytes` and `string`. They do not copy the internal data; used improperly, they can break the immutability invariant on strings provided by the `-safe-string` option. They are available for expert library authors, but for most purposes you should use the always-correct `Bytes.to_string[28.8]` and `Bytes.of_string[28.8]` instead.

val unsafe_to_string : bytes -> string

Unsafely convert a byte sequence into a string.

To reason about the use of `unsafe_to_string`, it is convenient to consider an "ownership" discipline. A piece of code that manipulates some data "owns" it; there are several disjoint ownership modes, including:

* Unique ownership: the data may be accessed and mutated

* Shared ownership: the data has several owners, that may only access it, not mutate it.

Unique ownership is linear: passing the data to another piece of code means giving up ownership (we cannot write the data again). A unique owner may decide to make the data shared (giving up mutation rights on it), but shared data may not become uniquely-owned again.

`unsafe_to_string` s can only be used when the caller owns the byte sequence s – either uniquely or as shared immutable data. The caller gives up ownership of s, and gains ownership of the returned string.

There are two valid use-cases that respect this ownership discipline:

1. Creating a string by initializing and mutating a byte sequence that is never changed after initialization is performed.

```hkl
let string_init len f : string =
    let s = Bytes.create len in
    for i = 0 to len - 1 do Bytes.set s i (f i) done;
    Bytes.unsafe_to_string s
```

This function is safe because the byte sequence `s` will never be accessed or mutated after `unsafe_to_string` is called. The `string_init` code gives up ownership of `s`, and returns the ownership of the resulting string to its caller.
```
| Int8_signed_elt

type int8_unsigned_elt =
  | Int8_unsigned_elt

type int16_signed_elt =
  | Int16_signed_elt

type int16_unsigned_elt =
  | Int16_unsigned_elt

type int32_elt =
  | Int32_elt

type int64_elt =
  | Int64_elt

type int_elt =
  | Int_elt

type nativeint_elt =
  | Nativeint_elt

type complex32_elt =
  | Complex32_elt

type complex64_elt =
  | Complex64_elt

type ('a, 'b) kind =
  | Float32 : (float, float32_elt) kind
  | Float64 : (float, float64_elt) kind
  | Int8_signed : (int, int8_signed_elt) kind
  | Int8_unsigned : (int, int8_unsigned_elt) kind
  | Int16_signed : (int, int16_signed_elt) kind
  | Int16_unsigned : (int, int16_unsigned_elt) kind
  | Int32 : (int32, int32_elt) kind
  | Int64 : (int64, int64_elt) kind
  | Int : (int, int_elt) kind
  | Nativeint : (nativeint, nativeint_elt) kind
  | Complex32 : (Complex.t, complex32_elt) kind
  | Complex64 : (Complex.t, complex64_elt) kind
  | Char : (char, int8_unsigned_elt) kind
  | Float16 : (float, float16_elt) kind
```

To each element kind is associated an OCaml type, which is the type of OCaml values that can be stored in the Bigarray or read back from it. This type is not necessarily the same as the type of the array elements proper: for instance, a Bigarray whose elements are of kind `float32_elt` contains 32-bit single precision floats, but reading or writing one of its elements from OCaml uses the OCaml type `float`, which is 64-bit double precision floats.

The GADT type `('a, 'b) kind` captures this association of an OCaml type `'a` for values read or written in the Bigarray, and of an element kind `'b` which represents the actual contents of the Bigarray. Its constructors list all possible associations of OCaml types with element kinds, and are re-exported below for backward-compatibility reasons.
Note that it would be unsafe if `s` was passed as an additional parameter to the function `f` as it could escape this way and be mutated in the future – `string_init` would give up ownership of `s` to pass it to `f`, and could not call `unsafe_to_string` safely.

We have provided the `String.init[28.53]`, `String.map[28.53]` and `String.mapi[28.53]` functions to cover most cases of building new strings. You should prefer those over `to_string` or `unsafe_to_string` whenever applicable.

2. Temporarily giving ownership of a byte sequence to a function that expects a uniquely owned string and returns ownership back, so that we can mutate the sequence again after the call ended.

```hcl
let bytes_length (s : bytes) =
    String.length (Bytes.unsafe_to_string s)
```

In this use-case, we do not promise that `s` will never be mutated after the call to `bytes_length s`. The `String.length[28.53]` function temporarily borrows unique ownership of the byte sequence (and sees it as a `string`), but returns this ownership back to the caller, which may assume that `s` is still a valid byte sequence after the call. Note that this is only correct because we know that `String.length[28.53]` does not capture its argument – it could escape by a side-channel such as a memoization combinator.

The caller may not mutate `s` while the string is borrowed (it has temporarily given up ownership). This affects concurrent programs, but also higher-order functions: if `String.length[28.53]` returned a closure to be called later, `s` should not be mutated until this closure is fully applied and returns ownership.

```hcl
val unsafe_of_string : string -> bytes
```

Unsafely convert a shared string to a byte sequence that should not be mutated.

The same ownership discipline that makes `unsafe_to_string` correct applies to `unsafe_of_string`: you may use it if you were the owner of the `string` value, and you will own the return `bytes` in the same mode.

In practice, unique ownership of string values is extremely difficult to reason about correctly. You should always assume strings are shared, never uniquely owned.

For example, string literals are implicitly shared by the compiler, so you never uniquely own them.

```hcl
let incorrect = Bytes.unsafe_of_string "hello"
let s = Bytes.of_string "hello"
```

The first declaration is incorrect, because the string literal `"hello"` could be shared by the compiler with other parts of the program, and mutating `incorrect` is a bug. You must always use the second version, which performs a copy and is thus correct.

Assuming unique ownership of strings that are not string literals, but are (partly) built from string literals, is also incorrect. For example, mutating `unsafe_of_string ("foo" ~ s)`
Using a generalized algebraic datatype (GADT) here allows writing well-typed polymorphic
functions whose return type depend on the argument type, such as:

let zero : type a b. (a, b) kind -> a = function
| Float32 -> 0.0 | Complex32 -> Complex.zero
| Float64 -> 0.0 | Complex64 -> Complex.zero
| Float16 -> 0.0
| Int8_signed -> 0 | Int8_unsigned -> 0
| Int16_signed -> 0 | Int16_unsigned -> 0
| Int32 -> 01 | Int64 -> 0L
| Int -> 0 | Nativeint -> 0n
| Char -> '\000'

Since: 5.2 Constructor Float16 for the GADT.

val float16 : (float, float16_elt) kind
See Bigarray char [29.5].

Since: 5.2

val float32 : (float, float32_elt) kind
See Bigarray char [29.5].

val float64 : (float, float64_elt) kind
See Bigarray char [29.5].

val complex32 : (Complex.t, complex32_elt) kind
See Bigarray char [29.5].

val complex64 : (Complex.t, complex64_elt) kind
See Bigarray char [29.5].

val int8_signed : (int, int8_signed_elt) kind
See Bigarray char [29.5].

val int8_unsigned : (int, int8_unsigned_elt) kind
See Bigarray char [29.5].

val int16_signed : (int, int16_signed_elt) kind
See Bigarray char [29.5].

val int16_unsigned : (int, int16_unsigned_elt) kind
See Bigarray char [29.5].

val int : (int, int_elt) kind
could mutate the shared string `"foo"` – assuming a rope-like representation of strings. More generally, functions operating on strings will assume shared ownership, they do not preserve unique ownership. It is thus incorrect to assume unique ownership of the result of `unsafe_of_string`.

The only case we have reasonable confidence is safe is if the produced `bytes` is shared – used as an immutable byte sequence. This is possibly useful for incremental migration of low-level programs that manipulate immutable sequences of bytes (for example ` Marshal.from_bytes[28.34]`) and previously used the `string` type for this purpose.

* `val split_on_char : char -> bytes -> bytes list`

`split_on_char sep s` returns the list of all (possibly empty) subsequences of `s` that are delimited by the `sep` character.

The function's output is specified by the following invariants:

* The list is not empty.

* Concatenating its elements using `sep` as a separator returns a byte sequence equal to the input (`Bytes.concat` (`Bytes.make` 1 `sep`) (`Bytes.split_on_char sep s`) = `s`).

* No byte sequence in the result contains the `sep` character.

**Since:** 4.13

## Iterators

* `val to_seq : t -> char Seq.t`

Iterate on the string, in increasing index order. Modifications of the string during iteration will be reflected in the sequence.

**Since:** 4.07

* `val to_seqi : t -> (int * char) Seq.t`

Iterate on the string, in increasing order, yielding indices along chars

**Since:** 4.07

* `val of_seq : char Seq.t -> t`

Create a string from the generator

**Since:** 4.07

## UTF codecs and validations

### UTF-8

* `val get_utf_8_uchar : t -> int -> Uchar.utf_decode`

`get_utf_8_uchar b i` decodes an UTF-8 character at index `i` in `b`.
See `Bigarray char` [29.5] and [29.5].

Beware that this is a bigarray containing OCaml integers (signed, 31 bits on 32-bit architectures, 63 bits on 64-bit architectures), which does not match the C int type.

`val int32 : (int32, int32_elt) kind`

See `Bigarray char` [29.5].

`val int64 : (int64, int64_elt) kind`

See `Bigarray char` [29.5].

`val nativeint : (nativeint, nativeint_elt) kind`

See `Bigarray char` [29.5].

`val char : (char, int8_unsigned_elt) kind`

As shown by the types of the values above, Bigarrays of kind `float16_elt`, `float32_elt` and `float64_elt` are accessed using the OCaml type `float`. Bigarrays of complex kinds `complex32_elt`, `complex64_elt` are accessed with the OCaml type `Complex.t` [29.12]. Bigarrays of integer kinds are accessed using the smallest OCaml integer type large enough to represent the array elements: `int` for 8- and 16-bit integer Bigarrays, as well as OCaml-integer Bigarrays; `int32` for 32-bit integer Bigarrays; `int64` for 64-bit integer Bigarrays; and `nativeint` for platform-native integer Bigarrays. Finally, Bigarrays of kind `int8_unsigned_elt` can also be accessed as arrays of characters instead of arrays of small integers, by using the kind value `char` instead of `int8_unsigned`.

`val kind_size_in_bytes : ('a, 'b) kind -> int`

`kind_size_in_bytes` k is the number of bytes used to store an element of type k.

Since: 4.03

## Array layouts

`type c_layout =`

| C_layout Typ

See `Bigarray fortran_layout` [29.5].

`type fortran_layout =`

| Fortran_layout_Typ

To facilitate interoperability with existing C and Fortran code, this library supports two different memory layouts for Bigarrays, one compatible with the C conventions, the other compatible with the Fortran conventions.

In the C-style layout, array indices start at 0, and multi-dimensional arrays are laid out in row-major format. That is, for a two-dimensional array, all elements of row 0 are contiguous in memory, followed by all elements of row 1, etc. In other terms, the array elements at `(x,y)` and `(x, y+1)` are adjacent in memory.
val set_utf_8_uchar : t -> int -> Uchar.t -> int
set_utf_8_uchar b i u UTF-8 encodes u at index i in b and returns the number of bytes n
that were written starting at i. If n is 0 there was not enough space to encode u at i and b
was left untouched. Otherwise a new character can be encoded at i + n.

val is_valid_utf_8 : t -> bool
is_valid_utf_8 b is true if and only if b contains valid UTF-8 data.

## UTF-16BE

val get_utf_16be_uchar : t -> int -> Uchar.utf_decode
get_utf_16be_uchar b i decodes an UTF-16BE character at index i in b.

val set_utf_16be_uchar : t -> int -> Uchar.t -> int
set_utf_16be_uchar b i u UTF-16BE encodes u at index i in b and returns the number of
bytes n that were written starting at i. If n is 0 there was not enough space to encode u at i
and b was left untouched. Otherwise a new character can be encoded at i + n.

val is_valid_utf_16be : t -> bool
is_valid_utf_16be b is true if and only if b contains valid UTF-16BE data.

## UTF-16LE

val get_utf_16le_uchar : t -> int -> Uchar.utf_decode
get_utf_16le_uchar b i decodes an UTF-16LE character at index i in b.

val set_utf_16le_uchar : t -> int -> Uchar.t -> int
set_utf_16le_uchar b i u UTF-16LE encodes u at index i in b and returns the number of
bytes n that were written starting at i. If n is 0 there was not enough space to encode u at i
and b was left untouched. Otherwise a new character can be encoded at i + n.

val is_valid_utf_16le : t -> bool
is_valid_utf_16le b is true if and only if b contains valid UTF-16LE data.

## Binary encoding/decoding of integers

The functions in this section binary encode and decode integers to and from byte sequences.

All following functions raise Invalid_argument if the space needed at index i to decode or encode the integer is not available.

Little-endian (resp. big-endian) encoding means that least (resp. most) significant bytes are stored first. Big-endian is also known as network byte order. Native-endian encoding is either little-endian or big-endian depending on Sys.big_endian[28.55].
In the Fortran-style layout, array indices start at 1, and multi-dimensional arrays are laid out in column-major format. That is, for a two-dimensional array, all elements of column 0 are contiguous in memory, followed by all elements of column 1, etc. In other terms, the array elements at (x,y) and (x+1, y) are adjacent in memory.

Each layout style is identified at the type level by the phantom types
`Bigarray.c_layout[29.5]` and `Bigarray.fortran_layout[29.5]` respectively.

Supported layouts

The GADT type 'a layout represents one of the two supported memory layouts: C-style or Fortran-style. Its constructors are re-exported as values below for backward-compatibility reasons.

```h
type 'a layout =
| C_layout : c_layout layout
| Fortran_layout : fortran_layout layout

val c_layout : c_layout layout

val fortran_layout : fortran_layout layout
```

Generic arrays (of arbitrarily many dimensions)

```h
module Genarray :
  sig
    type (!'a, !'b, !'c) t
```

The type `Genarray.t` is the type of Bigarrays with variable numbers of dimensions. Any number of dimensions between 0 and 16 is supported.

The three type parameters to `Genarray.t` identify the array element kind and layout, as follows:

* the first parameter, `'a`, is the OCaml type for accessing array elements (`float`, `int`, `int32`, `int64`, `nativeint`);

* the second parameter, `'b`, is the actual kind of array elements (`float32_elt`, `float64_elt`, `int8_signed_elt`, `int8_unsigned_elt`, etc);

* the third parameter, `'c`, identifies the array layout (`c_layout` or `fortran_layout`).

For instance, (`float`, `float32_elt`, `fortran_layout`) `Genarray.t` is the type of generic Bigarrays containing 32-bit floats in Fortran layout; reads and writes in this array use the OCaml type `float`.

```h
val create :
  ('a, 'b) Bigarray.kind ->
  'c Bigarraylayout -> int array -> ('a, 'b, 'c) t
```

`Genarray.create kind layout dimensions` returns a new Bigarray whose element kind is determined by the parameter `kind` (one of `float32`, `float64`, `int8_signed`, etc) and whose layout is determined by the parameter `layout` (one of `c_layout` or `fortran_layout`). The `dimensions` parameter is an array of integers that indicate the
32-bit and 64-bit integers are represented by the `int32` and `int64` types, which can be interpreted either as signed or unsigned numbers.

8-bit and 16-bit integers are represented by the `int` type, which has more bits than the binary encoding. These extra bits are handled as follows:

* Functions that decode signed (resp. unsigned) 8-bit or 16-bit integers represented by `int` values sign-extend (resp. zero-extend) their result.

* Functions that encode 8-bit or 16-bit integers represented by `int` values truncate their input to their least significant bytes.

**val get_uint8 : bytes -> int -> int**

`get_uint8` b i is b's unsigned 8-bit integer starting at byte index i.

Since: 4.08

**val get_int8 : bytes -> int -> int**

`get_int8` b i is b's signed 8-bit integer starting at byte index i.

Since: 4.08

**val get_uint16_ne : bytes -> int -> int**

`get_uint16_ne` b i is b's native-endian unsigned 16-bit integer starting at byte index i.

Since: 4.08

**val get_uint16_be : bytes -> int -> int**

`get_uint16_be` b i is b's big-endian unsigned 16-bit integer starting at byte index i.

Since: 4.08

**val get_uint16_le : bytes -> int -> int**

`get_uint16_le` b i is b's little-endian unsigned 16-bit integer starting at byte index i.

Since: 4.08

**val get_int16_ne : bytes -> int -> int**

`get_int16_ne` b i is b's native-endian signed 16-bit integer starting at byte index i.

Since: 4.08

**val get_int16_be : bytes -> int -> int**

`get_int16_be` b i is b's big-endian signed 16-bit integer starting at byte index i.

Since: 4.08

**val get_int16_le : bytes -> int -> int**

`get_int16_le` b i is b's little-endian signed 16-bit integer starting at byte index i.

Since: 4.08
size of the `Bigarray` in each dimension. The length of `dimensions` determines the number of dimensions of the `Bigarray`.

For instance, `Genarray.create int32 c_layout [14;6;8]` returns a fresh `Bigarray` of 32-bit integers, in C layout, having three dimensions, the three dimensions being 4, 6 and 8 respectively.

`Bigarrays` returned by `Genarray.create` are not initialized: the initial values of array elements is unspecified.

`Genarray.create` raises `Invalid_argument` if the number of dimensions is not in the range 0 to 16 inclusive, or if one of the dimensions is negative.

```kotlin
val init : 
    ('a, 'b) Bigarray.kind ->
    'c Bigarraylayout ->
    int array -> (int array -> 'a) -> ('a, 'b, 'c) t
```

`Genarray.init kind layout dimensions f` returns a new `Bigarray` `b` whose element `kind` is determined by the parameter `kind` (one of `float32`, `float64`, `int8_signed`, etc) and whose layout is determined by the parameter `layout` (one of `c_layout` or `fortran_layout`). The `dimensions` parameter is an array of integers that indicate the size of the `Bigarray` in each dimension. The length of `dimensions` determines the number of dimensions of the `Bigarray`.

Each element `Genarray.get b i` is initialized to the result of `f i`. In other words, `Genarray.init kind layout dimensions f` tabulates the results of `f` applied to the indices of a new `Bigarray` whose layout is described by `kind`, `layout` and `dimensions`. The index array `i` may be shared and mutated between calls to `f`.

For instance, `Genarray.init int c_layout [12; 1; 3]` (`Array.fold_left (+) 0`) returns a fresh `Bigarray` of integers, in C layout, having three dimensions (2, 1, 3, respectively), with the element values 0, 1, 2, 1, 2, 3.

`Genarray.init` raises `Invalid_argument` if the number of dimensions is not in the range 0 to 16 inclusive, or if one of the dimensions is negative.

Since: 4.12

```kotlin
val num_dim : ('a, 'b, 'c) t -> int
```

Return the number of dimensions of the given `Bigarray`.

```kotlin
val dims : ('a, 'b, 'c) t -> int array
```

`Genarray.dims` a returns all dimensions of the `Bigarray` `a`, as an array of integers of length `Genarray.num_dim` a.

```kotlin
val nth_dim : ('a, 'b, 'c) t -> int -> int
```

`Genarray.nth_dim` a n returns the n-th dimension of the `Bigarray` `a`. The first dimension corresponds to `n = 0`; the second dimension corresponds to `n = 1`; the last dimension, to `n = Genarray.num_dim` a - 1.

Raises `Invalid_argument` if `n` is less than 0 or greater or equal than `Genarray.num_dim` a.
val get_int32_ne : bytes -> int -> int32
get_int32_ne b i is b's native-endian 32-bit integer starting at byte index i.

Since: 4.08

val get_int32_be : bytes -> int -> int32
get_int32_be b i is b's big-endian 32-bit integer starting at byte index i.

Since: 4.08

val get_int32_le : bytes -> int -> int32
get_int32_le b i is b's little-endian 32-bit integer starting at byte index i.

Since: 4.08

val get_int64_ne : bytes -> int -> int64
get_int64_ne b i is b's native-endian 64-bit integer starting at byte index i.

Since: 4.08

val get_int64_be : bytes -> int -> int64
get_int64_be b i is b's big-endian 64-bit integer starting at byte index i.

Since: 4.08

val get_int64_le : bytes -> int -> int64
get_int64_le b i is b's little-endian 64-bit integer starting at byte index i.

Since: 4.08

val set_uint8 : bytes -> int -> int -> unit
set_uint8 b i v sets b's unsigned 8-bit integer starting at byte index i to v.

Since: 4.08

val set_int8 : bytes -> int -> int -> unit
set_int8 b i v sets b's signed 8-bit integer starting at byte index i to v.

Since: 4.08

val set_uint16_ne : bytes -> int -> int -> unit
set_uint16_ne b i v sets b's native-endian unsigned 16-bit integer starting at byte index i to v.

Since: 4.08

val set_uint16_be : bytes -> int -> int -> unit
set_uint16_be b i v sets b's big-endian unsigned 16-bit integer starting at byte index i to v.

Since: 4.08
```kotlin
val kind: ('a, 'b, 'c) t -> ('a, 'b) Bigarray.kind
```

Return the kind of the given Bigarray.

```kotlin
val layout: ('a, 'b, 'c) t -> 'c Bigarraylayout
```

Return the layout of the given Bigarray.

```kotlin
val change_layout: ('a, 'b, 'c) t ->
'a Bigarraylayout -> ('a, 'b, 'd) t
```

`Genarray.change_layout` returns a Bigarray with the specified layout, sharing the data with `a` (and hence having the same dimensions as `a`). No copying of elements is involved: the new array and the original array share the same storage space. The dimensions are reversed, such that `get v [| a; b |]` in C layout becomes `get v [| b+1; a+1 |]` in Fortran layout.

**Since:** 4.04

```kotlin
val size_in_bytes: ('a, 'b, 'c) t -> int
```

`size_in_bytes` is the number of elements in `a` multiplied by `a`'s `Bigarray.kind_size_in_bytes` [29.5].

**Since:** 4.03

```kotlin
val get: ('a, 'b, 'c) t -> int array -> 'a
```

Read an element of a generic Bigarray. `Genarray.get a [|i1; ...; iN|]` returns the element of `a` whose coordinates are `i1` in the first dimension, `i2` in the second dimension, ..., `iN` in the N-th dimension.

If `a` has C layout, the coordinates must be greater or equal than 0 and strictly less than the corresponding dimensions of `a`. If `a` has Fortran layout, the coordinates must be greater or equal than 1 and less or equal than the corresponding dimensions of `a`.

If `N > 3`, alternate syntax is provided: you can write `a.{i1, i2, ..., iN}` instead of `Genarray.get a [|i1; ...; iN|]`. (The syntax `a.{...}` with one, two or three coordinates is reserved for accessing one-, two- and three-dimensional arrays as described below.)

**Raises** `Invalid_argument` if the array `a` does not have exactly `N` dimensions, or if the coordinates are outside the array bounds.

```kotlin
val set: ('a, 'b, 'c) t -> int array -> 'a -> unit
```

Assign an element of a generic Bigarray. `Genarray.set a [|i1; ...; iN|] v` stores the value `v` in the element of `a` whose coordinates are `i1` in the first dimension, `i2` in the second dimension, ..., `iN` in the N-th dimension.

The array `a` must have exactly `N` dimensions, and all coordinates must lie inside the array bounds, as described for `Genarray.get`; otherwise, `Invalid_argument` is raised.

If `N > 3`, alternate syntax is provided: you can write `a.{i1, i2, ..., iN} <- v` instead of `Genarray.set a [|i1; ...; iN|] v`. (The syntax `a.{...}` <- `v` with one,
val set_uint16_le : bytes -> int -> int -> unit
set_uint16_le b i v sets b's little-endian unsigned 16-bit integer starting at byte index i
to v.

Since: 4.08

val set_int16_ne : bytes -> int -> int -> unit
set_int16_ne b i v sets b's native-endian signed 16-bit integer starting at byte index i to
v.

Since: 4.08

val set_int16_be : bytes -> int -> int -> unit
set_int16_be b i v sets b's big-endian signed 16-bit integer starting at byte index i to v.

Since: 4.08

val set_int16_le : bytes -> int -> int -> unit
set_int16_le b i v sets b's little-endian signed 16-bit integer starting at byte index i to v.

Since: 4.08

val set_int32_ne : bytes -> int -> int32 -> unit
set_int32_ne b i v sets b's native-endian 32-bit integer starting at byte index i to v.

Since: 4.08

val set_int32_be : bytes -> int -> int32 -> unit
set_int32_be b i v sets b's big-endian 32-bit integer starting at byte index i to v.

Since: 4.08

val set_int32_le : bytes -> int -> int32 -> unit
set_int32_le b i v sets b's little-endian 32-bit integer starting at byte index i to v.

Since: 4.08

val set_int64_ne : bytes -> int -> int64 -> unit
set_int64_ne b i v sets b's native-endian 64-bit integer starting at byte index i to v.

Since: 4.08

val set_int64_be : bytes -> int -> int64 -> unit
set_int64_be b i v sets b's big-endian 64-bit integer starting at byte index i to v.

Since: 4.08

val set_int64_le : bytes -> int -> int64 -> unit
set_int64_le b i v sets b's little-endian 64-bit integer starting at byte index i to v.

Since: 4.08
two or three coordinates is reserved for updating one-, two- and three-dimensional arrays
as described below.)

```fortran
val sub_left :
    ('a, 'b, Bigarray.c_layout) t ->
    int -> int -> ('a, 'b, Bigarray.c_layout) t
```

Extract a sub-array of the given Bigarray by restricting the first (left-most) dimension. `Genarray.sub_left` a `ofs len` returns a Bigarray with the same number of dimensions as a, and the same dimensions as a, except the first dimension, which corresponds to the interval `[ofs ... ofs + len - 1]` of the first dimension of a. No copying of elements is involved: the sub-array and the original array share the same storage space. In other terms, the element at coordinates `[|i1; ...; iN|]` of the sub-array is identical to the element at coordinates `[|i1+ofs; ...; iN|]` of the original array a.

`Genarray.sub_left` applies only to Bigarrays in C layout.

**Raises** `Invalid_argument` if `ofs` and `len` do not designate a valid sub-array of a, that is, if `ofs < 0`, or `len < 0`, or `ofs + len > Genarray.nth_dim` a 0.

```fortran
val sub_right :
    ('a, 'b, Bigarray.fortran_layout) t ->
    int -> int -> ('a, 'b, Bigarray.fortran_layout) t
```

Extract a sub-array of the given Bigarray by restricting the last (right-most) dimension. `Genarray.sub_right` a `ofs len` returns a Bigarray with the same number of dimensions as a, and the same dimensions as a, except the last dimension, which corresponds to the interval `[ofs ... ofs + len - 1]` of the last dimension of a. No copying of elements is involved: the sub-array and the original array share the same storage space. In other terms, the element at coordinates `[|i1; ...; iN|]` of the sub-array is identical to the element at coordinates `[|i1; ...; iN+ofs|]` of the original array a.

`Genarray.sub_right` applies only to Bigarrays in Fortran layout.

**Raises** `Invalid_argument` if `ofs` and `len` do not designate a valid sub-array of a, that is, if `ofs < 1`, or `len < 0`, or `ofs + len > Genarray.nth_dim` a (Genarray.num_dim a - 1).

```fortran
val slice_left :
    ('a, 'b, Bigarray.c_layout) t ->
    int array -> ('a, 'b, Bigarray.c_layout) t
```

Extract a sub-array of lower dimension from the given Bigarray by fixing one or several of the first (left-most) coordinates. `Genarray.slice_left` a `[|i1; ...; iM|]` returns the 'slice' of a obtained by setting the first M coordinates to `i1`, ..., `iM`. If a has N dimensions, the slice has dimension N - M, and the element at coordinates `[|j1; ...; j(N-M)|]` in the slice is identical to the element at coordinates `[|i1; ...; iM; j1; ...; j(N-M)|]` in the original array a. No copying of elements is involved: the slice and the original array share the same storage space.
## Byte sequences and concurrency safety

Care must be taken when concurrently accessing byte sequences from multiple domains: accessing a byte sequence will never crash a program, but unsynchronized accesses might yield surprising (non-sequentially-consistent) results.

## Atomicity

Every byte sequence operation that accesses more than one byte is not atomic. This includes iteration and scanning.

For example, consider the following program:

```clover
let size = 100_000_000
let b = Bytes.make size ' '
let update b f () =
    Bytes.iteri (fun i x -> Bytes.set b i (Char.chr (f (Char.code x)))) b
let d1 = Domain spawn (update b (fun x -> x + 1))
let d2 = Domain spawn (update b (fun x -> 2 * x + 1))
let () = Domain.join d1; Domain.join d2
```

the bytes sequence *b* may contain a non-deterministic mixture of '!', 'A', 'B', and 'C' values.

After executing this code, each byte of the sequence *b* is either '!', 'A', 'B', or 'C'. If atomicity is required, then the user must implement their own synchronization (for example, using `Mutex.t[28.36]`).

## Data races

If two domains only access disjoint parts of a byte sequence, then the observed behaviour is the equivalent to some sequential interleaving of the operations from the two domains.

A data race is said to occur when two domains access the same byte without synchronization and at least one of the accesses is a write. In the absence of data races, the observed behaviour is equivalent to some sequential interleaving of the operations from different domains.

Whenever possible, data races should be avoided by using synchronization to mediate the accesses to the elements of the sequence.

Indeed, in the presence of data races, programs will not crash but the observed behaviour may not be equivalent to any sequential interleaving of operations from different domains. Nevertheless, even in the presence of data races, a read operation will return the value of some prior write to that location.

## Mixed-size accesses

Another subtle point is that if a data race involves mixed-size writes and reads to the same location, the order in which those writes and reads are observed by domains is not specified. For instance, the following code write sequentially a 32-bit integer and a `char` to the same index

```clover
let b = Bytes.make 10 '\000'
let d1 = Domain spawn (fun () -> Bytes.set_int32_ne b 0 100; b.[0] <- 'd')
```
`Genarray.slice_left` applies only to Bigarrays in C layout.

**Raises** Invalid_argument if `M >= N`, or if `[|i1; ... ; iM|]` is outside the bounds of `a`.

```h
val slice_right :
    ('a, 'b, Bigarray.fortran_layout) t ->
    int array -> ('a, 'b, Bigarray.fortran_layout) t
```

Extract a sub-array of lower dimension from the given Bigarray by fixing one or several of the last (right-most) coordinates. `Genarray.slice_right a [|i1; ... ; iM|]` returns the 'slice' of `a` obtained by setting the last `M` coordinates to `i1, ..., iM`. If `a` has `N` dimensions, the slice has dimension `N - M`, and the element at coordinates `[|j1; ...; j(N-M)|]` in the slice is identical to the element at coordinates `[|j1; ...; j(N-M)|]` in the original array `a`. No copying of elements is involved: the slice and the original array share the same storage space.

`Genarray.slice_right` applies only to Bigarrays in Fortran layout.

**Raises** Invalid_argument if `M >= N`, or if `[|i1; ... ; iM|]` is outside the bounds of `a`.

```h
val blit : ('a, 'b, 'c) t -> ('a, 'b, 'c) t -> unit
```

Copy all elements of a Bigarray in another Bigarray. `Genarray.blit src dst` copies all elements of `src` into `dst`. Both arrays `src` and `dst` must have the same number of dimensions and equal dimensions. Copying a sub-array of `src` to a sub-array of `dst` can be achieved by applying `Genarray.blit` to sub-array or slices of `src` and `dst`.

```h
val fill : ('a, 'b, 'c) t -> 'a -> unit
```

Set all elements of a Bigarray to a given value. `Genarray.fill a v` stores the value `v` in all elements of the Bigarray `a`. Setting only some elements of `a` to `v` can be achieved by applying `Genarray.fill` to a sub-array or a slice of `a`.

end

## Zero-dimensional arrays

```h
module Array0 :
    sig
        type (!'a, !'b, !'c) t
```

The type of zero-dimensional Bigarrays whose elements have OCaml type `'a`, representation kind `'b`, and memory layout `'c'.

```h
val create : ('a, 'b) Bigarray.kind ->
    'c Bigarraylayout -> ('a, 'b, 'c) t
```
In this situation, a domain that observes the write of 'd' to b.0 is not guaranteed to also observe
the write to indices 1, 2, or 3.

## 28.9 Module BytesLabels : Byte sequence operations.

A byte sequence is a mutable data structure that contains a fixed-length sequence of bytes. Each byte can be indexed in constant time for reading or writing.

Given a byte sequence `s` of length `l`, we can access each of the `l` bytes of `s` via its index in the sequence. Indexes start at 0, and we will call an index valid in `s` if it falls within the range `[0...1-1]` (inclusive). A position is the point between two bytes or at the beginning or end of the sequence. We call a position valid in `s` if it falls within the range `[0...1]` (inclusive). Note that the byte at index `n` is between positions `n` and `n+1`.

Two parameters `start` and `len` are said to designate a valid range of `s` if `len >= 0` and `start` and `start+len` are valid positions in `s`.

Byte sequences can be modified in place, for instance via the `set` and `blit` functions described below. See also strings (module `String` [28.53]), which are almost the same data structure, but cannot be modified in place.

Bytes are represented by the OCaml type `char`.

The labeled version of this module can be used as described in the `StdLabels` [28.52] module.

**Since: 4.02**

`val length : bytes -> int`

Return the length (number of bytes) of the argument.

`val get : bytes -> int -> char`

`get s n` returns the byte at index `n` in argument `s`.

**Raises** `Invalid_argument` if `n` is not a valid index in `s`.

`val set : bytes -> int -> char -> unit`

`set s n c` modifies `s` in place, replacing the byte at index `n` with `c`.

**Raises** `Invalid_argument` if `n` is not a valid index in `s`.

`val create : int -> bytes`

`create n` returns a new byte sequence of length `n`. The sequence is uninitialized and contains arbitrary bytes.

**Raises** `Invalid_argument` if `n < 0` or `n > Sys.max_string_length` [28.55].

`val make : int -> char -> bytes`

`make n c` returns a new byte sequence of length `n`, filled with the byte `c`.

**Raises** `Invalid_argument` if `n < 0` or `n > Sys.max_string_length` [28.55].

`val init : int -> f:(int -> char) -> bytes`
`Array0.create kind layout` returns a new `Bigarray` of zero dimension. `kind` and `layout` determine the array element kind and the array layout as described for `Bigarray.Genarray.create[29.5]`.

```k
val init :
    ('a, 'b) Bigarray.kind ->
    'c Bigarraylayout -> 'a -> ('a, 'b, 'c) t
```

`Array0.init kind layout v` behaves like `Array0.create kind layout` except that the element is additionally initialized to the value `v`.

**Since: 4.12**

`val kind : ('a, 'b, 'c) t -> ('a, 'b) Bigarray.kind`

Return the kind of the given `Bigarray`.

`val layout : ('a, 'b, 'c) t -> 'c Bigarraylayout`

Return the layout of the given `Bigarray`.

`val change_layout : ('a, 'b, 'c) t ->
    'd Bigarraylayout -> ('a, 'b, 'd) t`

`Array0.change_layout` a layout returns a `Bigarray` with the specified layout, sharing the data with `a`. No copying of elements is involved: the new array and the original array share the same storage space.

**Since: 4.06**

`val size_in_bytes : ('a, 'b, 'c) t -> int`

`size_in_bytes` `a` is `a's` `Bigarray.kind_size_in_bytes[29.5]`.

`val get : ('a, 'b, 'c) t -> 'a`

`Array0.get` `a` returns the only element in `a`.

`val set : ('a, 'b, 'c) t -> 'a -> unit`

`Array0.set` `a` `x` `v` stores the value `v` in `a`.

`val blit : ('a, 'b, 'c) t -> ('a, 'b, 'c) t -> unit`

Copy the first `Bigarray` to the second `Bigarray`. See `Bigarray.Genarray.blit[29.5]` for more details.

`val fill : ('a, 'b, 'c) t -> 'a -> unit`

Fill the given `Bigarray` with the given value. See `Bigarray.Genarray.fill[29.5]` for more details.
`init n f` returns a fresh byte sequence of length `n`, with character `i` initialized to the result of `f i` (in increasing index order).

**Raises** `Invalid_argument` if `n` < 0 or `n` > `Sys.max_string_length[28.55]`.

**val empty : bytes**

A byte sequence of size 0.

**val copy : bytes -> bytes**

Return a new byte sequence that contains the same bytes as the argument.

**val of_string : string -> bytes**

Return a new byte sequence that contains the same bytes as the given string.

**val to_string : bytes -> string**

Return a new string that contains the same bytes as the given byte sequence.

**val sub : bytes -> pos:int -> len:int -> bytes**

`sub s ~pos ~len` returns a new byte sequence of length `len`, containing the subsequence of `s` that starts at position `pos` and has length `len`.

**Raises** `Invalid_argument` if `pos` and `len` do not designate a valid range of `s`.

**val sub_string : bytes -> pos:int -> len:int -> string**

Same as `BytesLabels.sub[28.9]` but return a string instead of a byte sequence.

**val extend : bytes -> left:int -> right:int -> bytes**

`extend s ~left ~right` returns a new byte sequence that contains the bytes of `s`, with `left` uninitialized bytes prepended and `right` uninitialized bytes appended to it. If `left` or `right` is negative, then bytes are removed (instead of appended) from the corresponding side of `s`.

**Since:** 4.05 in `BytesLabels`

**Raises** `Invalid_argument` if the result length is negative or longer than `Sys.max_string_length[28.55]` bytes.

**val fill : bytes -> pos:int -> len:int -> char -> unit**

`fill s ~pos ~len c` modifies `s` in place, replacing `len` characters with `c`, starting at `pos`.

**Raises** `Invalid_argument` if `pos` and `len` do not designate a valid range of `s`.

**val blit :**

`src:bytes -> src_pos:int -> dst:bytes -> dst_pos:int -> len:int -> unit`

`blit ~src ~src_pos ~dst ~dst_pos ~len` copies `len` bytes from byte sequence `src`, starting at index `src_pos`, to byte sequence `dst`, starting at index `dst_pos`. It works correctly even if `src` and `dst` are the same byte sequence, and the source and destination intervals overlap.

**Raises** `Invalid_argument` if `src_pos` and `len` do not designate a valid range of `src`, or if `dst_pos` and `len` do not designate a valid range of `dst`.
```h
val of_value :
    ('a, 'b) Bigarray.kind ->
    'c Bigarraylayout -> 'a -> ('a, 'b, 'c) t
```

Build a zero-dimensional Bigarray initialized from the given value.

end

Zero-dimensional arrays. The `Array0` structure provides operations similar to those of `Bigarray.Genarray` [29.5], but specialized to the case of zero-dimensional arrays that only contain a single scalar value. Statically knowing the number of dimensions of the array allows faster operations, and more precise static type-checking.

Since: 4.05

## One-dimensional arrays

```h
module Array1 :
    sig
        type (!'a, !'b, !'c) t
```

The type of one-dimensional Bigarrays whose elements have OCaml type `'a`, representation kind `'b`, and memory layout `'c`.

```h
val create :
    ('a, 'b) Bigarray.kind ->
    'c Bigarraylayout -> int -> ('a, 'b, 'c) t
```

`Array1.create kind layout dim` returns a new Bigarray of one dimension, whose size is `dim`. `kind` and `layout` determine the array element kind and the array layout as described for `Bigarray.Genarray.create` [29.5].

```h
val init :
    ('a, 'b) Bigarray.kind ->
    'c Bigarraylayout -> int -> (int -> 'a) -> ('a, 'b, 'c) t
```

`Array1.init kind layout dim f` returns a new Bigarray `b` of one dimension, whose size is `dim`. `kind` and `layout` determine the array element kind and the array layout as described for `Bigarray.Genarray.create` [29.5].

Each element `Array1.get b i` of the array is initialized to the result of `f i`.

In other words, `Array1.init kind layout dimensions f` tabulates the results of `f` applied to the indices of a new Bigarray whose layout is described by `kind`, `layout` and `dim`.

Since: 4.12

```h
val dim : ('a, 'b, 'c) t -> int
```

Return the size (dimension) of the given one-dimensional Bigarray.
val blit_string :

src:string -> src_pos:int -> dst:bytes -> dst_pos:int -> len:int -> unit

blit_string ~src ~src_pos ~dst ~dst_pos ~len copies len bytes from string src,
starting at index src_pos, to byte sequence dst, starting at index dst_pos.

Since: 4.05 in BytesLabels

Raises Invalid_argument if src_pos and len do not designate a valid range of src, or if
dst_pos and len do not designate a valid range of dst.

val concat : sep:bytes -> bytes list -> bytes

concat ~sep sl concatenates the list of byte sequences s1, inserting the separator byte
sequence sep between each, and returns the result as a new byte sequence.

Raises Invalid_argument if the result is longer than Sys.max_string_length[28.55] bytes.

val cat : bytes -> bytes -> bytes

cat s1 s2 concatenates s1 and s2 and returns the result as a new byte sequence.

Since: 4.05 in BytesLabels

Raises Invalid_argument if the result is longer than Sys.max_string_length[28.55] bytes.

val iter : f:(char -> unit) -> bytes -> unit

iter ~f s applies function f in turn to all the bytes of s. It is equivalent to f (get s 0);
f (get s 1); ...; f (get s (length s - 1)); ()

val iteri : f:(int -> char -> unit) -> bytes -> unit

Same as BytesLabels.iter[28.9], but the function is applied to the index of the byte as first
argument and the byte itself as second argument.

val map : f:(char -> char) -> bytes -> bytes

map ~f s applies function f in turn to all the bytes of s (in increasing index order) and
stores the resulting bytes in a new sequence that is returned as the result.

val mapi : f:(int -> char -> char) -> bytes -> bytes

mapi ~f s calls f with each character of s and its index (in increasing index order) and
stores the resulting bytes in a new sequence that is returned as the result.

val fold_left : f:('acc -> char -> 'acc) -> init:'acc -> bytes -> 'acc

fold_left f x s computes f (... (f (f x (get s 0)) (get s 1)) ...) (get s
(n-1)), where n is the length of s.

Since: 4.13

val fold_right : f:(char -> 'acc -> 'acc) -> bytes -> init:'acc -> 'acc

fold_right f s x computes f (get s 0) (f (get s 1) ( ... (f (get s (n-1)) x)
...)) , where n is the length of s.

Since: 4.13
`val kind : ('a, 'b, 'c) t -> ('a, 'b) Bigarray.kind`

Return the kind of the given Bigarray.

`val layout : ('a, 'b, 'c) t -> 'c Bigarraylayout`

Return the layout of the given Bigarray.

`val change_layout : ('a, 'b, 'c) t ->
'd Bigarraylayout -> ('a, 'b, 'd) t`

`Array1.change_layout a layout` returns a Bigarray with the specified layout, sharing the data with a (and hence having the same dimension as a). No copying of elements is involved: the new array and the original array share the same storage space.

**Since:** 4.06

`val size_in_bytes : ('a, 'b, 'c) t -> int`

`size_in_bytes` a is the number of elements in a multiplied by a's
`Bigarray.kind_size_in_bytes`[29.5].

**Since:** 4.03

`val get : ('a, 'b, 'c) t -> int -> 'a`

`Array1.get` a x, or alternatively `a.{x}`, returns the element of a at index x. x must be greater or equal than 0 and strictly less than `Array1.dim a` if a has C layout. If a has Fortran layout, x must be greater or equal than 1 and less or equal than `Array1.dim a`. Otherwise, `Invalid_argument` is raised.

`val set : ('a, 'b, 'c) t -> int -> 'a -> unit`

`Array1.set` a x v, also written `a.{x} <- v`, stores the value v at index x in a. x must be inside the bounds of a as described in `Bigarray.array1`. `get`[29.5]; otherwise, `Invalid_argument` is raised.

`val sub : ('a, 'b, 'c) t ->
    int -> int -> ('a, 'b, 'c) t`

Extract a sub-array of the given one-dimensional Bigarray. See
`Bigarray.Genarray.sub_left`[29.5] for more details.

`val slice : ('a, 'b, 'c) t -> int -> ('a, 'b, 'c) Bigarray.array0.t`

Extract a scalar (zero-dimensional slice) of the given one-dimensional Bigarray. The
integer parameter is the index of the scalar to extract. See
`Bigarray.Genarray.slice_left`[29.5] and `Bigarray.Genarray.slice_right`[29.5] for
more details.

**Since:** 4.05

`val blit : ('a, 'b, 'c) t -> ('a, 'b, 'c) t -> unit`
`val for_all : f:(char -> bool) -> bytes -> bool`

`for_all` `p s` checks if all characters in `s` satisfy the predicate `p`.

**Since:** 4.13

`val exists : f:(char -> bool) -> bytes -> bool`

`exists` `p s` checks if at least one character of `s` satisfies the predicate `p`.

**Since:** 4.13

`val trim : bytes -> bytes`

Return a copy of the argument, without leading and trailing whitespace. The bytes regarded as whitespace are the ASCII characters ' ', '\012', '\n', '\r', and '\t`.

`val escaped : bytes -> bytes`

Return a copy of the argument, with special characters represented by escape sequences, following the lexical conventions of OCaml. All characters outside the ASCII printable range (32..126) are escaped, as well as backslash and double-quote.

**Raises** `Invalid_argument` if the result is longer than `Sys.max_string_length[28.55]` bytes.

`val index : bytes -> char -> int`

`index` `s c` returns the index of the first occurrence of byte `c` in `s`.

**Raises** `Not_found` if `c` does not occur in `s`.

`val index_opt : bytes -> char -> int option`

`index_opt` `s c` returns the index of the first occurrence of byte `c` in `s` or `None` if `c` does not occur in `s`.

**Since:** 4.05

`val rindex : bytes -> char -> int`

`rindex` `s c` returns the index of the last occurrence of byte `c` in `s`.

**Raises** `Not_found` if `c` does not occur in `s`.

`val rindex_opt : bytes -> char -> int option`

`rindex_opt` `s c` returns the index of the last occurrence of byte `c` in `s` or `None` if `c` does not occur in `s`.

**Since:** 4.05

`val index_from : bytes -> int -> char -> int`

`index_from` `s i c` returns the index of the first occurrence of byte `c` in `s` after position `i`.

`index s c` is equivalent to `index_from s 0 c`.

**Raises**

* `Invalid_argument` if `i` is not a valid position in `s`.
Copy the first `Bigarray` to the second `Bigarray`. See `Bigarray.Genarray.blit[29.5]` for more details.

```hkl
val fill : ('a, 'b, 'c) t -> 'a -> unit
```

Fill the given `Bigarray` with the given value. See `Bigarray.Genarray.fill[29.5]` for more details.

```hkl
val of_array :
    ('a, 'b) Bigarray.kind ->
    'c Bigarraylayout -> 'a array -> ('a, 'b, 'c) t
```

Build a one-dimensional `Bigarray` initialized from the given array.

```hkl
val unsafe_get : ('a, 'b, 'c) t -> int -> 'a
```

Like `Bigarray Array1.get[29.5]`, but bounds checking is not always performed. Use with caution and only when the program logic guarantees that the access is within bounds.

```hkl
val unsafe_set : ('a, 'b, 'c) t -> int -> 'a -> unit
```

Like `Bigarray Array1.set[29.5]`, but bounds checking is not always performed. Use with caution and only when the program logic guarantees that the access is within bounds.

end

One-dimensional arrays. The `Array1` structure provides operations similar to those of `Bigarray.Genarray[29.5]`, but specialized to the case of one-dimensional arrays. (The `Bigarray Array2[29.5]` and `Bigarray Array3[29.5]` structures below provide operations specialized for two- and three-dimensional arrays.) Statically knowing the number of dimensions of the array allows faster operations, and more precise static type-checking.

## Two-dimensional arrays

```hkl
module Array2 :
sig
type (!'a, !'b, !'c) t
```

The type of two-dimensional `Bigarrays` whose elements have OCaml type `'a`, representation kind `'b`, and memory layout `'c`.

```hkl
val create :
    ('a, 'b) Bigarray.kind ->
    'c Bigarraylayout -> int -> int -> ('a, 'b, 'c) t
```
* `Not_found` if `c` does not occur in `s` after position `i`.

**val index_from_opt : bytes -> int -> char -> int option**

`index_from_opt` `s i c` returns the index of the first occurrence of byte `c` in `s` after position `i` or `None` if `c` does not occur in `s` after position `i`. `index_opt` `s c` is equivalent to `index_from_opt s 0 c`.

**Since:** 4.05

**Raises** `Invalid_argument` if `i` is not a valid position in `s`.

**val rindex_from : bytes -> int -> char -> int**

`rindex_from` `s i c` returns the index of the last occurrence of byte `c` in `s` before position `i+1`. `rindex` `s c` is equivalent to `rindex_from s (length s - 1) c`.

**Raises**

* `Invalid_argument` if `i+1` is not a valid position in `s`.

* `Not_found` if `c` does not occur in `s` before position `i+1`.

**val rindex_from_opt : bytes -> int -> char -> int option**

`rindex_from_opt` `s i c` returns the index of the last occurrence of byte `c` in `s` before position `i+1` or `None` if `c` does not occur in `s` before position `i+1`. `rindex_opt` `s c` is equivalent to `rindex_from s (length s - 1) c`.

**Since:** 4.05

**Raises** `Invalid_argument` if `i+1` is not a valid position in `s`.

**val contains : bytes -> char -> bool**

`contains` `s c` tests if byte `c` appears in `s`.

**val contains_from : bytes -> int -> char -> bool**

`contains_from` `s start c` tests if byte `c` appears in `s` after position `start`. `contains s c` is equivalent to `contains_from s 0 c`.

**Raises** `Invalid_argument` if `start` is not a valid position in `s`.

**val rcontains_from : bytes -> int -> char -> bool**

`rcontains_from` `s stop c` tests if byte `c` appears in `s` before position `stop+1`.

**Raises** `Invalid_argument` if `stop < 0` or `stop+1` is not a valid position in `s`.

**val uppercaseucleanss : bytes -> bytes**

Return a copy of the argument, with all lowercase letters translated to uppercase, using the US-ASCII character set.

**Since:** 4.05

**val lowercaseucleanss : bytes -> bytes**
`Array2.create kind layout dim1 dim2` returns a new `Bigarray` of two dimensions, whose size is `dim1` in the first dimension and `dim2` in the second dimension. `kind` and `layout` determine the array element kind and the array layout as described for `Bigarray.Genarray.create[29.5]`.

```k
val init :
    ('a, 'b) Bigarray.kind ->
    'c Bigarraylayout ->
    int -> int -> (int -> int -> 'a) -> ('a, 'b, 'c) t
```

`Array2.init kind layout dim1 dim2 f` returns a new `Bigarray` `b` of two dimensions, whose size is `dim2` in the first dimension and `dim2` in the second dimension. `kind` and `layout` determine the array element kind and the array layout as described for `Bigarray.Genarray.create[29.5]`.

Each element `Array2.get b i j` of the array is initialized to the result of `f i j`.

In other words, `Array2.init kind layout dim1 dim2 f` tabulates the results of `f` applied to the indices of a new `Bigarray` whose layout is described by `kind`, `layout`, `dim1` and `dim2`.

**Since:** 4.12

`val dim1 : ('a, 'b, 'c) t -> int`

Return the first dimension of the given two-dimensional `Bigarray`.

`val dim2 : ('a, 'b, 'c) t -> int`

Return the second dimension of the given two-dimensional `Bigarray`.

`val kind : ('a, 'b, 'c) t -> ('a, 'b) Bigarray.kind`

Return the kind of the given `Bigarray`.

`val layout : ('a, 'b, 'c) t -> 'c Bigarraylayout`

Return the layout of the given `Bigarray`.

`val change_layout : ('a, 'b, 'c) t ->
    'd Bigarraylayout -> ('a, 'b, 'd) t`

`Array2.change_layout` returns a `Bigarray` with the specified `layout`, sharing the data with `a` (and hence having the same dimensions as `a`). No copying of elements is involved: the new array and the original array share the same storage space. The dimensions are reversed, such that `get v [| a; b |]` in C layout becomes `get v [| b+1; a+1 |]` in Fortran layout.

**Since:** 4.06

`val size_in_bytes : ('a, 'b, 'c) t -> int`
Return a copy of the argument, with all uppercase letters translated to lowercase, using the US-ASCII character set.

**Since: 4.05**

**val capitalizeascii: bytes -> bytes**

Return a copy of the argument, with the first character set to uppercase, using the US-ASCII
character set.

**Since: 4.05**

**val un capital ize_ascii: bytes -> bytes**

Return a copy of the argument, with the first character set to lowercase, using the US-ASCII
character set.

**Since: 4.05**

**type t = bytes**

An alias for the type of byte sequences.

**val compare : t -> t -> int**

The comparison function for byte sequences, with the same specification as compare[27.2].
Along with the type t, this function compare allows the module Bytes to be passed as
argument to the functors Set.Make[28.49] and Map.Make[28.33].

**val equal : t -> t -> bool**

The equality function for byte sequences.

**Since: 4.05**

**val starts_with : prefix:bytes -> bytes -> bool**

starts_with ~prefix s is true if and only if s starts with prefix.

**Since: 4.13**

**val ends_with : suffix:bytes -> bytes -> bool**

ends_with ~suffix s is true if and only if s ends with suffix.

**Since: 4.13**

Unsafe conversions (for advanced users)

This section describes unsafe, low-level conversion functions between `bytes` and `string`. They do not copy the internal data; used improperly, they can break the immutability invariant on strings provided by the `-safe-string` option. They are available for expert library authors, but for most purposes you should use the always-correct `BytesLabels.to_string`[28.9] and `BytesLabels.of_string`[28.9] instead.

**val unsafe_to_string: bytes -> string**
`size_in_bytes` a is the number of elements in a multiplied by a's
`Bigarray.kind_size_in_bytes`[29.5].

Since: 4.03

`val get: ('a, 'b, 'c) t -> int -> int -> 'a`

`Array2.get` a x y, also written `a.{x,y}`, returns the element of a at coordinates (x, y). x and y must be within the bounds of a, as described for `Bigarray.Genarray.get`[29.5]; otherwise, `Invalid_argument` is raised.

`val set: ('a, 'b, 'c) t -> int -> int -> 'a -> unit`

`Array2.set` a x y v, or alternatively `a.{x,y} <- v`, stores the value v at coordinates (x, y) in a. x and y must be within the bounds of a, as described for `Bigarray.Genarray.set`[29.5]; otherwise, `Invalid_argument` is raised.

`val sub_left: ('a, 'b, Bigarray.c_layout) t -> int -> int -> ('a, 'b, Bigarray.c_layout) t`

Extract a two-dimensional sub-array of the given two-dimensional Bigarray by
restricting the first dimension. See `Bigarray.Genarray.sub_left`[29.5] for more details.
`Array2.sub_left` applies only to arrays with C layout.

`val sub_right: ('a, 'b, Bigarray.fortran_layout) t -> int -> int -> ('a, 'b, Bigarray.fortran_layout) t`

Extract a two-dimensional sub-array of the given two-dimensional Bigarray by
restricting the second dimension. See `Bigarray.Genarray.sub_right`[29.5] for more
details. `Array2.sub_right` applies only to arrays with Fortran layout.

`val slice_left: ('a, 'b, Bigarray.c_layout) t -> int -> ('a, 'b, Bigarray.c_layout) Bigarray Array1.t`

Extract a row (one-dimensional slice) of the given two-dimensional Bigarray. The integer
parameter is the index of the row to extract. See `Bigarray.Genarray.slice_left`[29.5]
for more details. `Array2.slice_left` applies only to arrays with C layout.

`val slice_right: ('a, 'b, Bigarray.fortran_layout) t -> int -> ('a, 'b, Bigarray.fortran_layout) Bigarray Array1.t`

Extract a column (one-dimensional slice) of the given two-dimensional Bigarray. The
integer parameter is the index of the column to extract. See
`Bigarray.Genarray.slice_right`[29.5] for more details. `Array2.slice_right` applies
only to arrays with Fortran layout.
Unsafely convert a byte sequence into a string.

To reason about the use of `unsafe_to_string`, it is convenient to consider an "ownership" discipline. A piece of code that manipulates some data "owns" it; there are several disjoint ownership modes, including:

* Unique ownership: the data may be accessed and mutated

* Shared ownership: the data has several owners, that may only access it, not mutate it.

Unique ownership is linear: passing the data to another piece of code means giving up ownership (we cannot write the data again). A unique owner may decide to make the data shared (giving up mutation rights on it), but shared data may not become uniquely-owned again.

`unsafe_to_string` `s` can only be used when the caller owns the byte sequence `s` – either uniquely or as shared immutable data. The caller gives up ownership of `s`, and gains ownership of the returned string.

There are two valid use-cases that respect this ownership discipline:

1. Creating a string by initializing and mutating a byte sequence that is never changed after initialization is performed.

```javascript
let string_init len f : string =
    let s = Bytes.create len in
    for i = 0 to len - 1 do Bytes.set s i (f i) done;
    Bytes.unsafe_to_string s
```

This function is safe because the byte sequence `s` will never be accessed or mutated after `unsafe_to_string` is called. The `string_init` code gives up ownership of `s`, and returns the ownership of the resulting string to its caller.

Note that it would be unsafe if `s` was passed as an additional parameter to the function `f` as it could escape this way and be mutated in the future – `string_init` would give up ownership of `s` to pass it to `f`, and could not call `unsafe_to_string` safely.

We have provided the `String.init[28.53]`, `String.map[28.53]` and `String.mapi[28.53]` functions to cover most cases of building new strings. You should prefer those over `to_string` or `unsafe_to_string` whenever applicable.

2. Temporarily giving ownership of a byte sequence to a function that expects a uniquely owned string and returns ownership back, so that we can mutate the sequence again after the call ended.

```javascript
let bytes_length (s : bytes) =
    String.length (Bytes.unsafe_to_string s)
```

In this use-case, we do not promise that `s` will never be mutated after the call to `bytes_length s`. The `String.length[28.53]` function temporarily borrows unique ownership
```hkl
val blit : ('a, 'b, 'c) t -> ('a, 'b, 'c) t -> unit
```

Copy the first `Bigarray` to the second `Bigarray`. See `Bigarray.Genarray.blit[29.5]` for more details.

```hkl
val fill : ('a, 'b, 'c) t -> 'a -> unit
```

Fill the given `Bigarray` with the given value. See `Bigarray.Genarray.fill[29.5]` for more details.

```hkl
val of_array :
```

```
('a, 'b) Bigarray.kind ->
```

```
'c Bigarraylayout -> 'a array array -> ('a, 'b, 'c) t
```

Build a two-dimensional `Bigarray` initialized from the given array of arrays.

```hkl
val unsafe_get : ('a, 'b, 'c) t -> int -> int -> 'a
```

Like `Bigarray Array2.get[29.5]`, but bounds checking is not always performed.

```hkl
val unsafe_set : ('a, 'b, 'c) t -> int -> int -> 'a -> unit
```

Like `Bigarray Array2.set[29.5]`, but bounds checking is not always performed.

end

Two-dimensional arrays. The `Array2` structure provides operations similar to those of `Bigarray.Genarray[29.5]`, but specialized to the case of two-dimensional arrays.

## Three-dimensional arrays

```hkl
module Array3 :
```

sig

```hkl
type (!'a, !'b, !'c) t
```

The type of three-dimensional `Bigarrays` whose elements have OCaml type `'a`, representation kind `'b`, and memory layout `'c`.

```hkl
val create :
```

```
('a, 'b) Bigarray.kind ->
```

```
'c Bigarraylayout -> int -> int -> int -> ('a, 'b, 'c) t
```

`Array3.create kind layout dim1 dim2 dim3` returns a new `Bigarray` of three dimensions, whose size is `dim1` in the first dimension, `dim2` in the second dimension, and `dim3` in the third. `kind` and `layout` determine the array element kind and the array layout as described for `Bigarray.Genarray.create[29.5]`.
of the byte sequence (and sees it as a *string*), but returns this ownership back to the caller, which may assume that *s* is still a valid byte sequence after the call. Note that this is only correct because we know that `String.length[28.53]` does not capture its argument – it could escape by a side-channel such as a memoization combinator.

The caller may not mutate *s* while the string is borrowed (it has temporarily given up ownership). This affects concurrent programs, but also higher-order functions: if `String.length[28.53]` returned a closure to be called later, *s* should not be mutated until this closure is fully applied and returns ownership.

### `val unsafe_of_string: string -> bytes`

Unsafely convert a shared string to a byte sequence that should not be mutated.

The same ownership discipline that makes `unsafe_to_string` correct applies to `unsafe_of_string`: you may use it if you were the owner of the `string` value, and you will own the return `bytes` in the same mode.

In practice, unique ownership of string values is extremely difficult to reason about correctly. You should always assume strings are shared, never uniquely owned.

For example, string literals are implicitly shared by the compiler, so you never uniquely own them.

```kotlin
let incorrect = Bytes.unsafe_of_string "hello"
let s = Bytes.of_string "hello"
```

The first declaration is incorrect, because the string literal `"hello"` could be shared by the compiler with other parts of the program, and mutating `incorrect` is a bug. You must always use the second version, which performs a copy and is thus correct.

Assuming unique ownership of strings that are not string literals, but are (partly) built from string literals, is also incorrect. For example, mutating `unsafe_of_string ("foo" ^ s)` could mutate the shared string `"foo"` – assuming a rope-like representation of strings. More generally, functions operating on strings will assume shared ownership, they do not preserve unique ownership. It is thus incorrect to assume unique ownership of the result of `unsafe_of_string`.

The only case we have reasonable confidence is safe is if the produced `bytes` is shared – used as an immutable byte sequence. This is possibly useful for incremental migration of low-level programs that manipulate immutable sequences of bytes (for example ` Marshal.from_bytes[28.34]`) and previously used the `string` type for this purpose.

### `val split_on_char: sep:char -> bytes -> bytes list`

`split_on_char sep s` returns the list of all (possibly empty) subsequences of *s* that are delimited by the `sep` character.

The function's output is specified by the following invariants:

* The list is not empty.
```k
val init :
    ('a, 'b) Bigarray.kind ->
    'c Bigarraylayout ->
    int ->
    int -> int -> (int -> int -> int -> 'a) -> ('a, 'b, 'c) t
```

`Array3.init kind layout dim1 dim2 dim3 f` returns a new `Bigarray b` of three dimensions, whose size is `dim1` in the first dimension, `dim2` in the second dimension, and `dim3` in the third. `kind` and `layout` determine the array element kind and the array layout as described for `Bigarray.Genarray.create[29.5]`.

Each element `Array3.get b i j k` of the array is initialized to the result of `f i j k`. In other words, `Array3.init kind layout dim1 dim2 dim3 f` tabulates the results of `f` applied to the indices of a new `Bigarray` whose layout is described by `kind`, `layout`, `dim1`, `dim2` and `dim3`.

**Since:** 4.12

`val dim1 : ('a, 'b, 'c) t -> int`

Return the first dimension of the given three-dimensional `Bigarray`.

`val dim2 : ('a, 'b, 'c) t -> int`

Return the second dimension of the given three-dimensional `Bigarray`.

`val dim3 : ('a, 'b, 'c) t -> int`

Return the third dimension of the given three-dimensional `Bigarray`.

`val kind : ('a, 'b, 'c) t -> ('a, 'b) Bigarray.kind`

Return the kind of the given `Bigarray`.

`val layout : ('a, 'b, 'c) t -> 'c Bigarraylayout`

Return the layout of the given `Bigarray`.

`val change_layout : ('a, 'b, 'c) t ->
    'd Bigarraylayout -> ('a, 'b, 'd) t`

`Array3.change_layout a layout` returns a `Bigarray` with the specified `layout`, sharing the data with `a` (and hence having the same dimensions as `a`). No copying of elements is involved: the new array and the original array share the same storage space. The dimensions are reversed, such that `get v [| a; b; c |]` in C layout becomes `get v [| c+1; b+1; a+1 |]` in Fortran layout.

**Since:** 4.06

`val size_in_bytes : ('a, 'b, 'c) t -> int`
* Concatenating its elements using `sep` as a separator returns a byte sequence equal to the input (Bytes.concat (Bytes.make 1 sep) (Bytes.split_on_char sep s) = s).

* No byte sequence in the result contains the `sep` character.

**Since:** 4.13

## Iterators

`val to_seq : t -> char Seq.t`

Iterate on the string, in increasing index order. Modifications of the string during iteration will be reflected in the sequence.

**Since:** 4.07

`val to_seqi : t -> (int * char) Seq.t`

Iterate on the string, in increasing order, yielding indices along chars

**Since:** 4.07

`val of_seq : char Seq.t -> t`

Create a string from the generator

**Since:** 4.07

## UTF codecs and validations

### UTF-8

`val get_utf_8_uchar : t -> int -> Uchar.utf_decode`

`get_utf_8_uchar b i` decodes an UTF-8 character at index `i` in `b`.

`val set_utf_8_uchar : t -> int -> Uchar.t -> int`

`set_utf_8_uchar b i u` UTF-8 encodes `u` at index `i` in `b` and returns the number of bytes `n` that were written starting at `i`. If `n` is 0 there was not enough space to encode `u` at `i` and `b` was left untouched. Otherwise a new character can be encoded at `i + n`.

`val is_valid_utf_8 : t -> bool`

`is_valid_utf_8 b` is true if and only if `b` contains valid UTF-8 data.

### UTF-16BE

`val get_utf_16be_uchar : t -> int -> Uchar.utf_decode`

`get_utf_16be_uchar b i` decodes an UTF-16BE character at index `i` in `b`.

`val set_utf_16be_uchar : t -> int -> Uchar.t -> int`
`size_in_bytes` a is the number of elements in a multiplied by a's
`Bigarray.kind_size_in_bytes`[29.5].

Since: 4.03

`val get: ('a, 'b, 'c) t -> int -> int -> int -> 'a`

`Array3.get` a x y z, also written `a.{x,y,z}`, returns the element of a at coordinates (x, y, z). x, y and z must be within the bounds of a, as described for `Bigarray.Genarray.get`[29.5]; otherwise, `Invalid_argument` is raised.

`val set: ('a, 'b, 'c) t -> int -> int -> int -> 'a -> unit`

`Array3.set` a x y v, or alternatively `a.{x,y,z} <- v`, stores the value v at coordinates (x, y, z) in a. x, y and z must be within the bounds of a, as described for `Bigarray.Genarray.set`[29.5]; otherwise, `Invalid_argument` is raised.

`val sub_left: ('a, 'b, Bigarray.c_layout) t -> int -> int -> ('a, 'b, Bigarray.c_layout) t`

Extract a three-dimensional sub-array of the given three-dimensional Bigarray by
restricting the first dimension. See `Bigarray.Genarray.sub_left`[29.5] for more details.
`Array3.sub_left` applies only to arrays with C layout.

`val sub_right: ('a, 'b, Bigarray.fortran_layout) t -> int -> int -> ('a, 'b, Bigarray.fortran_layout) t`

Extract a three-dimensional sub-array of the given three-dimensional Bigarray by
restricting the second dimension. See `Bigarray.Genarray.sub_right`[29.5] for more
details. `Array3.sub_right` applies only to arrays with Fortran layout.

`val slice_left_1: ('a, 'b, Bigarray.c_layout) t -> int -> int -> ('a, 'b, Bigarray.c_layout) Bigarray Array1.t`

Extract a one-dimensional slice of the given three-dimensional Bigarray by fixing the
first two coordinates. The integer parameters are the coordinates of the slice to extract.
See `Bigarray.Genarray.slice_left`[29.5] for more details. `Array3.slice_left_1`
applies only to arrays with C layout.

`val slice_right_1: ('a, 'b, Bigarray.fortran_layout) t -> int -> int -> ('a, 'b, Bigarray.fortran_layout) Bigarray Array1.t`

Extract a one-dimensional slice of the given three-dimensional Bigarray by fixing the last
two coordinates. The integer parameters are the coordinates of the slice to extract. See
`Bigarray.Genarray.slice_right`[29.5] for more details. `Array3.slice_right_1`
applies only to arrays with Fortran layout.
`set_utf_16be_uchar b i u` UTF-16BE encodes `u` at index `i` in `b` and returns the number of bytes `n` that were written starting at `i`. If `n` is 0 there was not enough space to encode `u` at `i` and `b` was left untouched. Otherwise a new character can be encoded at `i + n`.

`val is_valid_utf_16be : t -> bool`

`is_valid_utf_16be b` is `true` if and only if `b` contains valid UTF-16BE data.

## UTF-16LE

`val get_utf_16le_uchar : t -> int -> Uchar.utf_decode`

`get_utf_16le_uchar b i` decodes an UTF-16LE character at index `i` in `b`.

`val set_utf_16le_uchar : t -> int -> Uchar.t -> int`

`set_utf_16le_uchar b i u` UTF-16LE encodes `u` at index `i` in `b` and returns the number of bytes `n` that were written starting at `i`. If `n` is 0 there was not enough space to encode `u` at `i` and `b` was left untouched. Otherwise a new character can be encoded at `i + n`.

`val is_valid_utf_16le : t -> bool`

`is_valid_utf_16le b` is `true` if and only if `b` contains valid UTF-16LE data.

## Binary encoding/decoding of integers

The functions in this section binary encode and decode integers to and from byte sequences.

All following functions raise `Invalid_argument` if the space needed at index `i` to decode or encode the integer is not available.

Little-endian (resp. big-endian) encoding means that least (resp. most) significant bytes are stored first. Big-endian is also known as network byte order. Native-endian encoding is either little-endian or big-endian depending on `Sys.big_endian` [28.55].

32-bit and 64-bit integers are represented by the `int32` and `int64` types, which can be interpreted either as signed or unsigned numbers.

8-bit and 16-bit integers are represented by the `int` type, which has more bits than the binary encoding. These extra bits are handled as follows:

* Functions that decode signed (resp. unsigned) 8-bit or 16-bit integers represented by `int` values sign-extend (resp. zero-extend) their result.

* Functions that encode 8-bit or 16-bit integers represented by `int` values truncate their input to their least significant bytes.

`val get_uint8 : bytes -> int -> int`

`get_uint8 b i` is `b`'s unsigned 8-bit integer starting at byte index `i`.

Since: 4.08

`val get_int8 : bytes -> int -> int`
```h
val slice_left_2 :
    ('a, 'b, Bigarray.c_layout) t ->
    int -> ('a, 'b, Bigarray.c_layout) Bigarray Array2.t
```

Extract a two-dimensional slice of the given three-dimensional Bigarray by fixing the first coordinate. The integer parameter is the first coordinate of the slice to extract. See `Bigarray.Genarray.slice_left[29.5]` for more details. `Array3.slice_left_2` applies only to arrays with C layout.

```h
val slice_right_2 :
    ('a, 'b, Bigarray.fortran_layout) t ->
    int -> ('a, 'b, Bigarray.fortran_layout) Bigarray Array2.t
```

Extract a two-dimensional slice of the given three-dimensional Bigarray by fixing the last coordinate. The integer parameter is the coordinate of the slice to extract. See `Bigarray.Genarray.slice_right[29.5]` for more details. `Array3.slice_right_2` applies only to arrays with Fortran layout.

```h
val blit : ('a, 'b, 'c) t -> ('a, 'b, 'c) t -> unit
```

Copy the first Bigarray to the second Bigarray. See `Bigarray.Genarray.blit[29.5]` for more details.

```h
val fill : ('a, 'b, 'c) t -> 'a -> unit
```

Fill the given Bigarray with the given value. See `Bigarray.Genarray.fill[29.5]` for more details.

```h
val of_array :
    ('a, 'b) Bigarray.kind ->
    'c Bigarraylayout -> 'a array array array -> ('a, 'b, 'c) t
```

Build a three-dimensional Bigarray initialized from the given array of arrays of arrays.

```h
val unsafe_get : ('a, 'b, 'c) t -> int -> int -> int -> 'a
```

Like `Bigarray.array3.get[29.5]`, but bounds checking is not always performed.

```h
val unsafe_set : ('a, 'b, 'c) t -> int -> int -> int -> 'a -> unit
```

Like `Bigarray.array3.set[29.5]`, but bounds checking is not always performed.

end

Three-dimensional arrays. The `Array3` structure provides operations similar to those of `Bigarray.Genarray[29.5]`, but specialized to the case of three-dimensional arrays.
get_int8 b i is b's signed 8-bit integer starting at byte index i.

Since: 4.08

val get_uint16_ne : bytes -> int -> int

get_uint16_ne b i is b's native-endian unsigned 16-bit integer starting at byte index i.

Since: 4.08

val get_uint16_be : bytes -> int -> int

get_uint16_be b i is b's big-endian unsigned 16-bit integer starting at byte index i.

Since: 4.08

val get_uint16_le : bytes -> int -> int

get_uint16_le b i is b's little-endian unsigned 16-bit integer starting at byte index i.

Since: 4.08

val get_int16_ne : bytes -> int -> int

get_int16_ne b i is b's native-endian signed 16-bit integer starting at byte index i.

Since: 4.08

val get_int16_be : bytes -> int -> int

get_int16_be b i is b's big-endian signed 16-bit integer starting at byte index i.

Since: 4.08

val get_int16_le : bytes -> int -> int

get_int16_le b i is b's little-endian signed 16-bit integer starting at byte index i.

Since: 4.08

val get_int32_ne : bytes -> int -> int32

get_int32_ne b i is b's native-endian 32-bit integer starting at byte index i.

Since: 4.08

val get_int32_be : bytes -> int -> int32

get_int32_be b i is b's big-endian 32-bit integer starting at byte index i.

Since: 4.08

val get_int32_le : bytes -> int -> int32

get_int32_le b i is b's little-endian 32-bit integer starting at byte index i.

Since: 4.08

val get_int64_ne : bytes -> int -> int64
## Coercions between generic Bigarrays and fixed-dimension Bigarrays

val genarray_of_array0: ('a, 'b, 'c) Array0.t -> ('a, 'b, 'c) Genarray.t
Return the generic Bigarray corresponding to the given zero-dimensional Bigarray.

Since: 4.05

val genarray_of_array1: ('a, 'b, 'c) Array1.t -> ('a, 'b, 'c) Genarray.t
Return the generic Bigarray corresponding to the given one-dimensional Bigarray.

val genarray_of_array2: ('a, 'b, 'c) Array2.t -> ('a, 'b, 'c) Genarray.t
Return the generic Bigarray corresponding to the given two-dimensional Bigarray.

val genarray_of_array3: ('a, 'b, 'c) Array3.t -> ('a, 'b, 'c) Genarray.t
Return the generic Bigarray corresponding to the given three-dimensional Bigarray.

val array0_of_genarray: ('a, 'b, 'c) Genarray.t -> ('a, 'b, 'c) Array0.t
Return the zero-dimensional Bigarray corresponding to the given generic Bigarray.

Since: 4.05

Raises Invalid_argument if the generic Bigarray does not have exactly zero dimension.

val array1_of_genarray: ('a, 'b, 'c) Genarray.t -> ('a, 'b, 'c) Array1.t
Return the one-dimensional Bigarray corresponding to the given generic Bigarray.

Raises Invalid_argument if the generic Bigarray does not have exactly one dimension.

val array2_of_genarray: ('a, 'b, 'c) Genarray.t -> ('a, 'b, 'c) Array2.t
Return the two-dimensional Bigarray corresponding to the given generic Bigarray.

Raises Invalid_argument if the generic Bigarray does not have exactly two dimensions.

val array3_of_genarray: ('a, 'b, 'c) Genarray.t -> ('a, 'b, 'c) Array3.t
Return the three-dimensional Bigarray corresponding to the given generic Bigarray.

Raises Invalid_argument if the generic Bigarray does not have exactly three dimensions.

## Re-shaping Bigarrays

val reshape:

('a, 'b, 'c) Genarray.t ->

int array -> ('a, 'b, 'c) Genarray.t

reshape b [[d1;...;dN]] converts the Bigarray b to a N-dimensional array of dimensions d1...dN. The returned array and the original array b share their data and have the same layout. For instance, assuming that b is a one-dimensional array of dimension 12, reshape b [[3;4]] returns a two-dimensional array b' of dimensions 3 and 4. If b has C layout, the element (x,y) of b' corresponds to the element x * 3 + y of b. If b has Fortran layout, the
`get_int64_ne` b i is b's native-endian 64-bit integer starting at byte index i.

Since: 4.08

`val get_int64_be`: `bytes -> int -> int64`

`get_int64_be` b i is b's big-endian 64-bit integer starting at byte index i.

Since: 4.08

`val get_int64_le`: `bytes -> int -> int64`

`get_int64_le` b i is b's little-endian 64-bit integer starting at byte index i.

Since: 4.08

`val set_uint8`: `bytes -> int -> int -> unit`

`set_uint8` b i v sets b's unsigned 8-bit integer starting at byte index i to v.

Since: 4.08

`val set_int8`: `bytes -> int -> int -> unit`

`set_int8` b i v sets b's signed 8-bit integer starting at byte index i to v.

Since: 4.08

`val set_uint16_ne`: `bytes -> int -> int -> unit`

`set_uint16_ne` b i v sets b's native-endian unsigned 16-bit integer starting at byte index i to v.

Since: 4.08

`val set_uint16_be`: `bytes -> int -> int -> unit`

`set_uint16_be` b i v sets b's big-endian unsigned 16-bit integer starting at byte index i to v.

Since: 4.08

`val set_uint16_le`: `bytes -> int -> int -> unit`

`set_uint16_le` b i v sets b's little-endian unsigned 16-bit integer starting at byte index i to v.

Since: 4.08

`val set_int16_ne`: `bytes -> int -> int -> unit`

`set_int16_ne` b i v sets b's native-endian signed 16-bit integer starting at byte index i to v.

Since: 4.08

`val set_int16_be`: `bytes -> int -> int -> unit`

`set_int16_be` b i v sets b's big-endian signed 16-bit integer starting at byte index i to v.

Since: 4.08
element (x,y) of b' corresponds to the element x + (y - 1) * 4 of b. The returned
Bigarray must have exactly the same number of elements as the original Bigarray b. That is,
the product of the dimensions of b must be equal to i1 * ... * iN. Otherwise,
Invalid_argument is raised.

val reshape_0 : ('a, 'b, 'c) Genarray.t -> ('a, 'b, 'c) Array0.t

Specialized version of Bigarray reshape[29.5] for reshaping to zero-dimensional arrays.

Since: 4.05

val reshape_1 : ('a, 'b, 'c) Genarray.t -> int -> ('a, 'b, 'c) Array1.t

Specialized version of Bigarray. reshape[29.5] for reshaping to one-dimensional arrays.

val reshape_2 :
('a, 'b, 'c) Genarray.t ->
int -> int -> ('a, 'b, 'c) Array2.t

Specialized version of Bigarray. reshape[29.5] for reshaping to two-dimensional arrays.

val reshape_3 :
('a, 'b, 'c) Genarray.t ->
int -> int -> int -> ('a, 'b, 'c) Array3.t

Specialized version of Bigarray. reshape[29.5] for reshaping to three-dimensional arrays.

Bigarrays and concurrency safety

Care must be taken when concurrently accessing bigarrays from multiple domains: accessing a bigarray will never crash a program, but unsynchronized accesses might yield surprising (non-sequentially-consistent) results.

Atomicity

Every bigarray operation that accesses more than one array element is not atomic. This includes
slicing, bliting, and filling bigarrays.

For example, consider the following program:

open Bigarray
let size = 100_000_000
let a = Array1.init Int C_layout size (fun _ -> 1)
let update f a () =
  for i = 0 to size - 1 do a.{i} <- f a.{i} done
let d1 = Domain spawn (update (fun x -> x + 1) a)
let d2 = Domain spawn (update (fun x -> 2 * x + 1) a)
let () = Domain.join d1; Domain.join d2

After executing this code, each field of the bigarray a is either 2, 3, 4 or 5. If atomicity is required, then the user must implement their own synchronization (for example, using Mutex.t[29.38]).
val set_int16_le : bytes -> int -> int -> unit
  set_int16_le b i v sets b's little-endian signed 16-bit integer starting at byte index i to v.
  Since: 4.08

val set_int32_ne : bytes -> int -> int32 -> unit
  set_int32_ne b i v sets b's native-endian 32-bit integer starting at byte index i to v.
  Since: 4.08

val set_int32_be : bytes -> int -> int32 -> unit
  set_int32_be b i v sets b's big-endian 32-bit integer starting at byte index i to v.
  Since: 4.08

val set_int32_le : bytes -> int -> int32 -> unit
  set_int32_le b i v sets b's little-endian 32-bit integer starting at byte index i to v.
  Since: 4.08

val set_int64_ne : bytes -> int -> int64 -> unit
  set_int64_ne b i v sets b's native-endian 64-bit integer starting at byte index i to v.
  Since: 4.08

val set_int64_be : bytes -> int -> int64 -> unit
  set_int64_be b i v sets b's big-endian 64-bit integer starting at byte index i to v.
  Since: 4.08

val set_int64_le : bytes -> int -> int64 -> unit
  set_int64_le b i v sets b's little-endian 64-bit integer starting at byte index i to v.
  Since: 4.08

## Byte sequences and concurrency safety

Care must be taken when concurrently accessing byte sequences from multiple domains: accessing a byte sequence will never crash a program, but unsynchronized accesses might yield surprising (non-sequentially-consistent) results.

## Atomicity

Every byte sequence operation that accesses more than one byte is not atomic. This includes iteration and scanning.

For example, consider the following program:

```python
let size = 100_000_000
let b = Bytes.make size ' '
let update b f () =
```
## Data races

If two domains only access disjoint parts of the bigarray, then the observed behaviour is the equivalent to some sequential interleaving of the operations from the two domains.

A data race is said to occur when two domains access the same bigarray element without synchronization and at least one of the accesses is a write. In the absence of data races, the observed behaviour is equivalent to some sequential interleaving of the operations from different domains.

Whenever possible, data races should be avoided by using synchronization to mediate the accesses to the bigarray elements.

Indeed, in the presence of data races, programs will not crash but the observed behaviour may not be equivalent to any sequential interleaving of operations from different domains.

## Tearing

Bigarrays have a distinct caveat in the presence of data races: concurrent bigarray operations might produce surprising values due to tearing. More precisely, the interleaving of partial writes and reads might create values that would not exist with a sequential execution. For instance, at the end of

```pascal
let res = Array1.init Complex64 c_layout size (fun _ -> Complex.zero)
let d1 = Domain spawn (fun () -> Array1.fill res Complex.one)
let d2 = Domain spawn (fun () -> Array1.fill res Complex.i)
let () = Domain.join d1; Domain.join d2
```

the `res` bigarray might contain values that are neither `Complex.i` nor `Complex.one` (for instance $1 + i$).

## 29.6 Module Bool : Boolean values.

Since: 4.08

### Booleans

```pascal
type t = bool =
  | false
  | true
```

The type of booleans (truth values).

The constructors `false` and `true` are included here so that they have paths, but they are not intended to be used in user-defined data types.

```pascal
val not : bool -> bool

not b is the boolean negation of b.
```

```pascal
val (&&) : bool -> bool -> bool

e0 && e1 is the lazy boolean conjunction of expressions e0 and e1. If e0 evaluates to false, e1 is not evaluated. Right-associative operator at precedence level 3/11.
```
```clojure
Bytes.iteri (fun i x -> Bytes.set b i (Char.chr (f (Char.code x)))) b
let d1 = Domain spawn (update b (fun x -> x + 1))
let d2 = Domain spawn (update b (fun x -> 2 * x + 1))
let () = Domain.join d1; Domain.join d2
```

the bytes sequence `b` may contain a non-deterministic mixture of `!`, `'A'`, `'B'`, and `'C'` values.

After executing this code, each byte of the sequence `b` is either `'!'`, `'A'`, `'B'`, or `'C'`. If atomicity is required, then the user must implement their own synchronization (for example, using `Mutex.t[28.36]`).

## Data races

If two domains only access disjoint parts of a byte sequence, then the observed behaviour is the equivalent to some sequential interleaving of the operations from the two domains.

A data race is said to occur when two domains access the same byte without synchronization and at least one of the accesses is a write. In the absence of data races, the observed behaviour is equivalent to some sequential interleaving of the operations from different domains.

Whenever possible, data races should be avoided by using synchronization to mediate the accesses to the elements of the sequence.

Indeed, in the presence of data races, programs will not crash but the observed behaviour may not be equivalent to any sequential interleaving of operations from different domains. Nevertheless, even in the presence of data races, a read operation will return the value of some prior write to that location.

## Mixed-size accesses

Another subtle point is that if a data race involves mixed-size writes and reads to the same location, the order in which those writes and reads are observed by domains is not specified. For instance, the following code write sequentially a 32-bit integer and a `char` to the same index

```clojure
let b = Bytes.make 10 '\000'
let d1 = Domain spawn (fun () -> Bytes.set_int32_ne b 0 100; b.[0] <- 'd')
```

In this situation, a domain that observes the write of 'd' to `b.0` is not guaranteed to also observe the write to indices 1, 2, or 3.

## 28.10 Module Callback : Registering OCaml values with the C runtime.

This module allows OCaml values to be registered with the C runtime under a symbolic name, so that C code can later call back registered OCaml functions, or raise registered OCaml exceptions.

```hml
val register : string -> 'a -> unit
```
val (||) : bool -> bool -> bool

e0 || e1 is the lazy boolean disjunction of expressions e0 and e1. If e0 evaluates to true, e1 is not evaluated. Right-associative operator at precedence level 2/11.

val logand : bool -> bool -> bool

logand b1 b2 is true if and only if b1 and b2 are both true.

val logor : bool -> bool -> bool

logor b1 b2 is true if and only if either b1 or b2 is true.

val logxor : bool -> bool -> bool

logxor b1 b2 is true if exactly one of b1 and b2 is true.

## Predicates and comparisons

val equal : bool -> bool -> bool

equal b0 b1 is true if and only if b0 and b1 are both true or both false.

val compare : bool -> bool -> int

compare b0 b1 is a total order on boolean values. false is smaller than true.

## Converting

val to_int : bool -> int

to_int b is 0 if b is false and 1 if b is true.

val to_float : bool -> float

to_float b is 0. if b is false and 1. if b is true.

val to_string : bool -> string

to_string b is "true" if b is true and "false" if b is false.

val seeded_hash : int -> bool -> int

A seeded hash function for booleans, with the same output value as `Hashtbl.seeded_hash[29.26]`. This function allows this module to be passed as argument to the functor `Hashtbl.MakeSeeded[29.26]`.

Since: 5.1

val hash : bool -> int

An unseeded hash function for booleans, with the same output value as `Hashtbl.hash[29.26]`. This function allows this module to be passed as argument to the functor `Hashtbl.Make[29.26]`.

Since: 5.1
`Callback.register` n v registers the value v under the name n. C code can later retrieve a handle to v by calling `caml_named_value(n)`.

`val register_exception : string -> exn -> unit`

`Callback.register_exception` n exn registers the exception contained in the exception value exn under the name n. C code can later retrieve a handle to the exception by calling `caml_named_value(n)`. The exception value thus obtained is suitable for passing as first argument to `raiseConstant` or `raise_with_arg`.

## 28.11 Module Char : Character operations.

`val code : char -> int`

Return the ASCII code of the argument.

`val chr : int -> char`

Return the character with the given ASCII code.

**Raises** `Invalid_argument` if the argument is outside the range 0–255.

`val escaped : char -> string`

Return a string representing the given character, with special characters escaped following the lexical conventions of OCaml. All characters outside the ASCII printable range (32..126) are escaped, as well as backslash, double-quote, and single-quote.

`val lowercase artii : char -> char`

Convert the given character to its equivalent lowercase character, using the US-ASCII character set.

**Since:** 4.03

`val uppercase artii : char -> char`

Convert the given character to its equivalent uppercase character, using the US-ASCII character set.

**Since:** 4.03

`type t = char`

An alias for the type of characters.

`val compare : t -> t -> int`

The comparison function for characters, with the same specification as `compare` [27.2]. Along with the type t, this function `compare` allows the module `Char` to be passed as argument to the functors `Set.Make` [28.49] and `Map.Make` [28.33].

`val equal : t -> t -> bool`
## 29.7 Module Buffer : Extensible buffers.

This module implements buffers that automatically expand as necessary. It provides accumulative concatenation of strings in linear time (instead of quadratic time when strings are concatenated pairwise). For example:

```python
let concat Offers ss =
    let b = Buffer.create 16 in
    List.iter (Buffer.add_string b) ss;
    Buffer contents b
```

**Alert unsynchronized_access.** Unsynchronized accesses to buffers are a programming error.

### Unsynchronized accesses

Unsynchronized accesses to a buffer may lead to an invalid buffer state. Thus, concurrent accesses to a buffer must be synchronized (for instance with a `Mutex.t[29.38]`).

### type t

The abstract type of buffers.

#### val create : int -> t

`create` n returns a fresh buffer, initially empty. The n parameter is the initial size of the internal byte sequence that holds the buffer contents. That byte sequence is automatically reallocated when more than n characters are stored in the buffer, but shrinks back to n characters when `reset` is called. For best performance, n should be of the same order of magnitude as the number of characters that are expected to be stored in the buffer (for instance, 80 for a buffer that holds one output line). Nothing bad will happen if the buffer grows beyond that limit, however. In doubt, take n = 16 for instance. If n is not between 1 and Sys.max_string_length[29.60], it will be clipped to that interval.

#### val contents : t -> string

Return a copy of the current contents of the buffer. The buffer itself is unchanged.

#### val to_bytes : t -> bytes

Return a copy of the current contents of the buffer. The buffer itself is unchanged.

**Since: 4.02**

#### val sub : t -> int -> int -> string

`Buffer.sub b off len` returns a copy of `len` bytes from the current contents of the buffer b, starting at offset `off`.

**Raises** Invalid_argument if `off` and `len` do not designate a valid range of b.

#### val blit : t -> int -> bytes -> int -> int -> unit
The equal function for chars.

**Since: 4.03**

```rust
val seeded_hash: int -> t -> int
```

A seeded hash function for characters, with the same output value as `Hashtbl.seeded_hash[28.24]`. This function allows this module to be passed as argument to the functor `Hashtbl.MakeSeeded[28.24]`.

**Since: 5.1**

```rust
val hash: t -> int
```

An unseeded hash function for characters, with the same output value as `Hashtbl.hash[28.24]`. This function allows this module to be passed as argument to the functor `Hashtbl.Make[28.24]`.

**Since: 5.1**

## 28.12 Module Complex : Complex numbers.

This module provides arithmetic operations on complex numbers. Complex numbers are represented by their real and imaginary parts (cartesian representation). Each part is represented by a double-precision floating-point number (type `float`).

```rust
type t =
{
    re : float;
    im : float;
}
```

The type of complex numbers. `re` is the real part and `im` the imaginary part.

```rust
val zero : t
```

The complex number 0.

```rust
val one : t
```

The complex number 1.

```rust
val i : t
```

The complex number i.

```rust
val neg : t -> t
```

Unary negation.

```rust
val conj : t -> t
```

Conjugate: given the complex $x + i.y$, returns $x - i.y$.

```rust
val add : t -> t -> t
```
Buffer.blit src srcoff dst dstoff len copies len characters from the current contents
of the buffer src, starting at offset srcoff to dst, starting at character dstoff.

Since: 3.11.2

Raises Invalid_argument if srcoff and len do not designate a valid range of src, or if dstoff and len do not designate a valid range of dst.

val nth : t -> int -> char

Get the n-th character of the buffer.

Raises Invalid_argument if index out of bounds

val length : t -> int

Return the number of characters currently contained in the buffer.

val clear : t -> unit

Empty the buffer.

val reset : t -> unit

Empty the buffer and deallocate the internal byte sequence holding the buffer contents,
replacing it with the initial internal byte sequence of length n that was allocated by
Buffer.create[29.7] n. For long-lived buffers that may have grown a lot, reset allows faster
reclamation of the space used by the buffer.

val output_buffer : out_channel -> t -> unit

output_buffer oc b writes the current contents of buffer b on the output channel oc.

val truncate : t -> int -> unit

truncate b len truncates the length of b to len Note: the internal byte sequence is not
shortened.

Since: 4.05

Raises Invalid_argument if len < 0 or len > length b.

Appending

Note: all add_* operations can raise Failure if the internal byte sequence of the buffer would need
to grow beyond Sys.max_string_length[29.60].

val add_char : t -> char -> unit

add_char b c appends the character c at the end of buffer b.

val add_utf_8_uchar : t -> Uchar.t -> unit

add_utf_8_uchar b u appends the UTF-8[https://tools.ietf.org/html/rfc3629]
encoding of u at the end of buffer b.

Since: 4.06
Addition

`val sub : t -> t -> t`

Subtraction

`val mul : t -> t -> t`

Multiplication

`val inv : t -> t`

Multiplicative inverse (1/z).

`val div : t -> t -> t`

Division

`val sqrt : t -> t`

Square root. The result $x + i.y$ is such that $x > 0$ or $x = 0$ and $y >= 0$. This function has a discontinuity along the negative real axis.

`val norm2 : t -> float`

Norm squared: given $x + i.y$, returns $x^2 + y^2$.

`val norm : t -> float`

Norm: given $x + i.y$, returns $\sqrt{x^2 + y^2}$.

`val arg : t -> float`

Argument. The argument of a complex number is the angle in the complex plane between the positive real axis and a line passing through zero and the number. This angle ranges from $-\pi$ to $\pi$. This function has a discontinuity along the negative real axis.

`val polar : float -> float -> t`

`polar norm arg` returns the complex having norm `norm` and argument `arg`.

`val exp : t -> t`

Exponentiation. `exp z` returns $e$ to the $z$ power.

`val log : t -> t`

Natural logarithm (in base $e$).

`val pow : t -> t -> t`

Power function. `pow z1 z2` returns $z1$ to the $z2$ power.
val add_utf_16le_uchar : t -> Uchar.t -> unit
add_utf_16le_uchar b u appends the
UTF-16LE[https://tools.ietf.org/html/rfc2781] encoding of u at the end of buffer b.
Since: 4.06

val add_utf_16be_uchar : t -> Uchar.t -> unit
add_utf_16be_uchar b u appends the
UTF-16BE[https://tools.ietf.org/html/rfc2781] encoding of u at the end of buffer b.
Since: 4.06

val add_string : t -> string -> unit
add_string b s appends the string s at the end of buffer b.

val add_bytes : t -> bytes -> unit
add_bytes b s appends the byte sequence s at the end of buffer b.
Since: 4.02

val add_substring : t -> string -> int -> int -> unit
add_substring b s ofs len takes len characters from offset ofs in string s and appends them at the end of buffer b.
Raises Invalid_argument if ofs and len do not designate a valid range of s.

val add_subbytes : t -> bytes -> int -> int -> unit
add_subbytes b s ofs len takes len characters from offset ofs in byte sequence s and appends them at the end of buffer b.
Since: 4.02

Raises Invalid_argument if ofs and len do not designate a valid range of s.

val add_substitute : t -> (string -> string) -> string -> unit
add_substitute b f s appends the string pattern s at the end of buffer b with substitution.
The substitution process looks for variable references in the pattern and substitutes each
variable reference with its value, as obtained by applying the mapping f to the variable name.
Inside the string pattern, a variable reference is a non-escaped $ immediately followed by a
variable name, which is one of the following:

* a non empty sequence of alphanumeric or _ characters,

* an arbitrary sequence of characters enclosed by a pair of matching parentheses or curly brackets. An escaped `$` character is a `$` that immediately follows a backslash character; the two characters together stand for a plain `$`.

val add_buffer : t -> t -> unit
add_buffer b1 b2 appends the current contents of buffer b2 at the end of buffer b1. b2 is not modified.
## 28.13 Module Condition : Condition variables.

Condition variables are useful when several threads wish to access a shared data structure that is protected by a mutex (a mutual exclusion lock).

A condition variable is a communication channel. On the receiver side, one or more threads can indicate that they wish to wait for a certain property to become true. On the sender side, a thread can signal that this property has become true, causing one (or more) waiting threads to be woken up.

For instance, in the implementation of a queue data structure, if a thread that wishes to extract an element finds that the queue is currently empty, then this thread waits for the queue to become nonempty. A thread that inserts an element into the queue signals that the queue has become nonempty. A condition variable is used for this purpose. This communication channel conveys the information that the property "the queue is nonempty" is true, or more accurately, may be true. (We explain below why the receiver of a signal cannot be certain that the property holds.)

To continue the example of the queue, assuming that the queue has a fixed maximum capacity, then a thread that wishes to insert an element may find that the queue is full. Then, this thread must wait for the queue to become not full, and a thread that extracts an element of the queue signals that the queue has become not full. Another condition variable is used for this purpose.

In short, a condition variable `c` is used to convey the information that a certain property `P` about a shared data structure `D`, protected by a mutex `m`, may be true.

Condition variables provide an efficient alternative to busy-waiting. When one wishes to wait for the property `P` to be true, instead of writing a busy-waiting loop:

```python
Mutex.lock m;
while not P do
    Mutex unlock m; Mutex.lock m
done;
<update the data structure>;
Mutex unlock m
```

one uses `Condition.wait` [28.13] in the body of the loop, as follows:

```python
Mutex.lock m;
while not P do
    Condition.wait c m
done;
<update the data structure>;
Mutex unlock m
```

The busy-waiting loop is inefficient because the waiting thread consumes processing time and creates contention of the mutex `m`. Calling `Condition.wait` [28.13] allows the waiting thread to be suspended, so it does not consume any computing resources while waiting.

With a condition variable `c`, exactly one mutex `m` is associated. This association is implicit: the mutex `m` is not explicitly passed as an argument to `Condition.create` [28.13]. It is up to the programmer to know, for each condition variable `c`, which is the associated mutex `m`.
val add_channel : t -> in_channel -> int -> unit

add_channel b ic n reads at most n characters from the input channel ic and stores them
at the end of buffer b.

Raises

* End_of_file if the channel contains fewer than n characters. In this case, the characters are still added to the buffer, so as to avoid loss of data.

* Invalid_argument if len < 0 or len > Sys.max_string_length.

Buffers and Sequences

val to_seq : t -> char Seq.t

Iterate on the buffer, in increasing order.

The behavior is not specified if the buffer is modified during iteration.

Since: 4.07

val to_seqi : t -> (int * char) Seq.t

Iterate on the buffer, in increasing order, yielding indices along chars.

The behavior is not specified if the buffer is modified during iteration.

Since: 4.07

val add_seq : t -> char Seq.t -> unit

Add chars to the buffer

Since: 4.07

val of_seq : char Seq.t -> t

Create a buffer from the generator

Since: 4.07

Binary encoding of integers

The functions in this section append binary encodings of integers to buffers.

Little-endian (resp. big-endian) encoding means that least (resp. most) significant bytes are
stored first. Big-endian is also known as network byte order. Native-endian encoding is either
little-endian or big-endian depending on Sys.big_endian[29.60].

32-bit and 64-bit integers are represented by the `int32` and `int64` types, which can be interpreted either as signed or unsigned numbers.

8-bit and 16-bit integers are represented by the `int` type, which has more bits than the binary encoding. Functions that encode these values truncate their inputs to their least significant bytes.

val add_uint8 : t -> int -> unit
With a mutex `m`, several condition variables can be associated. In the example of the bounded queue, one condition variable is used to indicate that the queue is nonempty, and another condition variable is used to indicate that the queue is not full.

With a condition variable `c`, exactly one logical property `P` should be associated. Examples of such properties include "the queue is nonempty" and "the queue is not full". It is up to the programmer to keep track, for each condition variable, of the corresponding property `P`. A signal is sent on the condition variable `c` as an indication that the property `P` is true, or may be true. On the receiving end, however, a thread that is woken up cannot assume that `P` is true; after a call to `Condition.wait` [28.13] terminates, one must explicitly test whether `P` is true. There are several reasons why this is so. One reason is that, between the moment when the signal is sent and the moment when a waiting thread receives the signal and is scheduled, the property `P` may be falsified by some other thread that is able to acquire the mutex `m` and alter the data structure `D`. Another reason is that spurious wakeups may occur: a waiting thread can be woken up even if no signal was sent.

Here is a complete example, where a mutex protects a sequential unbounded queue, and where a condition variable is used to signal that the queue is nonempty.

```pascal
type 'a safe_queue =
    { queue : 'a Queue.t; mutex : Mutex.t; nonempty : Condition.t }

let create () =
    { queue = Queue.create(); mutex = Mutex.create();
        nonempty = Condition.create() }

let add v q =
    Mutex.lock q.mutex;
    let was_empty = Queue.is_empty q.queue in
    Queue.add v q.queue;
    if was_empty then Condition broadcasts q.nonempty;
    Mutex unlock q.mutex

let take q =
    Mutex.lock q.mutex;
    while Queue.is_empty q.queue do Condition.wait q.nonempty q.mutex done;
    let v = Queue.take q.queue in (* cannot fail since queue is nonempty *)
    Mutex unlock q.mutex;
    v
```

Because the call to `Condition broadcasts` [28.13] takes place inside the critical section, the following property holds whenever the mutex is unlocked: *if the queue is nonempty, then no thread is waiting*, or, in other words, *if some thread is waiting, then the queue must be empty*. This is a desirable property: if a thread that attempts to execute a `take` operation could remain suspended even though the queue is nonempty, that would be a problematic situation, known as a deadlock.

type t
`add_uint8 b i` appends a binary unsigned 8-bit integer `i` to `b`.

**Since:** 4.08

`val add_int8 : t -> int -> unit`

`add_int8 b i` appends a binary signed 8-bit integer `i` to `b`.

**Since:** 4.08

`val add_uint16_ne : t -> int -> unit`

`add_uint16_ne b i` appends a binary native-endian unsigned 16-bit integer `i` to `b`.

**Since:** 4.08

`val add_uint16_be : t -> int -> unit`

`add_uint16_be b i` appends a binary big-endian unsigned 16-bit integer `i` to `b`.

**Since:** 4.08

`val add_uint16_le : t -> int -> unit`

`add_uint16_le b i` appends a binary little-endian unsigned 16-bit integer `i` to `b`.

**Since:** 4.08

`val add_int16_ne : t -> int -> unit`

`add_int16_ne b i` appends a binary native-endian signed 16-bit integer `i` to `b`.

**Since:** 4.08

`val add_int16_be : t -> int -> unit`

`add_int16_be b i` appends a binary big-endian signed 16-bit integer `i` to `b`.

**Since:** 4.08

`val add_int16_le : t -> int -> unit`

`add_int16_le b i` appends a binary little-endian signed 16-bit integer `i` to `b`.

**Since:** 4.08

`val add_int32_ne : t -> int32 -> unit`

`add_int32_ne b i` appends a binary native-endian 32-bit integer `i` to `b`.

**Since:** 4.08

`val add_int32_be : t -> int32 -> unit`

`add_int32_be b i` appends a binary big-endian 32-bit integer `i` to `b`.

**Since:** 4.08

`val add_int32_le : t -> int32 -> unit`
The type of condition variables.

`val create : unit -> t`

`create()` creates and returns a new condition variable. This condition variable should be associated (in the programmer's mind) with a certain mutex `m` and with a certain property `P` of the data structure that is protected by the mutex `m`.

`val wait : t -> Mutex.t -> unit`

The call `wait c m` is permitted only if `m` is the mutex associated with the condition variable `c`, and only if `m` is currently locked. This call atomically unlocks the mutex `m` and suspends the current thread on the condition variable `c`. This thread can later be woken up after the condition variable `c` has been signaled via `Condition.signal[28.13]` or `Condition broadcasts[28.13]`; however, it can also be woken up for no reason. The mutex `m` is locked again before `wait` returns. One cannot assume that the property `P` associated with the condition variable `c` holds when `wait` returns; one must explicitly test whether `P` holds after calling `wait`.

`val signal : t -> unit`

`signal c` wakes up one of the threads waiting on the condition variable `c`, if there is one. If there is none, this call has no effect.

It is recommended to call `signal c` inside a critical section, that is, while the mutex `m` associated with `c` is locked.

`val broadcast : t -> unit`

`broadcast c` wakes up all threads waiting on the condition variable `c`. If there are none, this call has no effect.

It is recommended to call `broadcast c` inside a critical section, that is, while the mutex `m` associated with `c` is locked.

## 28.14 Module Domain

**Alert unstable.** The Domain interface may change in incompatible ways in the future.

### Domains

See 'Parallel programming' chapter in the manual.

`type !'a t`

A domain of type `'a t` runs independently, eventually producing a result of type `'a`, or an exception

`val spawn : (unit -> 'a) -> 'a t`

`spawn f` creates a new domain that runs in parallel with the current domain.

**Raises Failure** if the program has insufficient resources to create another domain.
`add_int32_le b i` appends a binary little-endian 32-bit integer `i` to `b`.

**Since:** 4.08

`val add_int64_ne : t -> int64 -> unit`

`add_int64_ne b i` appends a binary native-endian 64-bit integer `i` to `b`.

**Since:** 4.08

`val add_int64_be : t -> int64 -> unit`

`add_int64_be b i` appends a binary big-endian 64-bit integer `i` to `b`.

**Since:** 4.08

`val add_int64_le : t -> int64 -> unit`

`add_int64_ne b i` appends a binary little-endian 64-bit integer `i` to `b`.

**Since:** 4.08

## 29.8 Module Bytes: Byte sequence operations.

A byte sequence is a mutable data structure that contains a fixed-length sequence of bytes. Each byte can be indexed in constant time for reading or writing.

Given a byte sequence `s` of length `l`, we can access each of the `l` bytes of `s` via its index in the sequence. Indexes start at `0`, and we will call an index valid in `s` if it falls within the range `[0...1-1]` (inclusive). A position is the point between two bytes or at the beginning or end of the sequence. We call a position valid in `s` if it falls within the range `[0...1]` (inclusive). Note that the byte at index `n` is between positions `n` and `n+1`.

Two parameters `start` and `len` are said to designate a valid range of `s` if `len >= 0` and `start` and `start+len` are valid positions in `s`.

Byte sequences can be modified in place, for instance via the `set` and `blit` functions described below. See also strings (module `String` [29.58]), which are almost the same data structure, but cannot be modified in place.

Bytes are represented by the OCaml type `char`.

The labeled version of this module can be used as described in the `StdLabels` [29.57] module.

**Since:** 4.02

`val length : bytes -> int`

Return the length (number of bytes) of the argument.

`val get : bytes -> int -> char`

`get s n` returns the byte at index `n` in argument `s`.

**Raises** `Invalid_argument` if `n` is not a valid index in `s`.

`val set : bytes -> int -> char -> unit`
```rust
val join: 'a t -> 'a
```

join `d` blocks until domain `d` runs to completion. If `d` results in a value, then that is returned by `join d`. If `d` raises an uncaught exception, then that is re-raised by `join d`.

```rust
type id = private int
```

Domains have unique integer identifiers

```rust
val get_id: 'a t -> id
```

`get_id` `d` returns the identifier of the domain `d`

```rust
val self: unit -> id
```

`self()` is the identifier of the currently running domain

```rust
val before_first spawn: (unit -> unit) -> unit
```

`before_first spawn` `f` registers `f` to be called before the first domain is spawned by the program. The functions registered with `before_first spawn` are called on the main (initial) domain. The functions registered with `before_first spawn` are called in 'first in, first out' order: the oldest function added with `before_first spawn` is called first.

**Raises** `Invalid_argument` if the program has already spawned a domain.

```rust
val at_exit: (unit -> unit) -> unit
```

`at_exit` `f` registers `f` to be called when the current domain exits. Note that `at_exit` callbacks are domain-local and only apply to the calling domain. The registered functions are called in 'last in, first out' order: the function most recently added with `at_exit` is called first. An example:

```rust
let temp_file_key = Domain.DLS.new_key (fun _ ->
    let tmp = snd (Filename.open_temp_file "" "") in
    Domain.at_exit (fun () -> close_out_noerr tmp);
    tmp)
```

The snippet above creates a key that when retrieved for the first time will open a temporary file and register an `at_exit` callback to close it, thus guaranteeing the descriptor is not leaked in case the current domain exits.

```rust
val cpu_relax: unit -> unit
```

If busy-waiting, calling `cpu_relax()` between iterations will improve performance on some CPU architectures

```rust
val is_main_domain: unit -> bool
```

`is_main_domain()` returns true if called from the initial domain.

```rust
val recommended_domain_count: unit -> int
```
`set s n c` modifies `s` in place, replacing the byte at index `n` with `c`.

**Raises** `Invalid_argument` if `n` is not a valid index in `s`.

`val create : int -> bytes`

`create` `n` returns a new byte sequence of length `n`. The sequence is uninitialized and contains arbitrary bytes.

**Raises** `Invalid_argument` if `n < 0` or `n > Sys.max_string_length[29.60]`.

`val make : int -> char -> bytes`

`make n c` returns a new byte sequence of length `n`, filled with the byte `c`.

**Raises** `Invalid_argument` if `n < 0` or `n > Sys.max_string_length[29.60]`.

`val init : int -> (int -> char) -> bytes`

`init n f` returns a fresh byte sequence of length `n`, with character `i` initialized to the result of `f i` (in increasing index order).

**Raises** `Invalid_argument` if `n < 0` or `n > Sys.max_string_length[29.60]`.

`val empty : bytes`

A byte sequence of size 0.

`val copy : bytes -> bytes`

Return a new byte sequence that contains the same bytes as the argument.

`val of_string : string -> bytes`

Return a new byte sequence that contains the same bytes as the given string.

`val to_string : bytes -> string`

Return a new string that contains the same bytes as the given byte sequence.

`val sub : bytes -> int -> int -> bytes`

`sub s pos len` returns a new byte sequence of length `len`, containing the subsequence of `s` that starts at position `pos` and has length `len`.

**Raises** `Invalid_argument` if `pos` and `len` do not designate a valid range of `s`.

`val sub_string : bytes -> int -> int -> string`

Same as `Bytes.sub[29.8]` but return a string instead of a byte sequence.

`val extend : bytes -> int -> int -> bytes`

`extend s left right` returns a new byte sequence that contains the bytes of `s`, with `left` uninitialized bytes prepended and `right` uninitialized bytes appended to it. If `left` or `right` is negative, then bytes are removed (instead of appended) from the corresponding side of `s`.

**Since:** 4.05 in `BytesLabels`

**Raises** `Invalid_argument` if the result length is negative or longer than `Sys.max_string_length[29.60]` bytes.
The recommended maximum number of domains which should be running simultaneously (including domains already running).

The value returned is at least 1.

module DLS :

sig

Domain-local Storage

type 'a key

Type of a DLS key

val new_key : ?split_from_parent:('a -> 'a) -> (unit -> 'a) -> 'a key

new_key f returns a new key bound to initialiser f for accessing , domain-local variables. If split_from_parent is not provided, the value for a new domain will be computed on-demand by the new domain: the first get call will call the initializer f and store that value.

If split_from_parent is provided, spawning a domain will derive the child value (for
this key) from the parent value. This computation happens in the parent domain and it
always happens, regardless of whether the child domain will use it. If the splitting
function is expensive or requires child-side computation, consider using 'a Lazy.t key:

let init () = ...

let split_from_parent parent_value =
  ... parent-side computation ...;

lazy (
  ... child-side computation ...
)

let key = Domain.DLS.new_key ~split_from_parent init

let get () = Lazy.force (Domain.DLS.get key)

In this case a part of the computation happens on the child domain; in particular, it can
access parent_value concurrently with the parent domain, which may require explicit
synchronization to avoid data races.

val get : 'a key -> 'a

get k returns v if a value v is associated to the key k on the calling domain's
domain-local state. Sets k's value with its initialiser and returns it otherwise.

val set : 'a key -> 'a -> unit

set k v updates the calling domain's domain-local state to associate the key k with
value v. It overwrites any previous values associated to k, which cannot be restored later.
val `fill`: `bytes` -> `int` -> `int` -> `char` -> `unit`

fill `s` `pos` `len` `c` modifies `s` in place, replacing `len` characters with `c`, starting at `pos`.

**Raises** `Invalid_argument` if `pos` and `len` do not designate a valid range of `s`.

val `blit`: `bytes` -> `int` -> `bytes` -> `int` -> `int` -> `unit`

blit `src` `src_pos` `dst` `dst_pos` `len` copies `len` bytes from byte sequence `src`, starting at index `src_pos`, to byte sequence `dst`, starting at index `dst_pos`. It works correctly even if `src` and `dst` are the same byte sequence, and the source and destination intervals overlap.

**Raises** `Invalid_argument` if `src_pos` and `len` do not designate a valid range of `src`, or if `dst_pos` and `len` do not designate a valid range of `dst`.

val `blit_string`: `string` -> `int` -> `bytes` -> `int` -> `int` -> `unit`

blit_string `src` `src_pos` `dst` `dst_pos` `len` copies `len` bytes from string `src`, starting at index `src_pos`, to byte sequence `dst`, starting at index `dst_pos`.

**Since:** 4.05 in `BytesLabels`

**Raises** `Invalid_argument` if `src_pos` and `len` do not designate a valid range of `src`, or if `dst_pos` and `len` do not designate a valid range of `dst`.

val `concat`: `bytes` -> `bytes` list -> `bytes`

concat `sep` `s1` concatenates the list of byte sequences `s1`, inserting the separator byte sequence `sep` between each, and returns the result as a new byte sequence.

**Raises** `Invalid_argument` if the result is longer than `Sys.max_string_length[29.60]` bytes.

val `cat`: `bytes` -> `bytes` -> `bytes`

cat `s1 s2` concatenates `s1` and `s2` and returns the result as a new byte sequence.

**Since:** 4.05 in `BytesLabels`

**Raises** `Invalid_argument` if the result is longer than `Sys.max_string_length[29.60]` bytes.

val `iter`: `(char -> unit) -> bytes -> unit`

iter `f s` applies function `f` in turn to all the bytes of `s`. It is equivalent to `f (get s 0); f (get s 1); ...; f (get s (length s - 1));`.

val `iteri`: `(int -> char -> unit) -> bytes -> unit`

Same as `Bytes.iter[29.8]`, but the function is applied to the index of the byte as first argument and the byte itself as second argument.

val `map`: `(char -> char) -> bytes -> bytes`

map `f s` applies function `f` in turn to all the bytes of `s` (in increasing index order) and stores the resulting bytes in a new sequence that is returned as the result.

val `mapi`: `(int -> char -> char) -> bytes -> bytes`

mapi `f s` calls `f` with each character of `s` and its index (in increasing index order) and stores the resulting bytes in a new sequence that is returned as the result.
end

## 28.15 Module Digest : MD5 message digest.

This module provides functions to compute 128-bit 'digests' of arbitrary-length strings or files. The algorithm used is MD5.

The MD5 hash function is not cryptographically secure. Hence, this module should not be used for security-sensitive applications. More recent, stronger cryptographic primitives should be used instead.

```python
type t = string
```

The type of digests: 16-character strings.

```python
val compare : t -> t -> int
```

The comparison function for 16-character digest, with the same specification as `compare` [27.2] and the implementation shared with `String.copy` [28.53]. Along with the type `t`, this function `compare` allows the module `Digest` to be passed as argument to the functors `Set.Make` [28.49] and `Map.Make` [28.33].

**Since:** 4.00

```python
val equal : t -> t -> bool
```

The equal function for 16-character digest.

**Since:** 4.03

```python
val string : string -> t
```

Return the digest of the given string.

```python
val bytes : bytes -> t
```

Return the digest of the given byte sequence.

**Since:** 4.02

```python
val substring : string -> int -> int -> t
```

`Digest.substring` `s ofs len` returns the digest of the substring of `s` starting at index `ofs` and containing `len` characters.

```python
val subbytes : bytes -> int -> int -> t
```

`Digest.subbytes` `s ofs len` returns the digest of the subsequence of `s` starting at index `ofs` and containing `len` bytes.

**Since:** 4.02

```python
val channel : in_channel -> int -> t
```
val fold_left : ('acc -> char -> 'acc) -> 'acc -> bytes -> 'acc
fold_left f x s computes f (... (f (f x (get s 0)) (get s 1)) ...) (get s
(n-1)), where n is the length of s.

Since: 4.13

val fold_right : (char -> 'acc -> 'acc) -> bytes -> 'acc -> 'acc
fold_right f s x computes f (get s 0) (f (get s 1) ( ... (f (get s (n-1)) x)
...)), where n is the length of s.

Since: 4.13

val for_all : (char -> bool) -> bytes -> bool
for_all p s checks if all characters in s satisfy the predicate p.

Since: 4.13

val exists : (char -> bool) -> bytes -> bool
exists p s checks if at least one character of s satisfies the predicate p.

Since: 4.13

val trim : bytes -> bytes

Return a copy of the argument, without leading and trailing whitespace. The bytes regarded
as whitespace are the ASCII characters ' ', '\012', '\n', '\r', and '\t'.

val escaped : bytes -> bytes

Return a copy of the argument, with special characters represented by escape sequences,
following the lexical conventions of OCaml. All characters outside the ASCII printable range
(32..126) are escaped, as well as backslash and double-quote.

Raises Invalid_argument if the result is longer than Sys.max_string_length[29.60] bytes.

val index : bytes -> char -> int
index s c returns the index of the first occurrence of byte c in s.

Raises Not_found if c does not occur in s.

val index_opt : bytes -> char -> int option
index_opt s c returns the index of the first occurrence of byte c in s or None if c does not
occur in s.

Since: 4.05

val rindex : bytes -> char -> int
rindex s c returns the index of the last occurrence of byte c in s.

Raises Not_found if c does not occur in s.

val rindex_opt : bytes -> char -> int option
If `len` is nonnegative, `Digest-channel ic len` reads `len` characters from channel `ic` and returns their digest, or raises `End_of_file` if end-of-file is reached before `len` characters are read. If `len` is negative, `Digest-channel ic len` reads all characters from `ic` until end-of-file is reached and return their digest.

**val file : string -> t**

Return the digest of the file whose name is given.

**val output : out_channel -> t -> unit**

Write a digest on the given output channel.

**val input : in_channel -> t**

Read a digest from the given input channel.

**val to_hex : t -> string**

Return the printable hexadecimal representation of the given digest.

**Raises** `Invalid_argument` if the argument is not exactly 16 bytes.

**val from_hex : string -> t**

Convert a hexadecimal representation back into the corresponding digest.

**Since:** 4.00

**Raises** `Invalid_argument` if the argument is not exactly 32 hexadecimal characters.

## 28.16 Module Effect

**Alert unstable.** The Effect interface may change in incompatible ways in the future.

**Effects.**

See 'Language extensions/Effect handlers' section in the manual.

**type `_t = ..**

The type of effects.

**exception Unhandled : 'a t -> exn**

`Unhandled e` is raised when effect `e` is performed and there is no handler for it.

**exception Continuation_already_resumed**

Exception raised when a continuation is continued or discontinued more than once.

**val perform : 'a t -> 'a**

`perform e` performs an effect `e`.

**Raises** `Unhandled` if there is no handler for `e`.
`rindex_opt s c` returns the index of the last occurrence of byte `c` in `s` or `None` if `c` does not occur in `s`.

**Since:** 4.05

`val index_from : bytes -> int -> char -> int`

`index_from s i c` returns the index of the first occurrence of byte `c` in `s` after position `i`.

`index s c` is equivalent to `index_from s 0 c`.

**Raises**

* `Invalid_argument` if `i` is not a valid position in `s`.

* `Not_found` if `c` does not occur in `s` after position `i`.

`val index_from_opt : bytes -> int -> char -> int`

`index_from_opt s i c` returns the index of the first occurrence of byte `c` in `s` after position `i` or `None` if `c` does not occur in `s` after position `i`. `index_opt s c` is equivalent to `index_from_opt s 0 c`.

**Since:** 4.05

**Raises** `Invalid_argument` if `i` is not a valid position in `s`.

`val rindex_from : bytes -> int -> char -> int`

`rindex_from s i c` returns the index of the last occurrence of byte `c` in `s` before position `i+1`. `rindex s c` is equivalent to `rindex_from s (length s - 1) c`.

**Raises**

* `Invalid_argument` if `i+1` is not a valid position in `s`.

* `Not_found` if `c` does not occur in `s` before position `i+1`.

`val rindex_from_opt : bytes -> int -> char -> int`

`rindex_from_opt s i c` returns the index of the last occurrence of byte `c` in `s` before position `i+1` or `None` if `c` does not occur in `s` before position `i+1`. `rindex_opt s c` is equivalent to `rindex_from s (length s - 1) c`.

**Since:** 4.05

**Raises** `Invalid_argument` if `i+1` is not a valid position in `s`.

`val contains : bytes -> char -> bool`

`contains s c` tests if byte `c` appears in `s`.

`val contains_from : bytes -> int -> char -> bool`

`contains_from s start c` tests if byte `c` appears in `s` after position `start`. `contains s c` is equivalent to `contains_from s 0 c`.

**Raises** `Invalid_argument` if `start` is not a valid position in `s`.
module Deep :

sig

Deep handlers

type ('a, 'b) continuation

('a,'b) continuation is a delimited continuation that expects a 'a value and returns
a 'b value.

val continue : ('a, 'b) continuation -> 'a -> 'b

continue k x resumes the continuation k by passing x to k.

Raises Continuation already resumed if the continuation has already been resumed.

val discontinue : ('a, 'b) continuation -> exn -> 'b

discontinue k e resumes the continuation k by raising the exception e in k.

Raises Continuation already resumed if the continuation has already been resumed.

val discontinue_with_backtrace :

-> ('a, 'b) continuation

exn -> Printexc/raw_backtrace -> 'b

discontinue_with_backtrace k e bt resumes the continuation k by raising the
exception e in k using bt as the origin for the exception.

Raises Continuation already resumed if the continuation has already been resumed.

type ('a, 'b) handler =

{ retc : 'a -> 'b ;
    exnc : exn -> 'b ;
    effc : 'c. 'c Effect.t -> (( 'c, 'b) continuation -> 'b) option ;
}

('a,'b) handler is a handler record with three fields – retc is the value handler, exnc
handles exceptions, and effc handles the effects performed by the computation enclosed
by the handler.

val match_with : ('c -> 'a) -> 'c -> ('a, 'b) handler -> 'b

match_with f v h runs the computation f v in the handler h.

type 'a effect_handler =

{ effc : 'b. 'b Effect.t -> (( 'b, 'a) continuation -> 'a) option ; }

'a effect_handler is a deep handler with an identity value handler fun x -> x and
an exception handler that raises any exception fun e -> raise e.

val try_with : ('b -> 'a) -> 'b -> 'a effect_handler -> 'a
val rcontains_from : bytes -> int -> char -> bool

rcontains_from s stop c tests if byte c appears in s before position stop+1.

**Raises** Invalid_argument if stop < 0 or stop+1 is not a valid position in s.

val uppercase CHAR : bytes -> bytes

Return a copy of the argument, with all lowercase letters translated to uppercase, using the
US-ASCII character set.

**Since:** 4.03 (4.05 in BytesLabels)

val lowercase CHAR : bytes -> bytes

Return a copy of the argument, with all uppercase letters translated to lowercase, using the
US-ASCII character set.

**Since:** 4.03 (4.05 in BytesLabels)

val capitalize CHAR : bytes -> bytes

Return a copy of the argument, with the first character set to uppercase, using the US-ASCII
character set.

**Since:** 4.03 (4.05 in BytesLabels)

val un capital ize CHAR : bytes -> bytes

Return a copy of the argument, with the first character set to lowercase, using the US-ASCII
character set.

**Since:** 4.03 (4.05 in BytesLabels)

type t = bytes

An alias for the type of byte sequences.

val compare : t -> t -> int

The comparison function for byte sequences, with the same specification as compare[28.2].
Along with the type t, this function compare allows the module Bytes to be passed as
argument to the functors Set.Make[29.54] and Map.Make[29.35].

val equal : t -> t -> bool

The equality function for byte sequences.

**Since:** 4.03 (4.05 in BytesLabels)

val starts_with : prefix:bytes -> bytes -> bool

starts_with ~prefix s is true if and only if s starts with prefix.

**Since:** 4.13

val ends_with : suffix:bytes -> bytes -> bool

ends_with ~suffix s is true if and only if s ends with suffix.

**Since:** 4.13
`try_with` f v h runs the computation f v under the handler h.

`val get_callstack: ('a, 'b) continuation -> int -> Printexc/raw_backtrace`

`get_callstack` c n returns a description of the top of the call stack on the continuation c, with at most n entries.

end

module Shallow :

sig

type ('a, 'b) continuation

('a,'b) continuation is a delimited continuation that expects a 'a value and returns
a 'b value.

val fiber : ('a -> 'b) -> ('a, 'b) continuation

`fiber` f constructs a continuation that runs the computation f.

type ('a, 'b) handler =

{ retc : 'a -> 'b ;
  exnc : exn -> 'b ;
  effc : 'c. 'c Effect.t -> (( 'c, 'a) continuation -> 'b) option ;
}

('a,'b) handler is a handler record with three fields – `retc` is the value handler, `exnc` handles exceptions, and `effc` handles the effects performed by the computation enclosed by the handler.

val continue_with : ('c, 'a) continuation ->

'c -> ('a, 'b) handler -> 'b

`continue_with` k v h resumes the continuation k with value v with the handler h.

**Raises** `Continuation already resumed` if the continuation has already been resumed.

val discontinue_with :

('c, 'a) continuation ->

exn -> ('a, 'b) handler -> 'b

`discontinue_with` k e h resumes the continuation k by raising the exception e with the handler h.

**Raises** `Continuation already resumed` if the continuation has already been resumed.

val discontinue_with_backtrace :

('a, 'b) continuation ->

exn -> Printexc/raw_backtrace -> ('b, 'c) handler -> 'c
## Unsafe conversions (for advanced users)

This section describes unsafe, low-level conversion functions between `bytes` and `string`. They do not copy the internal data; used improperly, they can break the immutability invariant on strings. They are available for expert library authors, but for most purposes you should use the always-correct `Bytes.to_string` [29.8] and `Bytes.of_string` [29.8] instead.

### `val unsafe_to_string`: `bytes` -> `string`

Unsafely convert a byte sequence into a string.

To reason about the use of `unsafe_to_string`, it is convenient to consider an "ownership" discipline. A piece of code that manipulates some data "owns" it; there are several disjoint ownership modes, including:

* Unique ownership: the data may be accessed and mutated

* Shared ownership: the data has several owners, that may only access it, not mutate it.

Unique ownership is linear: passing the data to another piece of code means giving up ownership (we cannot write the data again). A unique owner may decide to make the data shared (giving up mutation rights on it), but shared data may not become uniquely-owned again.

`unsafe_to_string` `s` can only be used when the caller owns the byte sequence `s` — either uniquely or as shared immutable data. The caller gives up ownership of `s`, and gains ownership of the returned string.

There are two valid use-cases that respect this ownership discipline:

1. Creating a string by initializing and mutating a byte sequence that is never changed after initialization is performed.

```clojure
let string_init len f : string =
  let s = Bytes.create len in
  for i = 0 to len - 1 do Bytes.set s i (f i) done;
  Bytes.unsafe_to_string s
```

This function is safe because the byte sequence `s` will never be accessed or mutated after `unsafe_to_string` is called. The `string_init` code gives up ownership of `s`, and returns the ownership of the resulting string to its caller.

Note that it would be unsafe if `s` was passed as an additional parameter to the function `f` as it could escape this way and be mutated in the future — `string_init` would give up ownership of `s` to pass it to `f`, and could not call `unsafe_to_string` safely.

We have provided the `String.init` [29.58], `String.map` [29.58] and `String.mapi` [29.58] functions to cover most cases of building new strings. You should prefer those over `to_string` or `unsafe_to_string` whenever applicable.

2. Temporarily giving ownership of a byte sequence to a function that expects a uniquely owned string and returns ownership back, so that we can mutate the sequence again after the call ended.
`discontinue_with` k e bt h resumes the continuation k by raising the exception e with the handler h using the raw backtrace bt as the origin of the exception.

**Raises** `Continuation_already_resumed` if the continuation has already been resumed.

`val get_callstack: ('a, 'b) continuation -> int -> Printexc/raw_backtrace`

`get_callstack` c n returns a description of the top of the call stack on the continuation c, with at most n entries.

`end`

## 28.17 Module Either: Either type.

Either is the simplest and most generic sum/variant type: a value of (`'a', 'b' Either.t` is either a `Left` (`v: 'a'`) or a `Right` (`v: 'b'`).

It is a natural choice in the API of generic functions where values could fall in two different cases, possibly at different types, without assigning a specific meaning to what each case should be.

For example:

`List-partition_map: ('a -> ('b, 'c Either.t) -> 'a list -> 'b list * 'c list`

If you are looking for a parametrized type where one alternative means success and the other means failure, you should use the more specific type `Result.t` [28.46].

**Since:** 4.12

```h
type ('a, 'b) t =
| Left of 'a
| Right of 'b

A value of ('a, 'b Either.t contains either a value of 'a or a value of 'b
```

```h
val left: 'a -> ('a, 'b) t
    left v is Left v.
```

```h
val right: 'b -> ('a, 'b) t
    right v is Right v.
```

```h
val is_left: ('a, 'b) t -> bool
    is_left (Left v) is true, is_left (Right v) is false.
```

```h
val is_right: ('a, 'b) t -> bool
    is_right (Left v) is false, is_right (Right v) is true.
```

```h
val find_left: ('a, 'b) t -> 'a option
    find_left (Left v) is Some v, find_left (Right_) is None
```
```hkl
let bytes_length (s : bytes) =
    String.length (Bytes.unsafe_to_string s)
```

In this use-case, we do not promise that `s` will never be mutated after the call to `bytes_length s`. The `String.length[29.58]` function temporarily borrows unique ownership of the byte sequence (and sees it as a `string`), but returns this ownership back to the caller, which may assume that `s` is still a valid byte sequence after the call. Note that this is only correct because we know that `String.length[29.58]` does not capture its argument – it could escape by a side-channel such as a memoization combinator.

The caller may not mutate `s` while the string is borrowed (it has temporarily given up ownership). This affects concurrent programs, but also higher-order functions: if `String.length[29.58]` returned a closure to be called later, `s` should not be mutated until this closure is fully applied and returns ownership.

```hkl
val unsafe_of_string : string -> bytes
```

Unsafely convert a shared string to a byte sequence that should not be mutated.

The same ownership discipline that makes `unsafe_to_string` correct applies to `unsafe_of_string`: you may use it if you were the owner of the `string` value, and you will own the return `bytes` in the same mode.

In practice, unique ownership of string values is extremely difficult to reason about correctly. You should always assume strings are shared, never uniquely owned.

For example, string literals are implicitly shared by the compiler, so you never uniquely own them.

```hkl
let incorrect = Bytes.unsafe_of_string "hello"
let s = Bytes.of_string "hello"
```

The first declaration is incorrect, because the string literal `"hello"` could be shared by the compiler with other parts of the program, and mutating `incorrect` is a bug. You must always use the second version, which performs a copy and is thus correct.

Assuming unique ownership of strings that are not string literals, but are (partly) built from string literals, is also incorrect. For example, mutating `unsafe_of_string ("foo" ^ s)` could mutate the shared string `"foo"` – assuming a rope-like representation of strings. More generally, functions operating on strings will assume shared ownership, they do not preserve unique ownership. It is thus incorrect to assume unique ownership of the result of `unsafe_of_string`.

The only case we have reasonable confidence is safe is if the produced `bytes` is shared – used as an immutable byte sequence. This is possibly useful for incremental migration of low-level programs that manipulate immutable sequences of bytes (for example `Marshal.from_bytes[29.36]`) and previously used the `string` type for this purpose.

```hkl
val split_on_char : char -> bytes -> bytes list
```
val find_right : ('a, 'b) t -> 'b option
  find_right (Right v) is Some v, find_right (Left_) is None

val map_left : ('a1 -> 'a2) -> ('a1, 'b) t -> ('a2, 'b) t
  map_left f e is Left (f v) if e is Left v and e if e is Right _.

val map_right : ('b1 -> 'b2) -> ('a, 'b1) t -> ('a, 'b2) t
  map_right f e is Right (f v) if e is Right v and e if e is Left _.

val map :
  left: ('a1 -> 'a2) ->
  right: ('b1 -> 'b2) -> ('a1, 'b1) t -> ('a2, 'b2) t
    map ~left ~right (Left v) is Left (left v), map ~left ~right (Right v) is Right
    (right v).

val fold : left: ('a -> 'c) -> right: ('b -> 'c) -> ('a, 'b) t -> 'c
  fold ~left ~right (Left v) is left v, and fold ~left ~right (Right v) is right v.

val iter : left: ('a -> unit) -> right: ('b -> unit) -> ('a, 'b) t -> unit
  iter ~left ~right (Left v) is left v, and iter ~left ~right (Right v) is right v.

val for_all : left: ('a -> bool) -> right: ('b -> bool) -> ('a, 'b) t -> bool
  for_all ~left ~right (Left v) is left v, and for_all ~left ~right (Right v) is
  right v.

val equal :
  left: ('a -> 'a -> bool) ->
  right: ('b -> 'b -> bool) -> ('a, 'b) t -> ('a, 'b) t -> bool
    equal ~left ~right e0 e1 tests equality of e0 and e1 using left and right to
    respectively compare values wrapped by Left _ and Right _.

val compare :
  left: ('a -> 'a -> int) ->
  right: ('b -> 'b -> int) -> ('a, 'b) t -> ('a, 'b) t -> int
    compare ~left ~right e0 e1 totally orders e0 and e1 using left and right to
    respectively compare values wrapped by Left _ and Right _.
    Left _ values are smaller
    than Right _ values.

## 28.18 Module Ephemeron : Ephemerons and weak hash tables.

Ephemerons and weak hash tables are useful when one wants to cache or memorize the computation of a function, as long as the arguments and the function are used, without creating memory leaks by continuously keeping old computation results that are not useful anymore because one argument
`split_on_char sep s` returns the list of all (possibly empty) subsequences of `s` that are delimited by the `sep` character. If `s` is empty, the result is the singleton list `[empty]`.

The function's output is specified by the following invariants:

* The list is not empty.

* Concatenating its elements using `sep` as a separator returns a byte sequence equal to the input (`Bytes.concat` (`Bytes.make` 1 `sep`) (`Bytes.split_on_char` `sep s`) = `s`).

* No byte sequence in the result contains the `sep` character.

**Since:** 4.13

## Iterators

* `val to_seq : t -> char Seq.t`

Iterate on the string, in increasing index order. Modifications of the string during iteration will be reflected in the sequence.

**Since:** 4.07

* `val to_seqi : t -> (int * char) Seq.t`

Iterate on the string, in increasing order, yielding indices along chars

**Since:** 4.07

* `val of_seq : char Seq.t -> t`

Create a string from the generator

**Since:** 4.07

## UTF codecs and validations

### UTF-8

* `val get_utf_8_uchar : t -> int -> Uchar.utf_decode`

`get_utf_8_uchar b i` decodes an UTF-8 character at index `i` in `b`.

* `val set_utf_8_uchar : t -> int -> Uchar.t -> int`

`set_utf_8_uchar b i u` UTF-8 encodes `u` at index `i` in `b` and returns the number of bytes `n` that were written starting at `i`. If `n` is 0 there was not enough space to encode `u` at `i` and `b` was left untouched. Otherwise a new character can be encoded at `i + n`.

* `val is_valid_utf_8 : t -> bool`

`is_valid_utf_8 b` is true if and only if `b` contains valid UTF-8 data.
or the function is freed. An implementation using `Hashtbl.t[28.24]` is not suitable because all associations would keep the arguments and the result in memory.

Ephemerons can also be used for "adding" a field to an arbitrary boxed OCaml value: you can attach some information to a value created by an external library without memory leaks.

Ephemerons hold some keys and one or no data. They are all boxed OCaml values. The keys of an ephemeron have the same behavior as weak pointers according to the garbage collector. In fact OCaml weak pointers are implemented as ephemerons without data.

The keys and data of an ephemeron are said to be full if they point to a value, or empty if the value has never been set, has been unset, or was erased by the GC. In the function that accesses the keys or data these two states are represented by the `option` type.

The data is considered by the garbage collector alive if all the full keys are alive and if the ephemeron is alive. When one of the keys is not considered alive anymore by the GC, the data is emptied from the ephemeron. The data could be alive for another reason and in that case the GC will not free it, but the ephemeron will not hold the data anymore.

The ephemerons complicate the notion of liveness of values, because it is not anymore an equivalence with the reachability from root value by usual pointers (not weak and not ephemerons). With ephemerons the notion of liveness is constructed by the least fixpoint of: A value is alive if:

* it is a root value

* it is reachable from alive value by usual pointers

* it is the data of an alive ephemeron with all its full keys alive

**Notes:**

* All the types defined in this module cannot be marshaled using `output_value[27.2]` or the functions of the ` Marshal[28.34]` module.

Ephemerons are defined in a language agnostic way in this paper: B. Hayes, Ephemerons: A New Finalization Mechanism, OOPSLA’97

**Since:** 4.03

**Alert unsynchronized_access.** Unsynchronized accesses to weak hash tables are a programming error.

## Unsynchronized accesses

Unsynchronized accesses to a weak hash table may lead to an invalid weak hash table state. Thus, concurrent accesses to a buffer must be synchronized (for instance with a `Mutex.t[28.36]`).

```sml
module type S =
    sig
```

Propose the same interface as usual hash table. However since the bindings are weak, even if `mem h k` is true, a subsequent `find h k` may raise `Not_found` because the garbage collector can run between the two.

```sml
type key

type !'a t

val create : int -> 'a t
```
## UTF-16BE

```c
val get_utf_16be_uchar: t -> int -> Uchar.utf_decode
```

get_utf_16be_uchar b i decodes an UTF-16BE character at index i in b.

```c
val set_utf_16be_uchar: t -> int -> Uchar.t -> int
```

set_utf_16be_uchar b i u UTF-16BE encodes u at index i in b and returns the number of bytes n that were written starting at i. If n is 0 there was not enough space to encode u at i and b was left untouched. Otherwise a new character can be encoded at i + n.

```c
val is_valid_utf_16be: t -> bool
```

is_valid_utf_16be b is true if and only if b contains valid UTF-16BE data.

## UTF-16LE

```c
val get_utf_16le_uchar: t -> int -> Uchar.utf_decode
```

get_utf_16le_uchar b i decodes an UTF-16LE character at index i in b.

```c
val set_utf_16le_uchar: t -> int -> Uchar.t -> int
```

set_utf_16le_uchar b i u UTF-16LE encodes u at index i in b and returns the number of bytes n that were written starting at i. If n is 0 there was not enough space to encode u at i and b was left untouched. Otherwise a new character can be encoded at i + n.

```c
val is_valid_utf_16le: t -> bool
```

is_valid_utf_16le b is true if and only if b contains valid UTF-16LE data.

## Binary encoding/decoding of integers

The functions in this section binary encode and decode integers to and from byte sequences.

All following functions raise Invalid_argument if the space needed at index i to decode or encode the integer is not available.

Little-endian (resp. big-endian) encoding means that least (resp. most) significant bytes are stored first. Big-endian is also known as network byte order. Native-endian encoding is either little-endian or big-endian depending on Sys.big_endian[29.60].

32-bit and 64-bit integers are represented by the int32 and int64 types, which can be interpreted either as signed or unsigned numbers.

8-bit and 16-bit integers are represented by the int type, which has more bits than the binary encoding. These extra bits are handled as follows:

* Functions that decode signed (resp. unsigned) 8-bit or 16-bit integers represented by int values sign-extend (resp. zero-extend) their result.

* Functions that encode 8-bit or 16-bit integers represented by int values truncate their input to their least significant bytes.
```hkl
val clear : 'a t -> unit
val reset : 'a t -> unit
val copy : 'a t -> 'a t
val add : 'a t -> key -> 'a -> unit
val remove : 'a t -> key -> unit
val find : 'a t -> key -> 'a
val find_opt : 'a t -> key -> 'a option
val find_all : 'a t -> key -> 'a list
val replace : 'a t -> key -> 'a -> unit
val mem : 'a t -> key -> bool
val length : 'a t -> int
val stats : 'a t -> Hashtbl.statistics
val add_seq : 'a t -> (key * 'a) Seq.t -> unit
val replace_seq : 'a t -> (key * 'a) Seq.t -> unit
val of_seq : (key * 'a) Seq.t -> 'a t
val clean : 'a t -> unit
```

remove all dead bindings. Done automatically during automatic resizing.

```hkl
val stats_alive : 'a t -> Hashtbl.statistics
```

same as `Hashtbl.SeededS.stats[28.24]` but only count the alive bindings

end

The output signature of the functors `Ephemeron.K1.Make[28.18]` and `Ephemeron.K2.Make[28.18]`. These hash tables are weak in the keys. If all the keys of a binding are alive the binding is kept, but if one of the keys of the binding is dead then the binding is removed.

```hkl
module type SeededS =
sig
```

```hkl
type key

type !'a t

val create : ?random:bool -> int -> 'a t

val clear : 'a t -> unit

val reset : 'a t -> unit

val copy : 'a t -> 'a t

val add : 'a t -> key -> 'a -> unit

val remove : 'a t -> key -> unit

val find : 'a t -> key -> 'a
```
val get_uint8 : bytes -> int -> int
get_uint8 b i is b's unsigned 8-bit integer starting at byte index i.

Since: 4.08

val get_int8 : bytes -> int -> int
get_int8 b i is b's signed 8-bit integer starting at byte index i.

Since: 4.08

val get_uint16_ne : bytes -> int -> int
get_uint16_ne b i is b's native-endian unsigned 16-bit integer starting at byte index i.

Since: 4.08

val get_uint16_be : bytes -> int -> int
get_uint16_be b i is b's big-endian unsigned 16-bit integer starting at byte index i.

Since: 4.08

val get_uint16_le : bytes -> int -> int
get_uint16_le b i is b's little-endian unsigned 16-bit integer starting at byte index i.

Since: 4.08

val get_int16_ne : bytes -> int -> int
get_int16_ne b i is b's native-endian signed 16-bit integer starting at byte index i.

Since: 4.08

val get_int16_be : bytes -> int -> int
get_int16_be b i is b's big-endian signed 16-bit integer starting at byte index i.

Since: 4.08

val get_int16_le : bytes -> int -> int
get_int16_le b i is b's little-endian signed 16-bit integer starting at byte index i.

Since: 4.08

val get_int32_ne : bytes -> int -> int32
get_int32_ne b i is b's native-endian 32-bit integer starting at byte index i.

Since: 4.08

val get_int32_be : bytes -> int -> int32
get_int32_be b i is b's big-endian 32-bit integer starting at byte index i.

Since: 4.08

val get_int32_le : bytes -> int -> int32
val find_opt : 'a t -> key -> 'a option

val find_all : 'a t -> key -> 'a list

val replace : 'a t -> key -> 'a -> unit

val mem : 'a t -> key -> bool

val length : 'a t -> int

val stats : 'a t -> Hashtbl.statsistics

val add_seq : 'a t -> (key * 'a) Seq.t -> unit

val replace_seq : 'a t -> (key * 'a) Seq.t -> unit

val of_seq : (key * 'a) Seq.t -> 'a t

val clean : 'a t -> unit

remove all dead bindings. Done automatically during automatic resizing.

val stats_alive : 'a t -> Hashtbl.statsistics

same as Hashtbl.SeededS.stats[28.24] but only count the alive bindings

end

The output signature of the functors Ephemeron.K1.MakeSeeded[28.18] and Ephemeron.K2.MakeSeeded[28.18].

module K1 :

sig

type ('k, 'd) t

an ephemeron with one key

val make : 'k -> 'd -> ('k, 'd) t

Ephemeron.K1.make k d creates an ephemeron with key k and data d.

val query : ('k, 'd) t -> 'k -> 'd option

Ephemeron.K1.query eph key returns Some x (where x is the ephemeron's data) if key is physically equal to eph's key, and None if eph is empty or key is not equal to eph's key.

module Make :

functor (H : Hashtbl.HashedType) -> Ephemeron.S with type key = H.t

Functor building an implementation of a weak hash table

module MakeSeeded :

functor (H : Hashtbl.SeededHashedType) -> Ephemeron.SeededS with type key = H.t
`get_int32_le` b i is b's little-endian 32-bit integer starting at byte index i.

Since: 4.08

`val get_int64_ne : bytes -> int -> int64`

`get_int64_ne` b i is b's native-endian 64-bit integer starting at byte index i.

Since: 4.08

`val get_int64_be : bytes -> int -> int64`

`get_int64_be` b i is b's big-endian 64-bit integer starting at byte index i.

Since: 4.08

`val get_int64_le : bytes -> int -> int64`

`get_int64_le` b i is b's little-endian 64-bit integer starting at byte index i.

Since: 4.08

`val set_uint8 : bytes -> int -> int -> unit`

`set_uint8` b i v sets b's unsigned 8-bit integer starting at byte index i to v.

Since: 4.08

`val set_int8 : bytes -> int -> int -> unit`

`set_int8` b i v sets b's signed 8-bit integer starting at byte index i to v.

Since: 4.08

`val set_uint16_ne : bytes -> int -> int -> unit`

`set_uint16_ne` b i v sets b's native-endian unsigned 16-bit integer starting at byte index i to v.

Since: 4.08

`val set_uint16_be : bytes -> int -> int -> unit`

`set_uint16_be` b i v sets b's big-endian unsigned 16-bit integer starting at byte index i to v.

Since: 4.08

`val set_uint16_le : bytes -> int -> int -> unit`

`set_uint16_le` b i v sets b's little-endian unsigned 16-bit integer starting at byte index i to v.

Since: 4.08

`val set_int16_ne : bytes -> int -> int -> unit`

`set_int16_ne` b i v sets b's native-endian signed 16-bit integer starting at byte index i to v.

Since: 4.08
Functor building an implementation of a weak hash table. The seed is similar to the one of `Hashtbl.MakeSeeded`[28.24].

module Bucket :

sig

type ('k, 'd) t

A bucket is a mutable "list" of ephemerons.

val make : unit -> ('k, 'd) t

Create a new bucket.

val add : ('k, 'd) t -> 'k -> 'd -> unit

Add an ephemeron to the bucket.

val remove : ('k, 'd) t -> 'k -> unit

remove b k removes from b the most-recently added ephemeron with key k, or does nothing if there is no such ephemeron.

val find : ('k, 'd) t -> 'k -> 'd option

Returns the data of the most-recently added ephemeron with the given key, or `None` if there is no such ephemeron.

val length : ('k, 'd) t -> int

Returns an upper bound on the length of the bucket.

val clear : ('k, 'd) t -> unit

Remove all ephemerons from the bucket.

end

end

Ephemerons with one key.

module K2 :

sig

type ('k1, 'k2, 'd) t

an ephemeron with two keys

val make : 'k1 -> 'k2 -> 'd -> ('k1, 'k2, 'd) t

Same as `Ephemeron.K1.make`[28.18]

val query : ('k1, 'k2, 'd) t -> 'k1 -> 'k2 -> 'd option

Same as `Ephemeron.K1.query`[28.18]
val set_int16_be : bytes -> int -> int -> unit
  set_int16_be b i v sets b's big-endian signed 16-bit integer starting at byte index i to v.
  Since: 4.08

val set_int16_le : bytes -> int -> int -> unit
  set_int16_le b i v sets b's little-endian signed 16-bit integer starting at byte index i to v.
  Since: 4.08

val set_int32_ne : bytes -> int -> int32 -> unit
  set_int32_ne b i v sets b's native-endian 32-bit integer starting at byte index i to v.
  Since: 4.08

val set_int32_be : bytes -> int -> int32 -> unit
  set_int32_be b i v sets b's big-endian 32-bit integer starting at byte index i to v.
  Since: 4.08

val set_int32_le : bytes -> int -> int32 -> unit
  set_int32_le b i v sets b's little-endian 32-bit integer starting at byte index i to v.
  Since: 4.08

val set_int64_ne : bytes -> int -> int64 -> unit
  set_int64_ne b i v sets b's native-endian 64-bit integer starting at byte index i to v.
  Since: 4.08

val set_int64_be : bytes -> int -> int64 -> unit
  set_int64_be b i v sets b's big-endian 64-bit integer starting at byte index i to v.
  Since: 4.08

val set_int64_le : bytes -> int -> int64 -> unit
  set_int64_le b i v sets b's little-endian 64-bit integer starting at byte index i to v.
  Since: 4.08

Byte sequences and concurrency safety

Care must be taken when concurrently accessing byte sequences from multiple domains: accessing
a byte sequence will never crash a program, but unsynchronized accesses might yield surprising
(non-sequentially-consistent) results.
module Make :
functor (H1 : Hashtbl.HashedType) -> functor (H2 : Hashtbl.HashedType) ->
Ephemeron.S with type key = H1.t * H2.t

Functor building an implementation of a weak hash table

module MakeSeeded :
functor (H1 : Hashtbl.SeededHashedType) -> functor (H2 : Hashtbl.SeededHashedType)
-> Ephemeron.SeededS with type key = H1.t * H2.t

Functor building an implementation of a weak hash table. The seed is similar to the one
of `Hashtbl.MakeSeeded` [28.24].

module Bucket :
sig
type ('k1, 'k2, 'd) t
A bucket is a mutable "list" of ephemerons.
val make : unit -> ('k1, 'k2, 'd) t
Create a new bucket.
val add : ('k1, 'k2, 'd) t -> 'k1 -> 'k2 -> 'd -> unit
Add an ephemeron to the bucket.
val remove : ('k1, 'k2, 'd) t -> 'k1 -> 'k2 -> unit
remove b k1 k2 removes from b the most-recently added ephemeron with keys k1
and k2, or does nothing if there is no such ephemeron.
val find : ('k1, 'k2, 'd) t -> 'k1 -> 'k2 -> 'd option
Returns the data of the most-recently added ephemeron with the given keys, or
None if there is no such ephemeron.
val length : ('k1, 'k2, 'd) t -> int
Returns an upper bound on the length of the bucket.
val clear : ('k1, 'k2, 'd) t -> unit
Remove all ephemerons from the bucket.

end

end

Ephemerons with two keys.

module Kn :

sig
Atomicity

Every byte sequence operation that accesses more than one byte is not atomic. This includes
iteration and scanning.

For example, consider the following program:

```pascal
let size = 100_000_000
let b = Bytes.make size ' '
let update b f () =
    Bytes.iteri (fun i x -> Bytes.set b i (Char.chr (f (Char.code x)))) b
let d1 = Domain spawn (update b (fun x -> x + 1))
let d2 = Domain spawn (update b (fun x -> 2 * x + 1))
let () = Domain.join d1; Domain.join d2
```

the bytes sequence b may contain a non-deterministic mixture of '!', 'A', 'B', and 'C' values.

After executing this code, each byte of the sequence b is either '!', 'A', 'B', or 'C'. If atomicity is required, then the user must implement their own synchronization (for example, using Mutex.t[29.38]).

Data races

If two domains only access disjoint parts of a byte sequence, then the observed behaviour is the equivalent to some sequential interleaving of the operations from the two domains.

A data race is said to occur when two domains access the same byte without synchronization and at least one of the accesses is a write. In the absence of data races, the observed behaviour is equivalent to some sequential interleaving of the operations from different domains.

Whenever possible, data races should be avoided by using synchronization to mediate the accesses to the elements of the sequence.

Indeed, in the presence of data races, programs will not crash but the observed behaviour may not be equivalent to any sequential interleaving of operations from different domains. Nevertheless, even in the presence of data races, a read operation will return the value of some prior write to that location.

Mixed-size accesses

Another subtle point is that if a data race involves mixed-size writes and reads to the same location, the order in which those writes and reads are observed by domains is not specified. For instance, the following code write sequentially a 32-bit integer and a `char` to the same index

```pascal
let b = Bytes.make 10 '\000'
let d1 = Domain spawn (fun () -> Bytes.set_int32_ne b 0 100; b.[0] <- 'd' )
```

In this situation, a domain that observes the write of 'd' to b.0 is not guaranteed to also observe the write to indices 1, 2, or 3.
type ('k, 'd) t

an ephemeron with an arbitrary number of keys of the same type

val make : 'k array -> 'd -> ('k, 'd) t

Same as Ephemeron.K1.make[28.18]

val query : ('k, 'd) t -> 'k array -> 'd option

Same as Ephemeron.K1.query[28.18]

module Make :

functor (H : Hashtbl.HashedType) -> Ephemeron.S with type key = H.t array

Functor building an implementation of a weak hash table

module MakeSeeded :

functor (H : Hashtbl.SeededHashedType) -> Ephemeron.SeededS with type key = H.t array

Functor building an implementation of a weak hash table. The seed is similar to the one of Hashtbl.MakeSeeded[28.24].

module Bucket :

sig

type ('k, 'd) t

A bucket is a mutable "list" of ephemerons.

val make : unit -> ('k, 'd) t

Create a new bucket.

val add : ('k, 'd) t -> 'k array -> 'd -> unit

Add an ephemeron to the bucket.

val remove : ('k, 'd) t -> 'k array -> unit

remove b k removes from b the most-recently added ephemeron with keys k, or
does nothing if there is no such ephemeron.

val find : ('k, 'd) t -> 'k array -> 'd option

Returns the data of the most-recently added ephemeron with the given keys, or
None if there is no such ephemeron.

val length : ('k, 'd) t -> int

Returns an upper bound on the length of the bucket.

val clear : ('k, 'd) t -> unit
## 29.9 Module BytesLabels : Byte sequence operations.

A byte sequence is a mutable data structure that contains a fixed-length sequence of bytes. Each byte can be indexed in constant time for reading or writing.

Given a byte sequence `s` of length `l`, we can access each of the `l` bytes of `s` via its index in the sequence. Indexes start at 0, and we will call an index valid in `s` if it falls within the range `[0...1-1]` (inclusive). A position is the point between two bytes or at the beginning or end of the sequence. We call a position valid in `s` if it falls within the range `[0...1]` (inclusive). Note that the byte at index `n` is between positions `n` and `n+1`.

Two parameters `start` and `len` are said to designate a valid range of `s` if `len >= 0` and `start` and `start+len` are valid positions in `s`.

Byte sequences can be modified in place, for instance via the `set` and `blit` functions described below. See also strings (module `String` [29.58]), which are almost the same data structure, but cannot be modified in place.

Bytes are represented by the OCaml type `char`.

The labeled version of this module can be used as described in the `StdLabels` [29.57] module.

**Since: 4.02**

**val length : bytes -> int**

Return the length (number of bytes) of the argument.

**val get : bytes -> int -> char**

`get s n` returns the byte at index `n` in argument `s`.

**Raises Invalid_argument if n is not a valid index in s.**

**val set : bytes -> int -> char -> unit**

`set s n c` modifies `s` in place, replacing the byte at index `n` with `c`.

**Raises Invalid_argument if n is not a valid index in s.**

**val create : int -> bytes**

`create n` returns a new byte sequence of length `n`. The sequence is uninitialized and contains arbitrary bytes.

**Raises Invalid_argument if n < 0 or n > Sys.max_string_length[29.60].**

**val make : int -> char -> bytes**

`make n c` returns a new byte sequence of length `n`, filled with the byte `c`.

**Raises Invalid_argument if n < 0 or n > Sys.max_string_length[29.60].**

**val init : int -> f:(int -> char) -> bytes**

`init n f` returns a fresh byte sequence of length `n`, with character `i` initialized to the result of `f i` (in increasing index order).

**Raises Invalid_argument if n < 0 or n > Sys.max_string_length[29.60].**
Remove all ephemerons from the bucket.

end

end

Ephemerons with arbitrary number of keys of the same type.

## 28.19 Module Filename : Operations on file names.

**val current_dir_name : string**

The conventional name for the current directory (e.g. `.` in Unix).

**val parent_dir_name : string**

The conventional name for the parent of the current directory (e.g. `..` in Unix).

**val dir_sep : string**

The directory separator (e.g. `/` in Unix).

**Since: 3.11.2**

**val concat : string -> string -> string**

`concat dir file` returns a file name that designates file `file` in directory `dir`.

**val is_relative : string -> bool**

Return `true` if the file name is relative to the current directory, `false` if it is absolute (i.e. in Unix, starts with `/`).

**val is_implicit : string -> bool**

Return `true` if the file name is relative and does not start with an explicit reference to the current directory (`./` or `../` in Unix), `false` if it starts with an explicit reference to the root directory or the current directory.

**val check_suffix : string -> string -> bool**

`check_suffix name suff` returns `true` if the filename `name` ends with the suffix `suff`.

Under Windows ports (including Cygwin), comparison is case-insensitive, relying on `String.lowercase CHAR` . Note that this does not match exactly the interpretation of case-insensitive filename equivalence from Windows.

**val chop_suffix : string -> string -> string**

`chop_suffix name suff` removes the suffix `suff` from the filename `name`.

**Raises Invalid_argument if name does not end with the suffix suff.**

**val chop_suffix_opt : suffix: string -> string -> string option**
val empty : bytes

A byte sequence of size 0.

val copy : bytes -> bytes

Return a new byte sequence that contains the same bytes as the argument.

val of_string : string -> bytes

Return a new byte sequence that contains the same bytes as the given string.

val to_string : bytes -> string

Return a new string that contains the same bytes as the given byte sequence.

val sub : bytes -> pos:int -> len:int -> bytes

sub s ~pos ~len returns a new byte sequence of length len, containing the subsequence of s that starts at position pos and has length len.

**Raises** Invalid_argument if pos and len do not designate a valid range of s.

val sub_string : bytes -> pos:int -> len:int -> string

Same as BytesLabels.sub[29.9] but return a string instead of a byte sequence.

val extend : bytes -> left:int -> right:int -> bytes

extend s ~left ~right returns a new byte sequence that contains the bytes of s, with left uninitialized bytes prepended and right uninitialized bytes appended to it. If left or right is negative, then bytes are removed (instead of appended) from the corresponding side of s.

**Since:** 4.05 in BytesLabels

**Raises** Invalid_argument if the result length is negative or longer than Sys.max_string_length[29.60] bytes.

val fill : bytes -> pos:int -> len:int -> char -> unit

fill s ~pos ~len c modifies s in place, replacing len characters with c, starting at pos.

**Raises** Invalid_argument if pos and len do not designate a valid range of s.

val blit :

src:bytes -> src_pos:int -> dst:bytes -> dst_pos:int -> len:int -> unit

blit ~src ~src_pos ~dst ~dst_pos ~len copies len bytes from byte sequence src, starting at index src_pos, to byte sequence dst, starting at index dst_pos. It works correctly even if src and dst are the same byte sequence, and the source and destination intervals overlap.

**Raises** Invalid_argument if src_pos and len do not designate a valid range of src, or if dst_pos and len do not designate a valid range of dst.

val blit_string :

src:string -> src_pos:int -> dst:bytes -> dst_pos:int -> len:int -> unit
`chop_suffix_opt ~suffix filename` removes the suffix from the filename if possible, or returns `None` if the filename does not end with the suffix.

Under Windows ports (including Cygwin), comparison is case-insensitive, relying on `String.lowercase CHAR` . Note that this does not match exactly the interpretation of case-insensitive filename equivalence from Windows.

**Since: 4.08**

`val extension : string -> string`

`extension name` is the shortest suffix of name0 where:

* `name0` is the longest suffix of `name` that does not contain a directory separator;

* `ext` starts with a period;

* `ext` is preceded by at least one non-period character in `name0`.

If such a suffix does not exist, `extension name` is the empty string.

**Since: 4.04**

`val remove extension : string -> string`

Return the given file name without its extension, as defined in `Filename.extension` [28.19]. If the extension is empty, the function returns the given file name.

The following invariant holds for any file name `s`:

`remove extension s ^ extension s = s`

**Since: 4.04**

`val chop extension : string -> string`

Same as `Filename.remove extension` [28.19], but raise `Invalid_argument` if the given name has an empty extension.

`val basename : string -> string`

Split a file name into directory name / base file name. If `name` is a valid file name, then `concat (dirname name) (basename name)` returns a file name which is equivalent to `name`. Moreover, after setting the current directory to `dirname name` (with `Sys.chdir` [28.55]), references to `basename name` (which is a relative file name) designate the same file as `name` before the call to `Sys.chdir` [28.55].

This function conforms to the specification of POSIX.1-2008 for the `basename` utility.

`val dirname : string -> string`

See `Filename.basename` [28.19]. This function conforms to the specification of POSIX.1-2008 for the `dirname` utility.

`val null : string`
`blit_string ~src ~src_pos ~dst ~dst_pos ~len` copies `len` bytes from string `src`, starting at index `src_pos`, to byte sequence `dst`, starting at index `dst_pos`.

**Since:** 4.05 in BytesLabels

**Raises** `Invalid_argument` if `src_pos` and `len` do not designate a valid range of `src`, or if `dst_pos` and `len` do not designate a valid range of `dst`.

**val concat : sep:bytes -> bytes list -> bytes**

`concat ~sep sl` concatenates the list of byte sequences `sl`, inserting the separator byte sequence `sep` between each, and returns the result as a new byte sequence.

**Raises** `Invalid_argument` if the result is longer than `Sys.max_string_length[29.60]` bytes.

**val cat : bytes -> bytes -> bytes**

`cat s1 s2` concatenates `s1` and `s2` and returns the result as a new byte sequence.

**Since:** 4.05 in BytesLabels

**Raises** `Invalid_argument` if the result is longer than `Sys.max_string_length[29.60]` bytes.

**val iter : f:(char -> unit) -> bytes -> unit**

`iter ~f s` applies function `f` in turn to all the bytes of `s`. It is equivalent to `f (get s 0); f (get s 1); ...; f (get s (length s - 1));` (.)

**val iteri : f:(int -> char -> unit) -> bytes -> unit**

Same as `BytesLabels.iter[29.9]`, but the function is applied to the index of the byte as first argument and the byte itself as second argument.

**val map : f:(char -> char) -> bytes -> bytes**

`map ~f s` applies function `f` in turn to all the bytes of `s` (in increasing index order) and stores the resulting bytes in a new sequence that is returned as the result.

**val mapi : f:(int -> char -> char) -> bytes -> bytes**

`mapi ~f s` calls `f` with each character of `s` and its index (in increasing index order) and stores the resulting bytes in a new sequence that is returned as the result.

**val fold_left : f:'acc -> char -> 'acc) -> init:'acc -> bytes -> 'acc**

`fold_left f x s` computes `f (... (f (f x (get s 0)) (get s 1)) ...) (get s (n-1)))`, where `n` is the length of `s`.

**Since:** 4.13

**val fold_right : f:(char -> 'acc -> 'acc) -> bytes -> init:'acc -> 'acc**

`fold_right f s x` computes `f (get s 0) (f (get s 1) (... (f (get s (n-1)) x) ...))`, where `n` is the length of `s`.

**Since:** 4.13

**val for_all : f:(char -> bool) -> bytes -> bool**
`null` is `/dev/null` on POSIX and `"NUL"` on Windows. It represents a file on the OS that discards all writes and returns end of file on reads.

**Since: 4.10**

`val temp_file : ?temp_dir: string -> string -> string -> string`

`temp_file` prefix suffix returns the name of a fresh temporary file in the temporary directory. The base name of the temporary file is formed by concatenating `prefix`, then a suitably chosen integer number, then `suffix`. The optional argument `temp_dir` indicates the temporary directory to use, defaulting to the current result of `Filename.get_temp_dir_name[28.19]`. The temporary file is created empty, with permissions `0o600` (readable and writable only by the file owner). The file is guaranteed to be different from any other file that existed when `temp_file` was called.

**Before 3.11.2** no `?temp_dir` optional argument

**Raises** `Sys_error` if the file could not be created.

`val open_temp_file :`

`?mode: open_flag list ->`

`?perms: int ->`

`?temp_dir: string -> string -> string -> string * out_channel`

Same as `Filename.temp_file[28.19]`, but returns both the name of a fresh temporary file, and an output channel opened (atomically) on this file. This function is more secure than `temp_file`: there is no risk that the temporary file will be modified (e.g. replaced by a symbolic link) before the program opens it. The optional argument `mode` is a list of additional flags to control the opening of the file. It can contain one or several of `Open_append`, `Open_binary`, and `Open_text`. The default is `[Open_text]` (open in text mode). The file is created with permissions `perms` (defaults to readable and writable only by the file owner, `0o600`).

**Before 4.03** no `?perms` optional argument

**Before 3.11.2** no `?temp_dir` optional argument

**Raises** `Sys_error` if the file could not be opened.

`val temp_dir : ?temp_dir: string -> ?perms: int -> string -> string -> string`

`temp_dir` prefix suffix creates and returns the name of a fresh temporary directory with permissions `perms` (defaults to `0o700`) inside `temp_dir`. The base name of the temporary directory is formed by concatenating `prefix`, then a suitably chosen integer number, then `suffix`. The optional argument `temp_dir` indicates the temporary directory to use, defaulting to the current result of `Filename.get_temp_dir_name[28.19]`. The temporary directory is created empty, with permissions `0o700` (readable, writable, and searchable only by the file owner). The directory is guaranteed to be different from any other directory that existed when `temp_dir` was called.

If `temp_dir` does not exist, this function does not create it. Instead, it raises `Sys_error`.

**Since: 5.1**

**Raises** `Sys_error` if the directory could not be created.