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

Configure Feed

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

reset(false) -> resetRetainingCapacity()

Karl Seguin (Oct 9, 2023, 1:38 PM +0800) 75bce949 a88b6040

+21 -25
+13 -14
src/buffer.zig
··· 129 129 // created when we try to write more than static.len 130 130 dynamic: ?[]u8, 131 131 132 - 133 132 pub fn init(allocator: Allocator, size: usize) !Buffer { 134 133 const static = try allocator.alloc(u8, size); 135 134 return .{ ··· 152 151 } 153 152 } 154 153 155 - pub fn reset(self: *Buffer, clear_dynamic: bool) void { 154 + pub fn reset(self: *Buffer) void { 156 155 self._view.pos = 0; 157 - if (clear_dynamic) { 158 - if (self.dynamic) |dyn| { 159 - (self._da orelse self._a).free(dyn); 160 - self.dynamic = null; 161 - self._view.buf = self.static; 162 - } 163 - self._da = null; 156 + if (self.dynamic) |dyn| { 157 + (self._da orelse self._a).free(dyn); 158 + self.dynamic = null; 159 + self._view.buf = self.static; 164 160 } 161 + self._da = null; 162 + } 163 + 164 + pub fn resetRetainingCapacity(self: *Buffer) void { 165 + self._view.pos = 0; 165 166 } 166 167 167 168 pub fn len(self: Buffer) usize { ··· 337 338 try t.expectEqual(492, sb.len()); 338 339 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.", sb.string()); 339 340 340 - sb.reset(true); 341 + sb.reset(); 341 342 } 342 343 } 343 344 ··· 366 367 test "reset without clear" { 367 368 var sb = try Buffer.init(t.allocator, 5); 368 369 defer sb.deinit(); 369 - 370 - 371 370 372 371 try sb.write("hello world!1"); 373 372 try t.expectString("hello world!1", sb.string()); 374 373 375 - sb.reset(false); 374 + sb.resetRetainingCapacity(); 376 375 try t.expectEqual(0, sb.len()); 377 376 try t.expectEqual(false, sb.dynamic == null); 378 377 try sb.write("over 9000"); ··· 401 400 try control.appendSlice(input); 402 401 try t.expectString(control.items, sb.string()); 403 402 } 404 - sb.reset(true); 403 + sb.reset(); 405 404 control.clearRetainingCapacity(); 406 405 _ = arena.reset(.free_all); 407 406 }
+8 -11
src/pool.zig
··· 22 22 buffers[i] = sb; 23 23 } 24 24 25 - return Pool{ 26 - .mutex = Mutex{}, 25 + return .{ 26 + .mutex = .{}, 27 27 .buffers = buffers, 28 28 .allocator = allocator, 29 29 .available = pool_size, ··· 45 45 } 46 46 47 47 pub fn acquireWithAllocator(self: *Pool, dyn_allocator: Allocator) !*Buffer { 48 - self.mutex.lock(); 48 + const buffers = self.buffers; 49 49 50 - const buffers = self.buffers; 50 + self.mutex.lock(); 51 51 const available = self.available; 52 52 if (available == 0) { 53 53 // dont hold the lock over factory 54 54 self.mutex.unlock(); 55 - const allocator = self.allocator; 56 55 56 + const allocator = self.allocator; 57 57 const sb = try allocator.create(Buffer); 58 58 sb.* = try Buffer.init(allocator, self.buffer_size); 59 - if (comptime builtin.is_test) sb._view.buf[0] = 0; 60 59 sb._da = dyn_allocator; 61 60 return sb; 62 61 } ··· 69 68 } 70 69 71 70 pub fn release(self: *Pool, sb: *Buffer) void { 72 - sb.reset(true); 71 + sb.reset(); 73 72 self.mutex.lock(); 74 73 75 74 var buffers = self.buffers; ··· 125 124 } 126 125 127 126 test "pool: threadsafety" { 128 - var p = try Pool.init(t.allocator, 4, 20); 127 + var p = try Pool.init(t.allocator, 3, 20); 129 128 defer p.deinit(); 130 129 131 130 // initialize this to 0 since we're asserting that it's 0 ··· 136 135 const t1 = try std.Thread.spawn(.{}, testPool, .{&p}); 137 136 const t2 = try std.Thread.spawn(.{}, testPool, .{&p}); 138 137 const t3 = try std.Thread.spawn(.{}, testPool, .{&p}); 139 - const t4 = try std.Thread.spawn(.{}, testPool, .{&p}); 140 - const t5 = try std.Thread.spawn(.{}, testPool, .{&p}); 141 138 142 - t1.join(); t2.join(); t3.join(); t4.join(); t5.join(); 139 + t1.join(); t2.join(); t3.join(); 143 140 } 144 141 145 142 fn testPool(p: *Pool) void {