5 #ifndef BITCOIN_SUPPORT_ALLOCATORS_POOL_H
6 #define BITCOIN_SUPPORT_ALLOCATORS_POOL_H
14 #include <type_traits>
69 template <std::
size_t MAX_BLOCK_SIZE_BYTES, std::
size_t ALIGN_BYTES>
71 static_assert(ALIGN_BYTES > 0,
"ALIGN_BYTES must be nonzero");
72 static_assert((ALIGN_BYTES & (ALIGN_BYTES - 1)) == 0,
73 "ALIGN_BYTES must be a power of two");
83 static_assert(std::is_trivially_destructible_v<ListNode>,
84 "Make sure we don't need to manually call a destructor");
91 std::max(
alignof(
ListNode), ALIGN_BYTES);
93 "ELEM_ALIGN_BYTES must be a power of two");
96 "Units of size ELEM_SIZE_ALIGN need to be able to store a ListNode");
99 "MAX_BLOCK_SIZE_BYTES needs to be a multiple of the alignment.");
139 [[nodiscard]]
static constexpr std::size_t
147 [[nodiscard]]
static constexpr
bool
170 size_t remaining_available_bytes =
172 if (0 != remaining_available_bytes) {
221 ::operator
delete ((
void *)chunk,
230 void *
Allocate(std::size_t bytes, std::size_t alignment) {
244 const std::ptrdiff_t round_bytes =
259 return ::operator
new (bytes, std::align_val_t{alignment});
267 std::size_t alignment) noexcept {
277 ::operator
delete (p, std::align_val_t{alignment});
297 template <
class T, std::size_t MAX_BLOCK_SIZE_BYTES,
298 std::size_t ALIGN_BYTES =
alignof(T)>
302 template <
typename U, std::
size_t M, std::
size_t A>
320 : m_resource(other.resource()) {}
335 return static_cast<T *
>(
336 m_resource->
Allocate(n *
sizeof(T),
alignof(T)));
343 m_resource->
Deallocate(p, n *
sizeof(T),
alignof(T));
349 template <
class T1,
class T2, std::size_t MAX_BLOCK_SIZE_BYTES,
350 std::size_t ALIGN_BYTES>
354 return a.resource() == b.resource();
357 template <
class T1,
class T2, std::size_t MAX_BLOCK_SIZE_BYTES,
358 std::size_t ALIGN_BYTES>
Forwards all allocations/deallocations to the PoolResource.
PoolAllocator & operator=(const PoolAllocator &other) noexcept=default
PoolResource< MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES > * m_resource
T * allocate(size_t n)
Forwards each call to the resource.
friend class PoolAllocator
void deallocate(T *p, size_t n) noexcept
Forwards each call to the resource.
PoolAllocator(const PoolAllocator &other) noexcept=default
ResourceType * resource() const noexcept
PoolAllocator(ResourceType *resource) noexcept
Not explicit so we can easily construct it with the correct resource.
PoolAllocator(const PoolAllocator< U, MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES > &other) noexcept
A memory resource similar to std::pmr::unsynchronized_pool_resource, but optimized for node-based con...
std::array< ListNode *, MAX_BLOCK_SIZE_BYTES/ELEM_ALIGN_BYTES+1 > m_free_lists
Single linked lists of all data that came from deallocating.
PoolResource & operator=(PoolResource &&)=delete
void PlacementAddToList(void *p, ListNode *&node)
Replaces node with placement constructed ListNode that points to the previous node.
static constexpr std::size_t NumElemAlignBytes(std::size_t bytes)
How many multiple of ELEM_ALIGN_BYTES are necessary to fit bytes.
PoolResource(const PoolResource &)=delete
Disable copy & move semantics, these are not supported for the resource.
size_t ChunkSizeBytes() const
Size in bytes to allocate per chunk, currently hardcoded to a fixed size.
std::byte * m_available_memory_it
Points to the beginning of available memory for carving out allocations.
std::size_t NumAllocatedChunks() const
Number of allocated chunks.
static constexpr bool IsFreeListUsable(std::size_t bytes, std::size_t alignment)
True when it is possible to make use of the freelist.
friend class PoolResourceTester
Access to internals for testing purpose only.
void Deallocate(void *p, std::size_t bytes, std::size_t alignment) noexcept
Returns a block to the freelists, or deletes the block when it did not come from the chunks.
std::byte * m_available_memory_end
Points to the end of available memory for carving out allocations.
PoolResource(std::size_t chunk_size_bytes)
Construct a new PoolResource object which allocates the first chunk.
~PoolResource()
Deallocates all memory allocated associated with the memory resource.
static constexpr std::size_t ELEM_ALIGN_BYTES
Internal alignment value.
const size_t m_chunk_size_bytes
Size in bytes to allocate per chunk.
PoolResource()
Construct a new Pool Resource object, defaults to 2^18=262144 chunk size.
PoolResource(PoolResource &&)=delete
void * Allocate(std::size_t bytes, std::size_t alignment)
Allocates a block of bytes.
std::list< std::byte * > m_allocated_chunks
Contains all allocated pools of memory, used to free the data in the destructor.
PoolResource & operator=(const PoolResource &)=delete
void AllocateChunk()
Allocate one full memory chunk which will be used to carve out allocations.
bool operator!=(const PoolAllocator< T1, MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES > &a, const PoolAllocator< T2, MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES > &b) noexcept
bool operator==(const PoolAllocator< T1, MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES > &a, const PoolAllocator< T2, MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES > &b) noexcept
The rebind struct here is mandatory because we use non type template arguments for PoolAllocator.
In-place linked list of the allocations, used for the freelist.