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