Files
ghostty/src/simd/base64.zig
Qwerasd 6d5b4a3426 perf: replace std.debug.assert with inlined version
See doc comment in `quirks.zig` for reasoning
2025-11-17 12:13:56 -07:00

88 lines
2.4 KiB
Zig

const std = @import("std");
const options = @import("build_options");
const assert = @import("../quirks.zig").inlineAssert;
const scalar_decoder = @import("base64_scalar.zig").scalar_decoder;
const log = std.log.scoped(.simd_base64);
pub fn maxLen(input: []const u8) usize {
if (comptime options.simd) return ghostty_simd_base64_max_length(
input.ptr,
input.len,
);
return maxLenScalar(input);
}
fn maxLenScalar(input: []const u8) usize {
return scalar_decoder.calcSizeForSlice(scalarInput(input)) catch |err| {
log.warn("failed to calculate base64 size for payload: {}", .{err});
return 0;
};
}
pub fn decode(input: []const u8, output: []u8) error{Base64Invalid}![]const u8 {
if (comptime options.simd) {
const res = ghostty_simd_base64_decode(
input.ptr,
input.len,
output.ptr,
);
if (res < 0) return error.Base64Invalid;
return output[0..@intCast(res)];
}
return decodeScalar(input, output);
}
fn decodeScalar(
input_raw: []const u8,
output: []u8,
) error{Base64Invalid}![]const u8 {
const input = scalarInput(input_raw);
const size = maxLenScalar(input);
if (size == 0) return "";
assert(output.len >= size);
scalar_decoder.decode(
output,
scalarInput(input),
) catch return error.Base64Invalid;
return output[0..size];
}
/// For non-SIMD enabled builds, we trim the padding from the end of the
/// base64 input in order to get identical output with the SIMD version.
fn scalarInput(input: []const u8) []const u8 {
var i: usize = 0;
while (input[input.len - i - 1] == '=') i += 1;
return input[0 .. input.len - i];
}
// base64.cpp
extern "c" fn ghostty_simd_base64_max_length(
input: [*]const u8,
len: usize,
) usize;
extern "c" fn ghostty_simd_base64_decode(
input: [*]const u8,
len: usize,
output: [*]u8,
) isize;
test "base64 maxLen" {
const testing = std.testing;
const len = maxLen("aGVsbG8gd29ybGQ=");
try testing.expectEqual(11, len);
}
test "base64 decode" {
const testing = std.testing;
const alloc = testing.allocator;
const input = "aGVsbG8gd29ybGQ=";
const len = maxLen(input);
const output = try alloc.alloc(u8, len);
defer alloc.free(output);
const str = try decode(input, output);
try testing.expectEqualStrings("hello world", str);
}