Spec-Zone.ru › OCaml

Модуль BytesLabels

module BytesLabels: sig .. end

Операции с последовательностями байтов.

Последовательность байтов — это изменяемая структура данных, содержащая последовательность байтов фиксированной длины. К каждому байту можно обратиться по индексу за постоянное время для чтения или записи.

Для последовательности байтов s длины l мы можем обратиться к каждому из l байтов s по его индексу в последовательности. Индексы начинаются с 0; индекс в s считается допустимым, если он попадает в диапазон [0...l-1] (включительно). Позиция — это точка между двумя байтами, а также в начале или в конце последовательности. Позиция в s считается допустимой, если она попадает в диапазон [0...l] (включительно). Обратите внимание, что байт с индексом n находится между позициями n и n+1.

Два параметра start и len задают допустимый диапазон в s, если len >= 0 и start, а start+len являются допустимыми позициями в s.

Последовательности байтов можно изменять на месте, например с помощью описанных ниже функций set и blit. См. также строки (модуль String) — это почти такая же структура данных, но её нельзя изменять на месте.

Байты представлены типом OCaml char.

Версию этого модуля с метками можно использовать так, как описано в модуле StdLabels.

  • Начиная с 4.02
val length : bytes -> int

Возвращает длину аргумента (количество байтов).

val get : bytes -> int -> char

get s n возвращает байт с индексом n в аргументе s.

  • Вызывает исключение Invalid_argument, если n не является допустимым индексом в s.
val set : bytes -> int -> char -> unit

set s n c изменяет s на месте, заменяя байт с индексом n на c.

  • Вызывает исключение Invalid_argument, если n не является допустимым индексом в s.
val create : int -> bytes

create n возвращает новую последовательность байтов длины n. Последовательность не инициализирована и содержит произвольные байты.

  • Вызывает исключение Invalid_argument, если n < 0 или n > Sys.max_string_length.
val make : int -> char -> bytes

make n c возвращает новую последовательность байтов длины n, заполненную байтом c.

  • Вызывает исключение Invalid_argument, если n < 0 или n > Sys.max_string_length.
val init : int -> f:(int -> char) -> bytes

init n f возвращает новую последовательность байтов длины n, в которой символ i инициализируется результатом f i (в порядке возрастания индексов).

  • Вызывает исключение Invalid_argument, если n < 0 или n > Sys.max_string_length.
val empty : bytes

Последовательность байтов нулевого размера.

val copy : bytes -> bytes

Возвращает новую последовательность байтов, содержащую те же байты, что и аргумент.

val of_string : string -> bytes

Возвращает новую последовательность байтов, содержащую те же байты, что и заданная строка.

val to_string : bytes -> string

Возвращает новую строку, содержащую те же байты, что и заданная последовательность байтов.

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

sub s ~pos ~len возвращает новую последовательность байтов длины len, содержащую подпоследовательность s, которая начинается с позиции pos и имеет длину len.

  • Вызывает исключение Invalid_argument, если pos и len не задают допустимый диапазон в s.
val sub_string : bytes -> pos:int -> len:int -> string

То же, что и BytesLabels.sub, но возвращает строку вместо последовательности байтов.

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

extend s ~left ~right возвращает новую последовательность байтов, содержащую байты s, перед которыми добавлено left неинициализированных байтов, а после — right неинициализированных байтов. Если left или right отрицательно, байты удаляются (вместо добавления) с соответствующей стороны s.

  • Начиная с 4.05 в BytesLabels
  • Вызывает исключение Invalid_argument, если длина результата отрицательна или превышает Sys.max_string_length байтов.
val fill : bytes -> pos:int -> len:int -> char -> unit

fill s ~pos ~len c изменяет s на месте, заменяя len символов на c, начиная с pos.

  • Вызывает исключение Invalid_argument, если pos и len не задают допустимый диапазон в s.
val blit : src:bytes -> src_pos:int -> dst:bytes -> dst_pos:int -> len:int -> unit

blit ~src ~src_pos ~dst ~dst_pos ~len копирует len байтов из последовательности байтов src, начиная с индекса src_pos, в последовательность байтов dst, начиная с индекса dst_pos. Функция работает корректно, даже если src и dst — одна и та же последовательность байтов, а исходный и целевой интервалы перекрываются.

  • Вызывает исключение Invalid_argument, если src_pos и len не задают допустимый диапазон в src или если dst_pos и len не задают допустимый диапазон в dst.
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 копирует len байтов из строки src, начиная с индекса src_pos, в последовательность байтов dst, начиная с индекса dst_pos.

  • Начиная с 4.05 в BytesLabels
  • Вызывает исключение Invalid_argument, если src_pos и len не задают допустимый диапазон в src или если dst_pos и len не задают допустимый диапазон в dst.
val concat : sep:bytes -> bytes list -> bytes

concat ~sep sl объединяет список последовательностей байтов sl, вставляя между ними разделитель — последовательность байтов sep, и возвращает результат в виде новой последовательности байтов.

  • Вызывает исключение Invalid_argument, если результат превышает Sys.max_string_length байтов.
val cat : bytes -> bytes -> bytes

cat s1 s2 объединяет s1 и s2 и возвращает результат в виде новой последовательности байтов.

  • Начиная с 4.05 в BytesLabels
  • Вызывает исключение Invalid_argument, если результат превышает Sys.max_string_length байтов.
val iter : f:(char -> unit) -> bytes -> unit

iter ~f s последовательно применяет функцию f ко всем байтам s. Эквивалентно f (get s 0); f (get s 1); ...; f (get s
    (length s - 1)); ()
.

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

То же, что и BytesLabels.iter, но функция получает индекс байта в качестве первого аргумента, а сам байт — в качестве второго.

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

map ~f s последовательно применяет функцию f ко всем байтам s (в порядке возрастания индексов) и сохраняет полученные байты в новой последовательности, которую возвращает в качестве результата.

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

mapi ~f s вызывает f для каждого символа s и его индекса (в порядке возрастания индексов), а полученные байты сохраняет в новой последовательности, которую возвращает в качестве результата.

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

fold_left f x s вычисляет f (... (f (f x (get s 0)) (get s 1)) ...) (get s (n-1)), где n — длина s.

  • Начиная с 4.13
val fold_right : f:(char -> 'acc -> 'acc) -> bytes -> init:'acc -> 'acc

fold_right f s x вычисляет f (get s 0) (f (get s 1) ( ... (f (get s (n-1)) x) ...)), где n — длина s.

  • Начиная с 4.13
val for_all : f:(char -> bool) -> bytes -> bool

for_all p s проверяет, удовлетворяют ли все символы в s предикату p.

  • Начиная с 4.13
val exists : f:(char -> bool) -> bytes -> bool

exists p s проверяет, удовлетворяет ли хотя бы один символ в s предикату p.

  • Начиная с 4.13
val trim : bytes -> bytes

Возвращает копию аргумента без начальных и конечных пробельных символов. К пробельным относятся символы ASCII ' ', '\012', '\n', '\r' и '\t'.

val escaped : bytes -> bytes

Возвращает копию аргумента, в которой специальные символы представлены escape-последовательностями согласно лексическим правилам OCaml. Все символы за пределами диапазона печатных символов ASCII (32..126), а также обратная косая черта и двойная кавычка экранируются.

  • Вызывает исключение Invalid_argument, если результат превышает Sys.max_string_length байтов.
val index : bytes -> char -> int

index s c возвращает индекс первого вхождения байта c в s.

  • Вызывает исключение Not_found, если c не встречается в s.
val index_opt : bytes -> char -> int option

index_opt s c возвращает индекс первого вхождения байта c в s или None, если c не встречается в s.

  • Начиная с 4.05
val rindex : bytes -> char -> int

rindex s c возвращает индекс последнего вхождения байта c в s.

  • Вызывает исключение Not_found, если c не встречается в s.
val rindex_opt : bytes -> char -> int option

rindex_opt s c возвращает индекс последнего вхождения байта c в s или None, если c не встречается в s.

  • Начиная с 4.05
val index_from : bytes -> int -> char -> int

index_from s i c возвращает индекс первого вхождения байта c в s после позиции i. index s c эквивалентно index_from s 0 c.

  • Вызывает исключение
    • Invalid_argument, если i не является допустимой позицией в s.
    • Not_found, если c не встречается в s после позиции i.
val index_from_opt : bytes -> int -> char -> int option

index_from_opt s i c возвращает индекс первого вхождения байта c в s после позиции i или None, если c не встречается в s после позиции i. index_opt s c эквивалентно index_from_opt s 0 c.

  • Начиная с 4.05
  • Вызывает исключение Invalid_argument, если i не является допустимой позицией в s.
val rindex_from : bytes -> int -> char -> int

rindex_from s i c возвращает индекс последнего вхождения байта c в s перед позицией i+1. rindex s c эквивалентно rindex_from s (length s - 1) c.

  • Вызывает исключение
    • Invalid_argument, если i+1 не является допустимой позицией в s.
    • Not_found, если c не встречается в s перед позицией i+1.
val rindex_from_opt : bytes -> int -> char -> int option

rindex_from_opt s i c возвращает индекс последнего вхождения байта c в s перед позицией i+1 или None, если c не встречается в s перед позицией i+1. rindex_opt s c эквивалентно rindex_from s (length s - 1) c.

  • Начиная с 4.05
  • Вызывает исключение Invalid_argument, если i+1 не является допустимой позицией в s.
val contains : bytes -> char -> bool

contains s c проверяет, встречается ли байт c в s.

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

contains_from s start c проверяет, встречается ли байт c в s после позиции start. contains s c эквивалентно contains_from
    s 0 c
.

  • Вызывает исключение Invalid_argument, если start не является допустимой позицией в s.
val rcontains_from : bytes -> int -> char -> bool

rcontains_from s stop c проверяет, встречается ли байт c в s перед позицией stop+1.

  • Вызывает исключение Invalid_argument, если stop < 0 или stop+1 не является допустимой позицией в s.
val uppercase_ascii : bytes -> bytes

Возвращает копию аргумента, в которой все строчные буквы преобразованы в прописные с использованием набора символов US-ASCII.

  • Начиная с 4.05
val lowercase_ascii : bytes -> bytes

Возвращает копию аргумента, в которой все прописные буквы преобразованы в строчные с использованием набора символов US-ASCII.

  • Начиная с 4.05
val capitalize_ascii : bytes -> bytes

Возвращает копию аргумента, в которой первый символ преобразован в прописную букву с использованием набора символов US-ASCII.

  • Начиная с 4.05
val uncapitalize_ascii : bytes -> bytes

Возвращает копию аргумента, в которой первый символ преобразован в строчную букву с использованием набора символов US-ASCII.

  • Начиная с 4.05
type t = bytes 

Псевдоним типа последовательностей байтов.

val compare : t -> t -> int

Функция сравнения последовательностей байтов с той же спецификацией, что и у compare. Вместе с типом t эта функция compare позволяет передавать модуль Bytes в качестве аргумента функторам Set.Make и Map.Make.

val equal : t -> t -> bool

Функция проверки равенства последовательностей байтов.

  • Начиная с 4.05
val starts_with : prefix:bytes -> bytes -> bool

starts_with ~prefix s — это true тогда и только тогда, когда s начинается с prefix.

  • Начиная с 4.13
val ends_with : suffix:bytes -> bytes -> bool

ends_with ~suffix s — это true тогда и только тогда, когда s заканчивается на suffix.

  • Начиная с 4.13

Небезопасные преобразования (для опытных пользователей)

В этом разделе описаны небезопасные низкоуровневые функции преобразования между bytes и string. Они не копируют внутренние данные; при неправильном использовании они могут нарушить инвариант неизменяемости строк. Эти функции доступны опытным авторам библиотек, но в большинстве случаев следует использовать всегда корректные функции BytesLabels.to_string и BytesLabels.of_string.

val unsafe_to_string : bytes -> string

Небезопасно преобразует последовательность байтов в строку.

Чтобы рассуждать об использовании unsafe_to_string, удобно рассмотреть дисциплину «владения». Фрагмент кода, который работает с данными, «владеет» ими; существует несколько непересекающихся режимов владения, включая следующие:

  • Единоличное владение: данные можно читать и изменять
  • Совместное владение: у данных несколько владельцев, которые могут только читать их, но не изменять.

Единоличное владение линейно: передача данных другому фрагменту кода означает отказ от владения ими (мы больше не можем записывать данные). Единоличный владелец может сделать данные совместно используемыми (отказавшись от права изменять их), но совместно используемые данные уже не могут снова стать объектом единоличного владения.

unsafe_to_string s можно использовать, только если вызывающий код владеет последовательностью байтов s — единолично или как неизменяемыми совместно используемыми данными. Вызывающий код отказывается от владения s и получает владение возвращённой строкой.

Этой дисциплине владения соответствуют два допустимых варианта использования:

1. Создание строки посредством инициализации и изменения последовательности байтов, которая больше не изменяется после завершения инициализации.

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
   

Эта функция безопасна, поскольку к последовательности байтов s больше никогда не будут обращаться и её не будут изменять после вызова unsafe_to_string. Код string_init отказывается от владения s и возвращает владение результирующей строкой вызывающему коду.

Обратите внимание, что это было бы небезопасно, если бы s передавался в качестве дополнительного параметра функции f, поскольку таким образом он мог бы стать доступен извне и быть изменён в будущем: string_init отказался бы от владения s, передав его в f, и не смог бы безопасно вызвать unsafe_to_string.

Мы предоставили функции String.init, String.map и String.mapi, покрывающие большинство случаев создания новых строк. Если возможно, следует предпочитать их функциям to_string или unsafe_to_string.

2. Временная передача владения последовательностью байтов функции, которая ожидает строку в единоличном владении и возвращает владение обратно, чтобы после завершения вызова снова можно было изменять последовательность.

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

В этом случае мы не гарантируем, что s никогда не будет изменено после вызова bytes_length s. Функция String.length временно заимствует единоличное владение последовательностью байтов (и видит её как string), но возвращает владение вызывающему коду, который вправе считать, что s остаётся допустимой последовательностью байтов после вызова. Обратите внимание, что это корректно лишь потому, что мы знаем: String.length не сохраняет свой аргумент — он мог бы стать доступен извне через побочный канал, например комбинатор мемоизации.

Вызывающий код не должен изменять s, пока строка заимствована (в это время он временно отказался от владения). Это важно для конкурентных программ, а также для функций высшего порядка: если String.length возвращает замыкание для последующего вызова, s не следует изменять, пока это замыкание не будет полностью применено и не вернёт владение.

val unsafe_of_string : string -> bytes

Небезопасно преобразует совместно используемую строку в последовательность байтов, которую не следует изменять.

Та же дисциплина владения, которая обеспечивает корректность unsafe_to_string, применима и к unsafe_of_string: её можно использовать, если вы владели значением string, и возвращённым значением bytes вы будете владеть в том же режиме.

На практике крайне сложно корректно рассуждать о единоличном владении значениями строк. Всегда следует считать строки совместно используемыми, а не находящимися в единоличном владении.

Например, строковые литералы неявно совместно используются компилятором, поэтому единолично владеть ими невозможно.

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

Первое объявление некорректно, поскольку строковый литерал "hello" может совместно использоваться компилятором с другими частями программы, а изменение incorrect является ошибкой. Следует всегда использовать второй вариант, который выполняет копирование и поэтому является корректным.

Также некорректно предполагать единоличное владение строками, которые не являются строковыми литералами, но частично или полностью созданы на основе строковых литералов. Например, изменение unsafe_of_string ("foo" ^ s) может изменить совместно используемую строку "foo" — если предположить, что строки представлены в виде, подобном rope. В общем случае функции, работающие со строками, предполагают совместное владение и не сохраняют единоличное владение. Поэтому предполагать единоличное владение результатом unsafe_of_string некорректно.

Единственный случай, в котором мы с достаточной уверенностью можем считать это безопасным, — если созданное значение bytes используется совместно как неизменяемая последовательность байтов. Это может быть полезно для постепенной миграции низкоуровневых программ, работающих с неизменяемыми последовательностями байтов (например, Marshal.from_bytes) и ранее использовавших для этой цели тип string.

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

split_on_char sep s возвращает список всех (возможно, пустых) подпоследовательностей s, разделённых символом sep. Если s пусто, результатом является список из одного элемента [empty].

Результат функции определяется следующими инвариантами:

  • Список не пуст.
  • Объединение его элементов с использованием sep в качестве разделителя возвращает последовательность байтов, равную исходной (Bytes.concat (Bytes.make 1 sep)
          (Bytes.split_on_char sep s) = s
    ).
  • Ни одна последовательность байтов в результате не содержит символ sep.
  • Начиная с 4.13

Итераторы

val to_seq : t -> char Seq.t

Выполняет итерацию по строке в порядке возрастания индексов. Изменения строки во время итерации будут отражены в последовательности.

  • Начиная с 4.07
val to_seqi : t -> (int * char) Seq.t

Выполняет итерацию по строке в порядке возрастания индексов, возвращая индексы вместе с символами.

  • Начиная с 4.07
val of_seq : char Seq.t -> t

Создаёт строку из генератора.

  • Начиная с 4.07

Кодеки UTF и проверка корректности

UTF-8

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

get_utf_8_uchar b i декодирует символ UTF-8 с индексом i в b.

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

set_utf_8_uchar b i u кодирует u в UTF-8 по индексу i в b и возвращает количество записанных байтов n, начиная с i. Если n равно 0, места для кодирования u в i было недостаточно, и b осталось без изменений. В противном случае по адресу i + n можно закодировать новый символ.

val is_valid_utf_8 : t -> bool

is_valid_utf_8 b равно true тогда и только тогда, когда b содержит корректные данные UTF-8.

UTF-16BE

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

get_utf_16be_uchar b i декодирует символ UTF-16BE с индексом i в b.

val set_utf_16be_uchar : t -> int -> Uchar.t -> int

set_utf_16be_uchar b i u кодирует u в UTF-16BE по индексу i в b и возвращает количество записанных байтов n, начиная с i. Если n равно 0, места для кодирования u в i было недостаточно, и b осталось без изменений. В противном случае по адресу i + n можно закодировать новый символ.

val is_valid_utf_16be : t -> bool

is_valid_utf_16be b равно true тогда и только тогда, когда b содержит корректные данные UTF-16BE.

UTF-16LE

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

get_utf_16le_uchar b i декодирует символ UTF-16LE с индексом i в b.

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

set_utf_16le_uchar b i u кодирует u в UTF-16LE по индексу i в b и возвращает количество записанных байтов n, начиная с i. Если n равно 0, места для кодирования u в i было недостаточно, и b осталось без изменений. В противном случае по адресу i + n можно закодировать новый символ.

val is_valid_utf_16le : t -> bool

is_valid_utf_16le b равно true тогда и только тогда, когда b содержит корректные данные UTF-16LE.

Двоичное кодирование и декодирование целых чисел

Функции в этом разделе выполняют двоичное кодирование и декодирование целых чисел в последовательности байтов и из них.

Все следующие функции вызывают исключение Invalid_argument, если в позиции i недостаточно места для декодирования или кодирования целого числа.

Кодирование с порядком байтов от младшего к старшему (соответственно, от старшего к младшему) означает, что сначала сохраняются младшие (соответственно, старшие) значащие байты. Порядок байтов от старшего к младшему также известен как сетевой порядок байтов. Порядок байтов платформы — от младшего к старшему или от старшего к младшему — зависит от Sys.big_endian.

32-битные и 64-битные целые числа представлены типами int32 и int64, которые можно интерпретировать как знаковые или беззнаковые числа.

8-битные и 16-битные целые числа представлены типом int, который содержит больше битов, чем их двоичное представление. Дополнительные биты обрабатываются следующим образом:

  • Функции, декодирующие знаковые (соответственно, беззнаковые) 8-битные или 16-битные целые числа, представленные значениями int, расширяют результат знаком (соответственно, нулями).
  • Функции, кодирующие 8-битные или 16-битные целые числа, представленные значениями int, отбрасывают старшие байты входного значения.
val get_uint8 : bytes -> int -> int

get_uint8 b i — это беззнаковое 8-битное целое число в b, начиная с байтовой позиции i.

  • Начиная с версии 4.08
val get_int8 : bytes -> int -> int

get_int8 b i — это знаковое 8-битное целое число в b, начиная с байтовой позиции i.

  • Начиная с версии 4.08
val get_uint16_ne : bytes -> int -> int

get_uint16_ne b i — это беззнаковое 16-битное целое число в порядке байтов платформы в b, начиная с байтовой позиции i.

  • Начиная с версии 4.08
val get_uint16_be : bytes -> int -> int

get_uint16_be b i — это беззнаковое 16-битное целое число с порядком байтов от старшего к младшему в b, начиная с байтовой позиции i.

  • Начиная с версии 4.08
val get_uint16_le : bytes -> int -> int

get_uint16_le b i — это беззнаковое 16-битное целое число с порядком байтов от младшего к старшему в b, начиная с байтовой позиции i.

  • Начиная с версии 4.08
val get_int16_ne : bytes -> int -> int

get_int16_ne b i — это знаковое 16-битное целое число в порядке байтов платформы в b, начиная с байтовой позиции i.

  • Начиная с версии 4.08
val get_int16_be : bytes -> int -> int

get_int16_be b i — это знаковое 16-битное целое число с порядком байтов от старшего к младшему в b, начиная с байтовой позиции i.

  • Начиная с версии 4.08
val get_int16_le : bytes -> int -> int

get_int16_le b i — это знаковое 16-битное целое число с порядком байтов от младшего к старшему в b, начиная с байтовой позиции i.

  • Начиная с версии 4.08
val get_int32_ne : bytes -> int -> int32

get_int32_ne b i — это 32-битное целое число в порядке байтов платформы в b, начиная с байтовой позиции i.

  • Начиная с версии 4.08
val get_int32_be : bytes -> int -> int32

get_int32_be b i — это 32-битное целое число с порядком байтов от старшего к младшему в b, начиная с байтовой позиции i.

  • Начиная с версии 4.08
val get_int32_le : bytes -> int -> int32

get_int32_le b i — это 32-битное целое число с порядком байтов от младшего к старшему в b, начиная с байтовой позиции i.

  • Начиная с версии 4.08
val get_int64_ne : bytes -> int -> int64

get_int64_ne b i — это 64-битное целое число в порядке байтов платформы в b, начиная с байтовой позиции i.

  • Начиная с версии 4.08
val get_int64_be : bytes -> int -> int64

get_int64_be b i — это 64-битное целое число с порядком байтов от старшего к младшему в b, начиная с байтовой позиции i.

  • Начиная с версии 4.08
val get_int64_le : bytes -> int -> int64

get_int64_le b i — это 64-битное целое число с порядком байтов от младшего к старшему в b, начиная с байтовой позиции i.

  • Начиная с версии 4.08
val set_uint8 : bytes -> int -> int -> unit

set_uint8 b i v записывает значение v как беззнаковое 8-битное целое число в b, начиная с байтовой позиции i.

  • Начиная с версии 4.08
val set_int8 : bytes -> int -> int -> unit

set_int8 b i v записывает значение v как знаковое 8-битное целое число в b, начиная с байтовой позиции i.

  • Начиная с версии 4.08
val set_uint16_ne : bytes -> int -> int -> unit

set_uint16_ne b i v записывает значение v как беззнаковое 16-битное целое число в порядке байтов платформы в b, начиная с байтовой позиции i.

  • Начиная с версии 4.08
val set_uint16_be : bytes -> int -> int -> unit

set_uint16_be b i v записывает значение v как беззнаковое 16-битное целое число с порядком байтов от старшего к младшему в b, начиная с байтовой позиции i.

  • Начиная с версии 4.08
val set_uint16_le : bytes -> int -> int -> unit

set_uint16_le b i v записывает значение v как беззнаковое 16-битное целое число с порядком байтов от младшего к старшему в b, начиная с байтовой позиции i.

  • Начиная с версии 4.08
val set_int16_ne : bytes -> int -> int -> unit

set_int16_ne b i v записывает значение v как знаковое 16-битное целое число в порядке байтов платформы в b, начиная с байтовой позиции i.

  • Начиная с версии 4.08
val set_int16_be : bytes -> int -> int -> unit

set_int16_be b i v записывает значение v как знаковое 16-битное целое число с порядком байтов от старшего к младшему в b, начиная с байтовой позиции i.

  • Начиная с версии 4.08
val set_int16_le : bytes -> int -> int -> unit

set_int16_le b i v записывает значение v как знаковое 16-битное целое число с порядком байтов от младшего к старшему в b, начиная с байтовой позиции i.

  • Начиная с версии 4.08
val set_int32_ne : bytes -> int -> int32 -> unit

set_int32_ne b i v записывает значение v как 32-битное целое число в порядке байтов платформы в b, начиная с байтовой позиции i.

  • Начиная с версии 4.08
val set_int32_be : bytes -> int -> int32 -> unit

set_int32_be b i v записывает значение v как 32-битное целое число с порядком байтов от старшего к младшему в b, начиная с байтовой позиции i.

  • Начиная с версии 4.08
val set_int32_le : bytes -> int -> int32 -> unit

set_int32_le b i v записывает значение v как 32-битное целое число с порядком байтов от младшего к старшему в b, начиная с байтовой позиции i.

  • Начиная с версии 4.08
val set_int64_ne : bytes -> int -> int64 -> unit

set_int64_ne b i v записывает значение v как 64-битное целое число в порядке байтов платформы в b, начиная с байтовой позиции i.

  • Начиная с версии 4.08
val set_int64_be : bytes -> int -> int64 -> unit

set_int64_be b i v записывает значение v как 64-битное целое число с порядком байтов от старшего к младшему в b, начиная с байтовой позиции i.

  • Начиная с версии 4.08
val set_int64_le : bytes -> int -> int64 -> unit

set_int64_le b i v записывает значение v как 64-битное целое число с порядком байтов от младшего к старшему в b, начиная с байтовой позиции i.

  • Начиная с версии 4.08

Последовательности байтов и безопасность при параллельном выполнении

При одновременном доступе к последовательностям байтов из нескольких доменов следует соблюдать осторожность: обращение к последовательности байтов никогда не приведёт к аварийному завершению программы, однако несинхронизированный доступ может дать неожиданные результаты (не соответствующие последовательной согласованности).

Атомарность

Любая операция с последовательностью байтов, обращающаяся более чем к одному байту, не является атомарной. Это относится также к итерации и поиску.

Например, рассмотрим следующую программу:

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

последовательность байтов b может содержать недетерминированную смесь значений '!', 'A', 'B' и 'C'.

После выполнения этого кода каждый байт последовательности b будет равен '!', 'A', 'B' или 'C'. Если требуется атомарность, пользователь должен самостоятельно реализовать синхронизацию (например, с помощью Mutex.t).

Состояния гонки

Если два домена обращаются только к непересекающимся частям последовательности байтов, наблюдаемое поведение эквивалентно некоторому последовательному чередованию операций этих двух доменов.

Состояние гонки возникает, когда два домена обращаются к одному и тому же байту без синхронизации и хотя бы одно из обращений является записью. При отсутствии состояний гонки наблюдаемое поведение эквивалентно некоторому последовательному чередованию операций из разных доменов.

По возможности следует избегать состояний гонки, используя синхронизацию для упорядочивания обращений к элементам последовательности.

Действительно, при наличии состояний гонки программы не аварийно завершаются, однако наблюдаемое поведение может не быть эквивалентно никакому последовательному чередованию операций из разных доменов. Тем не менее даже при наличии состояний гонки операция чтения вернёт значение некоторой предыдущей записи в эту позицию.

Доступы разного размера

Ещё один тонкий момент: если состояние гонки включает записи и чтения разного размера в одну и ту же позицию, порядок, в котором домены наблюдают эти записи и чтения, не определён. Например, следующий код последовательно записывает 32-битное целое число и char в одну и ту же позицию

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

В этой ситуации домен, наблюдающий запись значения «d» в b.0, не обязательно также увидит запись в позиции 1, 2 или 3.

© 1995-2026 INRIA.
https://ocaml.org/manual/5.5/api/BytesLabels.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API