|
const std = @import("../std.zig"); const debug_mode = @import("builtin").mode == .Debug; |
MemoryPoolError |
pub const MemoryPoolError = error{OutOfMemory}; |
MemoryPool()A memory pool that can allocate objects of a single type very quickly. Use this when you need to allocate a lot of objects of the same type, because It outperforms general purpose allocators. |
pub fn MemoryPool(comptime Item: type) type { return MemoryPoolAligned(Item, @alignOf(Item)); } |
MemoryPoolAligned()A memory pool that can allocate objects of a single type very quickly. Use this when you need to allocate a lot of objects of the same type, because It outperforms general purpose allocators. |
pub fn MemoryPoolAligned(comptime Item: type, comptime alignment: u29) type { if (@alignOf(Item) == alignment) { return MemoryPoolExtra(Item, .{}); } else { return MemoryPoolExtra(Item, .{ .alignment = alignment }); } } |
Options |
pub const Options = struct { alignment: ?u29 = null, growable: bool = true, }; |
MemoryPoolExtra() The alignment of the memory pool items. Use |
pub fn MemoryPoolExtra(comptime Item: type, comptime pool_options: Options) type { return struct { const Pool = @This(); pub const item_size = @max(@sizeOf(Node), @sizeOf(Item)); pub const item_alignment = @max(@alignOf(Node), pool_options.alignment orelse 0); const Node = struct { next: ?*@This(), }; const NodePtr = *align(item_alignment) Node; const ItemPtr = *align(item_alignment) Item; arena: std.heap.ArenaAllocator, free_list: ?NodePtr = null, |
init() Size of the memory pool items. This is not necessarily the same as |
pub fn init(allocator: std.mem.Allocator) Pool { return .{ .arena = std.heap.ArenaAllocator.init(allocator) }; } |
initPreheated() Creates a new memory pool and pre-allocates |
pub fn initPreheated(allocator: std.mem.Allocator, initial_size: usize) MemoryPoolError!Pool { var pool = init(allocator); errdefer pool.deinit(); var i: usize = 0; while (i < initial_size) : (i += 1) { const raw_mem = try pool.allocNew(); const free_node = @as(NodePtr, @ptrCast(raw_mem)); free_node.* = Node{ .next = pool.free_list, }; pool.free_list = free_node; } return pool; } |
deinit()Destroys the memory pool and frees all allocated memory. |
pub fn deinit(pool: *Pool) void { pool.arena.deinit(); pool.* = undefined; } pub const ResetMode = std.heap.ArenaAllocator.ResetMode; |
reset() Resets the memory pool and destroys all allocated items. This can be used to batch-destroy all objects without invalidating the memory pool. |
pub fn reset(pool: *Pool, mode: ResetMode) bool { // TODO: Potentially store all allocated objects in a list as well, allowing to // just move them into the free list instead of actually releasing the memory. const reset_successful = pool.arena.reset(mode); pool.free_list = null; return reset_successful; } |
create()Creates a new item and adds it to the memory pool. |
pub fn create(pool: *Pool) !ItemPtr { const node = if (pool.free_list) |item| blk: { pool.free_list = item.next; break :blk item; } else if (pool_options.growable) @as(NodePtr, @ptrCast(try pool.allocNew())) else return error.OutOfMemory; const ptr = @as(ItemPtr, @ptrCast(node)); ptr.* = undefined; return ptr; } |
destroy() Destroys a previously created item. Only pass items to |
pub fn destroy(pool: *Pool, ptr: ItemPtr) void { ptr.* = undefined; const node = @as(NodePtr, @ptrCast(ptr)); node.* = Node{ .next = pool.free_list, }; pool.free_list = node; } fn allocNew(pool: *Pool) MemoryPoolError!*align(item_alignment) [item_size]u8 { const mem = try pool.arena.allocator().alignedAlloc(u8, item_alignment, item_size); return mem[0..item_size]; // coerce slice to array pointer } }; } |
Test:memory pool: basic |
test "memory pool: basic" { var pool = MemoryPool(u32).init(std.testing.allocator); defer pool.deinit(); const p1 = try pool.create(); const p2 = try pool.create(); const p3 = try pool.create(); // Assert uniqueness try std.testing.expect(p1 != p2); try std.testing.expect(p1 != p3); try std.testing.expect(p2 != p3); pool.destroy(p2); const p4 = try pool.create(); // Assert memory reuse try std.testing.expect(p2 == p4); } |
Test:memory pool: preheating (success) |
test "memory pool: preheating (success)" { var pool = try MemoryPool(u32).initPreheated(std.testing.allocator, 4); defer pool.deinit(); _ = try pool.create(); _ = try pool.create(); _ = try pool.create(); } |
Test:memory pool: preheating (failure) |
test "memory pool: preheating (failure)" { var failer = std.testing.failing_allocator; try std.testing.expectError(error.OutOfMemory, MemoryPool(u32).initPreheated(failer, 5)); } |
Test:memory pool: growable |
test "memory pool: growable" { var pool = try MemoryPoolExtra(u32, .{ .growable = false }).initPreheated(std.testing.allocator, 4); defer pool.deinit(); _ = try pool.create(); _ = try pool.create(); _ = try pool.create(); _ = try pool.create(); try std.testing.expectError(error.OutOfMemory, pool.create()); } |
Generated by zstd-browse2 on 2023-11-04 14:12:28 -0400. |