Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions bench/bench.zig
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const std = @import("std");
const vaxis = @import("vaxis");
const uucode = @import("uucode");

fn parseIterations(allocator: std.mem.Allocator) !usize {
var args = try std.process.argsWithAllocator(allocator);
Expand All @@ -20,6 +21,60 @@ fn printResults(writer: anytype, label: []const u8, iterations: usize, elapsed_n
);
}

// Mirrors the pre-fast-path parseGround work for ASCII to provide a baseline.
fn parseAsciiSlow(input: []const u8) !vaxis.Parser.Result {
std.debug.assert(input.len > 0);
var iter = uucode.utf8.Iterator.init(input);
const first_cp = iter.next() orelse return error.InvalidUTF8;

var n: usize = std.unicode.utf8CodepointSequenceLength(first_cp) catch return error.InvalidUTF8;

var code = first_cp;
var grapheme_iter = uucode.grapheme.Iterator(uucode.utf8.Iterator).init(.init(input));
var grapheme_len: usize = 0;
var cp_count: usize = 0;

while (grapheme_iter.next()) |result| {
cp_count += 1;
if (result.is_break) {
grapheme_len = grapheme_iter.i;
break;
}
}

if (grapheme_len > 0) {
n = grapheme_len;
if (cp_count > 1) {
code = vaxis.Key.multicodepoint;
}
}

const key: vaxis.Key = .{ .codepoint = code, .text = input[0..n] };
return .{ .event = .{ .key_press = key }, .n = n };
}

fn benchParseFast(writer: anytype, label: []const u8, parser: *vaxis.Parser, input: []const u8, iterations: usize) !void {
var timer = try std.time.Timer.start();
var i: usize = 0;
while (i < iterations) : (i += 1) {
const result = try parser.parse(input, null);
std.mem.doNotOptimizeAway(result);
}
const elapsed_ns = timer.read();
try printResults(writer, label, iterations, elapsed_ns, input.len * iterations);
}

fn benchParseSlow(writer: anytype, label: []const u8, input: []const u8, iterations: usize) !void {
var timer = try std.time.Timer.start();
var i: usize = 0;
while (i < iterations) : (i += 1) {
const result = try parseAsciiSlow(input);
std.mem.doNotOptimizeAway(result);
}
const elapsed_ns = timer.read();
try printResults(writer, label, iterations, elapsed_ns, input.len * iterations);
}

pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
Expand Down Expand Up @@ -59,4 +114,9 @@ pub fn main() !void {
const dirty_ns = timer.read();
const dirty_bytes: usize = dirty_writer.writer.end;
try printResults(stdout, "dirty", iterations, dirty_ns, dirty_bytes);

var parser: vaxis.Parser = .{};
const ascii_input = "a";
try benchParseSlow(stdout, "parse_ground_ascii_slow", ascii_input, iterations);
try benchParseFast(stdout, "parse_ground_ascii_fast", &parser, ascii_input, iterations);
}
1 change: 1 addition & 0 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ pub fn build(b: *std.Build) void {
.optimize = optimize,
.imports = &.{
.{ .name = "vaxis", .module = vaxis_mod },
.{ .name = "uucode", .module = uucode_dep.module("uucode") },
},
}),
});
Expand Down
12 changes: 12 additions & 0 deletions src/Parser.zig
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,18 @@ inline fn parseGround(input: []const u8) !Result {
std.debug.assert(input.len > 0);

const b = input[0];
// Fast path for printable ASCII only (0x20..0x7E). Control bytes are
// mapped to special key handling and ESC can start control sequences.
// Require the next byte to be ASCII (or absent) to avoid multi-codepoint
// graphemes like combining marks/keycap sequences that start with ASCII
// but continue with non-ASCII bytes.
if (b >= 0x20 and b <= 0x7E and (input.len == 1 or input[1] < 0x80)) {
return .{
.event = .{ .key_press = .{ .codepoint = b, .text = input[0..1] } },
.n = 1,
};
}

var n: usize = 1;
// ground state generates keypresses when parsing input. We
// generally get ascii characters, but anything less than
Expand Down