#pragma once #include "Internal/heap_allocator.inl.h" #include "Algorithm.h" namespace baselib { BASELIB_CPP_INTERFACE { // Heap allocator implementation providing platform dependent system heap allocation. // // Allocations are guaranteed to be aligned to at least the value of `default_alignment`. // For optimal performance, platform aligned allocation calls are only used when `default_alignment` exceeds platform minimum alignment guarantee. // This allocator is a stateless allocator (empty class). // // Notes on operation failure of allocator methods: // Operation failures will currently trigger process abort by the underlying system. // As a result the heap allocator currently will never return `nullptr`/`false` to signal failure, as is standard behaviour (nor any error state information). // template class heap_allocator { using impl = detail::heap_allocator; static_assert((default_alignment <= impl::max_alignment), "'default_alignment' exceeded max value"); static_assert((default_alignment != 0), "'default_alignment' must not be a zero value"); static_assert(::baselib::Algorithm::IsPowerOfTwo(default_alignment), "'default_alignment' must be a power of two value"); public: // Allocated memory is guaranteed to always be aligned to at least the value of `alignment`. static constexpr uint32_t alignment = default_alignment; // Typedefs typedef Baselib_ErrorState error_state; // Allocates a memory block large enough to hold `size` number of bytes. Zero size is valid. // // \returns Address to memory block of allocated memory. void* allocate(size_t size) const { error_state result = Baselib_ErrorState_Create(); return impl::allocate(size, &result); } // Allocates a memory block large enough to hold `size` number of bytes. Zero size is valid. // // \returns Address to memory block of allocated memory. void* allocate(size_t size, error_state *error_state_ptr) const { return impl::allocate(size, error_state_ptr); } // Reallocates previously allocated or reallocated memory block pointer reference `ptr` from `old_size` to `new_size` number of bytes. // Passing `nullptr` in `ptr` yield the same result as calling `allocate`. // // \returns Address to memory block of reallocated memory. void* reallocate(void* ptr, size_t old_size, size_t new_size) const { error_state result = Baselib_ErrorState_Create(); return impl::reallocate(ptr, old_size, new_size, &result); } // Reallocates previously allocated or reallocated memory block pointer reference `ptr` from `old_size` to `new_size` number of bytes. // Passing `nullptr` in `ptr` yield the same result as calling `allocate`. // // \returns Address to memory block of reallocated memory. void* reallocate(void* ptr, size_t old_size, size_t new_size, error_state *error_state_ptr) const { return impl::reallocate(ptr, old_size, new_size, error_state_ptr); } // Deallocates memory block previously allocated or reallocated with `size` pointed to by `ptr`. // Passing `nullptr` in `ptr` result in a no-op. // // \returns Always returns `true` (see notes on operation failure). bool deallocate(void* ptr, size_t size) const { error_state result = Baselib_ErrorState_Create(); return impl::deallocate(ptr, size, &result); } // Deallocates memory block previously allocated or reallocated with `size` pointed to by `ptr`. // Passing `nullptr` in `ptr` result in a no-op. // // \returns Always returns `true` (see notes on operation failure). bool deallocate(void* ptr, size_t size, error_state *error_state_ptr) const { return impl::deallocate(ptr, size, error_state_ptr); } // Calculate optimal allocation size given `size`. // // \returns Optimal size when allocating memory given `size`. constexpr size_t optimal_size(size_t size) const { return impl::optimal_size(size); } }; } }