Модуль Bytes
module Bytes: 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.
- Since 4.02
val length : bytes -> int
Возвращает длину (количество байтов) аргумента.
val get : bytes -> int -> char
get s n возвращает байт с индексом n в аргументе s.
-
Raises
Invalid_argumentеслиnне является допустимым индексом вs.
val set : bytes -> int -> char -> unit
set s n c изменяет s на месте, заменяя байт с индексом n на c.
-
Raises
Invalid_argumentеслиnне является допустимым индексом вs.
val create : int -> bytes
create n возвращает новую последовательность байтов длиной n. Последовательность неинициализирована и содержит произвольные байты.
-
Raises
Invalid_argumentеслиn < 0илиn >Sys.max_string_length.
val make : int -> char -> bytes
make n c возвращает новую последовательность байтов длиной n, заполненную байтом c.
-
Raises
Invalid_argumentеслиn < 0илиn >Sys.max_string_length.
val init : int -> (int -> char) -> bytes
init n f возвращает новую последовательность байтов длиной n, с символом i инициализированным результатом f i (в порядке возрастания индекса).
-
Raises
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 -> int -> int -> bytes
sub s pos len возвращает новую последовательность байтов длиной len, содержащую подпоследовательность s, которая начинается с позиции pos и имеет длину len.
-
Raises
Invalid_argumentеслиposиlenне определяют допустимого диапазонаs.
val sub_string : bytes -> int -> int -> string
То же, что и Bytes.sub, но возвращает строку вместо последовательности байтов.
val extend : bytes -> int -> int -> bytes
extend s left right возвращает новую последовательность байтов, которая содержит байты s, с left неинициализированными байтами, добавленными в начало, и right неинициализированными байтами, добавленными в конец. Если left или right отрицательны, то байты удаляются (а не добавляются) с соответствующей стороны от s.
- Since 4.05 in BytesLabels
-
Raises
Invalid_argumentесли длина результата отрицательна или длиннее, чемSys.max_string_lengthбайт.
val fill : bytes -> int -> int -> char -> unit
fill s pos len c изменяет s на месте, заменяя len символов на c, начиная с pos.
-
Raises
Invalid_argumentеслиposиlenне определяют допустимый диапазонs.
val blit : bytes -> int -> bytes -> int -> int -> unit
blit src src_pos dst dst_pos len копирует len байтов из последовательности байтов src, начиная с индекса src_pos, в последовательность байтов dst, начиная с индекса dst_pos . Она работает корректно даже если src и dst — одна и та же последовательность байтов, и интервалы источника и назначения перекрываются.
-
Raises
Invalid_argumentеслиsrc_posиlenне определяют допустимый диапазонsrc, или еслиdst_posиlenне определяют допустимый диапазонdst.
val blit_string : string -> int -> bytes -> int -> int -> unit
blit_string src src_pos dst dst_pos len копирует len байтов из строки src, начиная с индекса src_pos, в последовательность байтов dst, начиная с индекса dst_pos.
- Since 4.05 in BytesLabels
-
Raises
Invalid_argumentеслиsrc_posиlenне определяют допустимый диапазонsrc, или еслиdst_posиlenне определяют допустимый диапазонdst.
val concat : bytes -> bytes list -> bytes
concat sep sl конкатенирует список последовательностей байтов sl, вставляя разделительную последовательность байтов sep между каждыми, и возвращает результат как новую последовательность байтов.
-
Raises
Invalid_argumentесли результат длиннее, чемSys.max_string_lengthбайт.
val cat : bytes -> bytes -> bytes
cat s1 s2 конкатенирует s1 и s2 и возвращает результат как новую последовательность байтов.
- Since 4.05 in BytesLabels
-
Raises
Invalid_argumentесли результат длиннее, чемSys.max_string_lengthбайт.
val iter : (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 : (int -> char -> unit) -> bytes -> unit
То же, что и Bytes.iter, но функция применяется к индексу байта в качестве первого аргумента, а сам байт — как второй аргумент.
val map : (char -> char) -> bytes -> bytes
map f s применяет функцию f поочередно ко всем байтам s (в порядке возрастания индекса) и сохраняет получившиеся байты в новой последовательности, которая возвращается как результат.
val mapi : (int -> char -> char) -> bytes -> bytes
mapi f s вызывает f с каждым символом s и его индексом (в порядке возрастания индекса) и сохраняет получившиеся байты в новой последовательности, которая возвращается в качестве результата.
val fold_left : ('acc -> char -> 'acc) -> 'acc -> bytes -> 'acc
fold_left f x s вычисляет f (... (f (f x (get s 0)) (get s 1)) ...) (get s (n-1)), где n — длина s.
- Since 4.13
val fold_right : (char -> 'acc -> 'acc) -> bytes -> 'acc -> 'acc
fold_right f s x вычисляет f (get s 0) (f (get s 1) ( ... (f (get s (n-1)) x) ...)), где n — длина s.
- Since 4.13
val for_all : (char -> bool) -> bytes -> bool
for_all p s проверяет, удовлетворяют ли все символы в s предикату p.
- Since 4.13
val exists : (char -> bool) -> bytes -> bool
exists p s проверяет, удовлетворяет ли хотя бы один символ в s предикату p.
- Since 4.13
val trim : bytes -> bytes
Возвращает копию аргумента, без начальных и конечных пробелов. Байты, рассматриваемые как пробелы, — это символы ASCII ' ', '\012', '\n', '\r', и '\t'.
val escaped : bytes -> bytes
Возвращает копию аргумента, в котором специальные символы представлены последовательностями экранирования в соответствии с лексическими соглашениями OCaml. Все символы за пределами диапазона ASCII печатных символов (32..126), а также обратная косая черта и двойная кавычка, экранируются.
-
Raises
Invalid_argumentесли результат длиннее, чемSys.max_string_lengthбайт.
val index : bytes -> char -> int
index s c возвращает индекс первого вхождения байта c в s.
-
Raises
Not_foundеслиcне встречается вs.
val index_opt : bytes -> char -> int option
index_opt s c возвращает индекс первого вхождения байта c в s или None если c не встречается в s.
- Since 4.05
val rindex : bytes -> char -> int
rindex s c возвращает индекс последнего вхождения байта c в s.
-
Raises
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.03 (4.05 в BytesLabels)
val lowercase_ascii : bytes -> bytes
Возвращает копию аргумента, в котором все прописные буквы заменены строчными, используя US-ASCII набор символов.
- Since 4.03 (4.05 в BytesLabels)
val capitalize_ascii : bytes -> bytes
Возвращает копию аргумента, в котором первый символ заменён прописным, используя US-ASCII набор символов.
- Since 4.03 (4.05 в BytesLabels)
val uncapitalize_ascii : bytes -> bytes
Возвращает копию аргумента, в котором первый символ заменён строчным, используя US-ASCII набор символов.
- Since 4.03 (4.05 в BytesLabels)
type t = bytes
Псевдоним для типа последовательностей байтов.
val compare : t -> t -> int
val equal : t -> t -> bool
Функция равенства для последовательностей байтов.
- Since 4.03 (4.05 в BytesLabels)
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 . Они доступны для разработчиков экспертных библиотек, но для большинства целей следует использовать всегда корректные Bytes.to_string и Bytes.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 : 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 является b беззнаковым 8-битным целым числом, начинающимся с байта с индексом i.
- Since 4.08
val get_int8 : bytes -> int -> int
get_int8 b i является b знаковым 8-битным целым числом, начинающимся с байта с индексом i.
- Since 4.08
val get_uint16_ne : bytes -> int -> int
get_uint16_ne b i является b беззнаковым 16-битным целым числом в собственном порядке байтов, начинающимся с байта с индексом i.
- Since 4.08
val get_uint16_be : bytes -> int -> int
get_uint16_be b i является b беззнаковым 16-битным целым числом в прямом порядке байтов, начинающимся с байта с индексом i.
- Since 4.08
val get_uint16_le : bytes -> int -> int
get_uint16_le b i является b беззнаковым 16-битным целым числом в обратном порядке байтов, начинающимся с байта с индексом i.
- Since 4.08
val get_int16_ne : bytes -> int -> int
get_int16_ne b i является b знаковым 16-битным целым числом в собственном порядке байтов, начинающимся с байта с индексом i.
- Since 4.08
val get_int16_be : bytes -> int -> int
get_int16_be b i является b знаковым 16-битным целым числом в прямом порядке байтов, начинающимся с байта с индексом i.
- Since 4.08
val get_int16_le : bytes -> int -> int
get_int16_le b i является b знаковым 16-битным целым числом в обратном порядке байтов, начинающимся с байта с индексом i.
- Since 4.08
val get_int32_ne : bytes -> int -> int32
get_int32_ne b i является b 32-битным целым числом в собственном порядке байтов, начинающимся с байта с индексом i.
- Since 4.08
val get_int32_be : bytes -> int -> int32
get_int32_be b i является b 32-битным целым числом в прямом порядке байтов, начинающимся с байта с индексом i.
- Since 4.08
val get_int32_le : bytes -> int -> int32
get_int32_le b i является b 32-битным целым числом в обратном порядке байтов, начинающимся с байта с индексом i.
- Since 4.08
val get_int64_ne : bytes -> int -> int64
get_int64_ne b i является b 64-битным целым числом в собственном порядке байтов, начинающимся с байта с индексом i.
- Since 4.08
val get_int64_be : bytes -> int -> int64
get_int64_be b i является b 64-битным целым числом в прямом порядке байтов, начинающимся с байта с индексом i.
- Since 4.08
val get_int64_le : bytes -> int -> int64
get_int64_le b i является b 64-битным целым числом в обратном порядке байтов, начинающимся с байта с индексом 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 в собственном порядке байтов, начинающееся с байта с индексом i, в v.
- Since 4.08
val set_uint16_be : bytes -> int -> int -> unit
set_uint16_be b i v устанавливает беззнаковое 16-битное целое число b в прямом порядке байтов, начинающееся с байта с индексом i, в v.
- Since 4.08
val set_uint16_le : bytes -> int -> int -> unit
set_uint16_le b i v устанавливает беззнаковое 16-битное целое число b в обратном порядке байтов, начинающееся с байта с индексом i, в v.
- Since 4.08
val set_int16_ne : bytes -> int -> int -> unit
set_int16_ne b i v устанавливает знаковое 16-битное целое число b в собственном порядке байтов, начинающееся с байта с индексом i, в v.
- Since 4.08
val set_int16_be : bytes -> int -> int -> unit
set_int16_be b i v устанавливает знаковое 16-битное целое число b в прямом порядке байтов, начинающееся с байта с индексом i, в v.
- Since 4.08
val set_int16_le : bytes -> int -> int -> unit
set_int16_le b i v устанавливает знаковое 16-битное целое число b в обратном порядке байтов, начинающееся с байта с индексом i, в v.
- Since 4.08
val set_int32_ne : bytes -> int -> int32 -> unit
set_int32_ne b i v устанавливает 32-битное целое число b в собственном порядке байтов, начинающееся с байта с индексом i, в v.
- Since 4.08
val set_int32_be : bytes -> int -> int32 -> unit
set_int32_be b i v устанавливает 32-битное целое число b в прямом порядке байтов, начинающееся с байта с индексом i, в v.
- Since 4.08
val set_int32_le : bytes -> int -> int32 -> unit
set_int32_le b i v устанавливает 32-битное целое число b в обратном порядке байтов, начинающееся с байта с индексом i, в v.
- Since 4.08
val set_int64_ne : bytes -> int -> int64 -> unit
set_int64_ne b i v устанавливает 64-битное целое число b в собственном порядке байтов, начинающееся с байта с индексом i, в v.
- Since 4.08
val set_int64_be : bytes -> int -> int64 -> unit
set_int64_be b i v устанавливает 64-битное целое число b в прямом порядке байтов, начинающееся с байта с индексом i, в v.
- Since 4.08
val set_int64_le : bytes -> int -> int64 -> unit
set_int64_le b i v устанавливает 64-битное целое число b в обратном порядке байтов, начинающееся с байта с индексом 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/Bytes.html