| ... | ... | @@ -68,7 +68,7 @@ fn alloc(ctx: *anyopaque, len: usize, alignment: u29, len_align: u29, ra: usize) |
| 68 | 68 | _ = len_align; |
| 69 | 69 | _ = ra; |
| 70 | 70 | const aligned_len = @max(len, alignment); |
| 71 | | const slot_size = math.ceilPowerOfTwoAssert(usize, aligned_len); |
| 71 | const slot_size = math.ceilPowerOfTwo(usize, aligned_len) catch return error.OutOfMemory; |
| 72 | 72 | const class = math.log2(slot_size); |
| 73 | 73 | if (class < size_class_count) { |
| 74 | 74 | const addr = a: { |
| ... | ... | @@ -113,12 +113,28 @@ fn resize( |
| 113 | 113 | return_address: usize, |
| 114 | 114 | ) ?usize { |
| 115 | 115 | _ = ctx; |
| 116 | | _ = buf_align; |
| 117 | 116 | _ = return_address; |
| 118 | 117 | _ = len_align; |
| 119 | | _ = new_len; |
| 120 | | _ = buf; |
| 121 | | @panic("handle resize"); |
| 118 | // We don't want to move anything from one size class to another. But we can recover bytes |
| 119 | // in between powers of two. |
| 120 | const old_aligned_len = @max(buf.len, buf_align); |
| 121 | const new_aligned_len = @max(new_len, buf_align); |
| 122 | const old_small_slot_size = math.ceilPowerOfTwoAssert(usize, old_aligned_len); |
| 123 | const old_small_class = math.log2(old_small_slot_size); |
| 124 | if (old_small_class < size_class_count) { |
| 125 | const new_small_slot_size = math.ceilPowerOfTwo(usize, new_aligned_len) catch return null; |
| 126 | //std.debug.print("resize: old_small_slot_size={d} new_small_slot_size={d}\n", .{ |
| 127 | // old_small_slot_size, new_small_slot_size, |
| 128 | //}); |
| 129 | if (old_small_slot_size != new_small_slot_size) return null; |
| 130 | } else { |
| 131 | const old_bigpages_needed = (old_aligned_len + (bigpage_size - 1)) / bigpage_size; |
| 132 | const old_big_slot_size = math.ceilPowerOfTwoAssert(usize, old_bigpages_needed); |
| 133 | const new_bigpages_needed = (new_aligned_len + (bigpage_size - 1)) / bigpage_size; |
| 134 | const new_big_slot_size = math.ceilPowerOfTwo(usize, new_bigpages_needed) catch return null; |
| 135 | if (old_big_slot_size != new_big_slot_size) return null; |
| 136 | } |
| 137 | return new_len; |
| 122 | 138 | } |
| 123 | 139 | |
| 124 | 140 | fn free( |
| ... | ... | @@ -234,3 +250,44 @@ test "large allocations" { |
| 234 | 250 | test_ally.free(ptr3); |
| 235 | 251 | test_ally.free(ptr2); |
| 236 | 252 | } |
| 253 | |
| 254 | test "very large allocation" { |
| 255 | try std.testing.expectError(error.OutOfMemory, test_ally.alloc(u8, math.maxInt(usize))); |
| 256 | } |
| 257 | |
| 258 | test "realloc" { |
| 259 | var slice = try test_ally.alignedAlloc(u8, @alignOf(u32), 1); |
| 260 | defer test_ally.free(slice); |
| 261 | slice[0] = 0x12; |
| 262 | |
| 263 | // This reallocation should keep its pointer address. |
| 264 | const old_slice = slice; |
| 265 | slice = try test_ally.realloc(slice, 2); |
| 266 | try std.testing.expect(old_slice.ptr == slice.ptr); |
| 267 | try std.testing.expect(slice[0] == 0x12); |
| 268 | slice[1] = 0x34; |
| 269 | |
| 270 | // This requires upgrading to a larger size class |
| 271 | slice = try test_ally.realloc(slice, 17); |
| 272 | try std.testing.expect(slice[0] == 0x12); |
| 273 | try std.testing.expect(slice[1] == 0x34); |
| 274 | } |
| 275 | |
| 276 | test "shrink" { |
| 277 | var slice = try test_ally.alloc(u8, 20); |
| 278 | defer test_ally.free(slice); |
| 279 | |
| 280 | mem.set(u8, slice, 0x11); |
| 281 | |
| 282 | slice = test_ally.shrink(slice, 17); |
| 283 | |
| 284 | for (slice) |b| { |
| 285 | try std.testing.expect(b == 0x11); |
| 286 | } |
| 287 | |
| 288 | slice = test_ally.shrink(slice, 16); |
| 289 | |
| 290 | for (slice) |b| { |
| 291 | try std.testing.expect(b == 0x11); |
| 292 | } |
| 293 | } |