Модуль 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.0 в 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 ~src ~src_pos ~dst ~dst_pos ~len копирует len байтов из строки src, начиная с индекса src_pos, в последовательность байтов dst, начиная с индекса dst_pos.
- С момента 4.05.0 в 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.0 в 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:('a -> char -> 'a) -> init:'a -> bytes -> 'a
fold_left f x s вычисляет f (... (f (f x (get s 0)) (get s 1)) ...) (get s (n-1)), где n — длина s.
- С момента 4.13.0
val fold_right : f:(char -> 'a -> 'a) -> bytes -> init:'a -> 'a
fold_right f s x вычисляет f (get s 0) (f (get s 1) ( ... (f (get s (n-1)) x) ...)), где n — длина s.
- С момента 4.13.0
val for_all : f:(char -> bool) -> bytes -> bool
for_all p s проверяет, удовлетворяют ли все символы в s предикату p.
- С момента 4.13.0
val exists : f:(char -> bool) -> bytes -> bool
exists p s проверяет, удовлетворяет ли хотя бы один символ из s предикату p.
- С момента 4.13.0
val trim : bytes -> bytes
Возвращает копию аргумента без начальных и конечных пробелов. Байты, рассматриваемые как пробелы, это ASCII-символы ' ', '\012', '\n', '\r', и '\t'.
val escaped : bytes -> bytes
Возвращает копию аргумента, где специальные символы представлены последовательностями экранирования, следуя лексическим соглашениям 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.0
val lowercase_ascii : bytes -> bytes
Возвращает копию аргумента, с переводом всех заглавных букв в строчные, используя US-ASCII набор символов.
- Since 4.05.0
val capitalize_ascii : bytes -> bytes
Возвращает копию аргумента, с первой буквой в заглавную, используя US-ASCII набор символов.
- Since 4.05.0
val uncapitalize_ascii : bytes -> bytes
Возвращает копию аргумента, с первой буквой в строчную, используя US-ASCII набор символов.
- Since 4.05.0
type t = bytes
Псевдоним для типа последовательностей байтов.
val compare : t -> t -> int
val equal : t -> t -> bool
Функция проверки равенства для последовательностей байтов.
- Since 4.05.0
val starts_with : prefix:bytes -> bytes -> bool
starts_with ~prefix s является true тогда и только тогда, когда s начинается с prefix.
- Since 4.13.0
val ends_with : suffix:bytes -> bytes -> bool
ends_with ~suffix s является true тогда и только тогда, когда s заканчивается на suffix.
- Since 4.13.0
Небезопасные преобразования (для продвинутых пользователей)
В этом разделе описаны небезопасные, низкоуровневые функции преобразования между 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.
Выходная функция определяется следующими инвариантами:
- Список не пустой.
- Конкатенация её элементов с разделителем
sepвозвращает последовательность байтов, равную входному значению (Bytes.concat (Bytes.make 1 sep)).
(Bytes.split_on_char sep s) = s - Ни одна последовательность байтов в результате не содержит символ
sep.
- Since 4.13.0
Итераторы
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
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_int32_be b i v устанавливает целое 32-битное число b в формате big-endian, начиная с байтового индекса i, на значение v.
- Since 4.08
val set_int32_le : bytes -> int -> int32 -> unit
set_int32_le b i v устанавливает целое 32-битное число b в формате little-endian, начиная с байтового индекса i, на значение v.
- Since 4.08
val set_int64_ne : bytes -> int -> int64 -> unit
set_int64_ne b i v устанавливает целое 64-битное число b в формате native-endian, начиная с байтового индекса i, на значение v.
- Since 4.08
val set_int64_be : bytes -> int -> int64 -> unit
set_int64_be b i v устанавливает целое 64-битное число b в формате big-endian, начиная с байтового индекса i, на значение v.
- Since 4.08
val set_int64_le : bytes -> int -> int64 -> 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-2022 INRIA.
https://v2.ocaml.org/releases/5.0/htmlman/libref/StdLabels.Bytes.html