/* * Copyright (c) Jon Santmyer. * This source file is released under the LGPL Version 3 as detailed in * the LICENSE file provided in the following repository: * https://git.jonsantmyer.com/heap/ * */ #include "malloc.h" #include "assert.h" #include "string.h" void* __realloc_impl(heap_cache_t *cache, void *ptr, size_t w) { if(w == 0) { DBGPRINT("realloc: called with w == 0, freeing %p\n", ptr); __free_impl(cache, ptr); return NULL; } if(ptr == NULL) { DBGPRINT("realloc: called with NULL ptr, alloc %i\n", w); return __malloc_impl(cache, w); } w = REALW(w); bucket_obj_t *obj = OBJ_FROM_PTR(ptr); assert(OBJ_VALID(obj)); size_t objw = OBJ_WIDTH(obj); if(objw > w) return ptr; size_t wdiff = w - objw; DBGPRINT("realloc: ptr %p needs %i new bytes\n", ptr, wdiff); bucket_obj_t *after = OBJ_AFTER(obj); size_t afterw = 0; bucket_t *bucket = __bucket_from_obj(cache, obj); void *newptr = NULL; if(bucket == NULL) goto resize_fail; if((uintptr_t)after > bucket->limit) goto resize_fail; assert(OBJ_VALID(after)); afterw = OBJ_WIDTH(after); if(OBJ_TAKEN(after)) goto resize_fail; DBGPRINT("realloc: obj %p after obj %p is free (w %i)\n", after, obj, afterw); if(objw + sizeof(bucket_obj_t) + afterw < w) goto resize_fail; obj->size_taken = w | 1; if(bucket->firstfree == after) bucket->firstfree = OBJ_AFTER(obj); after = OBJ_AFTER(obj); *after = (bucket_obj_t){ .checksum = OBJ_CHECKSUM, .size_taken = afterw - wdiff }; DBGPRINT("realloc: moved obj %p (%i) to resize obj %p (%i)\n", after, after->size_taken, obj, obj->size_taken); return ptr; resize_fail: DBGPRINT("realloc: could not resize existing object, calling malloc\n"); newptr = __malloc_impl(cache, w); memcpy(newptr, ptr, obj->size_taken & ~1); __free_impl(cache, ptr); return newptr; }