1/// A memory pool lets you reuse shared objects. When objects are released,
2/// their state is not reset. This allows you to use it with objects such
3/// as ArenaAllocator.
4fn ObjectPool(Item: type, static_count: usize, dynamic_limit: usize, deinitFunction: anytype) type {
5 return struct {
6 static_data: [static_count]Item,
7 static_usage: std.StaticBitSet(static_count),
8 dynamic_unused: if (have_dynamic_pool) LinkedList else void,
9 dynamic_count: if (have_dynamic_limit) std.math.IntFittingRange(0, dynamic_limit) else void,
10
11 const have_dynamic_pool = dynamic_limit > 0;
12 const have_dynamic_limit = have_dynamic_pool and dynamic_limit < std.math.maxInt(usize);
13
14 const LinkedList = std.SinglyLinkedList(Item);
15
16 const empty: @This() = .{
17 .static_data = undefined,
18 .static_usage = .initFull(),
19 .dynamic_unused = .{},
20 };
21
22 pub fn get(pool: *@This(), allocator: std.mem.Allocator) !*Item {
23 if (pool.static_usage.toggleFirstSet()) |index| {
24 return &pool.static_data[index];
25 }
26 if (have_dynamic_pool) {
27 if (pool.dynamic_unused.popFirst()) |first| {
28 if (have_dynamic_limit)
29 pool.dynamic_count -= 1;
30 return &first.data;
31 }
32 }
33 return &(try allocator.create(LinkedList.Node)).data;
34 }
35
36 pub fn release(pool: *@This(), item: *Item, allocator: std.mem.Allocator) void {
37 deinitFunction(item);
38 _ = pool; // autofix
39 _ = allocator; // autofix
40 //
41 }
42 };
43}
44
45fn AutoObjectPool(Item: type) type {
46 return ObjectPool(Item, 32, 32, Item.deinit);
47}
48
49const std = @import("std");