91 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			91 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
 | |
| #pragma once
 | |
| 
 | |
| #if !defined(MIJIN_MEMORY_DATA_POOL_HPP_INCLUDED)
 | |
| #define MIJIN_MEMORY_DATA_POOL_HPP_INCLUDED 1
 | |
| 
 | |
| #include <array>
 | |
| #include <cassert>
 | |
| #include <cstddef>
 | |
| #include <cstdint>
 | |
| #include <memory>
 | |
| #include <vector>
 | |
| 
 | |
| namespace mijin
 | |
| {
 | |
| 
 | |
| //
 | |
| // public defines
 | |
| //
 | |
| 
 | |
| //
 | |
| // public constants
 | |
| //
 | |
| 
 | |
| //
 | |
| // public types
 | |
| //
 | |
| 
 | |
| template<std::size_t PAGE_SIZE = 4096ul * 1024ul>
 | |
| struct DataPool
 | |
| {
 | |
|     static_assert(PAGE_SIZE % alignof(std::max_align_t) == 0);
 | |
|     
 | |
|     struct alignas(std::max_align_t) Page : std::array<std::uint8_t, PAGE_SIZE> {};
 | |
| 
 | |
|     using page_ptr_t = std::unique_ptr<Page>;
 | |
| 
 | |
|     std::vector<page_ptr_t> pages;
 | |
|     std::size_t offset = 0;
 | |
| 
 | |
|     DataPool() = default;
 | |
|     DataPool(const DataPool&) = delete;
 | |
|     DataPool(DataPool&&) noexcept = default;
 | |
| 
 | |
|     DataPool& operator=(const DataPool&) = delete;
 | |
|     DataPool& operator=(DataPool&&) noexcept = default;
 | |
| 
 | |
|     void* allocate(std::size_t bytes, std::size_t alignment = 1);
 | |
|     inline void reset() { offset = 0; }
 | |
| 
 | |
|     template<typename T>
 | |
|     T* allocateAs(std::size_t elements = 1) {
 | |
|         return static_cast<T*>(allocate(sizeof(T) * elements, alignof(T)));
 | |
|     }
 | |
| };
 | |
| 
 | |
| //
 | |
| // public functions
 | |
| //
 | |
| 
 | |
| template<std::size_t PAGE_SIZE>
 | |
| void* DataPool<PAGE_SIZE>::allocate(std::size_t bytes, std::size_t alignment)
 | |
| {
 | |
|     assert(bytes > 0 && bytes <= PAGE_SIZE);
 | |
|     assert(alignment > 0 && alignment <= alignof(std::max_align_t));
 | |
| 
 | |
|     if (offset % alignment != 0) {
 | |
|         offset += alignment - (offset % alignment);
 | |
|     }
 | |
| 
 | |
|     const std::size_t remainingOnPage = PAGE_SIZE - (offset % PAGE_SIZE);
 | |
|     const std::size_t page = offset / PAGE_SIZE;
 | |
|     const std::size_t localOffset = offset % PAGE_SIZE;
 | |
|     if (remainingOnPage == PAGE_SIZE || remainingOnPage < bytes)
 | |
|     {
 | |
|         // next page
 | |
|         if (page + 1 >= pages.size()) {
 | |
|             pages.push_back(std::make_unique<Page>());
 | |
|         }
 | |
|         offset = PAGE_SIZE * (pages.size() - 1);
 | |
|     }
 | |
|     std::uint8_t* result = &(*pages[page])[localOffset];
 | |
|     offset += bytes;
 | |
|     assert(reinterpret_cast<std::uintptr_t>(result) % alignment == 0);
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| } // namespace mijin
 | |
| 
 | |
| #endif // !defined(MIJIN_MEMORY_DATA_POOL_HPP_INCLUDED)
 |