1const std = @import("std");
2const Allocator = std.mem.Allocator;
3
4pub fn Pool(comptime T: type) type {
5 return struct {
6 const Self = @This();
7
8 items: []T,
9 available: []bool,
10 allocator: Allocator,
11 capacity: usize,
12
13 pub fn init(
14 allocator: Allocator,
15 capacity: usize,
16 ) !Self {
17 const items = try allocator.alloc(T, capacity);
18 const available = try allocator.alloc(
19 bool, capacity,
20 );
21 @memset(available, true);
22 return Self{
23 .items = items,
24 .available = available,
25 .allocator = allocator,
26 .capacity = capacity,
27 };
28 }
29
30 pub fn deinit(self: *Self) void {
31 self.allocator.free(self.items);
32 self.allocator.free(self.available);
33 }
34
35 pub fn acquire(self: *Self) !*T {
36 for (self.available, 0..) |*slot, i| {
37 if (slot.*) {
38 slot.* = false;
39 return &self.items[i];
40 }
41 }
42 return error.PoolExhausted;
43 }
44
45 pub fn release(self: *Self, ptr: *T) void {
46 const addr = @intFromPtr(ptr);
47 const base = @intFromPtr(self.items.ptr);
48 const size = @sizeOf(T);
49 if (addr >= base and
50 addr < base + self.capacity * size)
51 {
52 const index = (addr - base) / size;
53 self.available[index] = true;
54 }
55 }
56
57 pub fn activeCount(self: *const Self) usize {
58 var count: usize = 0;
59 for (self.available) |free| {
60 if (!free) count += 1;
61 }
62 return count;
63 }
64
65 pub fn availableCount(self: *const Self) usize {
66 return self.capacity - self.activeCount();
67 }
68 };
69}