#ifndef DPA_MEM_H #define DPA_MEM_H #include #include #include #include #define DPA_MEM_SPACE_SIZE 0x10000000000 // 1tb /* Required allocator functions */ void* dpa_mem_impl_realloc(void*restrict, size_t); // size=0 means free, ptr=0 means allocate void* dpa_mem_impl_find_allocation_start(void*); // Takes a pointer anywhere within an allocation, returns the start of the allocation /* Internals for allocator implementation glue code */ void* dpa_internal_allocate_pages(size_t size); // Allocate some pages void dpa_internal_free_pages(void* page, size_t size); // deallocate some pages /* API */ void* dpa_malloc(size_t size); void* dpa_calloc(size_t size); bool dpa_realloc(void** data, size_t size); // Requires the refcount to be 1. Calling it with a value allocated using malloc instead of dpa_malloc will copy it & free the old pointer. void* dpa_dup(const void* data, size_t size); // Make a copy with our allocator void* dpa_dupref_rw(void* data, size_t size); // If allocated by us, increment refcount. Otherwise, copy it. const void* dpa_dupref_ro(const void* data, size_t size); // If ro, increment refcount, otherwise, copy and make ro void dpa_ref(const void* data); // Note, for memory not allocated with dpa_malloc, this is a no-op. void dpa_put(const void* data); // Note, for memory not allocated with dpa_malloc, this is a no-op. void dpa_destroy(const void* data); // Note, for memory not allocated with dpa_malloc, this is a no-op. static inline bool dpa_mem_is_mine(const void* a){ extern void* dpa_mem_space_start; return (char*)a - (char*)dpa_mem_space_start < DPA_MEM_SPACE_SIZE * 2; } /** * The new pointer will reference the same data, even if it is unwritable from the new one! * Make sure to drop all writable references if you use this function! * Functions who use dpa_dupref_ro may assume that the data is immutable! * And functions like memmove may fail if both pointers are used! */ static inline const void* dpa_readonly(const void* a){ extern void* dpa_mem_space_start; const uintptr_t oa = (char*)a - (char*)dpa_mem_space_start; if(oa < DPA_MEM_SPACE_SIZE) return (char*)a + DPA_MEM_SPACE_SIZE; return a; } static inline bool dpa_is_readonly(const void* a){ /* extern char __executable_start; extern char __etext; if((char*)a >= &__executable_start && (char*)a < &__etext) return true;*/ // TODO: find a way to check for stuff in readonly or .rodata segment // dpa_dupref_ro uses this to detrermine if it needs to copy it extern void* dpa_mem_space_start; const uintptr_t oa = (char*)a - (char*)dpa_mem_space_start - DPA_MEM_SPACE_SIZE; return oa < DPA_MEM_SPACE_SIZE; } static inline bool dpa_mem_is_same(const void* a, const void* b){ extern void* dpa_mem_space_start; if(a == b) return true; uintptr_t oa = (char*)a - (char*)dpa_mem_space_start; uintptr_t ob = (char*)b - (char*)dpa_mem_space_start; if(oa >= DPA_MEM_SPACE_SIZE * 2) return false; if(ob >= DPA_MEM_SPACE_SIZE * 2) return false; if(oa >= DPA_MEM_SPACE_SIZE) oa -= DPA_MEM_SPACE_SIZE; if(ob >= DPA_MEM_SPACE_SIZE) ob -= DPA_MEM_SPACE_SIZE; return oa == ob; } #endif