diff options
| author | 2026-02-04 18:36:18 -0500 | |
|---|---|---|
| committer | 2026-02-04 18:36:18 -0500 | |
| commit | e476250ea9326b2550847b301c265115ff375a31 (patch) | |
| tree | cf627ced47cecce80020b7a1f30aa51852c0c59b /src/Scripts.zig | |
| parent | Normalization and case folding (diff) | |
| download | zg-e476250ea9326b2550847b301c265115ff375a31.tar.gz zg-e476250ea9326b2550847b301c265115ff375a31.tar.xz zg-e476250ea9326b2550847b301c265115ff375a31.zip | |
Rest of the 'easy' stuff
This gets us up to feature parity with Jacob's work. I want to
eliminate that last allocation using the comptime hash map, and then
see about eliminating allocations from case comparisons as well.
That should just about do it.
Diffstat (limited to 'src/Scripts.zig')
| -rw-r--r-- | src/Scripts.zig | 82 |
1 files changed, 18 insertions, 64 deletions
diff --git a/src/Scripts.zig b/src/Scripts.zig index 719b01f..4938318 100644 --- a/src/Scripts.zig +++ b/src/Scripts.zig | |||
| @@ -1,8 +1,18 @@ | |||
| 1 | //! Scripts Module | 1 | //! Scripts Module |
| 2 | const Data = struct { | ||
| 3 | s1: []const u16 = undefined, | ||
| 4 | s2: []const u8 = undefined, | ||
| 5 | s3: []const u8 = undefined, | ||
| 6 | }; | ||
| 2 | 7 | ||
| 3 | s1: []u16 = undefined, | 8 | const scripts = scripts: { |
| 4 | s2: []u8 = undefined, | 9 | const data = @import("script"); |
| 5 | s3: []u8 = undefined, | 10 | break :scripts Data{ |
| 11 | .s1 = &data.s1, | ||
| 12 | .s2 = &data.s2, | ||
| 13 | .s3 = &data.s3, | ||
| 14 | }; | ||
| 15 | }; | ||
| 6 | 16 | ||
| 7 | /// Scripts enum | 17 | /// Scripts enum |
| 8 | pub const Script = enum { | 18 | pub const Script = enum { |
| @@ -178,76 +188,20 @@ pub const Script = enum { | |||
| 178 | Yi, | 188 | Yi, |
| 179 | Zanabazar_Square, | 189 | Zanabazar_Square, |
| 180 | }; | 190 | }; |
| 181 | const Scripts = @This(); | ||
| 182 | |||
| 183 | pub fn init(allocator: Allocator) Allocator.Error!Scripts { | ||
| 184 | var scripts = Scripts{}; | ||
| 185 | try scripts.setup(allocator); | ||
| 186 | return scripts; | ||
| 187 | } | ||
| 188 | |||
| 189 | pub fn setup(scripts: *Scripts, allocator: Allocator) Allocator.Error!void { | ||
| 190 | scripts.setupInner(allocator) catch |err| { | ||
| 191 | switch (err) { | ||
| 192 | error.OutOfMemory => |e| return e, | ||
| 193 | else => unreachable, | ||
| 194 | } | ||
| 195 | }; | ||
| 196 | } | ||
| 197 | |||
| 198 | inline fn setupInner(scripts: *Scripts, allocator: mem.Allocator) !void { | ||
| 199 | const in_bytes = @embedFile("scripts"); | ||
| 200 | var in_fbs = std.io.fixedBufferStream(in_bytes); | ||
| 201 | var reader = in_fbs.reader(); | ||
| 202 | |||
| 203 | const endian = builtin.cpu.arch.endian(); | ||
| 204 | |||
| 205 | const s1_len: u16 = try reader.readInt(u16, endian); | ||
| 206 | scripts.s1 = try allocator.alloc(u16, s1_len); | ||
| 207 | errdefer allocator.free(scripts.s1); | ||
| 208 | for (0..s1_len) |i| scripts.s1[i] = try reader.readInt(u16, endian); | ||
| 209 | |||
| 210 | const s2_len: u16 = try reader.readInt(u16, endian); | ||
| 211 | scripts.s2 = try allocator.alloc(u8, s2_len); | ||
| 212 | errdefer allocator.free(scripts.s2); | ||
| 213 | _ = try reader.readAll(scripts.s2); | ||
| 214 | |||
| 215 | const s3_len: u16 = try reader.readInt(u8, endian); | ||
| 216 | scripts.s3 = try allocator.alloc(u8, s3_len); | ||
| 217 | errdefer allocator.free(scripts.s3); | ||
| 218 | _ = try reader.readAll(scripts.s3); | ||
| 219 | } | ||
| 220 | |||
| 221 | pub fn deinit(self: *const Scripts, allocator: mem.Allocator) void { | ||
| 222 | allocator.free(self.s1); | ||
| 223 | allocator.free(self.s2); | ||
| 224 | allocator.free(self.s3); | ||
| 225 | } | ||
| 226 | 191 | ||
| 227 | /// Lookup the Script type for `cp`. | 192 | /// Lookup the Script type for `cp`. |
| 228 | pub fn script(self: Scripts, cp: u21) ?Script { | 193 | pub fn script(cp: u21) ?Script { |
| 229 | const byte = self.s3[self.s2[self.s1[cp >> 8] + (cp & 0xff)]]; | 194 | const byte = scripts.s3[scripts.s2[scripts.s1[cp >> 8] + (cp & 0xff)]]; |
| 230 | if (byte == 0) return null; | 195 | if (byte == 0) return null; |
| 231 | return @enumFromInt(byte); | 196 | return @enumFromInt(byte); |
| 232 | } | 197 | } |
| 233 | 198 | ||
| 234 | test "script" { | 199 | test "script" { |
| 235 | const self = try init(std.testing.allocator); | 200 | try testing.expectEqual(Script.Latin, script('A').?); |
| 236 | defer self.deinit(std.testing.allocator); | 201 | // try testing.expectEqual(Script.Deseret, script('𐐌').?); |
| 237 | try testing.expectEqual(Script.Latin, self.script('A').?); | ||
| 238 | } | ||
| 239 | |||
| 240 | fn testAllocator(allocator: Allocator) !void { | ||
| 241 | var prop = try Scripts.init(allocator); | ||
| 242 | prop.deinit(allocator); | ||
| 243 | } | ||
| 244 | |||
| 245 | test "Allocation failure" { | ||
| 246 | try testing.checkAllAllocationFailures(testing.allocator, testAllocator, .{}); | ||
| 247 | } | 202 | } |
| 248 | 203 | ||
| 249 | const std = @import("std"); | 204 | const std = @import("std"); |
| 250 | const builtin = @import("builtin"); | 205 | const builtin = @import("builtin"); |
| 251 | const mem = std.mem; | 206 | const unicode = std.unicode; |
| 252 | const Allocator = mem.Allocator; | ||
| 253 | const testing = std.testing; | 207 | const testing = std.testing; |