feature. See also
. The project being documented here (as the example) is the Zig library itself.
unicode.utf8ValidateSliceImpl
fn utf8ValidateSliceImpl(input: []const u8, comptime surrogates: Surrogates) bool
File
Code
fn utf8ValidateSliceImpl(input: []const u8, comptime surrogates: Surrogates) bool {
var remaining = input;
if (std.simd.suggestVectorLength(u8)) |chunk_len| {
const Chunk = @Vector(chunk_len, u8);
while (remaining.len >= chunk_len) {
const chunk: Chunk = remaining[0..chunk_len].*;
const mask: Chunk = @splat(0x80);
if (@reduce(.Or, chunk & mask == mask)) {
break;
}
remaining = remaining[chunk_len..];
}
}
const lo_cb = 0b10000000;
const hi_cb = 0b10111111;
const min_non_ascii_codepoint = 0x80;
// accept. The second nibble is the size.
const xx = 0xF1;
const as = 0xF0;
const s1 = 0x02;
const s2 = switch (surrogates) {
.cannot_encode_surrogate_half => 0x13,
.can_encode_surrogate_half => 0x03,
};
const s3 = 0x03;
const s4 = switch (surrogates) {
.cannot_encode_surrogate_half => 0x23,
.can_encode_surrogate_half => 0x03,
};
const s5 = 0x34;
const s6 = 0x04;
const s7 = 0x44;
// Information about the first byte in a UTF-8 sequence.
const first = comptime first: {
const a: [128]u8 = @splat(as);
const b: [64]u8 = @splat(xx);
const c: [64]u8 = .{
xx, xx, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1,
s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1,
s2, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s4, s3, s3,
s5, s6, s6, s6, s7, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
};
break :first a ++ b ++ c;
};
const n = remaining.len;
var i: usize = 0;
while (i < n) {
const first_byte = remaining[i];
if (first_byte < min_non_ascii_codepoint) {
i += 1;
continue;
}
const info = first[first_byte];
if (info == xx) {
return false;
}
const size = info & 7;
if (i + size > n) {
return false;
}
// with our defaults.
var accept_lo: u8 = lo_cb;
var accept_hi: u8 = hi_cb;
switch (info >> 4) {
0 => {},
1 => accept_lo = 0xA0,
2 => accept_hi = 0x9F,
3 => accept_lo = 0x90,
4 => accept_hi = 0x8F,
else => unreachable,
}
const c1 = remaining[i + 1];
if (c1 < accept_lo or accept_hi < c1) {
return false;
}
switch (size) {
2 => i += 2,
3 => {
const c2 = remaining[i + 2];
if (c2 < lo_cb or hi_cb < c2) {
return false;
}
i += 3;
},
4 => {
const c2 = remaining[i + 2];
if (c2 < lo_cb or hi_cb < c2) {
return false;
}
const c3 = remaining[i + 3];
if (c3 < lo_cb or hi_cb < c3) {
return false;
}
i += 4;
},
else => unreachable,
}
}
return true;
}