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>
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});
297template <
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));
349template <
class T1,
class T2, std::size_t MAX_BLOCK_SIZE_BYTES,
350 std::size_t ALIGN_BYTES>
354 return a.resource() == b.resource();
357template <
class T1,
class T2, std::size_t MAX_BLOCK_SIZE_BYTES,
358 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
friend class PoolAllocator
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...
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=(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::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.
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.
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.