mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
MemoryPool: add unmanaged variants and make them the default
This commit is contained in:
parent
250803661c
commit
4187d0e8fe
3 changed files with 283 additions and 115 deletions
|
|
@ -723,7 +723,7 @@ pub const SourceMappings = struct {
|
||||||
/// The default assumes that the first filename added is the root file.
|
/// The default assumes that the first filename added is the root file.
|
||||||
/// The value should be set to the correct offset if that assumption does not hold.
|
/// The value should be set to the correct offset if that assumption does not hold.
|
||||||
root_filename_offset: u32 = 0,
|
root_filename_offset: u32 = 0,
|
||||||
source_node_pool: std.heap.MemoryPool(Sources.Node) = std.heap.MemoryPool(Sources.Node).init(std.heap.page_allocator),
|
source_node_pool: std.heap.MemoryPool(Sources.Node) = .empty,
|
||||||
end_line: usize = 0,
|
end_line: usize = 0,
|
||||||
|
|
||||||
const sourceCompare = struct {
|
const sourceCompare = struct {
|
||||||
|
|
@ -742,7 +742,7 @@ pub const SourceMappings = struct {
|
||||||
|
|
||||||
pub fn deinit(self: *SourceMappings, allocator: Allocator) void {
|
pub fn deinit(self: *SourceMappings, allocator: Allocator) void {
|
||||||
self.files.deinit(allocator);
|
self.files.deinit(allocator);
|
||||||
self.source_node_pool.deinit();
|
self.source_node_pool.deinit(std.heap.page_allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find the node that 'contains' the `line`, i.e. the node's start_line is
|
/// Find the node that 'contains' the `line`, i.e. the node's start_line is
|
||||||
|
|
@ -823,7 +823,7 @@ pub const SourceMappings = struct {
|
||||||
.filename_offset = filename_offset,
|
.filename_offset = filename_offset,
|
||||||
};
|
};
|
||||||
var entry = self.sources.getEntryFor(key);
|
var entry = self.sources.getEntryFor(key);
|
||||||
var new_node = try self.source_node_pool.create();
|
var new_node = try self.source_node_pool.create(std.heap.page_allocator);
|
||||||
new_node.key = key;
|
new_node.key = key;
|
||||||
entry.set(new_node);
|
entry.set(new_node);
|
||||||
}
|
}
|
||||||
|
|
@ -869,7 +869,7 @@ pub const SourceMappings = struct {
|
||||||
.filename_offset = node.key.filename_offset,
|
.filename_offset = node.key.filename_offset,
|
||||||
};
|
};
|
||||||
var entry = self.sources.getEntryFor(key);
|
var entry = self.sources.getEntryFor(key);
|
||||||
var new_node = try self.source_node_pool.create();
|
var new_node = try self.source_node_pool.create(std.heap.page_allocator);
|
||||||
new_node.key = key;
|
new_node.key = key;
|
||||||
entry.set(new_node);
|
entry.set(new_node);
|
||||||
node = new_node;
|
node = new_node;
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,20 @@ pub const GeneralPurposeAllocatorConfig = DebugAllocatorConfig;
|
||||||
/// Deprecated; to be removed after 0.14.0 is tagged.
|
/// Deprecated; to be removed after 0.14.0 is tagged.
|
||||||
pub const GeneralPurposeAllocator = DebugAllocator;
|
pub const GeneralPurposeAllocator = DebugAllocator;
|
||||||
|
|
||||||
const memory_pool = @import("heap/memory_pool.zig");
|
/// A memory pool that can allocate objects of a single type very quickly.
|
||||||
pub const MemoryPool = memory_pool.MemoryPool;
|
/// Use this when you need to allocate a lot of objects of the same type,
|
||||||
pub const MemoryPoolAligned = memory_pool.MemoryPoolAligned;
|
/// because it outperforms general purpose allocators.
|
||||||
pub const MemoryPoolExtra = memory_pool.MemoryPoolExtra;
|
/// Functions that potentially allocate memory accept an `Allocator` parameter.
|
||||||
|
pub fn MemoryPool(comptime Item: type) type {
|
||||||
|
return memory_pool.Extra(Item, .{ .alignment = null });
|
||||||
|
}
|
||||||
|
pub const memory_pool = @import("heap/memory_pool.zig");
|
||||||
|
|
||||||
|
/// Deprecated; use `memory_pool.Aligned`.
|
||||||
|
pub const MemoryPoolAligned = memory_pool.Aligned;
|
||||||
|
/// Deprecated; use `memory_pool.Extra`.
|
||||||
|
pub const MemoryPoolExtra = memory_pool.Extra;
|
||||||
|
/// Deprecated; use `memory_pool.Options`.
|
||||||
pub const MemoryPoolOptions = memory_pool.Options;
|
pub const MemoryPoolOptions = memory_pool.Options;
|
||||||
|
|
||||||
/// TODO Utilize this on Windows.
|
/// TODO Utilize this on Windows.
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,26 @@
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
const Alignment = std.mem.Alignment;
|
const Alignment = std.mem.Alignment;
|
||||||
|
const MemoryPool = std.heap.MemoryPool;
|
||||||
|
|
||||||
const debug_mode = @import("builtin").mode == .Debug;
|
/// Deprecated.
|
||||||
|
pub fn Managed(comptime Item: type) type {
|
||||||
pub const MemoryPoolError = error{OutOfMemory};
|
return ExtraManaged(Item, .{ .alignment = null });
|
||||||
|
|
||||||
/// 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, .of(Item));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A memory pool that can allocate objects of a single type very quickly.
|
/// 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,
|
/// Use this when you need to allocate a lot of objects of the same type,
|
||||||
/// because It outperforms general purpose allocators.
|
/// because it outperforms general purpose allocators.
|
||||||
pub fn MemoryPoolAligned(comptime Item: type, comptime alignment: Alignment) type {
|
/// Allocated items are aligned to `alignment`-byte addresses or `@alignOf(Item)`
|
||||||
if (@alignOf(Item) == comptime alignment.toByteUnits()) {
|
/// if `alignment` is `null`.
|
||||||
return MemoryPoolExtra(Item, .{});
|
/// Functions that potentially allocate memory accept an `Allocator` parameter.
|
||||||
} else {
|
pub fn Aligned(comptime Item: type, comptime alignment: Alignment) type {
|
||||||
return MemoryPoolExtra(Item, .{ .alignment = alignment });
|
return Extra(Item, .{ .alignment = alignment });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deprecated.
|
||||||
|
pub fn AlignedManaged(comptime Item: type, comptime alignment: Alignment) type {
|
||||||
|
return ExtraManaged(Item, .{ .alignment = alignment });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const Options = struct {
|
pub const Options = struct {
|
||||||
|
|
@ -34,64 +34,70 @@ pub const Options = struct {
|
||||||
|
|
||||||
/// A memory pool that can allocate objects of a single type very quickly.
|
/// 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,
|
/// Use this when you need to allocate a lot of objects of the same type,
|
||||||
/// because It outperforms general purpose allocators.
|
/// because it outperforms general purpose allocators.
|
||||||
pub fn MemoryPoolExtra(comptime Item: type, comptime pool_options: Options) type {
|
/// Functions that potentially allocate memory accept an `Allocator` parameter.
|
||||||
|
pub fn Extra(comptime Item: type, comptime pool_options: Options) type {
|
||||||
|
if (pool_options.alignment) |a| {
|
||||||
|
if (a.compare(.eq, .of(Item))) {
|
||||||
|
var new_options = pool_options;
|
||||||
|
new_options.alignment = null;
|
||||||
|
return Extra(Item, new_options);
|
||||||
|
}
|
||||||
|
}
|
||||||
return struct {
|
return struct {
|
||||||
const Pool = @This();
|
const Pool = @This();
|
||||||
|
|
||||||
|
arena_state: std.heap.ArenaAllocator.State,
|
||||||
|
free_list: std.SinglyLinkedList,
|
||||||
|
|
||||||
/// Size of the memory pool items. This is not necessarily the same
|
/// Size of the memory pool items. This is not necessarily the same
|
||||||
/// as `@sizeOf(Item)` as the pool also uses the items for internal means.
|
/// as `@sizeOf(Item)` as the pool also uses the items for internal means.
|
||||||
pub const item_size = @max(@sizeOf(Node), @sizeOf(Item));
|
pub const item_size = @max(@sizeOf(Node), @sizeOf(Item));
|
||||||
|
|
||||||
// This needs to be kept in sync with Node.
|
|
||||||
const node_alignment: Alignment = .of(*anyopaque);
|
|
||||||
|
|
||||||
/// Alignment of the memory pool items. This is not necessarily the same
|
/// Alignment of the memory pool items. This is not necessarily the same
|
||||||
/// as `@alignOf(Item)` as the pool also uses the items for internal means.
|
/// as `@alignOf(Item)` as the pool also uses the items for internal means.
|
||||||
pub const item_alignment: Alignment = node_alignment.max(pool_options.alignment orelse .of(Item));
|
pub const item_alignment: Alignment = .max(pool_options.alignment orelse .of(Item), .of(Node));
|
||||||
|
|
||||||
const Node = struct {
|
const Node = std.SinglyLinkedList.Node;
|
||||||
next: ?*align(item_alignment.toByteUnits()) @This(),
|
|
||||||
};
|
|
||||||
const NodePtr = *align(item_alignment.toByteUnits()) Node;
|
|
||||||
const ItemPtr = *align(item_alignment.toByteUnits()) Item;
|
const ItemPtr = *align(item_alignment.toByteUnits()) Item;
|
||||||
|
|
||||||
arena: std.heap.ArenaAllocator,
|
/// A MemoryPool containing no elements.
|
||||||
free_list: ?NodePtr = null,
|
pub const empty: Pool = .{
|
||||||
|
.arena_state = .{},
|
||||||
|
.free_list = .{},
|
||||||
|
};
|
||||||
|
|
||||||
/// Creates a new memory pool.
|
/// Creates a new memory pool and pre-allocates `num` items.
|
||||||
pub fn init(allocator: std.mem.Allocator) Pool {
|
/// This allows up to `num` active allocations before an
|
||||||
return .{ .arena = std.heap.ArenaAllocator.init(allocator) };
|
/// `OutOfMemory` error might happen when calling `create()`.
|
||||||
}
|
pub fn initCapacity(allocator: Allocator, num: usize) Allocator.Error!Pool {
|
||||||
|
var pool: Pool = .empty;
|
||||||
/// Creates a new memory pool and pre-allocates `initial_size` items.
|
errdefer pool.deinit(allocator);
|
||||||
/// This allows the up to `initial_size` active allocations before a
|
try pool.addCapacity(allocator, num);
|
||||||
/// `OutOfMemory` error happens when calling `create()`.
|
|
||||||
pub fn initPreheated(allocator: std.mem.Allocator, initial_size: usize) MemoryPoolError!Pool {
|
|
||||||
var pool = init(allocator);
|
|
||||||
errdefer pool.deinit();
|
|
||||||
try pool.preheat(initial_size);
|
|
||||||
return pool;
|
return pool;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Destroys the memory pool and frees all allocated memory.
|
/// Destroys the memory pool and frees all allocated memory.
|
||||||
pub fn deinit(pool: *Pool) void {
|
pub fn deinit(pool: *Pool, allocator: Allocator) void {
|
||||||
pool.arena.deinit();
|
pool.arena_state.promote(allocator).deinit();
|
||||||
pool.* = undefined;
|
pool.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Preheats the memory pool by pre-allocating `size` items.
|
pub fn toManaged(pool: Pool, allocator: Allocator) ExtraManaged(Item, pool_options) {
|
||||||
/// This allows up to `size` active allocations before an
|
return .{
|
||||||
|
.allocator = allocator,
|
||||||
|
.unmanaged = pool,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pre-allocates `num` items and adds them to the memory pool.
|
||||||
|
/// This allows at least `num` active allocations before an
|
||||||
/// `OutOfMemory` error might happen when calling `create()`.
|
/// `OutOfMemory` error might happen when calling `create()`.
|
||||||
pub fn preheat(pool: *Pool, size: usize) MemoryPoolError!void {
|
pub fn addCapacity(pool: *Pool, allocator: Allocator, num: usize) Allocator.Error!void {
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (i < size) : (i += 1) {
|
while (i < num) : (i += 1) {
|
||||||
const raw_mem = try pool.allocNew();
|
const memory = try pool.allocNew(allocator);
|
||||||
const free_node = @as(NodePtr, @ptrCast(raw_mem));
|
pool.free_list.prepend(@ptrCast(memory));
|
||||||
free_node.* = Node{
|
|
||||||
.next = pool.free_list,
|
|
||||||
};
|
|
||||||
pool.free_list = free_node;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -106,28 +112,29 @@ pub fn MemoryPoolExtra(comptime Item: type, comptime pool_options: Options) type
|
||||||
/// be slower.
|
/// be slower.
|
||||||
///
|
///
|
||||||
/// NOTE: If `mode` is `free_all`, the function will always return `true`.
|
/// NOTE: If `mode` is `free_all`, the function will always return `true`.
|
||||||
pub fn reset(pool: *Pool, mode: ResetMode) bool {
|
pub fn reset(pool: *Pool, allocator: Allocator, mode: ResetMode) bool {
|
||||||
// TODO: Potentially store all allocated objects in a list as well, allowing to
|
// 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.
|
// just move them into the free list instead of actually releasing the memory.
|
||||||
|
|
||||||
const reset_successful = pool.arena.reset(mode);
|
var arena = pool.arena_state.promote(allocator);
|
||||||
|
defer pool.arena_state = arena.state;
|
||||||
|
|
||||||
pool.free_list = null;
|
const reset_successful = arena.reset(mode);
|
||||||
|
pool.free_list = .{};
|
||||||
|
|
||||||
return reset_successful;
|
return reset_successful;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new item and adds it to the memory pool.
|
/// Creates a new item and adds it to the memory pool.
|
||||||
pub fn create(pool: *Pool) !ItemPtr {
|
/// `allocator` may be `undefined` if pool is not `growable`.
|
||||||
const node = if (pool.free_list) |item| blk: {
|
pub fn create(pool: *Pool, allocator: Allocator) Allocator.Error!ItemPtr {
|
||||||
pool.free_list = item.next;
|
const ptr: ItemPtr = if (pool.free_list.popFirst()) |node|
|
||||||
break :blk item;
|
@ptrCast(@alignCast(node))
|
||||||
} else if (pool_options.growable)
|
else if (pool_options.growable)
|
||||||
@as(NodePtr, @ptrCast(try pool.allocNew()))
|
@ptrCast(try pool.allocNew(allocator))
|
||||||
else
|
else
|
||||||
return error.OutOfMemory;
|
return error.OutOfMemory;
|
||||||
|
|
||||||
const ptr = @as(ItemPtr, @ptrCast(node));
|
|
||||||
ptr.* = undefined;
|
ptr.* = undefined;
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
@ -136,87 +143,238 @@ pub fn MemoryPoolExtra(comptime Item: type, comptime pool_options: Options) type
|
||||||
/// Only pass items to `ptr` that were previously created with `create()` of the same memory pool!
|
/// Only pass items to `ptr` that were previously created with `create()` of the same memory pool!
|
||||||
pub fn destroy(pool: *Pool, ptr: ItemPtr) void {
|
pub fn destroy(pool: *Pool, ptr: ItemPtr) void {
|
||||||
ptr.* = undefined;
|
ptr.* = undefined;
|
||||||
|
pool.free_list.prepend(@ptrCast(ptr));
|
||||||
const node = @as(NodePtr, @ptrCast(ptr));
|
|
||||||
node.* = Node{
|
|
||||||
.next = pool.free_list,
|
|
||||||
};
|
|
||||||
pool.free_list = node;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn allocNew(pool: *Pool) MemoryPoolError!*align(item_alignment.toByteUnits()) [item_size]u8 {
|
fn allocNew(pool: *Pool, allocator: Allocator) Allocator.Error!*align(item_alignment.toByteUnits()) [item_size]u8 {
|
||||||
const mem = try pool.arena.allocator().alignedAlloc(u8, item_alignment, item_size);
|
var arena = pool.arena_state.promote(allocator);
|
||||||
return mem[0..item_size]; // coerce slice to array pointer
|
defer pool.arena_state = arena.state;
|
||||||
|
const memory = try arena.allocator().alignedAlloc(u8, item_alignment, item_size);
|
||||||
|
return memory[0..item_size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deprecated.
|
||||||
|
pub fn ExtraManaged(comptime Item: type, comptime pool_options: Options) type {
|
||||||
|
if (pool_options.alignment) |a| {
|
||||||
|
if (a.compare(.eq, .of(Item))) {
|
||||||
|
var new_options = pool_options;
|
||||||
|
new_options.alignment = null;
|
||||||
|
return ExtraManaged(Item, new_options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return struct {
|
||||||
|
const Pool = @This();
|
||||||
|
|
||||||
|
allocator: Allocator,
|
||||||
|
unmanaged: Unmanaged,
|
||||||
|
|
||||||
|
pub const Unmanaged = Extra(Item, pool_options);
|
||||||
|
pub const item_size = Unmanaged.item_size;
|
||||||
|
pub const item_alignment = Unmanaged.item_alignment;
|
||||||
|
|
||||||
|
const ItemPtr = Unmanaged.ItemPtr;
|
||||||
|
|
||||||
|
/// Creates a new memory pool.
|
||||||
|
pub fn init(allocator: Allocator) Pool {
|
||||||
|
return Unmanaged.empty.toManaged(allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new memory pool and pre-allocates `num` items.
|
||||||
|
/// This allows up to `num` active allocations before an
|
||||||
|
/// `OutOfMemory` error might happen when calling `create()`.
|
||||||
|
pub fn initCapacity(allocator: Allocator, num: usize) Allocator.Error!Pool {
|
||||||
|
return (try Unmanaged.initCapacity(allocator, num)).toManaged(allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Destroys the memory pool and frees all allocated memory.
|
||||||
|
pub fn deinit(pool: *Pool) void {
|
||||||
|
pool.unmanaged.deinit(pool.allocator);
|
||||||
|
pool.* = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pre-allocates `num` items and adds them to the memory pool.
|
||||||
|
/// This allows at least `num` active allocations before an
|
||||||
|
/// `OutOfMemory` error might happen when calling `create()`.
|
||||||
|
pub fn addCapacity(pool: *Pool, num: usize) Allocator.Error!void {
|
||||||
|
return pool.unmanaged.addCapacity(pool.allocator, num);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const ResetMode = Unmanaged.ResetMode;
|
||||||
|
|
||||||
|
/// Resets the memory pool and destroys all allocated items.
|
||||||
|
/// This can be used to batch-destroy all objects without invalidating the memory pool.
|
||||||
|
///
|
||||||
|
/// The function will return whether the reset operation was successful or not.
|
||||||
|
/// If the reallocation failed `false` is returned. The pool will still be fully
|
||||||
|
/// functional in that case, all memory is released. Future allocations just might
|
||||||
|
/// be slower.
|
||||||
|
///
|
||||||
|
/// NOTE: If `mode` is `free_all`, the function will always return `true`.
|
||||||
|
pub fn reset(pool: *Pool, mode: ResetMode) bool {
|
||||||
|
return pool.unmanaged.reset(pool.allocator, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new item and adds it to the memory pool.
|
||||||
|
pub fn create(pool: *Pool) Allocator.Error!ItemPtr {
|
||||||
|
return pool.unmanaged.create(pool.allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Destroys a previously created item.
|
||||||
|
/// Only pass items to `ptr` that were previously created with `create()` of the same memory pool!
|
||||||
|
pub fn destroy(pool: *Pool, ptr: ItemPtr) void {
|
||||||
|
return pool.unmanaged.destroy(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn allocNew(pool: *Pool) Allocator.Error!*align(item_alignment) [item_size]u8 {
|
||||||
|
return pool.unmanaged.allocNew(pool.allocator);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
test "basic" {
|
test "basic" {
|
||||||
var pool = MemoryPool(u32).init(std.testing.allocator);
|
const a = std.testing.allocator;
|
||||||
defer pool.deinit();
|
|
||||||
|
|
||||||
const p1 = try pool.create();
|
{
|
||||||
const p2 = try pool.create();
|
var pool: MemoryPool(u32) = .empty;
|
||||||
const p3 = try pool.create();
|
defer pool.deinit(a);
|
||||||
|
|
||||||
// Assert uniqueness
|
const p1 = try pool.create(a);
|
||||||
try std.testing.expect(p1 != p2);
|
const p2 = try pool.create(a);
|
||||||
try std.testing.expect(p1 != p3);
|
const p3 = try pool.create(a);
|
||||||
try std.testing.expect(p2 != p3);
|
|
||||||
|
|
||||||
pool.destroy(p2);
|
// Assert uniqueness
|
||||||
const p4 = try pool.create();
|
try std.testing.expect(p1 != p2);
|
||||||
|
try std.testing.expect(p1 != p3);
|
||||||
|
try std.testing.expect(p2 != p3);
|
||||||
|
|
||||||
// Assert memory reuse
|
pool.destroy(p2);
|
||||||
try std.testing.expect(p2 == p4);
|
const p4 = try pool.create(a);
|
||||||
|
|
||||||
|
// Assert memory reuse
|
||||||
|
try std.testing.expect(p2 == p4);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var pool: Managed(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 "preheating (success)" {
|
test "initCapacity (success)" {
|
||||||
var pool = try MemoryPool(u32).initPreheated(std.testing.allocator, 4);
|
const a = std.testing.allocator;
|
||||||
defer pool.deinit();
|
|
||||||
|
|
||||||
_ = try pool.create();
|
{
|
||||||
_ = try pool.create();
|
var pool: MemoryPool(u32) = try .initCapacity(a, 4);
|
||||||
_ = try pool.create();
|
defer pool.deinit(a);
|
||||||
|
|
||||||
|
_ = try pool.create(a);
|
||||||
|
_ = try pool.create(a);
|
||||||
|
_ = try pool.create(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var pool: Managed(u32) = try .initCapacity(a, 4);
|
||||||
|
defer pool.deinit();
|
||||||
|
|
||||||
|
_ = try pool.create();
|
||||||
|
_ = try pool.create();
|
||||||
|
_ = try pool.create();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "preheating (failure)" {
|
test "initCapacity (failure)" {
|
||||||
const failer = std.testing.failing_allocator;
|
const failer = std.testing.failing_allocator;
|
||||||
try std.testing.expectError(error.OutOfMemory, MemoryPool(u32).initPreheated(failer, 5));
|
try std.testing.expectError(error.OutOfMemory, MemoryPool(u32).initCapacity(failer, 5));
|
||||||
|
try std.testing.expectError(error.OutOfMemory, Managed(u32).initCapacity(failer, 5));
|
||||||
}
|
}
|
||||||
|
|
||||||
test "growable" {
|
test "growable" {
|
||||||
var pool = try MemoryPoolExtra(u32, .{ .growable = false }).initPreheated(std.testing.allocator, 4);
|
const a = std.testing.allocator;
|
||||||
defer pool.deinit();
|
|
||||||
|
|
||||||
_ = try pool.create();
|
{
|
||||||
_ = try pool.create();
|
var pool: Extra(u32, .{ .growable = false }) = try .initCapacity(a, 4);
|
||||||
_ = try pool.create();
|
defer pool.deinit(a);
|
||||||
_ = try pool.create();
|
|
||||||
|
|
||||||
try std.testing.expectError(error.OutOfMemory, pool.create());
|
_ = try pool.create(a);
|
||||||
|
_ = try pool.create(a);
|
||||||
|
_ = try pool.create(a);
|
||||||
|
_ = try pool.create(a);
|
||||||
|
|
||||||
|
try std.testing.expectError(error.OutOfMemory, pool.create(a));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var pool: ExtraManaged(u32, .{ .growable = false }) = try .initCapacity(a, 4);
|
||||||
|
defer pool.deinit();
|
||||||
|
|
||||||
|
_ = try pool.create();
|
||||||
|
_ = try pool.create();
|
||||||
|
_ = try pool.create();
|
||||||
|
_ = try pool.create();
|
||||||
|
|
||||||
|
try std.testing.expectError(error.OutOfMemory, pool.create());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "greater than pointer default alignment" {
|
test "greater than pointer default alignment" {
|
||||||
const Foo = struct {
|
const Foo = struct {
|
||||||
data: u64 align(16),
|
data: u64 align(16),
|
||||||
};
|
};
|
||||||
|
const a = std.testing.allocator;
|
||||||
|
|
||||||
var pool = MemoryPool(Foo).init(std.testing.allocator);
|
{
|
||||||
defer pool.deinit();
|
var pool: MemoryPool(Foo) = .empty;
|
||||||
|
defer pool.deinit(a);
|
||||||
|
|
||||||
const foo: *Foo = try pool.create();
|
const foo: *Foo = try pool.create(a);
|
||||||
_ = foo;
|
pool.destroy(foo);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var pool: Managed(Foo) = .init(a);
|
||||||
|
defer pool.deinit();
|
||||||
|
|
||||||
|
const foo: *Foo = try pool.create();
|
||||||
|
pool.destroy(foo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "greater than pointer manual alignment" {
|
test "greater than pointer manual alignment" {
|
||||||
const Foo = struct {
|
const Foo = struct {
|
||||||
data: u64,
|
data: u64,
|
||||||
};
|
};
|
||||||
|
const a = std.testing.allocator;
|
||||||
|
|
||||||
var pool = MemoryPoolAligned(Foo, .@"16").init(std.testing.allocator);
|
{
|
||||||
defer pool.deinit();
|
var pool: Aligned(Foo, .@"16") = .empty;
|
||||||
|
defer pool.deinit(a);
|
||||||
|
|
||||||
const foo: *align(16) Foo = try pool.create();
|
const foo: *align(16) Foo = try pool.create(a);
|
||||||
_ = foo;
|
pool.destroy(foo);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var pool: AlignedManaged(Foo, .@"16") = .init(a);
|
||||||
|
defer pool.deinit();
|
||||||
|
|
||||||
|
const foo: *align(16) Foo = try pool.create();
|
||||||
|
pool.destroy(foo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue