| ... | @@ -3,11 +3,6 @@ const Allocator = std.mem.Allocator; | ... | @@ -3,11 +3,6 @@ const Allocator = std.mem.Allocator; |
| 3 | const Alignment = std.mem.Alignment; | 3 | const Alignment = std.mem.Alignment; |
| 4 | const MemoryPool = std.heap.MemoryPool; | 4 | const MemoryPool = std.heap.MemoryPool; |
| 5 | | 5 | |
| 6 | /// Deprecated. | | |
| 7 | pub fn Managed(comptime Item: type) type { | | |
| 8 | return ExtraManaged(Item, .{ .alignment = null }); | | |
| 9 | } | | |
| 10 | | | |
| 11 | /// A memory pool that can allocate objects of a single type very quickly. | 6 | /// A memory pool that can allocate objects of a single type very quickly. |
| 12 | /// Use this when you need to allocate a lot of objects of the same type, | 7 | /// Use this when you need to allocate a lot of objects of the same type, |
| 13 | /// because it outperforms general purpose allocators. | 8 | /// because it outperforms general purpose allocators. |
| ... | @@ -18,11 +13,6 @@ pub fn Aligned(comptime Item: type, comptime alignment: Alignment) type { | ... | @@ -18,11 +13,6 @@ pub fn Aligned(comptime Item: type, comptime alignment: Alignment) type { |
| 18 | return Extra(Item, .{ .alignment = alignment }); | 13 | return Extra(Item, .{ .alignment = alignment }); |
| 19 | } | 14 | } |
| 20 | | 15 | |
| 21 | /// Deprecated. | | |
| 22 | pub fn AlignedManaged(comptime Item: type, comptime alignment: Alignment) type { | | |
| 23 | return ExtraManaged(Item, .{ .alignment = alignment }); | | |
| 24 | } | | |
| 25 | | | |
| 26 | pub const Options = struct { | 16 | pub const Options = struct { |
| 27 | /// The alignment of the memory pool items. Use `null` for natural alignment. | 17 | /// The alignment of the memory pool items. Use `null` for natural alignment. |
| 28 | alignment: ?Alignment = null, | 18 | alignment: ?Alignment = null, |
| ... | @@ -83,13 +73,6 @@ pub fn Extra(comptime Item: type, comptime pool_options: Options) type { | ... | @@ -83,13 +73,6 @@ pub fn Extra(comptime Item: type, comptime pool_options: Options) type { |
| 83 | pool.* = undefined; | 73 | pool.* = undefined; |
| 84 | } | 74 | } |
| 85 | | 75 | |
| 86 | pub fn toManaged(pool: Pool, allocator: Allocator) ExtraManaged(Item, pool_options) { | | |
| 87 | return .{ | | |
| 88 | .allocator = allocator, | | |
| 89 | .unmanaged = pool, | | |
| 90 | }; | | |
| 91 | } | | |
| 92 | | | |
| 93 | /// Pre-allocates `num` items and adds them to the memory pool. | 76 | /// Pre-allocates `num` items and adds them to the memory pool. |
| 94 | /// This allows at least `num` active allocations before an | 77 | /// This allows at least `num` active allocations before an |
| 95 | /// `OutOfMemory` error might happen when calling `create()`. | 78 | /// `OutOfMemory` error might happen when calling `create()`. |
| ... | @@ -114,7 +97,7 @@ pub fn Extra(comptime Item: type, comptime pool_options: Options) type { | ... | @@ -114,7 +97,7 @@ pub fn Extra(comptime Item: type, comptime pool_options: Options) type { |
| 114 | /// NOTE: If `mode` is `free_all`, the function will always return `true`. | 97 | /// NOTE: If `mode` is `free_all`, the function will always return `true`. |
| 115 | pub fn reset(pool: *Pool, allocator: Allocator, mode: ResetMode) bool { | 98 | pub fn reset(pool: *Pool, allocator: Allocator, mode: ResetMode) bool { |
| 116 | // TODO: Potentially store all allocated objects in a list as well, allowing to | 99 | // TODO: Potentially store all allocated objects in a list as well, allowing to |
| 117 | // just move them into the free list instead of actually releasing the memory. | 100 | // just move them into the free list instead of actually releasing the memory. |
| 118 | | 101 | |
| 119 | var arena = pool.arena_state.promote(allocator); | 102 | var arena = pool.arena_state.promote(allocator); |
| 120 | defer pool.arena_state = arena.state; | 103 | defer pool.arena_state = arena.state; |
| ... | @@ -155,182 +138,56 @@ pub fn Extra(comptime Item: type, comptime pool_options: Options) type { | ... | @@ -155,182 +138,56 @@ pub fn Extra(comptime Item: type, comptime pool_options: Options) type { |
| 155 | }; | 138 | }; |
| 156 | } | 139 | } |
| 157 | | 140 | |
| 158 | /// Deprecated. | | |
| 159 | pub fn ExtraManaged(comptime Item: type, comptime pool_options: Options) type { | | |
| 160 | if (pool_options.alignment) |a| { | | |
| 161 | if (a.compare(.eq, .of(Item))) { | | |
| 162 | var new_options = pool_options; | | |
| 163 | new_options.alignment = null; | | |
| 164 | return ExtraManaged(Item, new_options); | | |
| 165 | } | | |
| 166 | } | | |
| 167 | return struct { | | |
| 168 | const Pool = @This(); | | |
| 169 | | | |
| 170 | allocator: Allocator, | | |
| 171 | unmanaged: Unmanaged, | | |
| 172 | | | |
| 173 | pub const Unmanaged = Extra(Item, pool_options); | | |
| 174 | pub const item_size = Unmanaged.item_size; | | |
| 175 | pub const item_alignment = Unmanaged.item_alignment; | | |
| 176 | | | |
| 177 | const ItemPtr = Unmanaged.ItemPtr; | | |
| 178 | | | |
| 179 | /// Creates a new memory pool. | | |
| 180 | pub fn init(allocator: Allocator) Pool { | | |
| 181 | return Unmanaged.empty.toManaged(allocator); | | |
| 182 | } | | |
| 183 | | | |
| 184 | /// Creates a new memory pool and pre-allocates `num` items. | | |
| 185 | /// This allows up to `num` active allocations before an | | |
| 186 | /// `OutOfMemory` error might happen when calling `create()`. | | |
| 187 | pub fn initCapacity(allocator: Allocator, num: usize) Allocator.Error!Pool { | | |
| 188 | return (try Unmanaged.initCapacity(allocator, num)).toManaged(allocator); | | |
| 189 | } | | |
| 190 | | | |
| 191 | /// Destroys the memory pool and frees all allocated memory. | | |
| 192 | pub fn deinit(pool: *Pool) void { | | |
| 193 | pool.unmanaged.deinit(pool.allocator); | | |
| 194 | pool.* = undefined; | | |
| 195 | } | | |
| 196 | | | |
| 197 | /// Pre-allocates `num` items and adds them to the memory pool. | | |
| 198 | /// This allows at least `num` active allocations before an | | |
| 199 | /// `OutOfMemory` error might happen when calling `create()`. | | |
| 200 | pub fn addCapacity(pool: *Pool, num: usize) Allocator.Error!void { | | |
| 201 | return pool.unmanaged.addCapacity(pool.allocator, num); | | |
| 202 | } | | |
| 203 | | | |
| 204 | pub const ResetMode = Unmanaged.ResetMode; | | |
| 205 | | | |
| 206 | /// Resets the memory pool and destroys all allocated items. | | |
| 207 | /// This can be used to batch-destroy all objects without invalidating the memory pool. | | |
| 208 | /// | | |
| 209 | /// The function will return whether the reset operation was successful or not. | | |
| 210 | /// If the reallocation failed `false` is returned. The pool will still be fully | | |
| 211 | /// functional in that case, all memory is released. Future allocations just might | | |
| 212 | /// be slower. | | |
| 213 | /// | | |
| 214 | /// NOTE: If `mode` is `free_all`, the function will always return `true`. | | |
| 215 | pub fn reset(pool: *Pool, mode: ResetMode) bool { | | |
| 216 | return pool.unmanaged.reset(pool.allocator, mode); | | |
| 217 | } | | |
| 218 | | | |
| 219 | /// Creates a new item and adds it to the memory pool. | | |
| 220 | pub fn create(pool: *Pool) Allocator.Error!ItemPtr { | | |
| 221 | return pool.unmanaged.create(pool.allocator); | | |
| 222 | } | | |
| 223 | | | |
| 224 | /// Destroys a previously created item. | | |
| 225 | /// Only pass items to `ptr` that were previously created with `create()` of the same memory pool! | | |
| 226 | pub fn destroy(pool: *Pool, ptr: ItemPtr) void { | | |
| 227 | return pool.unmanaged.destroy(ptr); | | |
| 228 | } | | |
| 229 | | | |
| 230 | fn allocNew(pool: *Pool) Allocator.Error!*align(item_alignment) [item_size]u8 { | | |
| 231 | return pool.unmanaged.allocNew(pool.allocator); | | |
| 232 | } | | |
| 233 | }; | | |
| 234 | } | | |
| 235 | | | |
| 236 | test "basic" { | 141 | test "basic" { |
| 237 | const a = std.testing.allocator; | 142 | const a = std.testing.allocator; |
| 238 | | 143 | |
| 239 | { | 144 | var pool: MemoryPool(u32) = .empty; |
| 240 | var pool: MemoryPool(u32) = .empty; | 145 | defer pool.deinit(a); |
| 241 | defer pool.deinit(a); | | |
| 242 | | | |
| 243 | const p1 = try pool.create(a); | | |
| 244 | const p2 = try pool.create(a); | | |
| 245 | const p3 = try pool.create(a); | | |
| 246 | | | |
| 247 | // Assert uniqueness | | |
| 248 | try std.testing.expect(p1 != p2); | | |
| 249 | try std.testing.expect(p1 != p3); | | |
| 250 | try std.testing.expect(p2 != p3); | | |
| 251 | | 146 | |
| 252 | pool.destroy(p2); | 147 | const p1 = try pool.create(a); |
| 253 | const p4 = try pool.create(a); | 148 | const p2 = try pool.create(a); |
| 254 | | 149 | const p3 = try pool.create(a); |
| 255 | // Assert memory reuse | | |
| 256 | try std.testing.expect(p2 == p4); | | |
| 257 | } | | |
| 258 | | 150 | |
| 259 | { | 151 | // Assert uniqueness |
| 260 | var pool: Managed(u32) = .init(std.testing.allocator); | 152 | try std.testing.expect(p1 != p2); |
| 261 | defer pool.deinit(); | 153 | try std.testing.expect(p1 != p3); |
| | 154 | try std.testing.expect(p2 != p3); |
| 262 | | 155 | |
| 263 | const p1 = try pool.create(); | 156 | pool.destroy(p2); |
| 264 | const p2 = try pool.create(); | 157 | const p4 = try pool.create(a); |
| 265 | const p3 = try pool.create(); | | |
| 266 | | 158 | |
| 267 | // Assert uniqueness | 159 | // Assert memory reuse |
| 268 | try std.testing.expect(p1 != p2); | 160 | try std.testing.expect(p2 == p4); |
| 269 | try std.testing.expect(p1 != p3); | | |
| 270 | try std.testing.expect(p2 != p3); | | |
| 271 | | | |
| 272 | pool.destroy(p2); | | |
| 273 | const p4 = try pool.create(); | | |
| 274 | | | |
| 275 | // Assert memory reuse | | |
| 276 | try std.testing.expect(p2 == p4); | | |
| 277 | } | | |
| 278 | } | 161 | } |
| 279 | | 162 | |
| 280 | test "initCapacity (success)" { | 163 | test "initCapacity (success)" { |
| 281 | const a = std.testing.allocator; | 164 | const a = std.testing.allocator; |
| 282 | | 165 | |
| 283 | { | 166 | var pool: MemoryPool(u32) = try .initCapacity(a, 4); |
| 284 | var pool: MemoryPool(u32) = try .initCapacity(a, 4); | 167 | defer pool.deinit(a); |
| 285 | defer pool.deinit(a); | | |
| 286 | | | |
| 287 | _ = try pool.create(a); | | |
| 288 | _ = try pool.create(a); | | |
| 289 | _ = try pool.create(a); | | |
| 290 | } | | |
| 291 | | | |
| 292 | { | | |
| 293 | var pool: Managed(u32) = try .initCapacity(a, 4); | | |
| 294 | defer pool.deinit(); | | |
| 295 | | 168 | |
| 296 | _ = try pool.create(); | 169 | _ = try pool.create(a); |
| 297 | _ = try pool.create(); | 170 | _ = try pool.create(a); |
| 298 | _ = try pool.create(); | 171 | _ = try pool.create(a); |
| 299 | } | | |
| 300 | } | 172 | } |
| 301 | | 173 | |
| 302 | test "initCapacity (failure)" { | 174 | test "initCapacity (failure)" { |
| 303 | const failer = std.testing.failing_allocator; | 175 | const failer = std.testing.failing_allocator; |
| 304 | try std.testing.expectError(error.OutOfMemory, MemoryPool(u32).initCapacity(failer, 5)); | 176 | try std.testing.expectError(error.OutOfMemory, MemoryPool(u32).initCapacity(failer, 5)); |
| 305 | try std.testing.expectError(error.OutOfMemory, Managed(u32).initCapacity(failer, 5)); | | |
| 306 | } | 177 | } |
| 307 | | 178 | |
| 308 | test "growable" { | 179 | test "growable" { |
| 309 | const a = std.testing.allocator; | 180 | const a = std.testing.allocator; |
| 310 | | 181 | |
| 311 | { | 182 | var pool: Extra(u32, .{ .growable = false }) = try .initCapacity(a, 4); |
| 312 | var pool: Extra(u32, .{ .growable = false }) = try .initCapacity(a, 4); | 183 | defer pool.deinit(a); |
| 313 | defer pool.deinit(a); | | |
| 314 | | | |
| 315 | _ = try pool.create(a); | | |
| 316 | _ = try pool.create(a); | | |
| 317 | _ = try pool.create(a); | | |
| 318 | _ = try pool.create(a); | | |
| 319 | | | |
| 320 | try std.testing.expectError(error.OutOfMemory, pool.create(a)); | | |
| 321 | } | | |
| 322 | | | |
| 323 | { | | |
| 324 | var pool: ExtraManaged(u32, .{ .growable = false }) = try .initCapacity(a, 4); | | |
| 325 | defer pool.deinit(); | | |
| 326 | | 184 | |
| 327 | _ = try pool.create(); | 185 | _ = try pool.create(a); |
| 328 | _ = try pool.create(); | 186 | _ = try pool.create(a); |
| 329 | _ = try pool.create(); | 187 | _ = try pool.create(a); |
| 330 | _ = try pool.create(); | 188 | _ = try pool.create(a); |
| 331 | | 189 | |
| 332 | try std.testing.expectError(error.OutOfMemory, pool.create()); | 190 | try std.testing.expectError(error.OutOfMemory, pool.create(a)); |
| 333 | } | | |
| 334 | } | 191 | } |
| 335 | | 192 | |
| 336 | test "greater than pointer default alignment" { | 193 | test "greater than pointer default alignment" { |
| ... | @@ -339,21 +196,11 @@ test "greater than pointer default alignment" { | ... | @@ -339,21 +196,11 @@ test "greater than pointer default alignment" { |
| 339 | }; | 196 | }; |
| 340 | const a = std.testing.allocator; | 197 | const a = std.testing.allocator; |
| 341 | | 198 | |
| 342 | { | 199 | var pool: MemoryPool(Foo) = .empty; |
| 343 | var pool: MemoryPool(Foo) = .empty; | 200 | defer pool.deinit(a); |
| 344 | defer pool.deinit(a); | | |
| 345 | | | |
| 346 | const foo: *Foo = try pool.create(a); | | |
| 347 | pool.destroy(foo); | | |
| 348 | } | | |
| 349 | | | |
| 350 | { | | |
| 351 | var pool: Managed(Foo) = .init(a); | | |
| 352 | defer pool.deinit(); | | |
| 353 | | 201 | |
| 354 | const foo: *Foo = try pool.create(); | 202 | const foo: *Foo = try pool.create(a); |
| 355 | pool.destroy(foo); | 203 | pool.destroy(foo); |
| 356 | } | | |
| 357 | } | 204 | } |
| 358 | | 205 | |
| 359 | test "greater than pointer manual alignment" { | 206 | test "greater than pointer manual alignment" { |
| ... | @@ -362,19 +209,9 @@ test "greater than pointer manual alignment" { | ... | @@ -362,19 +209,9 @@ test "greater than pointer manual alignment" { |
| 362 | }; | 209 | }; |
| 363 | const a = std.testing.allocator; | 210 | const a = std.testing.allocator; |
| 364 | | 211 | |
| 365 | { | 212 | var pool: Aligned(Foo, .@"16") = .empty; |
| 366 | var pool: Aligned(Foo, .@"16") = .empty; | 213 | defer pool.deinit(a); |
| 367 | defer pool.deinit(a); | | |
| 368 | | | |
| 369 | const foo: *align(16) Foo = try pool.create(a); | | |
| 370 | pool.destroy(foo); | | |
| 371 | } | | |
| 372 | | 214 | |
| 373 | { | 215 | const foo: *align(16) Foo = try pool.create(a); |
| 374 | var pool: AlignedManaged(Foo, .@"16") = .init(a); | 216 | pool.destroy(foo); |
| 375 | defer pool.deinit(); | | |
| 376 | | | |
| 377 | const foo: *align(16) Foo = try pool.create(); | | |
| 378 | pool.destroy(foo); | | |
| 379 | } | | |
| 380 | } | 217 | } |