/* * This software is licensed under the terms of the MIT License. * See COPYING for further information. * --- * Copyright (c) 2011-2024, Lukas Weber . * Copyright (c) 2012-2024, Andrei Alexeyev . */ #include "memory.h" #include "util.h" #include "../util.h" #include #define MEMALIGN_METHOD_C11 0 #define MEMALIGN_METHOD_POSIX 1 #define MEMALIGN_METHOD_WIN32 2 #if defined(TAISEI_BUILDCONF_HAVE_POSIX_MEMALIGN) #define MEMALIGN_METHOD MEMALIGN_METHOD_POSIX #elif defined(TAISEI_BUILDCONF_HAVE_ALIGNED_ALLOC) #define MEMALIGN_METHOD MEMALIGN_METHOD_C11 #elif defined(TAISEI_BUILDCONF_HAVE_ALIGNED_MALLOC_FREE) #define MEMALIGN_METHOD MEMALIGN_METHOD_WIN32 #else #error No usable aligned malloc implementation #endif void mem_free(void *ptr) { #if MEMALIGN_METHOD == MEMALIGN_METHOD_WIN32 _aligned_free(ptr); #else libc_free(ptr); #endif } void *mem_alloc(size_t size) { #if MEMALIGN_METHOD == MEMALIGN_METHOD_WIN32 void *p = NOT_NULL(_aligned_malloc(size, alignof(max_align_t))); memset(p, 0, size); return p; #else return NOT_NULL(libc_calloc(1, size)); #endif } void *mem_alloc_array(size_t num_members, size_t size) { #if MEMALIGN_METHOD == MEMALIGN_METHOD_WIN32 size_t array_size = mem_util_calc_array_size(num_members, size); void *p = NOT_NULL(_aligned_malloc(array_size, alignof(max_align_t))); memset(p, 0, array_size); return p; #else return NOT_NULL(libc_calloc(num_members, size)); #endif } void *mem_realloc(void *ptr, size_t size) { if(ptr == NULL) { return mem_alloc(size); } if(size == 0) { mem_free(ptr); return ptr; } #if MEMALIGN_METHOD == MEMALIGN_METHOD_WIN32 return NOT_NULL(_aligned_realloc(ptr, size, alignof(max_align_t))); #else return NOT_NULL(libc_realloc(ptr, size)); #endif } void *mem_alloc_aligned(size_t size, size_t alignment) { assert((alignment & (alignment - 1)) == 0); assert((alignment / sizeof(void*)) * sizeof(void*) == alignment); #if MEMALIGN_METHOD == MEMALIGN_METHOD_C11 size_t nsize = ((size - 1) / alignment + 1) * alignment; assert(nsize >= size); void *p = NOT_NULL(aligned_alloc(alignment, nsize)); memset(p, 0, size); return p; #elif MEMALIGN_METHOD == MEMALIGN_METHOD_POSIX void *p; attr_unused int r = posix_memalign(&p, alignment, size); assert(r == 0); assume(p != NULL); memset(p, 0, size); return p; #elif MEMALIGN_METHOD == MEMALIGN_METHOD_WIN32 void *p = NOT_NULL(_aligned_malloc(size, alignment)); memset(p, 0, size); return p; #else #error No usable aligned malloc implementation #endif } void *mem_alloc_array_aligned(size_t num_members, size_t size, size_t alignment) { return mem_alloc_aligned(mem_util_calc_array_size(num_members, size), alignment); } void *mem_dup(const void *src, size_t size) { return memcpy(mem_alloc(size), src, size); } // SDL's calling convention may differ from the default, so wrap when necessary. static void SDLCALL mem_sdlcall_free(void *ptr) { mem_free(ptr); } static void *SDLCALL mem_sdlcall_malloc(size_t size) { return mem_alloc(size); } static void *SDLCALL mem_sdlcall_calloc(size_t num_members, size_t size) { return mem_alloc_array(num_members, size); } static void *SDLCALL mem_sdlcall_realloc(void *ptr, size_t size) { return mem_realloc(ptr, size); } #define _mem_choose_compatible_func(orig, wrapper) \ __builtin_choose_expr( \ __builtin_types_compatible_p(typeof(orig), typeof(wrapper)), \ orig, wrapper) void mem_install_sdl_callbacks(void) { SDL_SetMemoryFunctions( _mem_choose_compatible_func(mem_alloc, mem_sdlcall_malloc), _mem_choose_compatible_func(mem_alloc_array, mem_sdlcall_calloc), _mem_choose_compatible_func(mem_realloc, mem_sdlcall_realloc), _mem_choose_compatible_func(mem_free, mem_sdlcall_free) ); }