@@ -95,7 +95,20 @@ pub fn MemoryPoolExtra(comptime Item: type, comptime pool_options: Options) type
95
95
}
96
96
}
97
97
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
+ };
99
112
100
113
/// Resets the memory pool and destroys all allocated items.
101
114
/// 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
107
120
///
108
121
/// NOTE: If `mode` is `free_all`, the function will always return `true`.
109
122
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
+ };
115
129
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 ;
118
138
}
119
139
120
140
/// Creates a new item and adds it to the memory pool.
@@ -217,3 +237,25 @@ test "greater than pointer manual alignment" {
217
237
const foo : * align (16 ) Foo = try pool .create ();
218
238
_ = foo ;
219
239
}
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