const recv_buffers = try ByteArrayPool.init(gpa, config.connections_max, recv_size);
const send_buffers = try ByteArrayPool.init(gpa, config.connections_max, send_size);
if the second try throws, than the memory allocation created by the first try is leaked. Possible fixes: const recv_buffers = try ByteArrayPool.init(gpa, config.connections_max, recv_size);
errdefer recv_buffers.deinit(gpa);
const send_buffers = try ByteArrayPool.init(gpa, config.connections_max, send_size);
errdefer send_buffers.deinit(gpa);
B) ask the caller to pass in an arena instead of gpa to do bulk cleanup (types & code stays the same, but naming & contract changes): const recv_buffers = try ByteArrayPool.init(arena, config.connections_max, recv_size);
const send_buffers = try ByteArrayPool.init(arena, config.connections_max, send_size);
C) declare OOMs to be fatal errors const recv_buffers = ByteArrayPool.init(gpa, config.connections_max, recv_size) catch |err| oom(err);
const send_buffers = ByteArrayPool.init(gpa, config.connections_max, send_size) catch |err| oom(err);
fn oom(_: error.OutOfMemory) noreturn { @panic("oom"); }
You might also be interesting in https://matklad.github.io/2025/12/23/static-allocation-compi..., it's essentially a complimentary article to what @MatthiasPortzel says here https://news.ycombinator.com/item?id=46423691 pub fn shuffle(g: *Gen, T: type, slice: []T) void {
if (slice.len <= 1) return;
for (0..slice.len - 1) |i| {
const j = g.range_inclusive(u64, i, slice.len - 1);
std.mem.swap(T, &slice[i], &slice[j]);
}
}
And this is a function that enumerates all permutations, in order, exactly once: pub fn shuffle(g: *Gen, T: type, slice: []T) void {
if (slice.len <= 1) return;
for (0..slice.len - 1) |i| {
const j = g.range_inclusive(u64, i, slice.len - 1);
std.mem.swap(T, &slice[i], &slice[j]);
}
}
Yes, they are exactly the same function. What matters is Gen. If it looks like this