diff options
| author | 2025-04-30 20:30:39 -0400 | |
|---|---|---|
| committer | 2025-04-30 20:30:39 -0400 | |
| commit | 10048b0d31d0db923ae39c6bbd67139ed6252f6f (patch) | |
| tree | 65df1666aacd102f59b4ac0844ccc7f7ddda91db /src/GeneralCategories.zig | |
| parent | Setup variants for all allocating modules (diff) | |
| download | zg-10048b0d31d0db923ae39c6bbd67139ed6252f6f.tar.gz zg-10048b0d31d0db923ae39c6bbd67139ed6252f6f.tar.xz zg-10048b0d31d0db923ae39c6bbd67139ed6252f6f.zip | |
Allocation Failure Tests
These turned up an excessive amount of allocations in CanonData and
CompatData, which have been reduced to two through the somewhat
squirrely use of 'magic numbers'.
There are now allocation tests for every allocated structure in the
library, and they run to completion in a reasonable amount of time.
So, that's nice.
Diffstat (limited to 'src/GeneralCategories.zig')
| -rw-r--r-- | src/GeneralCategories.zig | 79 |
1 files changed, 49 insertions, 30 deletions
diff --git a/src/GeneralCategories.zig b/src/GeneralCategories.zig index b7c82c0..3e76d82 100644 --- a/src/GeneralCategories.zig +++ b/src/GeneralCategories.zig | |||
| @@ -46,7 +46,16 @@ pub fn init(allocator: Allocator) Allocator.Error!GeneralCategories { | |||
| 46 | return gencat; | 46 | return gencat; |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | pub fn setup(self: *GeneralCategories, allocator: Allocator) Allocator.Error!void { | 49 | pub fn setup(gencat: *GeneralCategories, allocator: Allocator) Allocator.Error!void { |
| 50 | gencat.setupInner(allocator) catch |err| { | ||
| 51 | switch (err) { | ||
| 52 | error.OutOfMemory => |e| return e, | ||
| 53 | else => unreachable, | ||
| 54 | } | ||
| 55 | }; | ||
| 56 | } | ||
| 57 | |||
| 58 | inline fn setupInner(gencat: *GeneralCategories, allocator: Allocator) !void { | ||
| 50 | const decompressor = compress.flate.inflate.decompressor; | 59 | const decompressor = compress.flate.inflate.decompressor; |
| 51 | const in_bytes = @embedFile("gencat"); | 60 | const in_bytes = @embedFile("gencat"); |
| 52 | var in_fbs = std.io.fixedBufferStream(in_bytes); | 61 | var in_fbs = std.io.fixedBufferStream(in_bytes); |
| @@ -56,35 +65,35 @@ pub fn setup(self: *GeneralCategories, allocator: Allocator) Allocator.Error!voi | |||
| 56 | const endian = builtin.cpu.arch.endian(); | 65 | const endian = builtin.cpu.arch.endian(); |
| 57 | 66 | ||
| 58 | const s1_len: u16 = reader.readInt(u16, endian) catch unreachable; | 67 | const s1_len: u16 = reader.readInt(u16, endian) catch unreachable; |
| 59 | self.s1 = try allocator.alloc(u16, s1_len); | 68 | gencat.s1 = try allocator.alloc(u16, s1_len); |
| 60 | errdefer allocator.free(self.s1); | 69 | errdefer allocator.free(gencat.s1); |
| 61 | for (0..s1_len) |i| self.s1[i] = try reader.readInt(u16, endian); | 70 | for (0..s1_len) |i| gencat.s1[i] = try reader.readInt(u16, endian); |
| 62 | 71 | ||
| 63 | const s2_len: u16 = reader.readInt(u16, endian) catch unreachable; | 72 | const s2_len: u16 = reader.readInt(u16, endian) catch unreachable; |
| 64 | self.s2 = try allocator.alloc(u5, s2_len); | 73 | gencat.s2 = try allocator.alloc(u5, s2_len); |
| 65 | errdefer allocator.free(self.s2); | 74 | errdefer allocator.free(gencat.s2); |
| 66 | for (0..s2_len) |i| self.s2[i] = @intCast(reader.readInt(u8, endian) catch unreachable); | 75 | for (0..s2_len) |i| gencat.s2[i] = @intCast(reader.readInt(u8, endian) catch unreachable); |
| 67 | 76 | ||
| 68 | const s3_len: u16 = reader.readInt(u8, endian) catch unreachable; | 77 | const s3_len: u16 = reader.readInt(u8, endian) catch unreachable; |
| 69 | self.s3 = try allocator.alloc(u5, s3_len); | 78 | gencat.s3 = try allocator.alloc(u5, s3_len); |
| 70 | errdefer allocator.free(self.s3); | 79 | errdefer allocator.free(gencat.s3); |
| 71 | for (0..s3_len) |i| self.s3[i] = @intCast(reader.readInt(u8, endian) catch unreachable); | 80 | for (0..s3_len) |i| gencat.s3[i] = @intCast(reader.readInt(u8, endian) catch unreachable); |
| 72 | } | 81 | } |
| 73 | 82 | ||
| 74 | pub fn deinit(self: *const GeneralCategories, allocator: mem.Allocator) void { | 83 | pub fn deinit(gencat: *const GeneralCategories, allocator: mem.Allocator) void { |
| 75 | allocator.free(self.s1); | 84 | allocator.free(gencat.s1); |
| 76 | allocator.free(self.s2); | 85 | allocator.free(gencat.s2); |
| 77 | allocator.free(self.s3); | 86 | allocator.free(gencat.s3); |
| 78 | } | 87 | } |
| 79 | 88 | ||
| 80 | /// Lookup the General Category for `cp`. | 89 | /// Lookup the General Category for `cp`. |
| 81 | pub fn gc(self: GeneralCategories, cp: u21) Gc { | 90 | pub fn gc(gencat: GeneralCategories, cp: u21) Gc { |
| 82 | return @enumFromInt(self.s3[self.s2[self.s1[cp >> 8] + (cp & 0xff)]]); | 91 | return @enumFromInt(gencat.s3[gencat.s2[gencat.s1[cp >> 8] + (cp & 0xff)]]); |
| 83 | } | 92 | } |
| 84 | 93 | ||
| 85 | /// True if `cp` has an C general category. | 94 | /// True if `cp` has an C general category. |
| 86 | pub fn isControl(self: GeneralCategories, cp: u21) bool { | 95 | pub fn isControl(gencat: GeneralCategories, cp: u21) bool { |
| 87 | return switch (self.gc(cp)) { | 96 | return switch (gencat.gc(cp)) { |
| 88 | .Cc, | 97 | .Cc, |
| 89 | .Cf, | 98 | .Cf, |
| 90 | .Cn, | 99 | .Cn, |
| @@ -96,8 +105,8 @@ pub fn isControl(self: GeneralCategories, cp: u21) bool { | |||
| 96 | } | 105 | } |
| 97 | 106 | ||
| 98 | /// True if `cp` has an L general category. | 107 | /// True if `cp` has an L general category. |
| 99 | pub fn isLetter(self: GeneralCategories, cp: u21) bool { | 108 | pub fn isLetter(gencat: GeneralCategories, cp: u21) bool { |
| 100 | return switch (self.gc(cp)) { | 109 | return switch (gencat.gc(cp)) { |
| 101 | .Ll, | 110 | .Ll, |
| 102 | .Lm, | 111 | .Lm, |
| 103 | .Lo, | 112 | .Lo, |
| @@ -109,8 +118,8 @@ pub fn isLetter(self: GeneralCategories, cp: u21) bool { | |||
| 109 | } | 118 | } |
| 110 | 119 | ||
| 111 | /// True if `cp` has an M general category. | 120 | /// True if `cp` has an M general category. |
| 112 | pub fn isMark(self: GeneralCategories, cp: u21) bool { | 121 | pub fn isMark(gencat: GeneralCategories, cp: u21) bool { |
| 113 | return switch (self.gc(cp)) { | 122 | return switch (gencat.gc(cp)) { |
| 114 | .Mc, | 123 | .Mc, |
| 115 | .Me, | 124 | .Me, |
| 116 | .Mn, | 125 | .Mn, |
| @@ -120,8 +129,8 @@ pub fn isMark(self: GeneralCategories, cp: u21) bool { | |||
| 120 | } | 129 | } |
| 121 | 130 | ||
| 122 | /// True if `cp` has an N general category. | 131 | /// True if `cp` has an N general category. |
| 123 | pub fn isNumber(self: GeneralCategories, cp: u21) bool { | 132 | pub fn isNumber(gencat: GeneralCategories, cp: u21) bool { |
| 124 | return switch (self.gc(cp)) { | 133 | return switch (gencat.gc(cp)) { |
| 125 | .Nd, | 134 | .Nd, |
| 126 | .Nl, | 135 | .Nl, |
| 127 | .No, | 136 | .No, |
| @@ -131,8 +140,8 @@ pub fn isNumber(self: GeneralCategories, cp: u21) bool { | |||
| 131 | } | 140 | } |
| 132 | 141 | ||
| 133 | /// True if `cp` has an P general category. | 142 | /// True if `cp` has an P general category. |
| 134 | pub fn isPunctuation(self: GeneralCategories, cp: u21) bool { | 143 | pub fn isPunctuation(gencat: GeneralCategories, cp: u21) bool { |
| 135 | return switch (self.gc(cp)) { | 144 | return switch (gencat.gc(cp)) { |
| 136 | .Pc, | 145 | .Pc, |
| 137 | .Pd, | 146 | .Pd, |
| 138 | .Pe, | 147 | .Pe, |
| @@ -146,8 +155,8 @@ pub fn isPunctuation(self: GeneralCategories, cp: u21) bool { | |||
| 146 | } | 155 | } |
| 147 | 156 | ||
| 148 | /// True if `cp` has an S general category. | 157 | /// True if `cp` has an S general category. |
| 149 | pub fn isSymbol(self: GeneralCategories, cp: u21) bool { | 158 | pub fn isSymbol(gencat: GeneralCategories, cp: u21) bool { |
| 150 | return switch (self.gc(cp)) { | 159 | return switch (gencat.gc(cp)) { |
| 151 | .Sc, | 160 | .Sc, |
| 152 | .Sk, | 161 | .Sk, |
| 153 | .Sm, | 162 | .Sm, |
| @@ -158,8 +167,8 @@ pub fn isSymbol(self: GeneralCategories, cp: u21) bool { | |||
| 158 | } | 167 | } |
| 159 | 168 | ||
| 160 | /// True if `cp` has an Z general category. | 169 | /// True if `cp` has an Z general category. |
| 161 | pub fn isSeparator(self: GeneralCategories, cp: u21) bool { | 170 | pub fn isSeparator(gencat: GeneralCategories, cp: u21) bool { |
| 162 | return switch (self.gc(cp)) { | 171 | return switch (gencat.gc(cp)) { |
| 163 | .Zl, | 172 | .Zl, |
| 164 | .Zp, | 173 | .Zp, |
| 165 | .Zs, | 174 | .Zs, |
| @@ -168,8 +177,18 @@ pub fn isSeparator(self: GeneralCategories, cp: u21) bool { | |||
| 168 | }; | 177 | }; |
| 169 | } | 178 | } |
| 170 | 179 | ||
| 180 | fn testAllocator(allocator: Allocator) !void { | ||
| 181 | var gen_cat = try GeneralCategories.init(allocator); | ||
| 182 | gen_cat.deinit(allocator); | ||
| 183 | } | ||
| 184 | |||
| 185 | test "Allocation failure" { | ||
| 186 | try testing.checkAllAllocationFailures(testing.allocator, testAllocator, .{}); | ||
| 187 | } | ||
| 188 | |||
| 171 | const std = @import("std"); | 189 | const std = @import("std"); |
| 172 | const builtin = @import("builtin"); | 190 | const builtin = @import("builtin"); |
| 173 | const compress = std.compress; | 191 | const compress = std.compress; |
| 174 | const mem = std.mem; | 192 | const mem = std.mem; |
| 193 | const testing = std.testing; | ||
| 175 | const Allocator = mem.Allocator; | 194 | const Allocator = mem.Allocator; |