@@ -95,7 +95,20 @@ pub fn MemoryPoolExtra(comptime Item: type, comptime pool_options: Options) type
9595 }
9696 }
9797
98- pub const ResetMode = std .heap .ArenaAllocator .ResetMode ;
98+ pub const ResetMode = union (enum ) {
99+ /// Releases all allocated memory in the arena.
100+ free_all ,
101+ /// This will pre-heat the memory pool for future allocations by allocating a
102+ /// large enough buffer to accomodate the highest amount of actively allocated items
103+ /// in the past. Preheating will speed up the allocation process by invoking the
104+ /// backing allocator less often than before. If `reset()` is used in a loop, this
105+ /// means if the highest amount of actively allocated items is never being surpassed,
106+ /// no memory allocations are performed anymore.
107+ retain_capacity ,
108+ /// This is the same as `retain_capacity`, but the memory will be shrunk to
109+ /// only hold at most this value of items.
110+ retain_with_limit : usize ,
111+ };
99112
100113 /// Resets the memory pool and destroys all allocated items.
101114 /// This can be used to batch-destroy all objects without invalidating the memory pool.
@@ -107,14 +120,21 @@ pub fn MemoryPoolExtra(comptime Item: type, comptime pool_options: Options) type
107120 ///
108121 /// NOTE: If `mode` is `free_all`, the function will always return `true`.
109122 pub fn reset (pool : * Pool , mode : ResetMode ) bool {
110- // TODO: Potentially store all allocated objects in a list as well, allowing to
111- // just move them into the free list instead of actually releasing the memory.
112-
113- const reset_successful = pool .arena .reset (mode );
114-
123+ const ArenaResetMode = std .heap .ArenaAllocator .ResetMode ;
124+ const arena_mode = switch (mode ) {
125+ .free_all = > .free_all ,
126+ .retain_capacity = > .retain_capacity ,
127+ .retain_with_limit = > | limit | ArenaResetMode { .retain_with_limit = limit * item_size },
128+ };
115129 pool .free_list = null ;
116-
117- return reset_successful ;
130+ if (! pool .arena .reset (arena_mode )) return false ;
131+ // When the backing arena allocator is being reset to
132+ // a capacity greater than 0, then its internals consists
133+ // of a *single* buffer node of said capacity. This means,
134+ // we can safely pre-heat without causing additional allocations.
135+ const arena_capacity = pool .arena .queryCapacity () / item_size ;
136+ if (arena_capacity != 0 ) pool .preheat (arena_capacity ) catch unreachable ;
137+ return true ;
118138 }
119139
120140 /// Creates a new item and adds it to the memory pool.
@@ -217,3 +237,25 @@ test "greater than pointer manual alignment" {
217237 const foo : * align (16 ) Foo = try pool .create ();
218238 _ = foo ;
219239}
240+
241+ test "reset" {
242+ const pool_extra = MemoryPoolExtra (u32 , .{ .growable = false });
243+ var pool = try pool_extra .initPreheated (std .testing .allocator , 3 );
244+ defer pool .deinit ();
245+
246+ try std .testing .expect (pool .create () != error .OutOfMemory );
247+ try std .testing .expect (pool .create () != error .OutOfMemory );
248+ try std .testing .expect (pool .create () != error .OutOfMemory );
249+ try std .testing .expect (pool .create () == error .OutOfMemory );
250+
251+ try std .testing .expect (pool .reset (.{ .retain_with_limit = 2 }));
252+
253+ try std .testing .expect (pool .create () != error .OutOfMemory );
254+ try std .testing .expect (pool .create () != error .OutOfMemory );
255+ try std .testing .expect (pool .create () == error .OutOfMemory );
256+
257+ try std .testing .expect (pool .reset (.{ .retain_with_limit = 1 }));
258+
259+ try std .testing .expect (pool .create () != error .OutOfMemory );
260+ try std .testing .expect (pool .create () == error .OutOfMemory );
261+ }
0 commit comments