diff options
| author | 2024-02-16 21:46:22 -0400 | |
|---|---|---|
| committer | 2024-02-16 21:46:22 -0400 | |
| commit | e523efa9f7da1949134af9679876a2bc6bb141d4 (patch) | |
| tree | 375984495870bd99913acd5cdc868bec5b42607e | |
| parent | display_width with table (diff) | |
| download | zg-e523efa9f7da1949134af9679876a2bc6bb141d4.tar.gz zg-e523efa9f7da1949134af9679876a2bc6bb141d4.tar.xz zg-e523efa9f7da1949134af9679876a2bc6bb141d4.zip | |
SIMD strWidth ASCII optimization
| -rw-r--r-- | src/display_width.zig | 37 | ||||
| -rw-r--r-- | src/main.zig | 12 |
2 files changed, 44 insertions, 5 deletions
diff --git a/src/display_width.zig b/src/display_width.zig index e06aa8f..b96f872 100644 --- a/src/display_width.zig +++ b/src/display_width.zig | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const simd = std.simd; | ||
| 2 | const testing = std.testing; | 3 | const testing = std.testing; |
| 3 | 4 | ||
| 4 | const CodePointIterator = @import("CodePoint").CodePointIterator; | 5 | const CodePointIterator = @import("CodePoint").CodePointIterator; |
| @@ -14,8 +15,42 @@ pub fn codePointWidth(cp: u21) i3 { | |||
| 14 | return dwp.stage_2[dwp.stage_1[cp >> 8] + (cp & 0xff)]; | 15 | return dwp.stage_2[dwp.stage_1[cp >> 8] + (cp & 0xff)]; |
| 15 | } | 16 | } |
| 16 | 17 | ||
| 17 | fn strWidth(str: []const u8) usize { | 18 | fn isAsciiOnly(str: []const u8) bool { |
| 19 | const vec_len = simd.suggestVectorLength(u8) orelse @panic("No SIMD support."); | ||
| 20 | const Vec = @Vector(vec_len, u8); | ||
| 21 | var i: usize = 0; | ||
| 22 | |||
| 23 | while (i < str.len) : (i += vec_len) { | ||
| 24 | if (str[i..].len < vec_len) return for (str[i..]) |b| { | ||
| 25 | if (b > 127) break false; | ||
| 26 | } else true; | ||
| 27 | |||
| 28 | const v1 = str[i..].ptr[0..vec_len].*; | ||
| 29 | const v2: Vec = @splat(127); | ||
| 30 | if (@reduce(.Or, v1 > v2)) return false; | ||
| 31 | } | ||
| 32 | |||
| 33 | return true; | ||
| 34 | } | ||
| 35 | |||
| 36 | /// strWidth returns the total display width of `str` as the number of cells | ||
| 37 | /// required in a fixed-pitch font (i.e. a terminal screen). | ||
| 38 | pub fn strWidth(str: []const u8) usize { | ||
| 18 | var total: isize = 0; | 39 | var total: isize = 0; |
| 40 | |||
| 41 | if (isAsciiOnly(str)) { | ||
| 42 | for (str) |b| { | ||
| 43 | // Backspace and delete | ||
| 44 | if (b == 0x8 or b == 0x7f) { | ||
| 45 | total -= 1; | ||
| 46 | } else if (b >= 0x20) { | ||
| 47 | total += 1; | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | return if (total > 0) @intCast(total) else 0; | ||
| 52 | } | ||
| 53 | |||
| 19 | var giter = GraphemeIterator.init(str); | 54 | var giter = GraphemeIterator.init(str); |
| 20 | 55 | ||
| 21 | while (giter.next()) |gc| { | 56 | while (giter.next()) |gc| { |
diff --git a/src/main.zig b/src/main.zig index 3e65c7b..e7c0828 100644 --- a/src/main.zig +++ b/src/main.zig | |||
| @@ -3,7 +3,9 @@ const std = @import("std"); | |||
| 3 | // const GraphemeIterator = @import("ziglyph").GraphemeIterator; | 3 | // const GraphemeIterator = @import("ziglyph").GraphemeIterator; |
| 4 | // const GraphemeIterator = @import("Grapheme").GraphemeIterator; | 4 | // const GraphemeIterator = @import("Grapheme").GraphemeIterator; |
| 5 | // const codePointWidth = @import("ziglyph").display_width.codePointWidth; | 5 | // const codePointWidth = @import("ziglyph").display_width.codePointWidth; |
| 6 | const codePointWidth = @import("display_width").codePointWidth; | 6 | // const codePointWidth = @import("display_width").codePointWidth; |
| 7 | // const strWidth = @import("ziglyph").display_width.strWidth; | ||
| 8 | const strWidth = @import("display_width").strWidth; | ||
| 7 | const CodePointIterator = @import("CodePoint").CodePointIterator; | 9 | const CodePointIterator = @import("CodePoint").CodePointIterator; |
| 8 | 10 | ||
| 9 | pub fn main() !void { | 11 | pub fn main() !void { |
| @@ -14,14 +16,16 @@ pub fn main() !void { | |||
| 14 | const input = try std.fs.cwd().readFileAlloc(allocator, "lang_mix.txt", std.math.maxInt(u32)); | 16 | const input = try std.fs.cwd().readFileAlloc(allocator, "lang_mix.txt", std.math.maxInt(u32)); |
| 15 | defer allocator.free(input); | 17 | defer allocator.free(input); |
| 16 | 18 | ||
| 17 | var result: isize = 0; | 19 | var result: usize = 0; |
| 18 | // var iter = GraphemeIterator.init(input); | 20 | // var iter = GraphemeIterator.init(input); |
| 19 | var iter = CodePointIterator{ .bytes = input }; | 21 | // var iter = CodePointIterator{ .bytes = input }; |
| 22 | var iter = std.mem.splitScalar(u8, input, '\n'); | ||
| 20 | 23 | ||
| 21 | var timer = try std.time.Timer.start(); | 24 | var timer = try std.time.Timer.start(); |
| 22 | 25 | ||
| 23 | // for (0..50) |_| { | 26 | // for (0..50) |_| { |
| 24 | while (iter.next()) |cp| result += codePointWidth(@intCast(cp.code)); | 27 | // while (iter.next()) |cp| result += codePointWidth(@intCast(cp.code)); |
| 28 | while (iter.next()) |line| result += strWidth(line); | ||
| 25 | // iter.cp_iter.i = 0; | 29 | // iter.cp_iter.i = 0; |
| 26 | // } | 30 | // } |
| 27 | 31 | ||