| ... | ... | @@ -368,112 +368,88 @@ pub const brk_allocator: Allocator = .{ |
| 368 | 368 | .vtable = &BrkAllocator.vtable, |
| 369 | 369 | }; |
| 370 | 370 | |
| 371 | | /// Returns a `StackFallbackAllocator` allocating using either a |
| 372 | | /// `FixedBufferAllocator` on an array of size `size` and falling back to |
| 373 | | /// `fallback_allocator` if that fails. |
| 374 | | pub fn stackFallback(comptime size: usize, fallback_allocator: Allocator) StackFallbackAllocator(size) { |
| 375 | | return StackFallbackAllocator(size){ |
| 376 | | .buffer = undefined, |
| 377 | | .fallback_allocator = fallback_allocator, |
| 378 | | .fixed_buffer_allocator = undefined, |
| 379 | | }; |
| 380 | | } |
| 371 | /// An allocator that attempts to allocate from the given buffer, falling back to |
| 372 | /// `fallback_allocator` if this fails. |
| 373 | pub const StackFallbackAllocator = struct { |
| 374 | const Self = @This(); |
| 375 | |
| 376 | fallback_allocator: Allocator, |
| 377 | fixed_buffer_allocator: FixedBufferAllocator, |
| 378 | |
| 379 | pub fn init(buf: []u8, fallback_allocator: Allocator) Self { |
| 380 | return .{ |
| 381 | .fallback_allocator = fallback_allocator, |
| 382 | .fixed_buffer_allocator = .init(buf), |
| 383 | }; |
| 384 | } |
| 381 | 385 | |
| 382 | | /// An allocator that attempts to allocate using a |
| 383 | | /// `FixedBufferAllocator` using an array of size `size`. If the |
| 384 | | /// allocation fails, it will fall back to using |
| 385 | | /// `fallback_allocator`. Easily created with `stackFallback`. |
| 386 | | pub fn StackFallbackAllocator(comptime size: usize) type { |
| 387 | | return struct { |
| 388 | | const Self = @This(); |
| 389 | | |
| 390 | | buffer: [size]u8, |
| 391 | | fallback_allocator: Allocator, |
| 392 | | fixed_buffer_allocator: FixedBufferAllocator, |
| 393 | | get_called: if (std.debug.runtime_safety) bool else void = |
| 394 | | if (std.debug.runtime_safety) false else {}, |
| 395 | | |
| 396 | | /// This function both fetches a `Allocator` interface to this |
| 397 | | /// allocator *and* resets the internal buffer allocator. |
| 398 | | pub fn get(self: *Self) Allocator { |
| 399 | | if (std.debug.runtime_safety) { |
| 400 | | assert(!self.get_called); // `get` called multiple times; instead use `const allocator = stackFallback(N).get();` |
| 401 | | self.get_called = true; |
| 402 | | } |
| 403 | | self.fixed_buffer_allocator = FixedBufferAllocator.init(self.buffer[0..]); |
| 404 | | return .{ |
| 405 | | .ptr = self, |
| 406 | | .vtable = &.{ |
| 407 | | .alloc = alloc, |
| 408 | | .resize = resize, |
| 409 | | .remap = remap, |
| 410 | | .free = free, |
| 411 | | }, |
| 412 | | }; |
| 413 | | } |
| 386 | pub fn allocator(self: *Self) Allocator { |
| 387 | return .{ |
| 388 | .ptr = self, |
| 389 | .vtable = &.{ |
| 390 | .alloc = alloc, |
| 391 | .resize = resize, |
| 392 | .remap = remap, |
| 393 | .free = free, |
| 394 | }, |
| 395 | }; |
| 396 | } |
| 414 | 397 | |
| 415 | | /// Unlike most std allocators `StackFallbackAllocator` modifies |
| 416 | | /// its internal state before returning an implementation of |
| 417 | | /// the`Allocator` interface and therefore also doesn't use |
| 418 | | /// the usual `.allocator()` method. |
| 419 | | pub const allocator = @compileError("use 'const allocator = stackFallback(N).get();' instead"); |
| 420 | | |
| 421 | | fn alloc( |
| 422 | | ctx: *anyopaque, |
| 423 | | len: usize, |
| 424 | | alignment: Alignment, |
| 425 | | ra: usize, |
| 426 | | ) ?[*]u8 { |
| 427 | | const self: *Self = @ptrCast(@alignCast(ctx)); |
| 428 | | return FixedBufferAllocator.alloc(&self.fixed_buffer_allocator, len, alignment, ra) orelse |
| 429 | | return self.fallback_allocator.rawAlloc(len, alignment, ra); |
| 430 | | } |
| 398 | fn alloc( |
| 399 | ctx: *anyopaque, |
| 400 | len: usize, |
| 401 | alignment: Alignment, |
| 402 | ra: usize, |
| 403 | ) ?[*]u8 { |
| 404 | const self: *Self = @ptrCast(@alignCast(ctx)); |
| 405 | return FixedBufferAllocator.alloc(&self.fixed_buffer_allocator, len, alignment, ra) orelse |
| 406 | return self.fallback_allocator.rawAlloc(len, alignment, ra); |
| 407 | } |
| 431 | 408 | |
| 432 | | fn resize( |
| 433 | | ctx: *anyopaque, |
| 434 | | buf: []u8, |
| 435 | | alignment: Alignment, |
| 436 | | new_len: usize, |
| 437 | | ra: usize, |
| 438 | | ) bool { |
| 439 | | const self: *Self = @ptrCast(@alignCast(ctx)); |
| 440 | | if (self.fixed_buffer_allocator.ownsPtr(buf.ptr)) { |
| 441 | | return FixedBufferAllocator.resize(&self.fixed_buffer_allocator, buf, alignment, new_len, ra); |
| 442 | | } else { |
| 443 | | return self.fallback_allocator.rawResize(buf, alignment, new_len, ra); |
| 444 | | } |
| 409 | fn resize( |
| 410 | ctx: *anyopaque, |
| 411 | buf: []u8, |
| 412 | alignment: Alignment, |
| 413 | new_len: usize, |
| 414 | ra: usize, |
| 415 | ) bool { |
| 416 | const self: *Self = @ptrCast(@alignCast(ctx)); |
| 417 | if (self.fixed_buffer_allocator.ownsPtr(buf.ptr)) { |
| 418 | return FixedBufferAllocator.resize(&self.fixed_buffer_allocator, buf, alignment, new_len, ra); |
| 419 | } else { |
| 420 | return self.fallback_allocator.rawResize(buf, alignment, new_len, ra); |
| 445 | 421 | } |
| 422 | } |
| 446 | 423 | |
| 447 | | fn remap( |
| 448 | | context: *anyopaque, |
| 449 | | memory: []u8, |
| 450 | | alignment: Alignment, |
| 451 | | new_len: usize, |
| 452 | | return_address: usize, |
| 453 | | ) ?[*]u8 { |
| 454 | | const self: *Self = @ptrCast(@alignCast(context)); |
| 455 | | if (self.fixed_buffer_allocator.ownsPtr(memory.ptr)) { |
| 456 | | return FixedBufferAllocator.remap(&self.fixed_buffer_allocator, memory, alignment, new_len, return_address); |
| 457 | | } else { |
| 458 | | return self.fallback_allocator.rawRemap(memory, alignment, new_len, return_address); |
| 459 | | } |
| 424 | fn remap( |
| 425 | context: *anyopaque, |
| 426 | memory: []u8, |
| 427 | alignment: Alignment, |
| 428 | new_len: usize, |
| 429 | return_address: usize, |
| 430 | ) ?[*]u8 { |
| 431 | const self: *Self = @ptrCast(@alignCast(context)); |
| 432 | if (self.fixed_buffer_allocator.ownsPtr(memory.ptr)) { |
| 433 | return FixedBufferAllocator.remap(&self.fixed_buffer_allocator, memory, alignment, new_len, return_address); |
| 434 | } else { |
| 435 | return self.fallback_allocator.rawRemap(memory, alignment, new_len, return_address); |
| 460 | 436 | } |
| 437 | } |
| 461 | 438 | |
| 462 | | fn free( |
| 463 | | ctx: *anyopaque, |
| 464 | | buf: []u8, |
| 465 | | alignment: Alignment, |
| 466 | | ra: usize, |
| 467 | | ) void { |
| 468 | | const self: *Self = @ptrCast(@alignCast(ctx)); |
| 469 | | if (self.fixed_buffer_allocator.ownsPtr(buf.ptr)) { |
| 470 | | return FixedBufferAllocator.free(&self.fixed_buffer_allocator, buf, alignment, ra); |
| 471 | | } else { |
| 472 | | return self.fallback_allocator.rawFree(buf, alignment, ra); |
| 473 | | } |
| 439 | fn free( |
| 440 | ctx: *anyopaque, |
| 441 | buf: []u8, |
| 442 | alignment: Alignment, |
| 443 | ra: usize, |
| 444 | ) void { |
| 445 | const self: *Self = @ptrCast(@alignCast(ctx)); |
| 446 | if (self.fixed_buffer_allocator.ownsPtr(buf.ptr)) { |
| 447 | return FixedBufferAllocator.free(&self.fixed_buffer_allocator, buf, alignment, ra); |
| 448 | } else { |
| 449 | return self.fallback_allocator.rawFree(buf, alignment, ra); |
| 474 | 450 | } |
| 475 | | }; |
| 476 | | } |
| 451 | } |
| 452 | }; |
| 477 | 453 | |
| 478 | 454 | test c_allocator { |
| 479 | 455 | if (builtin.link_libc) { |
| ... | ... | @@ -525,22 +501,23 @@ test ArenaAllocator { |
| 525 | 501 | try testAllocatorAlignedShrink(allocator); |
| 526 | 502 | } |
| 527 | 503 | |
| 528 | | test "StackFallbackAllocator" { |
| 504 | test StackFallbackAllocator { |
| 505 | var buf: [4096]u8 = undefined; |
| 529 | 506 | { |
| 530 | | var stack_allocator = stackFallback(4096, std.testing.allocator); |
| 531 | | try testAllocator(stack_allocator.get()); |
| 507 | var stack_allocator: StackFallbackAllocator = .init(&buf, std.testing.allocator); |
| 508 | try testAllocator(stack_allocator.allocator()); |
| 532 | 509 | } |
| 533 | 510 | { |
| 534 | | var stack_allocator = stackFallback(4096, std.testing.allocator); |
| 535 | | try testAllocatorAligned(stack_allocator.get()); |
| 511 | var stack_allocator: StackFallbackAllocator = .init(&buf, std.testing.allocator); |
| 512 | try testAllocatorAligned(stack_allocator.allocator()); |
| 536 | 513 | } |
| 537 | 514 | { |
| 538 | | var stack_allocator = stackFallback(4096, std.testing.allocator); |
| 539 | | try testAllocatorLargeAlignment(stack_allocator.get()); |
| 515 | var stack_allocator: StackFallbackAllocator = .init(&buf, std.testing.allocator); |
| 516 | try testAllocatorLargeAlignment(stack_allocator.allocator()); |
| 540 | 517 | } |
| 541 | 518 | { |
| 542 | | var stack_allocator = stackFallback(4096, std.testing.allocator); |
| 543 | | try testAllocatorAlignedShrink(stack_allocator.get()); |
| 519 | var stack_allocator: StackFallbackAllocator = .init(&buf, std.testing.allocator); |
| 520 | try testAllocatorAlignedShrink(stack_allocator.allocator()); |
| 544 | 521 | } |
| 545 | 522 | } |
| 546 | 523 | |