mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
Implement TODO: Resets for mempools.
Respect arena reset result.
This commit is contained in:
parent
d28bb706bd
commit
37fefe4ab3
1 changed files with 51 additions and 8 deletions
|
|
@ -101,7 +101,20 @@ pub fn Extra(comptime Item: type, comptime pool_options: Options) type {
|
||||||
for (uni_slc) |*unit| pool.free_list.prepend(@ptrCast(unit));
|
for (uni_slc) |*unit| pool.free_list.prepend(@ptrCast(unit));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const ResetMode = std.heap.ArenaAllocator.ResetMode;
|
pub const ResetMode = union(enum) {
|
||||||
|
/// Releases all allocated memory in the arena.
|
||||||
|
free_all,
|
||||||
|
/// This will pre-heat the memory pool for future allocations by allocating a
|
||||||
|
/// large enough buffer to accomodate the highest amount of actively allocated items
|
||||||
|
/// in the past. Preheating will speed up the allocation process by invoking the
|
||||||
|
/// backing allocator less often than before. If `reset()` is used in a loop, this
|
||||||
|
/// means if the highest amount of actively allocated items is never being surpassed,
|
||||||
|
/// no memory allocations are performed anymore.
|
||||||
|
retain_capacity,
|
||||||
|
/// This is the same as `retain_capacity`, but the memory will be shrunk to
|
||||||
|
/// only hold at most this value of items.
|
||||||
|
retain_with_limit: usize,
|
||||||
|
};
|
||||||
|
|
||||||
/// Resets the memory pool and destroys all allocated items.
|
/// Resets the memory pool and destroys all allocated items.
|
||||||
/// This can be used to batch-destroy all objects without invalidating the memory pool.
|
/// This can be used to batch-destroy all objects without invalidating the memory pool.
|
||||||
|
|
@ -113,16 +126,24 @@ pub fn Extra(comptime Item: type, comptime pool_options: Options) type {
|
||||||
///
|
///
|
||||||
/// 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, allocator: Allocator, 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
|
|
||||||
// just move them into the free list instead of actually releasing the memory.
|
|
||||||
|
|
||||||
var arena = pool.arena_state.promote(allocator);
|
var arena = pool.arena_state.promote(allocator);
|
||||||
defer pool.arena_state = arena.state;
|
defer pool.arena_state = arena.state;
|
||||||
|
|
||||||
const reset_successful = arena.reset(mode);
|
const ArenaResetMode = std.heap.ArenaAllocator.ResetMode;
|
||||||
pool.free_list = .{};
|
const arena_mode = switch (mode) {
|
||||||
|
.free_all => .free_all,
|
||||||
return reset_successful;
|
.retain_capacity => .retain_capacity,
|
||||||
|
.retain_with_limit => |limit| ArenaResetMode{ .retain_with_limit = limit * item_size },
|
||||||
|
};
|
||||||
|
pool.free_list = null;
|
||||||
|
if (!arena.reset(arena_mode)) return false;
|
||||||
|
// When the backing arena allocator is being reset to
|
||||||
|
// a capacity greater than 0, then its internals consists
|
||||||
|
// of a *single* buffer node of said capacity. This means,
|
||||||
|
// we can safely pre-heat without causing additional allocations.
|
||||||
|
const arena_capacity = pool.arena.queryCapacity() / item_size;
|
||||||
|
if (arena_capacity != 0) pool.addCapacity(arena_capacity) catch unreachable;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new item and adds it to the memory pool.
|
/// Creates a new item and adds it to the memory pool.
|
||||||
|
|
@ -381,3 +402,25 @@ test "greater than pointer manual alignment" {
|
||||||
pool.destroy(foo);
|
pool.destroy(foo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "reset" {
|
||||||
|
const a = std.testing.allocator;
|
||||||
|
var pool: MemoryPool(u32) = .empty;
|
||||||
|
defer pool.deinit(a);
|
||||||
|
|
||||||
|
try std.testing.expect(pool.create(a) != error.OutOfMemory);
|
||||||
|
try std.testing.expect(pool.create(a) != error.OutOfMemory);
|
||||||
|
try std.testing.expect(pool.create(a) != error.OutOfMemory);
|
||||||
|
try std.testing.expect(pool.create(a) == error.OutOfMemory);
|
||||||
|
|
||||||
|
try std.testing.expect(pool.reset(.{ .retain_with_limit = 2 }));
|
||||||
|
|
||||||
|
try std.testing.expect(pool.create(a) != error.OutOfMemory);
|
||||||
|
try std.testing.expect(pool.create(a) != error.OutOfMemory);
|
||||||
|
try std.testing.expect(pool.create(a) == error.OutOfMemory);
|
||||||
|
|
||||||
|
try std.testing.expect(pool.reset(.{ .retain_with_limit = 1 }));
|
||||||
|
|
||||||
|
try std.testing.expect(pool.create(a) != error.OutOfMemory);
|
||||||
|
try std.testing.expect(pool.create(a) == error.OutOfMemory);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue