2023-02-10 15:13:26 +08:00

96 lines
4.6 KiB
C++

#pragma once
#include "../../C/Baselib_Memory.h"
#include "../../Cpp/Algorithm.h"
// Internal, to enable override of default C Api implementation for unit-tests
#ifndef detail_BASELIB_PAGE_ALLOCATOR_TEST_IMPL
#define detail_BASELIB_PAGE_ALLOCATOR_TEST_IMPL 0
#endif
namespace baselib
{
BASELIB_CPP_INTERFACE
{
namespace detail
{
// Default memory allocation methods
struct page_allocator_impl
{
static constexpr auto Baselib_Memory_AllocatePages = ::Baselib_Memory_AllocatePages;
static constexpr auto Baselib_Memory_ReleasePages = ::Baselib_Memory_ReleasePages;
static constexpr auto Baselib_Memory_SetPageState = ::Baselib_Memory_SetPageState;
};
// Test memory allocation methods
struct page_allocator_impl_test
{
static Baselib_Memory_PageAllocation Baselib_Memory_AllocatePages(uint64_t pageSize, uint64_t pageCount, uint64_t alignmentInMultipleOfPageSize, Baselib_Memory_PageState pageState, Baselib_ErrorState* errorState);
static void Baselib_Memory_ReleasePages(Baselib_Memory_PageAllocation pageAllocation, Baselib_ErrorState* errorState);
static void Baselib_Memory_SetPageState(void* addressOfFirstPage, uint64_t pageSize, uint64_t pageCount, Baselib_Memory_PageState pageState, Baselib_ErrorState* errorState);
};
typedef enum Memory_PageState : int
{
Memory_PageState_Reserved = Baselib_Memory_PageState_Reserved,
Memory_PageState_NoAccess = Baselib_Memory_PageState_NoAccess,
Memory_PageState_ReadOnly = Baselib_Memory_PageState_ReadOnly,
Memory_PageState_ReadWrite = Baselib_Memory_PageState_ReadWrite,
Memory_PageState_ReadOnly_Executable = Baselib_Memory_PageState_ReadOnly_Executable | Baselib_Memory_PageState_ReadOnly,
Memory_PageState_ReadWrite_Executable = Baselib_Memory_PageState_ReadWrite_Executable | Baselib_Memory_PageState_ReadWrite,
} Memory_PageState;
template<uint32_t alignment>
class page_allocator
{
// Use test memory allocation implementation if detail_BASELIB_HEAP_ALLOCATOR_TEST_IMPL is true
using Impl = typename std::conditional<detail_BASELIB_PAGE_ALLOCATOR_TEST_IMPL, page_allocator_impl_test, page_allocator_impl>::type;
const size_t m_PageSize;
const size_t m_PageSizeAligned;
FORCE_INLINE constexpr size_t PagedCountFromSize(size_t size) const
{
return (size + (m_PageSize - 1)) / m_PageSize;
}
FORCE_INLINE size_t DefaultPageSize() const
{
Baselib_Memory_PageSizeInfo info;
Baselib_Memory_GetPageSizeInfo(&info);
return static_cast<size_t>(info.defaultPageSize);
}
public:
page_allocator() : page_allocator(DefaultPageSize()) {}
page_allocator(size_t page_size) : m_PageSize(page_size), m_PageSizeAligned(page_size > alignment ? page_size : alignment) {}
void* allocate(size_t size, int state, Baselib_ErrorState *error_state_ptr) const
{
Baselib_Memory_PageAllocation pa = Impl::Baselib_Memory_AllocatePages(m_PageSize, PagedCountFromSize(size), m_PageSizeAligned / m_PageSize, (Baselib_Memory_PageState)state, error_state_ptr);
return pa.ptr;
}
bool deallocate(void* ptr, size_t size, Baselib_ErrorState *error_state_ptr) const
{
Impl::Baselib_Memory_ReleasePages({ptr, m_PageSize, PagedCountFromSize(size)}, error_state_ptr);
return (error_state_ptr->code == Baselib_ErrorCode_Success);
}
constexpr size_t optimal_size(size_t size) const
{
return (size + m_PageSizeAligned - 1) & ~(m_PageSizeAligned - 1);
}
bool set_page_state(void* ptr, size_t size, int state, Baselib_ErrorState *error_state_ptr) const
{
Impl::Baselib_Memory_SetPageState(ptr, m_PageSize, PagedCountFromSize(size), (Baselib_Memory_PageState)state, error_state_ptr);
return (error_state_ptr->code == Baselib_ErrorCode_Success);
}
};
}
}
}
#undef detail_BASELIB_PAGE_ALLOCATOR_TEST_IMPL