API reference
SIMD Unicode validation and transcoding, plus base64, in Zig with no C.
enum
Error
src
pub const Error = result.Error
Why an input was rejected. The UTF kinds and their positions match
simdutf's error_code and result, so simdutf is a differential oracle.
Fields
none none
header_bits header_bits
A UTF-8 byte of the form 11111xxx.
too_short too_short
A UTF-8 sequence that ends before its continuation bytes do.
too_long too_long
A continuation byte where none was expected.
overlong overlong
A UTF-8 sequence longer than the shortest one for its code point, including the leads 0xC0 and 0xC1.
too_large too_large
A code point above U+10FFFF, including 4-byte sequences led by 0xF5-0xF7.
surrogate surrogate
A surrogate code point (U+D800-U+DFFF) in UTF-8 or UTF-32, or an unpaired surrogate in UTF-16.
not_ascii not_ascii
A byte above 0x7F where only ASCII is allowed.
invalid_base64_character invalid_base64_character
A byte that is not in the base64 alphabet and not ignorable space.
base64_input_remainder base64_input_remainder
Base64 input whose last chunk cannot be decoded under the options.
base64_extra_bits base64_extra_bits
Base64 input with nonzero bits in the padding position.
output_buffer_too_small output_buffer_too_small
The output buffer is smaller than the operation needs.
module
scalar
src
Scalar reference implementations, one code unit at a time. They define the expected result for every SIMD path: a SIMD function must return exactly what its scalar counterpart returns, error kind and position included, on every input.
Functions
pub fn validateUtf8(bytes: []const u8) Result
src
Validates UTF-8, classifying errors exactly as simdutf's scalar
validate_with_errors does, so simdutf can serve as a differential
oracle. On failure count is the index of the first byte of the
ill-formed sequence.
pub fn validateAscii(bytes: []const u8) Result
src
Validates ASCII. On failure count is the index of the first byte above
0x7F.
pub fn validateUtf16le(units: []const u16) Result
src
Validates UTF-16 stored little-endian. On failure count is the index of
the unpaired surrogate: a low one with no high one before it, or a high
one not followed by a low one.
pub fn validateUtf16be(units: []const u16) Result
src
Validates UTF-16 stored big-endian, as validateUtf16le does.
pub fn validateUtf32(units: []const u32) Result
src
Validates UTF-32 in native byte order. On failure count is the index of
the first value above U+10FFFF or in the surrogate range.
module
scalar_convert
src
Scalar reference transcoders and length functions, one code point at a
time. They define the result of every conversion: each SIMD path in
convert.zig and length.zig returns exactly what its counterpart here
returns, error kind and position included, on every input.
more
A checked conversion (utf8ToUtf16, ...) validates as it converts and
stops at the first ill-formed character, with simdutf's error kind and the
index of that character in the input. Before writing a character it checks
that the output has room for it, and fails with output_buffer_too_small
at that character's index when it does not; the output then holds the
conversion of everything before it. A buffer sized by the matching length
function never fails that way, even on invalid input, because the length
functions count every prefix at least as large as it converts.
A valid conversion (validUtf8ToUtf16, ...) assumes well-formed input and
an output buffer the matching length function sized; it returns the number
of code units written.
UTF-16 functions take the byte order of the code units in memory as a
comptime Endian, as simdutf's char16_t functions do. UTF-32 is native.
Functions
A UTF-16 code unit stored in byte order e, as a native value, or a
native value as one stored in byte order e: the same swap both ways.
pub fn utf8ToUtf16(comptime e: Endian, src: []const u8, dst: []u16) Result
src
pub fn validUtf8ToUtf16(comptime e: Endian, src: []const u8, dst: []u16) usize
src
pub fn utf8ToUtf32(src: []const u8, dst: []u32) Result
src
pub fn validUtf8ToUtf32(src: []const u8, dst: []u32) usize
src
pub fn utf8ToLatin1(src: []const u8, dst: []u8) Result
src
Converts UTF-8 holding only U+0000-U+00FF to Latin-1, classifying errors
as simdutf does: a two-byte character above U+00FF, and any three- or
four-byte lead, is too_large at its first byte, before its continuation
bytes are looked at.
pub fn validUtf8ToLatin1(src: []const u8, dst: []u8) usize
src
pub fn utf16ToUtf8(comptime e: Endian, src: []const u16, dst: []u8) Result
src
pub fn validUtf16ToUtf8(comptime e: Endian, src: []const u16, dst: []u8) usize
src
pub fn utf16ToUtf32(comptime e: Endian, src: []const u16, dst: []u32) Result
src
pub fn validUtf16ToUtf32(comptime e: Endian, src: []const u16, dst: []u32) usize
src
pub fn utf16ToLatin1(comptime e: Endian, src: []const u16, dst: []u8) Result
src
Every code unit above 0xFF, surrogates included, is too_large at its
index, as simdutf reports it.
pub fn validUtf16ToLatin1(comptime e: Endian, src: []const u16, dst: []u8) usize
src
pub fn utf16ToUtf16Swapped(comptime e: Endian, src: []const u16, dst: []u16) Result
src
Converts UTF-16 in byte order e to the other byte order, failing on an
unpaired surrogate as utf16ToUtf8 does.
pub fn validUtf16ToUtf16Swapped(src: []const u16, dst: []u16) usize
src
pub fn utf32ToUtf8(src: []const u32, dst: []u8) Result
src
pub fn validUtf32ToUtf8(src: []const u32, dst: []u8) usize
src
pub fn utf32ToUtf16(comptime e: Endian, src: []const u32, dst: []u16) Result
src
pub fn validUtf32ToUtf16(comptime e: Endian, src: []const u32, dst: []u16) usize
src
pub fn utf32ToLatin1(src: []const u32, dst: []u8) Result
src
Every code point above 0xFF is too_large at its index.
pub fn validUtf32ToLatin1(src: []const u32, dst: []u8) usize
src
pub fn latin1ToUtf8(src: []const u8, dst: []u8) Result
src
pub fn validLatin1ToUtf8(src: []const u8, dst: []u8) usize
src
pub fn latin1ToUtf16(comptime e: Endian, src: []const u8, dst: []u16) Result
src
pub fn validLatin1ToUtf16(comptime e: Endian, src: []const u8, dst: []u16) usize
src
pub fn latin1ToUtf32(src: []const u8, dst: []u32) Result
src
pub fn validLatin1ToUtf32(src: []const u8, dst: []u32) usize
src
Code points in UTF-8: the bytes that are not continuation bytes.
pub fn countUtf16(comptime e: Endian, src: []const u16) usize
src
Code points in UTF-16: the code units that are not low surrogates.
pub fn utf16FromUtf8(src: []const u8) usize
src
UTF-16 code units for UTF-8: one per character, two per four-byte one.
pub fn utf8FromUtf16(comptime e: Endian, src: []const u16) usize
src
UTF-8 bytes for UTF-16: every surrogate counts two, so a pair counts four. On unpaired surrogates simdutf disagrees with itself (its SIMD blocks count two, its scalar tail three); this is the per-unit rule.
pub fn utf8FromUtf32(src: []const u32) usize
src
pub fn utf16FromUtf32(src: []const u32) usize
src
pub fn utf8FromLatin1(src: []const u8) usize
src
module
convert
src
Transcoding between UTF-8, UTF-16LE, UTF-16BE, UTF-32, and Latin-1, with SIMD. Callers own every buffer; nothing allocates.
more
Each conversion has two forms. The checked form (utf8ToUtf16le)
validates as it converts and returns a Result: on success the number of
code units written, on failure simdutf's error kind and the index in the
input of the first ill-formed character. When the output runs out it
fails with output_buffer_too_small at the first character that does not
fit; a buffer sized by the matching length function always fits. The
valid form (validUtf8ToUtf16le) assumes well-formed input and a buffer
the length function sized, and returns the number of code units written.
Results equal those of scalar_convert.zig on every input.
UTF-16LE and UTF-16BE name the byte order of the code units in memory, as
simdutf's char16_t functions do; UTF-32 is native.
The kernels follow Lemire and Muła, "Transcoding Billions of Unicode Characters per Second with SIMD Instructions" (2022), and on AVX-512 with VBMI2 Clausecker and Lemire, "Transcoding Unicode Characters with AVX-512 Instructions" (2023). UTF-8 is decoded a 64-byte block at a time: each byte gets the value of a character ending there, and the values that end characters are packed by shuffle tables keyed by the end-of-character mask (by lane compression on AVX-512), with 12-byte windows for the tail. UTF-16 and UTF-32 are encoded by expanding code points into lanes and packing them, with ASCII and two-byte fast paths. UTF-8 is validated in the same pass with Keiser and Lemire's three-lookup check. Every table is built at comptime.
Functions
pub fn utf8ToUtf16le(src: []const u8, dst: []u16) Result
src
pub fn utf8ToUtf16be(src: []const u8, dst: []u16) Result
src
pub fn utf8ToUtf32(src: []const u8, dst: []u32) Result
src
pub fn utf8ToLatin1(src: []const u8, dst: []u8) Result
src
pub fn validUtf8ToUtf16le(src: []const u8, dst: []u16) usize
src
pub fn validUtf8ToUtf16be(src: []const u8, dst: []u16) usize
src
pub fn validUtf8ToUtf32(src: []const u8, dst: []u32) usize
src
pub fn validUtf8ToLatin1(src: []const u8, dst: []u8) usize
src
pub fn utf16leToUtf8(src: []const u16, dst: []u8) Result
src
pub fn utf16beToUtf8(src: []const u16, dst: []u8) Result
src
pub fn utf16leToUtf32(src: []const u16, dst: []u32) Result
src
pub fn utf16beToUtf32(src: []const u16, dst: []u32) Result
src
pub fn utf16leToLatin1(src: []const u16, dst: []u8) Result
src
pub fn utf16beToLatin1(src: []const u16, dst: []u8) Result
src
pub fn utf16leToUtf16be(src: []const u16, dst: []u16) Result
src
Swaps the byte order, failing on an unpaired surrogate.
pub fn utf16beToUtf16le(src: []const u16, dst: []u16) Result
src
Swaps the byte order, failing on an unpaired surrogate.
pub fn validUtf16leToUtf8(src: []const u16, dst: []u8) usize
src
pub fn validUtf16beToUtf8(src: []const u16, dst: []u8) usize
src
pub fn validUtf16leToUtf32(src: []const u16, dst: []u32) usize
src
pub fn validUtf16beToUtf32(src: []const u16, dst: []u32) usize
src
pub fn validUtf16leToLatin1(src: []const u16, dst: []u8) usize
src
pub fn validUtf16beToLatin1(src: []const u16, dst: []u8) usize
src
pub fn validUtf16leToUtf16be(src: []const u16, dst: []u16) usize
src
pub fn validUtf16beToUtf16le(src: []const u16, dst: []u16) usize
src
pub fn utf32ToUtf8(src: []const u32, dst: []u8) Result
src
pub fn utf32ToUtf16le(src: []const u32, dst: []u16) Result
src
pub fn utf32ToUtf16be(src: []const u32, dst: []u16) Result
src
pub fn utf32ToLatin1(src: []const u32, dst: []u8) Result
src
pub fn validUtf32ToUtf8(src: []const u32, dst: []u8) usize
src
pub fn validUtf32ToUtf16le(src: []const u32, dst: []u16) usize
src
pub fn validUtf32ToUtf16be(src: []const u32, dst: []u16) usize
src
pub fn validUtf32ToLatin1(src: []const u32, dst: []u8) usize
src
pub fn latin1ToUtf8(src: []const u8, dst: []u8) Result
src
pub fn latin1ToUtf16le(src: []const u8, dst: []u16) Result
src
pub fn latin1ToUtf16be(src: []const u8, dst: []u16) Result
src
pub fn latin1ToUtf32(src: []const u8, dst: []u32) Result
src
pub fn validLatin1ToUtf8(src: []const u8, dst: []u8) usize
src
pub fn validLatin1ToUtf16le(src: []const u8, dst: []u16) usize
src
pub fn validLatin1ToUtf16be(src: []const u8, dst: []u16) usize
src
pub fn validLatin1ToUtf32(src: []const u8, dst: []u32) usize
src
module
length
src
How many code units each conversion writes, and how many code points an
input holds. Each function is defined on any input, valid or not, and
returns exactly what its counterpart in scalar_convert.zig returns; on
valid input that is simdutf's answer. An output buffer of the size a
length function gives always fits the matching checked conversion, even
when the input turns out to be invalid.
Functions
Code points in UTF-8: the bytes that are not continuation bytes.
pub fn countUtf16le(src: []const u16) usize
src
Code points in UTF-16LE: the code units that are not low surrogates.
pub fn countUtf16be(src: []const u16) usize
src
Code points in UTF-16BE: the code units that are not low surrogates.
pub fn utf16FromUtf8(src: []const u8) usize
src
UTF-16 code units for UTF-8: one per character, two per four-byte one.
pub fn utf16FromUtf32(src: []const u32) usize
src
UTF-16 code units for UTF-32: one per code point, two above U+FFFF.
pub fn utf16FromLatin1(src: []const u8) usize
src
UTF-16 code units for Latin-1: one per byte.
pub fn utf32FromUtf8(src: []const u8) usize
src
UTF-32 code units for UTF-8: one per character.
pub fn utf32FromUtf16le(src: []const u16) usize
src
UTF-32 code units for UTF-16LE: one per code point.
pub fn utf32FromUtf16be(src: []const u16) usize
src
UTF-32 code units for UTF-16BE: one per code point.
pub fn utf32FromLatin1(src: []const u8) usize
src
UTF-32 code units for Latin-1: one per byte.
pub fn utf8FromUtf16le(src: []const u16) usize
src
UTF-8 bytes for UTF-16LE: a surrogate counts two, so a pair counts four.
pub fn utf8FromUtf16be(src: []const u16) usize
src
UTF-8 bytes for UTF-16BE: a surrogate counts two, so a pair counts four.
pub fn utf8FromUtf32(src: []const u32) usize
src
UTF-8 bytes for UTF-32: one to four per code point.
pub fn utf8FromLatin1(src: []const u8) usize
src
UTF-8 bytes for Latin-1: one per byte below 0x80, two above.
pub fn latin1FromUtf8(src: []const u8) usize
src
Latin-1 bytes for UTF-8: one per character.
pub fn latin1FromUtf16(src: []const u16) usize
src
Latin-1 bytes for UTF-16: one per code unit.
pub fn latin1FromUtf32(src: []const u32) usize
src
Latin-1 bytes for UTF-32: one per code point.
module
base64
src
Base64 encoding and decoding with SIMD, after Muła and Lemire, "Faster
Base64 Encoding and Decoding Using AVX2 Instructions" (2018), and "Base64
encoding and decoding at almost the speed of a memory copy" (2020) for
AVX-512 VBMI. Each step of the main loops turns 48 bytes into 64
characters or back; the last step works on a zero-padded block and writes
only what the input fills, so short inputs take the same vector code.
Decoding skips ASCII whitespace as WHATWG's forgiving-base64 does: a
block with whitespace has it compressed out into a staging buffer, which
is decoded once it holds 64 characters. The scalar reference in
scalar_base64.zig takes over at errors and at an output buffer too
small to finish in vectors, and every path here returns exactly what it
returns.
Constants
value
for ([_]Isa{ .avx512vbmi, .avx2, .ssse3, .neon }) |isa| {
if (isa.supported()) break isa;
} else .genericThe kernel encode and decode use: the widest the target supports, or
with runtime dispatch, the widest the tier they run in supports.
Functions
pub fn encodedLen(n: usize, options: EncodeOptions) usize
src
The number of characters encode writes for n bytes.
pub fn maxDecodedLen(n: usize) usize
src
The most bytes decode can write for n input characters, whatever
they are.
Encodes src into dst and returns the number of characters written,
encodedLen(src.len, options). dst must hold that many.
Decodes base64 src into dst, skipping ASCII whitespace (tab, LF, FF,
CR, and space), with padding optional unless options.last_chunk is
.strict.
more
On success count is the number of bytes written. On failure it is a
position in src: for invalid_base64_character, the offending
character, which includes a misplaced =; for base64_input_remainder
and base64_extra_bits, the end of the encoded data; for
output_buffer_too_small, the first character of the chunk that does not
fit, where decoding can resume with more room. A dst of
maxDecodedLen(src.len) bytes always fits. On failure the contents of
dst are unspecified.
dst may start where src does, to decode in place, with the same
result as decoding into a buffer of its own; on failure the contents of
src are then unspecified too. Otherwise the two must not overlap.
pub fn encodeWith(comptime isa: Isa, comptime alphabet: Alphabet, dst: []u8, src: []const u8, padding: bool) usize
src
pub fn decodeWith(
comptime isa: Isa,
comptime alphabet: Alphabet,
dst: []u8,
src: []const u8,
last_chunk: LastChunk,
) Result
src
Types
module
scalar
src
Scalar base64, one character at a time: the reference every SIMD path in
base64.zig must match, result and error position included. Decoding
follows WHATWG forgiving-base64 and the TC39 Uint8Array.fromBase64
last-chunk rules, with simdutf's base64_to_binary error kinds and
positions.
Constants
A character's 6-bit value, or space or invalid.
Functions
pub fn encodedLen(n: usize, options: EncodeOptions) usize
src
The number of characters encode writes for n bytes.
pub fn maxDecodedLen(n: usize) usize
src
The most bytes decode can write for n input characters, whatever
they are.
Encodes src into dst and returns the number of characters written,
encodedLen(src.len, options). dst must hold that many.
pub inline fn encodeChars(dst: []u8, src: []const u8, table: *const [64]u8, padding: bool) usize
src
encode with the alphabet's characters and the padding flag apart:
SIMD paths inline it, and LLVM keeps an options struct inlined into
them in memory.
pub fn decodeTable(alphabet: Alphabet) *const [256]u8
src
The decoding table: each byte's value, space for the ASCII whitespace
WHATWG's forgiving-base64 skips (tab, LF, FF, CR, space), and invalid
for everything else, = included.
Decodes base64 src into dst, skipping ASCII whitespace.
more
On success count is the number of bytes written. On failure it is a
position in src: for invalid_base64_character, the offending
character, which includes a misplaced = and the first of trailing
padding that does not fit the last chunk; for base64_input_remainder
and base64_extra_bits, the end of the encoded data, before any trailing
padding and whitespace; for output_buffer_too_small, the first character
of the chunk that does not fit, where decoding can resume. dst needs at
most maxDecodedLen(src.len) bytes. On failure the contents of dst are
unspecified.
pub fn decodeFrom(dst: []u8, src: []const u8, t: Trim, start: usize, out: usize, options: DecodeOptions) Result
src
Decodes src[i..t.len] into dst[o..] and finishes the input, where
t is trim(src) and i starts a chunk: the characters before it, less
whitespace, are a multiple of four and already decoded into dst[0..o].
SIMD paths call it for the part of the input they leave.
Types
enum
LastChunk
src
What decoding does with a last chunk of two or three characters, as the
TC39 lastChunkHandling option does.
Fields
loose loose
Decode it, padded or not, and ignore nonzero bits past the last byte.
strict strict
Require it to be padded to four characters with =, and reject
nonzero bits past the last byte.
stop_before_partial stop_before_partial
Leave an unpadded partial chunk undecoded, without an error.
struct
EncodeOptions
src
Fields
enum
LastChunk
src
pub const LastChunk = scalar.LastChunk
What decoding does with a last chunk of two or three characters, as the
TC39 lastChunkHandling option does.
Fields
loose loose
Decode it, padded or not, and ignore nonzero bits past the last byte.
strict strict
Require it to be padded to four characters with =, and reject
nonzero bits past the last byte.
stop_before_partial stop_before_partial
Leave an unpadded partial chunk undecoded, without an error.
struct
DecodeOptions
src
pub const DecodeOptions = scalar.DecodeOptions
Fields
alphabet: Alphabet = .standard
last_chunk: LastChunk = .loose
enum
Isa
src
The instruction sets with a kernel here. generic is plain @Vector
code for any target; the others call LLVM intrinsics for byte lookups,
permutes, and multiply-adds, so they need the LLVM backend.
Fields
generic generic
ssse3 ssse3
avx2 avx2
avx512vbmi avx512vbmi
AVX-512 with VBMI (vpermb, vpermi2b, vpmultishiftqb); with
VBMI2 it also compresses whitespace out with vpcompressb.
neon neon
Functions
Whether this build can run the kernel.
module
validate
src
Validation of UTF-8, ASCII, UTF-16LE/BE, and UTF-32, with SIMD.
more
Each function checks 64-byte blocks and stops at the first block that
fails. Inputs of four blocks or more check their first block unaligned
and the rest from the next 64-byte boundary, so no load splits a cache
line; a final partial block is the last 64 bytes of the input,
overlapping the block before it. Inputs shorter than a block are
zero-padded into one. The WithErrors forms find the position in the
failing block: ASCII, UTF-16, and UTF-32 from its lane masks, UTF-8 by
rerunning the scalar validator in scalar.zig from the last character
boundary before it, so error kinds and positions are exactly the scalar
validators'.
Functions
Reports whether bytes is well-formed UTF-8.
pub fn utf8WithErrors(bytes: []const u8) Result
src
Validates UTF-8. On failure count is the index of the first byte of the
ill-formed sequence, and err says what is wrong with it.
Reports whether every byte is below 0x80.
pub fn asciiWithErrors(bytes: []const u8) Result
src
Validates ASCII. On failure count is the index of the first byte above
0x7F.
Reports whether units is well-formed UTF-16 stored little-endian.
pub fn utf16leWithErrors(units: []const u16) Result
src
Validates UTF-16 stored little-endian. On failure count is the index of
the unpaired surrogate.
Reports whether units is well-formed UTF-16 stored big-endian.
pub fn utf16beWithErrors(units: []const u16) Result
src
Validates UTF-16 stored big-endian. On failure count is the index of
the unpaired surrogate.
Reports whether every value is a Unicode scalar value: at most U+10FFFF and not a surrogate.
pub fn utf32WithErrors(units: []const u32) Result
src
Validates UTF-32 in native byte order. On failure count is the index of
the first value above U+10FFFF (too_large) or in the surrogate range
(surrogate).