A poolable string builder (aka string buffer) for Zig
0

Configure Feed

Select the types of activity you want to include in your feed.

accomodate Zig test runner changes

Karl Seguin (Jan 30, 2025, 8:26 AM +0800) affc5657 9b17ad57

+520 -527
+15 -15
build.zig
··· 1 1 const std = @import("std"); 2 2 3 3 pub fn build(b: *std.Build) !void { 4 - const target = b.standardTargetOptions(.{}); 5 - const optimize = b.standardOptimizeOption(.{}); 4 + const target = b.standardTargetOptions(.{}); 5 + const optimize = b.standardOptimizeOption(.{}); 6 6 7 - _ = b.addModule("buffer", .{ 8 - .root_source_file = b.path("src/buffer.zig"), 9 - }); 7 + _ = b.addModule("buffer", .{ 8 + .root_source_file = b.path("src/buffer.zig"), 9 + }); 10 10 11 - const lib_test = b.addTest(.{ 12 - .root_source_file = b.path("src/buffer.zig"), 13 - .target = target, 14 - .optimize = optimize, 15 - .test_runner = b.path("test_runner.zig"), 16 - }); 17 - const run_test = b.addRunArtifact(lib_test); 18 - run_test.has_side_effects = true; 11 + const lib_test = b.addTest(.{ 12 + .root_source_file = b.path("src/buffer.zig"), 13 + .target = target, 14 + .optimize = optimize, 15 + .test_runner = .{ .path = b.path("test_runner.zig"), .mode = .simple }, 16 + }); 17 + const run_test = b.addRunArtifact(lib_test); 18 + run_test.has_side_effects = true; 19 19 20 - const test_step = b.step("test", "Run tests"); 21 - test_step.dependOn(&run_test.step); 20 + const test_step = b.step("test", "Run tests"); 21 + test_step.dependOn(&run_test.step); 22 22 }
+394 -397
src/buffer.zig
··· 6 6 pub const Pool = @import("pool.zig").Pool; 7 7 8 8 pub const Buffer = struct { 9 - // Two allocators! This is largely a feature meant to be used with the Pool. 10 - // Imagine you have a pool of 100 Buffers. Each one has a static buffer 11 - // of 2K, allocated with a general purpose allocator. We store that in _a. 12 - // Now you acquire one and start to write. You write more than 2K, so we 13 - // need to allocate `dynamic`. Yes, we could use our general purpose allocator 14 - // (aka _a), but what if the app would like to use a different allocator for 15 - // that, like an Arena? 16 - // Thus, `static` is always allocated with _a, and apps can opt to use a 17 - // different allocator, _da, to manage `dynamic`. `_da` is meant to be set 18 - // via pool.acquireWithAllocator since we expect _da to be transient. 19 - _a: Allocator, 9 + // Two allocators! This is largely a feature meant to be used with the Pool. 10 + // Imagine you have a pool of 100 Buffers. Each one has a static buffer 11 + // of 2K, allocated with a general purpose allocator. We store that in _a. 12 + // Now you acquire one and start to write. You write more than 2K, so we 13 + // need to allocate `dynamic`. Yes, we could use our general purpose allocator 14 + // (aka _a), but what if the app would like to use a different allocator for 15 + // that, like an Arena? 16 + // Thus, `static` is always allocated with _a, and apps can opt to use a 17 + // different allocator, _da, to manage `dynamic`. `_da` is meant to be set 18 + // via pool.acquireWithAllocator since we expect _da to be transient. 19 + _a: Allocator, 20 20 21 - _da: ?Allocator, 21 + _da: ?Allocator, 22 22 23 - // where in buf we are 24 - pos: usize, 23 + // where in buf we are 24 + pos: usize, 25 25 26 - // points to either static of dynamic.? 27 - buf: []u8, 26 + // points to either static of dynamic.? 27 + buf: []u8, 28 28 29 - // fixed size, created on startup 30 - static: []u8, 29 + // fixed size, created on startup 30 + static: []u8, 31 31 32 - // created when we try to write more than static.len 33 - dynamic: ?[]u8, 32 + // created when we try to write more than static.len 33 + dynamic: ?[]u8, 34 34 35 - pub fn init(allocator: Allocator, size: usize) !Buffer { 36 - const static = try allocator.alloc(u8, size); 37 - return .{ 38 - ._a = allocator, 39 - ._da = null, 40 - .pos = 0, 41 - .buf = static, 42 - .static = static, 43 - .dynamic = null, 44 - }; 45 - } 35 + pub fn init(allocator: Allocator, size: usize) !Buffer { 36 + const static = try allocator.alloc(u8, size); 37 + return .{ 38 + ._a = allocator, 39 + ._da = null, 40 + .pos = 0, 41 + .buf = static, 42 + .static = static, 43 + .dynamic = null, 44 + }; 45 + } 46 46 47 - pub fn deinit(self: Buffer) void { 48 - const allocator = self._a; 49 - allocator.free(self.static); 50 - if (self.dynamic) |dyn| { 51 - (self._da orelse allocator).free(dyn); 52 - } 53 - } 47 + pub fn deinit(self: Buffer) void { 48 + const allocator = self._a; 49 + allocator.free(self.static); 50 + if (self.dynamic) |dyn| { 51 + (self._da orelse allocator).free(dyn); 52 + } 53 + } 54 54 55 - pub fn reset(self: *Buffer) void { 56 - self.pos = 0; 57 - if (self.dynamic) |dyn| { 58 - (self._da orelse self._a).free(dyn); 59 - self.dynamic = null; 60 - self.buf = self.static; 61 - } 62 - self._da = null; 63 - } 64 - 65 - pub fn resetRetainingCapacity(self: *Buffer) void { 66 - self.pos = 0; 67 - } 68 - 69 - pub fn len(self: Buffer) usize { 70 - return self.pos; 71 - } 55 + pub fn reset(self: *Buffer) void { 56 + self.pos = 0; 57 + if (self.dynamic) |dyn| { 58 + (self._da orelse self._a).free(dyn); 59 + self.dynamic = null; 60 + self.buf = self.static; 61 + } 62 + self._da = null; 63 + } 72 64 73 - pub fn string(self: Buffer) []const u8 { 74 - return self.buf[0..self.pos]; 75 - } 65 + pub fn resetRetainingCapacity(self: *Buffer) void { 66 + self.pos = 0; 67 + } 76 68 77 - pub fn truncate(self: *Buffer, n: usize) void { 78 - const pos = self.pos; 79 - if (n >= pos) { 80 - self.pos = 0; 81 - return; 82 - } 83 - self.pos = pos - n; 84 - } 69 + pub fn len(self: Buffer) usize { 70 + return self.pos; 71 + } 85 72 86 - pub fn skip(self: *Buffer, n: usize) !View { 87 - try self.ensureUnusedCapacity(n); 88 - const pos = self.pos; 89 - self.pos = pos + n; 90 - return .{ 91 - .pos = pos, 92 - .buf = self, 93 - }; 94 - } 73 + pub fn string(self: Buffer) []const u8 { 74 + return self.buf[0..self.pos]; 75 + } 95 76 96 - pub fn writeByte(self: *Buffer, b: u8) !void { 97 - try self.ensureUnusedCapacity(1); 98 - self.writeByteAssumeCapacity(b); 99 - } 77 + pub fn truncate(self: *Buffer, n: usize) void { 78 + const pos = self.pos; 79 + if (n >= pos) { 80 + self.pos = 0; 81 + return; 82 + } 83 + self.pos = pos - n; 84 + } 100 85 101 - pub fn writeByteAssumeCapacity(self: *Buffer, b: u8) void { 102 - const pos = self.pos; 103 - writeByteInto(self.buf, pos, b); 104 - self.pos = pos + 1; 105 - } 86 + pub fn skip(self: *Buffer, n: usize) !View { 87 + try self.ensureUnusedCapacity(n); 88 + const pos = self.pos; 89 + self.pos = pos + n; 90 + return .{ 91 + .pos = pos, 92 + .buf = self, 93 + }; 94 + } 106 95 96 + pub fn writeByte(self: *Buffer, b: u8) !void { 97 + try self.ensureUnusedCapacity(1); 98 + self.writeByteAssumeCapacity(b); 99 + } 107 100 108 - pub fn writeByteNTimes(self: *Buffer, b: u8, n: usize) !void { 109 - try self.ensureUnusedCapacity(n); 110 - const pos = self.pos; 111 - writeByteNTimesInto(self.buf, pos, b, n); 112 - self.pos = pos + n; 113 - } 101 + pub fn writeByteAssumeCapacity(self: *Buffer, b: u8) void { 102 + const pos = self.pos; 103 + writeByteInto(self.buf, pos, b); 104 + self.pos = pos + 1; 105 + } 114 106 115 - pub fn write(self: *Buffer, data: []const u8) !void { 116 - try self.ensureUnusedCapacity(data.len); 117 - self.writeAssumeCapacity(data); 118 - } 107 + pub fn writeByteNTimes(self: *Buffer, b: u8, n: usize) !void { 108 + try self.ensureUnusedCapacity(n); 109 + const pos = self.pos; 110 + writeByteNTimesInto(self.buf, pos, b, n); 111 + self.pos = pos + n; 112 + } 119 113 120 - pub fn writeAssumeCapacity(self: *Buffer, data:[] const u8) void { 121 - const pos = self.pos; 122 - writeInto(self.buf, pos, data); 123 - self.pos = pos + data.len; 124 - } 114 + pub fn write(self: *Buffer, data: []const u8) !void { 115 + try self.ensureUnusedCapacity(data.len); 116 + self.writeAssumeCapacity(data); 117 + } 125 118 126 - // unsafe 127 - pub fn writeAt(self: *Buffer, data: []const u8, pos: usize) void { 128 - @memcpy(self.buf[pos..pos+data.len], data); 129 - } 119 + pub fn writeAssumeCapacity(self: *Buffer, data: []const u8) void { 120 + const pos = self.pos; 121 + writeInto(self.buf, pos, data); 122 + self.pos = pos + data.len; 123 + } 130 124 125 + // unsafe 126 + pub fn writeAt(self: *Buffer, data: []const u8, pos: usize) void { 127 + @memcpy(self.buf[pos .. pos + data.len], data); 128 + } 131 129 132 - pub fn writeU16Little(self: *Buffer, value: u16) !void { 133 - return self.writeIntT(u16, value, .little); 134 - } 130 + pub fn writeU16Little(self: *Buffer, value: u16) !void { 131 + return self.writeIntT(u16, value, .little); 132 + } 135 133 136 - pub fn writeU32Little(self: *Buffer, value: u32) !void { 137 - return self.writeIntT(u32, value, .little); 138 - } 134 + pub fn writeU32Little(self: *Buffer, value: u32) !void { 135 + return self.writeIntT(u32, value, .little); 136 + } 139 137 140 - pub fn writeU64Little(self: *Buffer, value: u64) !void { 141 - return self.writeIntT(u64, value, .little); 142 - } 138 + pub fn writeU64Little(self: *Buffer, value: u64) !void { 139 + return self.writeIntT(u64, value, .little); 140 + } 143 141 144 - pub fn writeIntLittle(self: *Buffer, comptime T: type, value: T) !void { 145 - return self.writeIntT(T, value, .little); 146 - } 142 + pub fn writeIntLittle(self: *Buffer, comptime T: type, value: T) !void { 143 + return self.writeIntT(T, value, .little); 144 + } 147 145 148 - pub fn writeU16Big(self: *Buffer, value: u16) !void { 149 - return self.writeIntT(u16, value, .big); 150 - } 146 + pub fn writeU16Big(self: *Buffer, value: u16) !void { 147 + return self.writeIntT(u16, value, .big); 148 + } 151 149 152 - pub fn writeU32Big(self: *Buffer, value: u32) !void { 153 - return self.writeIntT(u32, value, .big); 154 - } 150 + pub fn writeU32Big(self: *Buffer, value: u32) !void { 151 + return self.writeIntT(u32, value, .big); 152 + } 155 153 156 - pub fn writeU64Big(self: *Buffer, value: u64) !void { 157 - return self.writeIntT(u64, value, .big); 158 - } 154 + pub fn writeU64Big(self: *Buffer, value: u64) !void { 155 + return self.writeIntT(u64, value, .big); 156 + } 159 157 160 - pub fn writeIntBig(self: *Buffer, comptime T: type, value: T) !void { 161 - return self.writeIntT(T, value, .big); 162 - } 158 + pub fn writeIntBig(self: *Buffer, comptime T: type, value: T) !void { 159 + return self.writeIntT(T, value, .big); 160 + } 163 161 164 - pub fn writeIntT(self: *Buffer, comptime T: type, value: T, endian: Endian) !void { 165 - const l = @divExact(@typeInfo(T).int.bits, 8); 166 - const pos = self.pos; 167 - try self.ensureUnusedCapacity(l); 168 - writeIntInto(T, self.buf, pos, value, l, endian); 169 - self.pos = pos + l; 170 - } 162 + pub fn writeIntT(self: *Buffer, comptime T: type, value: T, endian: Endian) !void { 163 + const l = @divExact(@typeInfo(T).int.bits, 8); 164 + const pos = self.pos; 165 + try self.ensureUnusedCapacity(l); 166 + writeIntInto(T, self.buf, pos, value, l, endian); 167 + self.pos = pos + l; 168 + } 171 169 172 - pub fn ensureUnusedCapacity(self: *Buffer, n: usize) !void { 173 - return self.ensureTotalCapacity(self.pos + n); 174 - } 170 + pub fn ensureUnusedCapacity(self: *Buffer, n: usize) !void { 171 + return self.ensureTotalCapacity(self.pos + n); 172 + } 175 173 176 - pub fn ensureTotalCapacity(self: *Buffer, required_capacity: usize) !void { 177 - const buf = self.buf; 178 - if (required_capacity <= buf.len) { 179 - return; 180 - } 174 + pub fn ensureTotalCapacity(self: *Buffer, required_capacity: usize) !void { 175 + const buf = self.buf; 176 + if (required_capacity <= buf.len) { 177 + return; 178 + } 181 179 182 - // from std.ArrayList 183 - var new_capacity = buf.len; 184 - while (true) { 185 - new_capacity +|= new_capacity / 2 + 8; 186 - if (new_capacity >= required_capacity) break; 187 - } 180 + // from std.ArrayList 181 + var new_capacity = buf.len; 182 + while (true) { 183 + new_capacity +|= new_capacity / 2 + 8; 184 + if (new_capacity >= required_capacity) break; 185 + } 188 186 189 - const allocator = self._da orelse self._a; 190 - if (buf.ptr == self.static.ptr or !allocator.resize(buf, new_capacity)) { 191 - const new_buffer = try allocator.alloc(u8, new_capacity); 192 - @memcpy(new_buffer[0..buf.len], buf); 187 + const allocator = self._da orelse self._a; 188 + if (buf.ptr == self.static.ptr or !allocator.resize(buf, new_capacity)) { 189 + const new_buffer = try allocator.alloc(u8, new_capacity); 190 + @memcpy(new_buffer[0..buf.len], buf); 193 191 194 - if (self.dynamic) |dyn| { 195 - allocator.free(dyn); 196 - } 192 + if (self.dynamic) |dyn| { 193 + allocator.free(dyn); 194 + } 197 195 198 - self.buf = new_buffer; 199 - self.dynamic = new_buffer; 200 - } else { 201 - const new_buffer = buf.ptr[0..new_capacity]; 202 - self.buf = new_buffer; 203 - self.dynamic = new_buffer; 204 - } 205 - } 196 + self.buf = new_buffer; 197 + self.dynamic = new_buffer; 198 + } else { 199 + const new_buffer = buf.ptr[0..new_capacity]; 200 + self.buf = new_buffer; 201 + self.dynamic = new_buffer; 202 + } 203 + } 206 204 207 - pub fn copy(self: Buffer, allocator: Allocator) ![]const u8 { 208 - const pos = self.pos; 209 - const c = try allocator.alloc(u8, pos); 210 - @memcpy(c, self.buf[0..pos]); 211 - return c; 212 - } 205 + pub fn copy(self: Buffer, allocator: Allocator) ![]const u8 { 206 + const pos = self.pos; 207 + const c = try allocator.alloc(u8, pos); 208 + @memcpy(c, self.buf[0..pos]); 209 + return c; 210 + } 213 211 214 - pub fn writer(self: *Buffer) Writer.IOWriter { 215 - return .{.context = Writer.init(self)}; 216 - } 212 + pub fn writer(self: *Buffer) Writer.IOWriter { 213 + return .{ .context = Writer.init(self) }; 214 + } 217 215 218 - pub const Writer = struct { 219 - w: *Buffer, 216 + pub const Writer = struct { 217 + w: *Buffer, 220 218 221 - pub const Error = Allocator.Error; 222 - pub const IOWriter = std.io.Writer(Writer, error{OutOfMemory}, Writer.write); 219 + pub const Error = Allocator.Error; 220 + pub const IOWriter = std.io.Writer(Writer, error{OutOfMemory}, Writer.write); 223 221 224 - fn init(w: *Buffer) Writer { 225 - return .{.w = w}; 226 - } 222 + fn init(w: *Buffer) Writer { 223 + return .{ .w = w }; 224 + } 227 225 228 - pub fn write(self: Writer, data: []const u8) Allocator.Error!usize { 229 - try self.w.write(data); 230 - return data.len; 231 - } 232 - }; 226 + pub fn write(self: Writer, data: []const u8) Allocator.Error!usize { 227 + try self.w.write(data); 228 + return data.len; 229 + } 230 + }; 233 231 }; 234 232 235 233 pub const View = struct { 236 - pos: usize, 237 - buf: *Buffer, 234 + pos: usize, 235 + buf: *Buffer, 238 236 239 - pub fn writeByte(self: *View, b: u8) void { 240 - const pos = self.pos; 241 - writeByteInto(self.buf.buf, pos, b); 242 - self.pos = pos + 1; 243 - } 237 + pub fn writeByte(self: *View, b: u8) void { 238 + const pos = self.pos; 239 + writeByteInto(self.buf.buf, pos, b); 240 + self.pos = pos + 1; 241 + } 244 242 245 - pub fn writeByteNTimes(self: *View, b: u8, n: usize) void { 246 - const pos = self.pos; 247 - writeByteNTimesInto(self.buf.buf, pos, b, n); 248 - self.pos = pos + n; 249 - } 243 + pub fn writeByteNTimes(self: *View, b: u8, n: usize) void { 244 + const pos = self.pos; 245 + writeByteNTimesInto(self.buf.buf, pos, b, n); 246 + self.pos = pos + n; 247 + } 250 248 251 - pub fn write(self: *View, data: []const u8) void { 252 - const pos = self.pos; 253 - writeInto(self.buf.buf, pos, data); 254 - self.pos = pos + data.len; 255 - } 249 + pub fn write(self: *View, data: []const u8) void { 250 + const pos = self.pos; 251 + writeInto(self.buf.buf, pos, data); 252 + self.pos = pos + data.len; 253 + } 256 254 257 - pub fn writeU16(self: *View, value: u16) void { 258 - return self.writeIntT(u16, value, self.endian); 259 - } 255 + pub fn writeU16(self: *View, value: u16) void { 256 + return self.writeIntT(u16, value, self.endian); 257 + } 260 258 261 - pub fn writeI16(self: *View, value: i16) void { 262 - return self.writeIntT(i16, value, self.endian); 263 - } 259 + pub fn writeI16(self: *View, value: i16) void { 260 + return self.writeIntT(i16, value, self.endian); 261 + } 264 262 265 - pub fn writeU32(self: *View, value: u32) void { 266 - return self.writeIntT(u32, value, self.endian); 267 - } 263 + pub fn writeU32(self: *View, value: u32) void { 264 + return self.writeIntT(u32, value, self.endian); 265 + } 268 266 269 - pub fn writeI32(self: *View, value: i32) void { 270 - return self.writeIntT(i32, value, self.endian); 271 - } 267 + pub fn writeI32(self: *View, value: i32) void { 268 + return self.writeIntT(i32, value, self.endian); 269 + } 272 270 273 - pub fn writeU64(self: *View, value: u64) void { 274 - return self.writeIntT(u64, value, self.endian); 275 - } 271 + pub fn writeU64(self: *View, value: u64) void { 272 + return self.writeIntT(u64, value, self.endian); 273 + } 276 274 277 - pub fn writeI64(self: *View, value: i64) void { 278 - return self.writeIntT(i64, value, self.endian); 279 - } 275 + pub fn writeI64(self: *View, value: i64) void { 276 + return self.writeIntT(i64, value, self.endian); 277 + } 280 278 281 - pub fn writeU16Little(self: *View, value: u16) void { 282 - return self.writeIntT(u16, value, .little); 283 - } 279 + pub fn writeU16Little(self: *View, value: u16) void { 280 + return self.writeIntT(u16, value, .little); 281 + } 284 282 285 - pub fn writeI16Little(self: *View, value: i16) void { 286 - return self.writeIntT(i16, value, .little); 287 - } 283 + pub fn writeI16Little(self: *View, value: i16) void { 284 + return self.writeIntT(i16, value, .little); 285 + } 288 286 289 - pub fn writeU32Little(self: *View, value: u32) void { 290 - return self.writeIntT(u32, value, .little); 291 - } 287 + pub fn writeU32Little(self: *View, value: u32) void { 288 + return self.writeIntT(u32, value, .little); 289 + } 292 290 293 - pub fn writeI32Little(self: *View, value: i32) void { 294 - return self.writeIntT(i32, value, .little); 295 - } 291 + pub fn writeI32Little(self: *View, value: i32) void { 292 + return self.writeIntT(i32, value, .little); 293 + } 296 294 297 - pub fn writeU64Little(self: *View, value: u64) void { 298 - return self.writeIntT(u64, value, .little); 299 - } 295 + pub fn writeU64Little(self: *View, value: u64) void { 296 + return self.writeIntT(u64, value, .little); 297 + } 300 298 301 - pub fn writeI64Little(self: *View, value: i64) void { 302 - return self.writeIntT(i64, value, .little); 303 - } 299 + pub fn writeI64Little(self: *View, value: i64) void { 300 + return self.writeIntT(i64, value, .little); 301 + } 304 302 305 - pub fn writeIntLittle(self: *View, comptime T: type, value: T) void { 306 - self.writeIntT(T, value, .little); 307 - } 303 + pub fn writeIntLittle(self: *View, comptime T: type, value: T) void { 304 + self.writeIntT(T, value, .little); 305 + } 308 306 309 - pub fn writeU16Big(self: *View, value: u16) void { 310 - return self.writeIntT(u16, value, .big); 311 - } 307 + pub fn writeU16Big(self: *View, value: u16) void { 308 + return self.writeIntT(u16, value, .big); 309 + } 312 310 313 - pub fn writeI16Big(self: *View, value: i16) void { 314 - return self.writeIntT(i16, value, .big); 315 - } 311 + pub fn writeI16Big(self: *View, value: i16) void { 312 + return self.writeIntT(i16, value, .big); 313 + } 316 314 317 - pub fn writeU32Big(self: *View, value: u32) void { 318 - return self.writeIntT(u32, value, .big); 319 - } 315 + pub fn writeU32Big(self: *View, value: u32) void { 316 + return self.writeIntT(u32, value, .big); 317 + } 320 318 321 - pub fn writeI32Big(self: *View, value: i32) void { 322 - return self.writeIntT(i32, value, .big); 323 - } 319 + pub fn writeI32Big(self: *View, value: i32) void { 320 + return self.writeIntT(i32, value, .big); 321 + } 324 322 325 - pub fn writeU64Big(self: *View, value: u64) void { 326 - return self.writeIntT(u64, value, .big); 327 - } 323 + pub fn writeU64Big(self: *View, value: u64) void { 324 + return self.writeIntT(u64, value, .big); 325 + } 328 326 329 - pub fn writeI64Big(self: *View, value: i64) void { 330 - return self.writeIntT(i64, value, .big); 331 - } 327 + pub fn writeI64Big(self: *View, value: i64) void { 328 + return self.writeIntT(i64, value, .big); 329 + } 332 330 333 - pub fn writeIntBig(self: *View, comptime T: type, value: T) void { 334 - self.writeIntT(T, value, .big); 335 - } 331 + pub fn writeIntBig(self: *View, comptime T: type, value: T) void { 332 + self.writeIntT(T, value, .big); 333 + } 336 334 337 - pub fn writeIntT(self: *View, comptime T: type, value: T, endian: Endian) void { 338 - const l = @divExact(@typeInfo(T).int.bits, 8); 339 - const pos = self.pos; 340 - writeIntInto(T, self.buf.buf, pos, value, l, endian); 341 - self.pos = pos + l; 342 - } 335 + pub fn writeIntT(self: *View, comptime T: type, value: T, endian: Endian) void { 336 + const l = @divExact(@typeInfo(T).int.bits, 8); 337 + const pos = self.pos; 338 + writeIntInto(T, self.buf.buf, pos, value, l, endian); 339 + self.pos = pos + l; 340 + } 343 341 }; 344 342 345 343 // Functions that write for either a *StringBuilder or a *View 346 344 inline fn writeInto(buf: []u8, pos: usize, data: []const u8) void { 347 - const end_pos = pos + data.len; 348 - @memcpy(buf[pos..end_pos], data); 345 + const end_pos = pos + data.len; 346 + @memcpy(buf[pos..end_pos], data); 349 347 } 350 348 351 349 inline fn writeByteInto(buf: []u8, pos: usize, b: u8) void { 352 - buf[pos] = b; 350 + buf[pos] = b; 353 351 } 354 352 355 353 inline fn writeByteNTimesInto(buf: []u8, pos: usize, b: u8, n: usize) void { 356 - for (0..n) |offset| { 357 - buf[pos+offset] = b; 358 - } 354 + for (0..n) |offset| { 355 + buf[pos + offset] = b; 356 + } 359 357 } 360 358 361 359 inline fn writeIntInto(comptime T: type, buf: []u8, pos: usize, value: T, l: usize, endian: Endian) void { 362 - const end_pos = pos + l; 363 - std.mem.writeInt(T, buf[pos..end_pos][0..l], value, endian); 360 + const end_pos = pos + l; 361 + std.mem.writeInt(T, buf[pos..end_pos][0..l], value, endian); 364 362 } 365 363 366 364 const t = @import("t.zig"); 367 365 test { 368 - std.testing.refAllDecls(@This()); 366 + std.testing.refAllDecls(@This()); 369 367 } 370 368 371 369 test "growth" { 372 - var w = try Buffer.init(t.allocator, 10); 373 - defer w.deinit(); 370 + var w = try Buffer.init(t.allocator, 10); 371 + defer w.deinit(); 374 372 375 - // we reset at the end of the loop, and things should work the exact same 376 - // after a reset 377 - for (0..5) |_| { 378 - try t.expectEqual(0, w.len()); 379 - try w.writeByte('o'); 380 - try t.expectEqual(1, w.len()); 381 - try t.expectString("o", w.string()); 382 - try t.expectEqual(null, w.dynamic); 373 + // we reset at the end of the loop, and things should work the exact same 374 + // after a reset 375 + for (0..5) |_| { 376 + try t.expectEqual(0, w.len()); 377 + try w.writeByte('o'); 378 + try t.expectEqual(1, w.len()); 379 + try t.expectString("o", w.string()); 380 + try t.expectEqual(null, w.dynamic); 383 381 384 - // stays in static 385 - try w.write("ver 9000!"); 386 - try t.expectEqual(10, w.len()); 387 - try t.expectString("over 9000!", w.string()); 388 - try t.expectEqual(null, w.dynamic); 382 + // stays in static 383 + try w.write("ver 9000!"); 384 + try t.expectEqual(10, w.len()); 385 + try t.expectString("over 9000!", w.string()); 386 + try t.expectEqual(null, w.dynamic); 389 387 390 - // grows into dynamic 391 - try w.write("!!!"); 392 - try t.expectEqual(13, w.len()); 393 - try t.expectString("over 9000!!!!", w.string()); 394 - try t.expectEqual(false, w.dynamic == null); 388 + // grows into dynamic 389 + try w.write("!!!"); 390 + try t.expectEqual(13, w.len()); 391 + try t.expectString("over 9000!!!!", w.string()); 392 + try t.expectEqual(false, w.dynamic == null); 395 393 394 + try w.write("If you were to run this code, you'd almost certainly see a segmentation fault (aka, segfault). We create a Response which involves creating an ArenaAllocator and from that, an Allocator. This allocator is then used to format our string. For the purpose of this example, we create a 2nd response and immediately free it. We need this for the same reason that warning1 in our first example printed an almost ok value: we want to re-initialize the memory in our init function stack."); 395 + try t.expectEqual(492, w.len()); 396 + try t.expectString("over 9000!!!!If you were to run this code, you'd almost certainly see a segmentation fault (aka, segfault). We create a Response which involves creating an ArenaAllocator and from that, an Allocator. This allocator is then used to format our string. For the purpose of this example, we create a 2nd response and immediately free it. We need this for the same reason that warning1 in our first example printed an almost ok value: we want to re-initialize the memory in our init function stack.", w.string()); 396 397 397 - try w.write("If you were to run this code, you'd almost certainly see a segmentation fault (aka, segfault). We create a Response which involves creating an ArenaAllocator and from that, an Allocator. This allocator is then used to format our string. For the purpose of this example, we create a 2nd response and immediately free it. We need this for the same reason that warning1 in our first example printed an almost ok value: we want to re-initialize the memory in our init function stack."); 398 - try t.expectEqual(492, w.len()); 399 - try t.expectString("over 9000!!!!If you were to run this code, you'd almost certainly see a segmentation fault (aka, segfault). We create a Response which involves creating an ArenaAllocator and from that, an Allocator. This allocator is then used to format our string. For the purpose of this example, we create a 2nd response and immediately free it. We need this for the same reason that warning1 in our first example printed an almost ok value: we want to re-initialize the memory in our init function stack.", w.string()); 400 - 401 - w.reset(); 402 - } 398 + w.reset(); 399 + } 403 400 } 404 401 405 402 test "growth with int" { 406 - var w = try Buffer.init(t.allocator, 10); 407 - defer w.deinit(); 403 + var w = try Buffer.init(t.allocator, 10); 404 + defer w.deinit(); 408 405 409 - try w.writeU64Big(9000); 410 - try w.writeU64Big(10000); 411 - try t.expectSlice(u8, &.{0, 0, 0, 0, 0, 0, 0x23, 0x28}, w.string()[0..8]); 412 - try t.expectSlice(u8, &.{0, 0, 0, 0, 0, 0, 0x27, 0x10}, w.string()[8..16]); 406 + try w.writeU64Big(9000); 407 + try w.writeU64Big(10000); 408 + try t.expectSlice(u8, &.{ 0, 0, 0, 0, 0, 0, 0x23, 0x28 }, w.string()[0..8]); 409 + try t.expectSlice(u8, &.{ 0, 0, 0, 0, 0, 0, 0x27, 0x10 }, w.string()[8..16]); 413 410 } 414 411 415 412 test "truncate" { 416 - var w = try Buffer.init(t.allocator, 10); 417 - defer w.deinit(); 413 + var w = try Buffer.init(t.allocator, 10); 414 + defer w.deinit(); 418 415 419 - w.truncate(100); 420 - try t.expectEqual(0, w.len()); 416 + w.truncate(100); 417 + try t.expectEqual(0, w.len()); 421 418 422 - try w.write("hello world!1"); 419 + try w.write("hello world!1"); 423 420 424 - w.truncate(0); 425 - try t.expectEqual(13, w.len()); 426 - try t.expectString("hello world!1", w.string()); 421 + w.truncate(0); 422 + try t.expectEqual(13, w.len()); 423 + try t.expectString("hello world!1", w.string()); 427 424 428 - w.truncate(1); 429 - try t.expectEqual(12, w.len()); 430 - try t.expectString("hello world!", w.string()); 425 + w.truncate(1); 426 + try t.expectEqual(12, w.len()); 427 + try t.expectString("hello world!", w.string()); 431 428 432 - w.truncate(5); 433 - try t.expectEqual(7, w.len()); 434 - try t.expectString("hello w", w.string()); 429 + w.truncate(5); 430 + try t.expectEqual(7, w.len()); 431 + try t.expectString("hello w", w.string()); 435 432 } 436 433 437 434 test "reset without clear" { 438 - var w = try Buffer.init(t.allocator, 5); 439 - defer w.deinit(); 435 + var w = try Buffer.init(t.allocator, 5); 436 + defer w.deinit(); 440 437 441 - try w.write("hello world!1"); 442 - try t.expectString("hello world!1", w.string()); 438 + try w.write("hello world!1"); 439 + try t.expectString("hello world!1", w.string()); 443 440 444 - w.resetRetainingCapacity(); 445 - try t.expectEqual(0, w.len()); 446 - try t.expectEqual(false, w.dynamic == null); 447 - try w.write("over 9000"); 448 - try w.write("over 9000"); 441 + w.resetRetainingCapacity(); 442 + try t.expectEqual(0, w.len()); 443 + try t.expectEqual(false, w.dynamic == null); 444 + try w.write("over 9000"); 445 + try w.write("over 9000"); 449 446 } 450 447 451 448 test "fuzz" { 452 - var control = std.ArrayList(u8).init(t.allocator); 453 - defer control.deinit(); 449 + var control = std.ArrayList(u8).init(t.allocator); 450 + defer control.deinit(); 454 451 455 - var r = t.getRandom(); 456 - const random = r.random(); 452 + var r = t.getRandom(); 453 + const random = r.random(); 457 454 458 - var arena = std.heap.ArenaAllocator.init(t.allocator); 459 - defer arena.deinit(); 455 + var arena = std.heap.ArenaAllocator.init(t.allocator); 456 + defer arena.deinit(); 460 457 461 - const aa = arena.allocator(); 458 + const aa = arena.allocator(); 462 459 463 - for (1..100) |_| { 464 - var w = try Buffer.init(t.allocator, random.uintAtMost(u16, 1000) + 1); 465 - defer w.deinit(); 460 + for (1..100) |_| { 461 + var w = try Buffer.init(t.allocator, random.uintAtMost(u16, 1000) + 1); 462 + defer w.deinit(); 466 463 467 - for (1..100) |_| { 468 - const input = testString(aa, random); 469 - try w.write(input); 470 - try control.appendSlice(input); 471 - try t.expectString(control.items, w.string()); 472 - } 473 - w.reset(); 474 - control.clearRetainingCapacity(); 475 - _ = arena.reset(.free_all); 476 - } 464 + for (1..100) |_| { 465 + const input = testString(aa, random); 466 + try w.write(input); 467 + try control.appendSlice(input); 468 + try t.expectString(control.items, w.string()); 469 + } 470 + w.reset(); 471 + control.clearRetainingCapacity(); 472 + _ = arena.reset(.free_all); 473 + } 477 474 } 478 475 479 476 test "writer" { 480 - var w = try Buffer.init(t.allocator, 10); 481 - defer w.deinit(); 477 + var w = try Buffer.init(t.allocator, 10); 478 + defer w.deinit(); 482 479 483 - try std.json.stringify(.{.over = 9000, .spice = "must flow", .ok = true}, .{}, w.writer()); 484 - try t.expectString("{\"over\":9000,\"spice\":\"must flow\",\"ok\":true}", w.string()); 480 + try std.json.stringify(.{ .over = 9000, .spice = "must flow", .ok = true }, .{}, w.writer()); 481 + try t.expectString("{\"over\":9000,\"spice\":\"must flow\",\"ok\":true}", w.string()); 485 482 } 486 483 487 484 test "copy" { 488 - var w = try Buffer.init(t.allocator, 10); 489 - defer w.deinit(); 485 + var w = try Buffer.init(t.allocator, 10); 486 + defer w.deinit(); 490 487 491 - try w.write("hello!!"); 492 - const c = try w.copy(t.allocator); 493 - defer t.allocator.free(c); 494 - try t.expectString("hello!!", c); 488 + try w.write("hello!!"); 489 + const c = try w.copy(t.allocator); 490 + defer t.allocator.free(c); 491 + try t.expectString("hello!!", c); 495 492 } 496 493 497 494 test "write little" { 498 - var w = try Buffer.init(t.allocator, 20); 499 - defer w.deinit(); 500 - try w.writeU64Little(11234567890123456789); 501 - try t.expectSlice(u8, &[_]u8{21, 129, 209, 7, 249, 51, 233, 155}, w.string()); 495 + var w = try Buffer.init(t.allocator, 20); 496 + defer w.deinit(); 497 + try w.writeU64Little(11234567890123456789); 498 + try t.expectSlice(u8, &[_]u8{ 21, 129, 209, 7, 249, 51, 233, 155 }, w.string()); 502 499 503 - try w.writeU32Little(3283856184); 504 - try t.expectSlice(u8, &[_]u8{21, 129, 209, 7, 249, 51, 233, 155, 56, 171, 187, 195}, w.string()); 500 + try w.writeU32Little(3283856184); 501 + try t.expectSlice(u8, &[_]u8{ 21, 129, 209, 7, 249, 51, 233, 155, 56, 171, 187, 195 }, w.string()); 505 502 506 - try w.writeU16Little(15000); 507 - try t.expectSlice(u8, &[_]u8{21, 129, 209, 7, 249, 51, 233, 155, 56, 171, 187, 195, 152, 58}, w.string()); 503 + try w.writeU16Little(15000); 504 + try t.expectSlice(u8, &[_]u8{ 21, 129, 209, 7, 249, 51, 233, 155, 56, 171, 187, 195, 152, 58 }, w.string()); 508 505 } 509 506 510 507 test "write big" { 511 - var w = try Buffer.init(t.allocator, 20); 512 - defer w.deinit(); 513 - try w.writeU64Big(11234567890123456789); 514 - try t.expectSlice(u8, &[_]u8{155, 233, 51, 249, 7, 209, 129, 21}, w.string()); 508 + var w = try Buffer.init(t.allocator, 20); 509 + defer w.deinit(); 510 + try w.writeU64Big(11234567890123456789); 511 + try t.expectSlice(u8, &[_]u8{ 155, 233, 51, 249, 7, 209, 129, 21 }, w.string()); 515 512 516 - try w.writeU32Big(3283856184); 517 - try t.expectSlice(u8, &[_]u8{155, 233, 51, 249, 7, 209, 129, 21, 195, 187, 171, 56}, w.string()); 513 + try w.writeU32Big(3283856184); 514 + try t.expectSlice(u8, &[_]u8{ 155, 233, 51, 249, 7, 209, 129, 21, 195, 187, 171, 56 }, w.string()); 518 515 519 - try w.writeU16Big(15000); 520 - try t.expectSlice(u8, &[_]u8{155, 233, 51, 249, 7, 209, 129, 21, 195, 187, 171, 56, 58, 152}, w.string()); 516 + try w.writeU16Big(15000); 517 + try t.expectSlice(u8, &[_]u8{ 155, 233, 51, 249, 7, 209, 129, 21, 195, 187, 171, 56, 58, 152 }, w.string()); 521 518 } 522 519 523 520 test "skip & view" { 524 - var w = try Buffer.init(t.allocator, 10); 525 - defer w.deinit(); 521 + var w = try Buffer.init(t.allocator, 10); 522 + defer w.deinit(); 526 523 527 - var view = try w.skip(4); 528 - try w.write("hello world!!"); 524 + var view = try w.skip(4); 525 + try w.write("hello world!!"); 529 526 530 - view.writeU32Big(@intCast(w.len() - 4)); 527 + view.writeU32Big(@intCast(w.len() - 4)); 531 528 532 - try w.writeByte('\n'); 533 - try t.expectSlice(u8, &[_]u8{0, 0, 0, 13, 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!', '!', '\n'}, w.string()); 529 + try w.writeByte('\n'); 530 + try t.expectSlice(u8, &[_]u8{ 0, 0, 0, 13, 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!', '!', '\n' }, w.string()); 534 531 } 535 532 536 533 test "writeAt" { 537 - var w = try Buffer.init(t.allocator, 200); 538 - defer w.deinit(); 534 + var w = try Buffer.init(t.allocator, 200); 535 + defer w.deinit(); 539 536 540 - try w.write("hello"); 541 - try w.write(&.{0, 0, 0, 0, 0}); 542 - try w.write("world"); 537 + try w.write("hello"); 538 + try w.write(&.{ 0, 0, 0, 0, 0 }); 539 + try w.write("world"); 543 540 544 - w.writeAt(" ", 5); 545 - w.writeAt("123 ", 6); 546 - try t.expectString("hello 123 world", w.string()); 541 + w.writeAt(" ", 5); 542 + w.writeAt("123 ", 6); 543 + try t.expectString("hello 123 world", w.string()); 547 544 } 548 545 549 546 fn testString(allocator: Allocator, random: std.Random) []const u8 { 550 - var s = allocator.alloc(u8, random.uintAtMost(u8, 100) + 1) catch unreachable; 551 - for (0..s.len) |i| { 552 - s[i] = random.uintAtMost(u8, 90) + 32; 553 - } 554 - return s; 547 + var s = allocator.alloc(u8, random.uintAtMost(u8, 100) + 1) catch unreachable; 548 + for (0..s.len) |i| { 549 + s[i] = random.uintAtMost(u8, 90) + 32; 550 + } 551 + return s; 555 552 }
+107 -111
src/pool.zig
··· 7 7 const Allocator = std.mem.Allocator; 8 8 9 9 pub const Pool = struct { 10 - mutex: Mutex, 11 - available: usize, 12 - allocator: Allocator, 13 - buffer_size: usize, 14 - buffers: []*Buffer, 10 + mutex: Mutex, 11 + available: usize, 12 + allocator: Allocator, 13 + buffer_size: usize, 14 + buffers: []*Buffer, 15 15 16 - pub fn init(allocator: Allocator, pool_size: u16, buffer_size: usize) !Pool { 17 - const buffers = try allocator.alloc(*Buffer, pool_size); 16 + pub fn init(allocator: Allocator, pool_size: u16, buffer_size: usize) !Pool { 17 + const buffers = try allocator.alloc(*Buffer, pool_size); 18 18 19 - for (0..pool_size) |i| { 20 - const sb = try allocator.create(Buffer); 21 - sb.* = try Buffer.init(allocator, buffer_size); 22 - buffers[i] = sb; 23 - } 19 + for (0..pool_size) |i| { 20 + const sb = try allocator.create(Buffer); 21 + sb.* = try Buffer.init(allocator, buffer_size); 22 + buffers[i] = sb; 23 + } 24 24 25 - return .{ 26 - .mutex = .{}, 27 - .buffers = buffers, 28 - .allocator = allocator, 29 - .available = pool_size, 30 - .buffer_size = buffer_size 31 - }; 32 - } 25 + return .{ .mutex = .{}, .buffers = buffers, .allocator = allocator, .available = pool_size, .buffer_size = buffer_size }; 26 + } 33 27 34 - pub fn deinit(self: *Pool) void { 35 - const allocator = self.allocator; 36 - for (self.buffers) |sb| { 37 - sb.deinit(); 38 - allocator.destroy(sb); 39 - } 40 - allocator.free(self.buffers); 41 - } 28 + pub fn deinit(self: *Pool) void { 29 + const allocator = self.allocator; 30 + for (self.buffers) |sb| { 31 + sb.deinit(); 32 + allocator.destroy(sb); 33 + } 34 + allocator.free(self.buffers); 35 + } 42 36 43 - pub fn acquire(self: *Pool) !*Buffer { 44 - return self.acquireWithAllocator(self.allocator); 45 - } 37 + pub fn acquire(self: *Pool) !*Buffer { 38 + return self.acquireWithAllocator(self.allocator); 39 + } 46 40 47 - pub fn acquireWithAllocator(self: *Pool, dyn_allocator: Allocator) !*Buffer { 48 - const buffers = self.buffers; 41 + pub fn acquireWithAllocator(self: *Pool, dyn_allocator: Allocator) !*Buffer { 42 + const buffers = self.buffers; 49 43 50 - self.mutex.lock(); 51 - const available = self.available; 52 - if (available == 0) { 53 - // dont hold the lock over factory 54 - self.mutex.unlock(); 44 + self.mutex.lock(); 45 + const available = self.available; 46 + if (available == 0) { 47 + // dont hold the lock over factory 48 + self.mutex.unlock(); 55 49 56 - const allocator = self.allocator; 57 - const sb = try allocator.create(Buffer); 58 - sb.* = try Buffer.init(allocator, self.buffer_size); 59 - sb._da = dyn_allocator; 60 - return sb; 61 - } 62 - const index = available - 1; 63 - const sb = buffers[index]; 64 - self.available = index; 65 - self.mutex.unlock(); 66 - sb._da = dyn_allocator; 67 - return sb; 68 - } 50 + const allocator = self.allocator; 51 + const sb = try allocator.create(Buffer); 52 + sb.* = try Buffer.init(allocator, self.buffer_size); 53 + sb._da = dyn_allocator; 54 + return sb; 55 + } 56 + const index = available - 1; 57 + const sb = buffers[index]; 58 + self.available = index; 59 + self.mutex.unlock(); 60 + sb._da = dyn_allocator; 61 + return sb; 62 + } 69 63 70 - pub fn release(self: *Pool, sb: *Buffer) void { 71 - sb.reset(); 72 - self.mutex.lock(); 64 + pub fn release(self: *Pool, sb: *Buffer) void { 65 + sb.reset(); 66 + self.mutex.lock(); 73 67 74 - var buffers = self.buffers; 75 - const available = self.available; 76 - if (available == buffers.len) { 77 - self.mutex.unlock(); 78 - const allocator = self.allocator; 79 - sb.deinit(); 80 - allocator.destroy(sb); 81 - return; 82 - } 83 - buffers[available] = sb; 84 - self.available = available + 1; 85 - self.mutex.unlock(); 86 - } 68 + var buffers = self.buffers; 69 + const available = self.available; 70 + if (available == buffers.len) { 71 + self.mutex.unlock(); 72 + const allocator = self.allocator; 73 + sb.deinit(); 74 + allocator.destroy(sb); 75 + return; 76 + } 77 + buffers[available] = sb; 78 + self.available = available + 1; 79 + self.mutex.unlock(); 80 + } 87 81 }; 88 82 89 83 const t = @import("t.zig"); 90 84 test "pool: acquire and release" { 91 - var p = try Pool.init(t.allocator, 2, 100); 92 - defer p.deinit(); 85 + var p = try Pool.init(t.allocator, 2, 100); 86 + defer p.deinit(); 93 87 94 - const sb1a = p.acquire() catch unreachable; 95 - const sb2a = p.acquire() catch unreachable; 96 - const sb3a = p.acquire() catch unreachable; // this should be dynamically generated 88 + const sb1a = p.acquire() catch unreachable; 89 + const sb2a = p.acquire() catch unreachable; 90 + const sb3a = p.acquire() catch unreachable; // this should be dynamically generated 97 91 98 - try t.expectEqual(false, sb1a == sb2a); 99 - try t.expectEqual(false, sb2a == sb3a); 92 + try t.expectEqual(false, sb1a == sb2a); 93 + try t.expectEqual(false, sb2a == sb3a); 100 94 101 - p.release(sb1a); 95 + p.release(sb1a); 102 96 103 - const sb1b = p.acquire() catch unreachable; 104 - try t.expectEqual(true, sb1a == sb1b); 97 + const sb1b = p.acquire() catch unreachable; 98 + try t.expectEqual(true, sb1a == sb1b); 105 99 106 - p.release(sb3a); 107 - p.release(sb2a); 108 - p.release(sb1b); 100 + p.release(sb3a); 101 + p.release(sb2a); 102 + p.release(sb1b); 109 103 } 110 104 111 105 test "pool: dynamic allocator" { 112 - var p = try Pool.init(t.allocator, 2, 5); 113 - defer p.deinit(); 106 + var p = try Pool.init(t.allocator, 2, 5); 107 + defer p.deinit(); 114 108 115 - var arena = std.heap.ArenaAllocator.init(t.allocator); 116 - defer arena.deinit(); 109 + var arena = std.heap.ArenaAllocator.init(t.allocator); 110 + defer arena.deinit(); 117 111 118 - var sb = p.acquireWithAllocator(arena.allocator()) catch unreachable; 119 - try sb.write("hello world how's it going?"); 120 - try sb.write("he"); 121 - try sb.write("hello world"); 122 - try sb.write("are you doing well? I hope so, I don't love how this is being implemented, but I think the feature is worthwhile"); 123 - p.release(sb); 112 + var sb = p.acquireWithAllocator(arena.allocator()) catch unreachable; 113 + try sb.write("hello world how's it going?"); 114 + try sb.write("he"); 115 + try sb.write("hello world"); 116 + try sb.write("are you doing well? I hope so, I don't love how this is being implemented, but I think the feature is worthwhile"); 117 + p.release(sb); 124 118 } 125 119 126 120 test "pool: threadsafety" { 127 - var p = try Pool.init(t.allocator, 3, 20); 128 - defer p.deinit(); 121 + var p = try Pool.init(t.allocator, 3, 20); 122 + defer p.deinit(); 129 123 130 - // initialize this to 0 since we're asserting that it's 0 131 - for (p.buffers) |sb| { 132 - sb.buf[0] = 0; 133 - } 124 + // initialize this to 0 since we're asserting that it's 0 125 + for (p.buffers) |sb| { 126 + sb.buf[0] = 0; 127 + } 134 128 135 - const t1 = try std.Thread.spawn(.{}, testPool, .{&p}); 136 - const t2 = try std.Thread.spawn(.{}, testPool, .{&p}); 137 - const t3 = try std.Thread.spawn(.{}, testPool, .{&p}); 129 + const t1 = try std.Thread.spawn(.{}, testPool, .{&p}); 130 + const t2 = try std.Thread.spawn(.{}, testPool, .{&p}); 131 + const t3 = try std.Thread.spawn(.{}, testPool, .{&p}); 138 132 139 - t1.join(); t2.join(); t3.join(); 133 + t1.join(); 134 + t2.join(); 135 + t3.join(); 140 136 } 141 137 142 138 fn testPool(p: *Pool) void { 143 - var r = t.getRandom(); 144 - const random = r.random(); 139 + var r = t.getRandom(); 140 + const random = r.random(); 145 141 146 - for (0..5000) |_| { 147 - var sb = p.acquire() catch unreachable; 148 - // no other thread should have set this to 255 149 - std.debug.assert(sb.buf[0] == 0); 142 + for (0..5000) |_| { 143 + var sb = p.acquire() catch unreachable; 144 + // no other thread should have set this to 255 145 + std.debug.assert(sb.buf[0] == 0); 150 146 151 - sb.buf[0] = 255; 152 - std.time.sleep(random.uintAtMost(u32, 100000)); 153 - sb.buf[0] = 0; 154 - p.release(sb); 155 - } 147 + sb.buf[0] = 255; 148 + std.time.sleep(random.uintAtMost(u32, 100000)); 149 + sb.buf[0] = 0; 150 + p.release(sb); 151 + } 156 152 }
+4 -4
src/t.zig
··· 5 5 // when expected is frequently a comptime. 6 6 // https://github.com/ziglang/zig/issues/4437 7 7 pub fn expectEqual(expected: anytype, actual: anytype) !void { 8 - try std.testing.expectEqual(@as(@TypeOf(actual), expected), actual); 8 + try std.testing.expectEqual(@as(@TypeOf(actual), expected), actual); 9 9 } 10 10 pub const expectString = std.testing.expectEqualStrings; 11 11 pub const expectSlice = std.testing.expectEqualSlices; 12 12 13 13 pub fn getRandom() std.Random.DefaultPrng { 14 - var seed: u64 = undefined; 15 - std.posix.getrandom(std.mem.asBytes(&seed)) catch unreachable; 16 - return std.Random.DefaultPrng.init(seed); 14 + var seed: u64 = undefined; 15 + std.posix.getrandom(std.mem.asBytes(&seed)) catch unreachable; 16 + return std.Random.DefaultPrng.init(seed); 17 17 }