taisei/src/memory/memory.c
2024-09-10 14:28:36 +02:00

140 lines
3.7 KiB
C

/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2024, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2024, Andrei Alexeyev <akari@taisei-project.org>.
*/
#include "memory.h"
#include "util.h"
#include "../util.h"
#include <stdlib.h>
#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)
);
}