--- layout: site.njk title: zul.pool ---

A thread-safe object pool which will dynamically grow when empty and revert to the configured size.

{% highlight zig %} // create a pool for our Expensive class. // Our Expensive class takes a special initializing context, here an usize which // we set to 10_000. This is just to pass data from the pool into Expensive.init var pool = try zul.pool.Growing(Expensive, usize).init(allocator, 10_000, .{.count = 100}); defer pool.deinit(); // acquire will either pick an item from the pool // if the pool is empty, it'll create a new one (hence, "Growing") var exp1 = try pool.acquire(); defer pool.release(exp1); ... // pooled object must have 3 functions const Expensive = struct { // an init function pub fn init(allocator: Allocator, size: usize) !Expensive { return .{ // ... }; } // a deinit method pub fn deinit(self: *Expensive) void { // ... } // a reset method, called when the item is released back to the pool pub fn reset(self: *Expensive) void { // ... } }; {% endhighlight %}

fn Growing(comptime T: type, comptime C: type) Growing(T, C)

The Growing pool is a generic function that takes two parameters. T is the type of object being pool. C is the type of data to pass into T.init. In many cases, C will be void, in which case T.init will not receive the value:

{% highlight zig %} var pool = try zul.pool.Growing(Expensive, void).init(allocator, {}, .{.count = 100}); defer pool.deinit(); ... const Expensive = struct { // Because the context was defined as `void`, the `init` function does not // take a 2nd paremeter. pub fn init(allocator: Allocator) !Expensive { return .{ // ... }; } // ... }; {% endhighlight %}

T must have an init(allocator: Allocator, ctx: C) !T function. It must also have the following two methods: deinit(self: *T) void and reset(self: *T) void. Because the pool will dynamically create T when empty, deinit will be called when items are released back into a full pool (as well as when pool.deinit is called). reset is called whenever an item is released back into the pool.

{% highlight zig %} fn init( // Allocator is used to create the pool, create the pooled items, and is passed // to the T.init allocator: std.mem.Allocator, // An arbitrary context to passed to T.init ctx: C opts: .{ // number of items to keep in the pool .count: usize, } ) !Growing(T, C) {% endhighlight %}

Creates a pool.Growing.

This is method thread-safe.

Returns an *T. When available, *T will be retrieved from the pooled objects. When the pool is empty, a new *T is created.

Releases *T back into the pool. If the pool is full, t.deinit() is called and then discarded.