| ... | @@ -1,26 +1,26 @@ | ... | @@ -1,26 +1,26 @@ |
| 1 | const std = @import("../std.zig"); | 1 | const std = @import("../std.zig"); |
| | 2 | const Allocator = std.mem.Allocator; |
| 2 | const Alignment = std.mem.Alignment; | 3 | const Alignment = std.mem.Alignment; |
| | 4 | const MemoryPool = std.heap.MemoryPool; |
| 3 | | 5 | |
| 4 | const debug_mode = @import("builtin").mode == .Debug; | 6 | /// Deprecated. |
| 5 | | 7 | pub fn Managed(comptime Item: type) type { |
| 6 | pub const MemoryPoolError = error{OutOfMemory}; | 8 | return ExtraManaged(Item, .{ .alignment = null }); |
| | 9 | } |
| 7 | | 10 | |
| 8 | /// A memory pool that can allocate objects of a single type very quickly. | 11 | /// A memory pool that can allocate objects of a single type very quickly. |
| 9 | /// Use this when you need to allocate a lot of objects of the same type, | 12 | /// Use this when you need to allocate a lot of objects of the same type, |
| 10 | /// because It outperforms general purpose allocators. | 13 | /// because it outperforms general purpose allocators. |
| 11 | pub fn MemoryPool(comptime Item: type) type { | 14 | /// Allocated items are aligned to `alignment`-byte addresses or `@alignOf(Item)` |
| 12 | return MemoryPoolAligned(Item, .of(Item)); | 15 | /// if `alignment` is `null`. |
| | 16 | /// Functions that potentially allocate memory accept an `Allocator` parameter. |
| | 17 | pub fn Aligned(comptime Item: type, comptime alignment: Alignment) type { |
| | 18 | return Extra(Item, .{ .alignment = alignment }); |
| 13 | } | 19 | } |
| 14 | | 20 | |
| 15 | /// A memory pool that can allocate objects of a single type very quickly. | 21 | /// Deprecated. |
| 16 | /// Use this when you need to allocate a lot of objects of the same type, | 22 | pub fn AlignedManaged(comptime Item: type, comptime alignment: Alignment) type { |
| 17 | /// because It outperforms general purpose allocators. | 23 | return ExtraManaged(Item, .{ .alignment = alignment }); |
| 18 | pub fn MemoryPoolAligned(comptime Item: type, comptime alignment: Alignment) type { | | |
| 19 | if (@alignOf(Item) == comptime alignment.toByteUnits()) { | | |
| 20 | return MemoryPoolExtra(Item, .{}); | | |
| 21 | } else { | | |
| 22 | return MemoryPoolExtra(Item, .{ .alignment = alignment }); | | |
| 23 | } | | |
| 24 | } | 24 | } |
| 25 | | 25 | |
| 26 | pub const Options = struct { | 26 | pub const Options = struct { |
| ... | @@ -34,64 +34,70 @@ pub const Options = struct { | ... | @@ -34,64 +34,70 @@ pub const Options = struct { |
| 34 | | 34 | |
| 35 | /// A memory pool that can allocate objects of a single type very quickly. | 35 | /// A memory pool that can allocate objects of a single type very quickly. |
| 36 | /// Use this when you need to allocate a lot of objects of the same type, | 36 | /// Use this when you need to allocate a lot of objects of the same type, |
| 37 | /// because It outperforms general purpose allocators. | 37 | /// because it outperforms general purpose allocators. |
| 38 | pub fn MemoryPoolExtra(comptime Item: type, comptime pool_options: Options) type { | 38 | /// Functions that potentially allocate memory accept an `Allocator` parameter. |
| | 39 | pub fn Extra(comptime Item: type, comptime pool_options: Options) type { |
| | 40 | if (pool_options.alignment) |a| { |
| | 41 | if (a.compare(.eq, .of(Item))) { |
| | 42 | var new_options = pool_options; |
| | 43 | new_options.alignment = null; |
| | 44 | return Extra(Item, new_options); |
| | 45 | } |
| | 46 | } |
| 39 | return struct { | 47 | return struct { |
| 40 | const Pool = @This(); | 48 | const Pool = @This(); |
| 41 | | 49 | |
| | 50 | arena_state: std.heap.ArenaAllocator.State, |
| | 51 | free_list: std.SinglyLinkedList, |
| | 52 | |
| 42 | /// Size of the memory pool items. This is not necessarily the same | 53 | /// Size of the memory pool items. This is not necessarily the same |
| 43 | /// as `@sizeOf(Item)` as the pool also uses the items for internal means. | 54 | /// as `@sizeOf(Item)` as the pool also uses the items for internal means. |
| 44 | pub const item_size = @max(@sizeOf(Node), @sizeOf(Item)); | 55 | pub const item_size = @max(@sizeOf(Node), @sizeOf(Item)); |
| 45 | | 56 | |
| 46 | // This needs to be kept in sync with Node. | | |
| 47 | const node_alignment: Alignment = .of(*anyopaque); | | |
| 48 | | | |
| 49 | /// Alignment of the memory pool items. This is not necessarily the same | 57 | /// Alignment of the memory pool items. This is not necessarily the same |
| 50 | /// as `@alignOf(Item)` as the pool also uses the items for internal means. | 58 | /// as `@alignOf(Item)` as the pool also uses the items for internal means. |
| 51 | pub const item_alignment: Alignment = node_alignment.max(pool_options.alignment orelse .of(Item)); | 59 | pub const item_alignment: Alignment = .max(pool_options.alignment orelse .of(Item), .of(Node)); |
| 52 | | 60 | |
| 53 | const Node = struct { | 61 | const Node = std.SinglyLinkedList.Node; |
| 54 | next: ?*align(item_alignment.toByteUnits()) @This(), | | |
| 55 | }; | | |
| 56 | const NodePtr = *align(item_alignment.toByteUnits()) Node; | | |
| 57 | const ItemPtr = *align(item_alignment.toByteUnits()) Item; | 62 | const ItemPtr = *align(item_alignment.toByteUnits()) Item; |
| 58 | | 63 | |
| 59 | arena: std.heap.ArenaAllocator, | 64 | /// A MemoryPool containing no elements. |
| 60 | free_list: ?NodePtr = null, | 65 | pub const empty: Pool = .{ |
| 61 | | 66 | .arena_state = .{}, |
| 62 | /// Creates a new memory pool. | 67 | .free_list = .{}, |
| 63 | pub fn init(allocator: std.mem.Allocator) Pool { | 68 | }; |
| 64 | return .{ .arena = std.heap.ArenaAllocator.init(allocator) }; | | |
| 65 | } | | |
| 66 | | 69 | |
| 67 | /// Creates a new memory pool and pre-allocates `initial_size` items. | 70 | /// Creates a new memory pool and pre-allocates `num` items. |
| 68 | /// This allows the up to `initial_size` active allocations before a | 71 | /// This allows up to `num` active allocations before an |
| 69 | /// `OutOfMemory` error happens when calling `create()`. | 72 | /// `OutOfMemory` error might happen when calling `create()`. |
| 70 | pub fn initPreheated(allocator: std.mem.Allocator, initial_size: usize) MemoryPoolError!Pool { | 73 | pub fn initCapacity(allocator: Allocator, num: usize) Allocator.Error!Pool { |
| 71 | var pool = init(allocator); | 74 | var pool: Pool = .empty; |
| 72 | errdefer pool.deinit(); | 75 | errdefer pool.deinit(allocator); |
| 73 | try pool.preheat(initial_size); | 76 | try pool.addCapacity(allocator, num); |
| 74 | return pool; | 77 | return pool; |
| 75 | } | 78 | } |
| 76 | | 79 | |
| 77 | /// Destroys the memory pool and frees all allocated memory. | 80 | /// Destroys the memory pool and frees all allocated memory. |
| 78 | pub fn deinit(pool: *Pool) void { | 81 | pub fn deinit(pool: *Pool, allocator: Allocator) void { |
| 79 | pool.arena.deinit(); | 82 | pool.arena_state.promote(allocator).deinit(); |
| 80 | pool.* = undefined; | 83 | pool.* = undefined; |
| 81 | } | 84 | } |
| 82 | | 85 | |
| 83 | /// Preheats the memory pool by pre-allocating `size` items. | 86 | pub fn toManaged(pool: Pool, allocator: Allocator) ExtraManaged(Item, pool_options) { |
| 84 | /// This allows up to `size` active allocations before an | 87 | return .{ |
| | 88 | .allocator = allocator, |
| | 89 | .unmanaged = pool, |
| | 90 | }; |
| | 91 | } |
| | 92 | |
| | 93 | /// Pre-allocates `num` items and adds them to the memory pool. |
| | 94 | /// This allows at least `num` active allocations before an |
| 85 | /// `OutOfMemory` error might happen when calling `create()`. | 95 | /// `OutOfMemory` error might happen when calling `create()`. |
| 86 | pub fn preheat(pool: *Pool, size: usize) MemoryPoolError!void { | 96 | pub fn addCapacity(pool: *Pool, allocator: Allocator, num: usize) Allocator.Error!void { |
| 87 | var i: usize = 0; | 97 | var i: usize = 0; |
| 88 | while (i < size) : (i += 1) { | 98 | while (i < num) : (i += 1) { |
| 89 | const raw_mem = try pool.allocNew(); | 99 | const memory = try pool.allocNew(allocator); |
| 90 | const free_node = @as(NodePtr, @ptrCast(raw_mem)); | 100 | pool.free_list.prepend(@ptrCast(memory)); |
| 91 | free_node.* = Node{ | | |
| 92 | .next = pool.free_list, | | |
| 93 | }; | | |
| 94 | pool.free_list = free_node; | | |
| 95 | } | 101 | } |
| 96 | } | 102 | } |
| 97 | | 103 | |
| ... | @@ -106,28 +112,29 @@ pub fn MemoryPoolExtra(comptime Item: type, comptime pool_options: Options) type | ... | @@ -106,28 +112,29 @@ pub fn MemoryPoolExtra(comptime Item: type, comptime pool_options: Options) type |
| 106 | /// be slower. | 112 | /// be slower. |
| 107 | /// | 113 | /// |
| 108 | /// NOTE: If `mode` is `free_all`, the function will always return `true`. | 114 | /// NOTE: If `mode` is `free_all`, the function will always return `true`. |
| 109 | pub fn reset(pool: *Pool, mode: ResetMode) bool { | 115 | pub fn reset(pool: *Pool, allocator: Allocator, mode: ResetMode) bool { |
| 110 | // TODO: Potentially store all allocated objects in a list as well, allowing to | 116 | // 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. | 117 | // just move them into the free list instead of actually releasing the memory. |
| 112 | | 118 | |
| 113 | const reset_successful = pool.arena.reset(mode); | 119 | var arena = pool.arena_state.promote(allocator); |
| | 120 | defer pool.arena_state = arena.state; |
| 114 | | 121 | |
| 115 | pool.free_list = null; | 122 | const reset_successful = arena.reset(mode); |
| | 123 | pool.free_list = .{}; |
| 116 | | 124 | |
| 117 | return reset_successful; | 125 | return reset_successful; |
| 118 | } | 126 | } |
| 119 | | 127 | |
| 120 | /// Creates a new item and adds it to the memory pool. | 128 | /// Creates a new item and adds it to the memory pool. |
| 121 | pub fn create(pool: *Pool) !ItemPtr { | 129 | /// `allocator` may be `undefined` if pool is not `growable`. |
| 122 | const node = if (pool.free_list) |item| blk: { | 130 | pub fn create(pool: *Pool, allocator: Allocator) Allocator.Error!ItemPtr { |
| 123 | pool.free_list = item.next; | 131 | const ptr: ItemPtr = if (pool.free_list.popFirst()) |node| |
| 124 | break :blk item; | 132 | @ptrCast(@alignCast(node)) |
| 125 | } else if (pool_options.growable) | 133 | else if (pool_options.growable) |
| 126 | @as(NodePtr, @ptrCast(try pool.allocNew())) | 134 | @ptrCast(try pool.allocNew(allocator)) |
| 127 | else | 135 | else |
| 128 | return error.OutOfMemory; | 136 | return error.OutOfMemory; |
| 129 | | 137 | |
| 130 | const ptr = @as(ItemPtr, @ptrCast(node)); | | |
| 131 | ptr.* = undefined; | 138 | ptr.* = undefined; |
| 132 | return ptr; | 139 | return ptr; |
| 133 | } | 140 | } |
| ... | @@ -136,87 +143,238 @@ pub fn MemoryPoolExtra(comptime Item: type, comptime pool_options: Options) type | ... | @@ -136,87 +143,238 @@ pub fn MemoryPoolExtra(comptime Item: type, comptime pool_options: Options) type |
| 136 | /// Only pass items to `ptr` that were previously created with `create()` of the same memory pool! | 143 | /// Only pass items to `ptr` that were previously created with `create()` of the same memory pool! |
| 137 | pub fn destroy(pool: *Pool, ptr: ItemPtr) void { | 144 | pub fn destroy(pool: *Pool, ptr: ItemPtr) void { |
| 138 | ptr.* = undefined; | 145 | ptr.* = undefined; |
| | 146 | pool.free_list.prepend(@ptrCast(ptr)); |
| | 147 | } |
| 139 | | 148 | |
| 140 | const node = @as(NodePtr, @ptrCast(ptr)); | 149 | fn allocNew(pool: *Pool, allocator: Allocator) Allocator.Error!*align(item_alignment.toByteUnits()) [item_size]u8 { |
| 141 | node.* = Node{ | 150 | var arena = pool.arena_state.promote(allocator); |
| 142 | .next = pool.free_list, | 151 | defer pool.arena_state = arena.state; |
| 143 | }; | 152 | const memory = try arena.allocator().alignedAlloc(u8, item_alignment, item_size); |
| 144 | pool.free_list = node; | 153 | return memory[0..item_size]; |
| | 154 | } |
| | 155 | }; |
| | 156 | } |
| | 157 | |
| | 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); |
| 145 | } | 217 | } |
| 146 | | 218 | |
| 147 | fn allocNew(pool: *Pool) MemoryPoolError!*align(item_alignment.toByteUnits()) [item_size]u8 { | 219 | /// Creates a new item and adds it to the memory pool. |
| 148 | const mem = try pool.arena.allocator().alignedAlloc(u8, item_alignment, item_size); | 220 | pub fn create(pool: *Pool) Allocator.Error!ItemPtr { |
| 149 | return mem[0..item_size]; // coerce slice to array pointer | 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); |
| 150 | } | 232 | } |
| 151 | }; | 233 | }; |
| 152 | } | 234 | } |
| 153 | | 235 | |
| 154 | test "basic" { | 236 | test "basic" { |
| 155 | var pool = MemoryPool(u32).init(std.testing.allocator); | 237 | const a = std.testing.allocator; |
| 156 | defer pool.deinit(); | 238 | |
| | 239 | { |
| | 240 | var pool: MemoryPool(u32) = .empty; |
| | 241 | defer pool.deinit(a); |
| 157 | | 242 | |
| 158 | const p1 = try pool.create(); | 243 | const p1 = try pool.create(a); |
| 159 | const p2 = try pool.create(); | 244 | const p2 = try pool.create(a); |
| 160 | const p3 = try pool.create(); | 245 | const p3 = try pool.create(a); |
| 161 | | 246 | |
| 162 | // Assert uniqueness | 247 | // Assert uniqueness |
| 163 | try std.testing.expect(p1 != p2); | 248 | try std.testing.expect(p1 != p2); |
| 164 | try std.testing.expect(p1 != p3); | 249 | try std.testing.expect(p1 != p3); |
| 165 | try std.testing.expect(p2 != p3); | 250 | try std.testing.expect(p2 != p3); |
| | 251 | |
| | 252 | pool.destroy(p2); |
| | 253 | const p4 = try pool.create(a); |
| | 254 | |
| | 255 | // Assert memory reuse |
| | 256 | try std.testing.expect(p2 == p4); |
| | 257 | } |
| 166 | | 258 | |
| 167 | pool.destroy(p2); | 259 | { |
| 168 | const p4 = try pool.create(); | 260 | var pool: Managed(u32) = .init(std.testing.allocator); |
| | 261 | defer pool.deinit(); |
| 169 | | 262 | |
| 170 | // Assert memory reuse | 263 | const p1 = try pool.create(); |
| 171 | try std.testing.expect(p2 == p4); | 264 | const p2 = try pool.create(); |
| | 265 | const p3 = try pool.create(); |
| | 266 | |
| | 267 | // Assert uniqueness |
| | 268 | try std.testing.expect(p1 != p2); |
| | 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 | } |
| 172 | } | 278 | } |
| 173 | | 279 | |
| 174 | test "preheating (success)" { | 280 | test "initCapacity (success)" { |
| 175 | var pool = try MemoryPool(u32).initPreheated(std.testing.allocator, 4); | 281 | const a = std.testing.allocator; |
| 176 | defer pool.deinit(); | 282 | |
| | 283 | { |
| | 284 | var pool: MemoryPool(u32) = try .initCapacity(a, 4); |
| | 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(); |
| 177 | | 295 | |
| 178 | _ = try pool.create(); | 296 | _ = try pool.create(); |
| 179 | _ = try pool.create(); | 297 | _ = try pool.create(); |
| 180 | _ = try pool.create(); | 298 | _ = try pool.create(); |
| | 299 | } |
| 181 | } | 300 | } |
| 182 | | 301 | |
| 183 | test "preheating (failure)" { | 302 | test "initCapacity (failure)" { |
| 184 | const failer = std.testing.failing_allocator; | 303 | const failer = std.testing.failing_allocator; |
| 185 | try std.testing.expectError(error.OutOfMemory, MemoryPool(u32).initPreheated(failer, 5)); | 304 | try std.testing.expectError(error.OutOfMemory, MemoryPool(u32).initCapacity(failer, 5)); |
| | 305 | try std.testing.expectError(error.OutOfMemory, Managed(u32).initCapacity(failer, 5)); |
| 186 | } | 306 | } |
| 187 | | 307 | |
| 188 | test "growable" { | 308 | test "growable" { |
| 189 | var pool = try MemoryPoolExtra(u32, .{ .growable = false }).initPreheated(std.testing.allocator, 4); | 309 | const a = std.testing.allocator; |
| 190 | defer pool.deinit(); | | |
| 191 | | 310 | |
| 192 | _ = try pool.create(); | 311 | { |
| 193 | _ = try pool.create(); | 312 | var pool: Extra(u32, .{ .growable = false }) = try .initCapacity(a, 4); |
| 194 | _ = try pool.create(); | 313 | defer pool.deinit(a); |
| 195 | _ = try pool.create(); | 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 | } |
| 196 | | 322 | |
| 197 | try std.testing.expectError(error.OutOfMemory, pool.create()); | 323 | { |
| | 324 | var pool: ExtraManaged(u32, .{ .growable = false }) = try .initCapacity(a, 4); |
| | 325 | defer pool.deinit(); |
| | 326 | |
| | 327 | _ = try pool.create(); |
| | 328 | _ = try pool.create(); |
| | 329 | _ = try pool.create(); |
| | 330 | _ = try pool.create(); |
| | 331 | |
| | 332 | try std.testing.expectError(error.OutOfMemory, pool.create()); |
| | 333 | } |
| 198 | } | 334 | } |
| 199 | | 335 | |
| 200 | test "greater than pointer default alignment" { | 336 | test "greater than pointer default alignment" { |
| 201 | const Foo = struct { | 337 | const Foo = struct { |
| 202 | data: u64 align(16), | 338 | data: u64 align(16), |
| 203 | }; | 339 | }; |
| | 340 | const a = std.testing.allocator; |
| | 341 | |
| | 342 | { |
| | 343 | var pool: MemoryPool(Foo) = .empty; |
| | 344 | defer pool.deinit(a); |
| | 345 | |
| | 346 | const foo: *Foo = try pool.create(a); |
| | 347 | pool.destroy(foo); |
| | 348 | } |
| 204 | | 349 | |
| 205 | var pool = MemoryPool(Foo).init(std.testing.allocator); | 350 | { |
| 206 | defer pool.deinit(); | 351 | var pool: Managed(Foo) = .init(a); |
| | 352 | defer pool.deinit(); |
| 207 | | 353 | |
| 208 | const foo: *Foo = try pool.create(); | 354 | const foo: *Foo = try pool.create(); |
| 209 | _ = foo; | 355 | pool.destroy(foo); |
| | 356 | } |
| 210 | } | 357 | } |
| 211 | | 358 | |
| 212 | test "greater than pointer manual alignment" { | 359 | test "greater than pointer manual alignment" { |
| 213 | const Foo = struct { | 360 | const Foo = struct { |
| 214 | data: u64, | 361 | data: u64, |
| 215 | }; | 362 | }; |
| | 363 | const a = std.testing.allocator; |
| | 364 | |
| | 365 | { |
| | 366 | var pool: Aligned(Foo, .@"16") = .empty; |
| | 367 | defer pool.deinit(a); |
| 216 | | 368 | |
| 217 | var pool = MemoryPoolAligned(Foo, .@"16").init(std.testing.allocator); | 369 | const foo: *align(16) Foo = try pool.create(a); |
| 218 | defer pool.deinit(); | 370 | pool.destroy(foo); |
| | 371 | } |
| 219 | | 372 | |
| 220 | const foo: *align(16) Foo = try pool.create(); | 373 | { |
| 221 | _ = foo; | 374 | var pool: AlignedManaged(Foo, .@"16") = .init(a); |
| | 375 | defer pool.deinit(); |
| | 376 | |
| | 377 | const foo: *align(16) Foo = try pool.create(); |
| | 378 | pool.destroy(foo); |
| | 379 | } |
| 222 | } | 380 | } |