Spec-Zone.ru › OCaml

Модуль StdLabels.Bytes

module Bytes: BytesLabels
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

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

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.

  • Since 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.

  • Raises
    • 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.

  • Since 4.05
  • Raises 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.

  • Raises
    • 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.

  • Since 4.05
  • Raises 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
.

  • Raises Invalid_argument если start не является допустимой позицией в s.
val rcontains_from : bytes -> int -> char -> bool

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

  • Raises Invalid_argument если stop < 0 или stop+1 не является допустимой позицией в s.
val uppercase_ascii : bytes -> bytes

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

  • Since 4.05
val lowercase_ascii : bytes -> bytes

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

  • Since 4.05
val capitalize_ascii : bytes -> bytes

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

  • Since 4.05
val uncapitalize_ascii : bytes -> bytes

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

  • Since 4.05
type t = bytes 

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

val compare : t -> t -> int

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

val equal : t -> t -> bool

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

  • Since 4.05
val starts_with : prefix:bytes -> bytes -> bool

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

  • Since 4.13
val ends_with : suffix:bytes -> bytes -> bool

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

  • Since 4.13

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

Этот раздел описывает небезопасные, низкоуровневые функции преобразования между bytes и string. Они не копируют внутренние данные; при неправильном использовании они могут нарушить инвариант неизменяемости строк, предоставляемый опцией -safe-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" — предполагая представление строк в виде веревки. Более общо, функции, работающие со строками, предполагают совместное владение, они не сохраняют уникальное владение. Поэтому неверно предполагать уникальное владение результатом 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.
  • Since 4.13

Итераторы

val to_seq : t -> char Seq.t

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

  • Since 4.07
val to_seqi : t -> (int * char) Seq.t

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

  • Since 4.07
val of_seq : char Seq.t -> t

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

  • Since 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 кодирует UTF-8 u по индексу 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 кодирует UTF-16BE u по индексу 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 кодирует UTF-16LE u по индексу 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.

  • Since 4.08
val get_int8 : bytes -> int -> int

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

  • Since 4.08
val get_uint16_ne : bytes -> int -> int

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

  • Since 4.08
val get_uint16_be : bytes -> int -> int

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

  • Since 4.08
val get_uint16_le : bytes -> int -> int

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

  • Since 4.08
val get_int16_ne : bytes -> int -> int

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

  • Since 4.08
val get_int16_be : bytes -> int -> int

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

  • Since 4.08
val get_int16_le : bytes -> int -> int

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

  • Since 4.08
val get_int32_ne : bytes -> int -> int32

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

  • Since 4.08
val get_int32_be : bytes -> int -> int32

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

  • Since 4.08
val get_int32_le : bytes -> int -> int32

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

  • Since 4.08
val get_int64_ne : bytes -> int -> int64

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

  • Since 4.08
val get_int64_be : bytes -> int -> int64

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

  • Since 4.08
END_OF_DOCUMENT_MARKER
val get_int64_le : bytes -> int -> int64

get_int64_le b i — это целое 64-битное число в формате little-endian, начинающееся с байта с индексом i.

  • Since 4.08
val set_uint8 : bytes -> int -> int -> unit

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

  • Since 4.08
val set_int8 : bytes -> int -> int -> unit

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

  • Since 4.08
val set_uint16_ne : bytes -> int -> int -> unit

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

  • Since 4.08
val set_uint16_be : bytes -> int -> int -> unit

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

  • Since 4.08
val set_uint16_le : bytes -> int -> int -> unit

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

  • Since 4.08
val set_int16_ne : bytes -> int -> int -> unit

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

  • Since 4.08
val set_int16_be : bytes -> int -> int -> unit

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

  • Since 4.08
val set_int16_le : bytes -> int -> int -> unit

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

  • Since 4.08
val set_int32_ne : bytes -> int -> int32 -> unit

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

  • Since 4.08
val set_int32_be : bytes -> int -> int32 -> unit

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

  • Since 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-2024 INRIA.
https://ocaml.org/manual/5.2/api/StdLabels.Bytes.html

Spec-Zone.ru

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