| ... | ... | @@ -302,8 +302,17 @@ pub const FixedBufferAllocator = struct { |
| 302 | 302 | } |
| 303 | 303 | |
| 304 | 304 | fn realloc(allocator: *Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 { |
| 305 | const self = @fieldParentPtr(FixedBufferAllocator, "allocator", allocator); |
| 306 | assert(old_mem.len <= self.end_index); |
| 305 | 307 | if (new_size <= old_mem.len) { |
| 306 | 308 | return old_mem[0..new_size]; |
| 309 | } else if (old_mem.ptr == self.buffer.ptr + self.end_index - old_mem.len) { |
| 310 | const start_index = self.end_index - old_mem.len; |
| 311 | const new_end_index = start_index + new_size; |
| 312 | if (new_end_index > self.buffer.len) return error.OutOfMemory; |
| 313 | const result = self.buffer[start_index..new_end_index]; |
| 314 | self.end_index = new_end_index; |
| 315 | return result; |
| 307 | 316 | } else { |
| 308 | 317 | const result = try alloc(allocator, new_size, alignment); |
| 309 | 318 | mem.copy(u8, result, old_mem); |
| ... | ... | @@ -467,6 +476,35 @@ test "FixedBufferAllocator" { |
| 467 | 476 | try testAllocatorLargeAlignment(&fixed_buffer_allocator.allocator); |
| 468 | 477 | } |
| 469 | 478 | |
| 479 | test "FixedBufferAllocator Reuse memory on realloc" { |
| 480 | var small_fixed_buffer: [10]u8 = undefined; |
| 481 | // check if we re-use the memory |
| 482 | { |
| 483 | var fixed_buffer_allocator = FixedBufferAllocator.init(small_fixed_buffer[0..]); |
| 484 | |
| 485 | var slice0 = try fixed_buffer_allocator.allocator.alloc(u8, 5); |
| 486 | assert(slice0.len == 5); |
| 487 | var slice1 = try fixed_buffer_allocator.allocator.realloc(u8, slice0, 10); |
| 488 | assert(slice1.ptr == slice0.ptr); |
| 489 | assert(slice1.len == 10); |
| 490 | debug.assertError(fixed_buffer_allocator.allocator.realloc(u8, slice1, 11), error.OutOfMemory); |
| 491 | } |
| 492 | // check that we don't re-use the memory if it's not the most recent block |
| 493 | { |
| 494 | var fixed_buffer_allocator = FixedBufferAllocator.init(small_fixed_buffer[0..]); |
| 495 | |
| 496 | var slice0 = try fixed_buffer_allocator.allocator.alloc(u8, 2); |
| 497 | slice0[0] = 1; |
| 498 | slice0[1] = 2; |
| 499 | var slice1 = try fixed_buffer_allocator.allocator.alloc(u8, 2); |
| 500 | var slice2 = try fixed_buffer_allocator.allocator.realloc(u8, slice0, 4); |
| 501 | assert(slice0.ptr != slice2.ptr); |
| 502 | assert(slice1.ptr != slice2.ptr); |
| 503 | assert(slice2[0] == 1); |
| 504 | assert(slice2[1] == 2); |
| 505 | } |
| 506 | } |
| 507 | |
| 470 | 508 | test "ThreadSafeFixedBufferAllocator" { |
| 471 | 509 | var fixed_buffer_allocator = ThreadSafeFixedBufferAllocator.init(test_fixed_buffer_allocator_memory[0..]); |
| 472 | 510 | |
| ... | ... | @@ -482,12 +520,14 @@ fn testAllocator(allocator: *mem.Allocator) !void { |
| 482 | 520 | item.* = try allocator.create(@intCast(i32, i)); |
| 483 | 521 | } |
| 484 | 522 | |
| 485 | | for (slice) |item, i| { |
| 523 | slice = try allocator.realloc(*i32, slice, 20000); |
| 524 | assert(slice.len == 20000); |
| 525 | |
| 526 | for (slice[0..100]) |item, i| { |
| 527 | assert(item.* == @intCast(i32, i)); |
| 486 | 528 | allocator.destroy(item); |
| 487 | 529 | } |
| 488 | 530 | |
| 489 | | slice = try allocator.realloc(*i32, slice, 20000); |
| 490 | | assert(slice.len == 20000); |
| 491 | 531 | slice = try allocator.realloc(*i32, slice, 50); |
| 492 | 532 | assert(slice.len == 50); |
| 493 | 533 | slice = try allocator.realloc(*i32, slice, 25); |