| 284 | } |
| 285 | |
| 286 | void* region_realloc(MemoryRegion* region, void* ptr, u64 size) |
| 287 | { |
| 288 | assert(region); |
| 289 | if (!ptr) { return region_alloc(region, size); } |
| 290 | if (size == 0) { return nullptr; } |
| 291 | |
| 292 | size = alloc_align(size + sizeof(RegionAllocHeader)); |
| 293 | if (size > region->blockSize) { return nullptr; } |
| 294 | |
| 295 | // If the current block is already large enough, skip looping over the memory blocks. |
| 296 | RegionAllocHeader* header = (RegionAllocHeader*)((u8*)ptr - sizeof(RegionAllocHeader)); |
| 297 | if (header->size >= size) |
| 298 | { |
| 299 | return ptr; |
| 300 | } |
| 301 | |
| 302 | // First try to reallocate in the same region. |
| 303 | u32 prevSize = 0; |
| 304 | for (s32 i = (s32)region->blockCount - 1; i >= 0; i--) |
| 305 | { |
| 306 | MemoryBlock* block = region->memBlocks[i]; |
| 307 | if (ptr >= block) |
| 308 | { |
| 309 | RegionAllocHeader* header = (RegionAllocHeader*)((u8*)ptr - sizeof(RegionAllocHeader)); |
| 310 | RegionAllocHeader* nextHeader = (RegionAllocHeader*)((u8*)header + header->size); |
| 311 | assert(header->free == 0); |
| 312 | |
| 313 | if ((u8*)nextHeader >= (u8*)block + region->blockSize) |
| 314 | { |
| 315 | nextHeader = nullptr; |
| 316 | } |
| 317 | // If it is big enough, just stick to the same memory. |
| 318 | if (header->size >= size) |
| 319 | { |
| 320 | return ptr; |
| 321 | } |
| 322 | // If the next block is free, merge the two blocks and then allocate from that. |
| 323 | if (nextHeader && nextHeader->free && header->size + nextHeader->size >= size) |
| 324 | { |
| 325 | VERIFY_MEMORY(); |
| 326 | // Remove the nextHeader from the freelist. |
| 327 | assert(nextHeader->free == 1); |
| 328 | removeHeaderFromFreelist(block, nextHeader); |
| 329 | |
| 330 | // Merge blocks. |
| 331 | block->sizeFree += header->size; |
| 332 | header->size += nextHeader->size; |
| 333 | block->count--; |
| 334 | |
| 335 | // Allocate from the new header. |
| 336 | if (header->size - size >= MIN_SPLIT_SIZE) |
| 337 | { |
| 338 | // Split. |
| 339 | u64 split0 = size; |
| 340 | u64 split1 = header->size - split0; |
| 341 | RegionAllocHeader* next = (RegionAllocHeader*)((u8*)header + split0); |
| 342 | |
| 343 | // Reset the header. |
no test coverage detected