5#ifndef BITCOIN_SUPPORT_ALLOCATORS_POOL_H
6#define BITCOIN_SUPPORT_ALLOCATORS_POOL_H
69template <std::
size_t MAX_BLOCK_SIZE_BYTES, std::
size_t ALIGN_BYTES>
72 static_assert(ALIGN_BYTES > 0,
"ALIGN_BYTES must be nonzero");
73 static_assert((ALIGN_BYTES & (ALIGN_BYTES - 1)) == 0,
"ALIGN_BYTES must be a power of two");
83 static_assert(std::is_trivially_destructible_v<ListNode>,
"Make sure we don't need to manually call a destructor");
90 static_assert(
sizeof(
ListNode) <=
ELEM_ALIGN_BYTES,
"Units of size ELEM_SIZE_ALIGN need to be able to store a ListNode");
91 static_assert((MAX_BLOCK_SIZE_BYTES & (
ELEM_ALIGN_BYTES - 1)) == 0,
"MAX_BLOCK_SIZE_BYTES needs to be a multiple of the alignment.");
134 [[nodiscard]]
static constexpr bool IsFreeListUsable(std::size_t bytes, std::size_t alignment)
157 if (0 != remaining_available_bytes) {
212 void*
Allocate(std::size_t bytes, std::size_t alignment)
224 const std::ptrdiff_t round_bytes =
static_cast<std::ptrdiff_t
>(num_alignments *
ELEM_ALIGN_BYTES);
235 return ::operator
new (bytes, std::align_val_t{alignment});
241 void Deallocate(
void* p, std::size_t bytes, std::size_t alignment)
noexcept
250 ::operator
delete (p, std::align_val_t{alignment});
275template <
class T, std::
size_t MAX_BLOCK_SIZE_BYTES, std::
size_t ALIGN_BYTES = alignof(T)>
280 template <
typename U, std::
size_t M, std::
size_t A>
308 template <
typename U>
318 return static_cast<T*
>(
m_resource->Allocate(n *
sizeof(
T),
alignof(
T)));
335template <
class T1,
class T2, std::
size_t MAX_BLOCK_SIZE_BYTES, std::
size_t ALIGN_BYTES>
339 return a.resource() == b.resource();
342template <
class T1,
class T2, std::
size_t MAX_BLOCK_SIZE_BYTES, std::
size_t ALIGN_BYTES>
Forwards all allocations/deallocations to the PoolResource.
PoolResource< MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES > * m_resource
ResourceType * resource() const noexcept
PoolAllocator & operator=(const PoolAllocator &other) noexcept=default
void deallocate(T *p, size_t n) noexcept
Forwards each call to the resource.
PoolAllocator(const PoolAllocator &other) noexcept=default
PoolAllocator(ResourceType *resource) noexcept
Not explicit so we can easily construct it with the correct resource.
T * allocate(size_t n)
Forwards each call to the 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...
PoolResource & operator=(const 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::array< ListNode *, MAX_BLOCK_SIZE_BYTES/ELEM_ALIGN_BYTES+1 > m_free_lists
Single linked lists of all data that came from deallocating.
std::byte * m_available_memory_it
Points to the beginning of available memory for carving out allocations.
PoolResource & operator=(PoolResource &&)=delete
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.
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.
std::list< std::byte * > m_allocated_chunks
Contains all allocated pools of memory, used to free the data in the destructor.
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.
void AllocateChunk()
Allocate one full memory chunk which will be used to carve out allocations.
Helper to get access to private parts of PoolResource.
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.