Flow
Documentation for the Flow C++ Library
Loading...
Searching...
No Matches
flow::BuddyMemoryResource Class Reference

Fixed-size buddy allocator implementing the MemoryResource interface. The min block size is 1 byte, the maximum is 1<<64 bytes. More...

#include <flow_buddy_memory_resource.h>

Inheritance diagram for flow::BuddyMemoryResource:

Classes

struct  BuddyBlock

Public Member Functions

 BuddyMemoryResource (void *buffer, std::size_t capacity, std::size_t alignment=alignof(std::max_align_t))
 Constructs a buddy allocator over a user-provided buffer.
virtual void * allocateImp (std::size_t bytes, std::size_t alignment) override
virtual void deallocateImp (void *address, std::size_t bytes, std::size_t alignment) override
Public Member Functions inherited from flow::MemoryResource
virtual ~MemoryResource ()=default
void * allocate (std::size_t bytes, std::size_t alignment=alignof(std::max_align_t))
void deallocate (void *address, std::size_t bytes, std::size_t alignment=alignof(std::max_align_t))

Private Member Functions

std::size_t getLevelSize (std::size_t level) const noexcept
BuddyBlockpopFront (std::size_t level) noexcept
void pushFront (BuddyBlock *block, std::size_t level) noexcept
bool isEmpty (std::size_t level) const noexcept
BuddyBlockgetBuddy (BuddyBlock *block, std::size_t blockSize) const noexcept
bool eraseBlock (BuddyBlock *block, std::size_t level) noexcept

Private Attributes

std::byte * beginBuffer_
std::size_t capacity_
BuddyBlock freeList_ [kMaxLevel]

Static Private Attributes

static constexpr std::size_t kMaxLevel = 64

Detailed Description

Fixed-size buddy allocator implementing the MemoryResource interface. The min block size is 1 byte, the maximum is 1<<64 bytes.

Definition at line 13 of file flow_buddy_memory_resource.h.

Constructor & Destructor Documentation

◆ BuddyMemoryResource()

flow::BuddyMemoryResource::BuddyMemoryResource ( void * buffer,
std::size_t capacity,
std::size_t alignment = alignof(std::max_align_t) )
inlineexplicit

Constructs a buddy allocator over a user-provided buffer.

Parameters
bufferPointer to buffer.
capacityBuffer size in bytes.
alignmentRequired alignment.
Exceptions
std::bad_allocIf buffer cannot satisfy alignment.

Definition at line 76 of file flow_buddy_memory_resource.h.

77 : freeList_() {
78
79 // Not enough capacity after alignment.
80 if (!std::align(alignment, alignment, buffer, capacity)) {
81 throw std::bad_alloc();
82 }
83 beginBuffer_ = static_cast<std::byte*>(buffer);
84 capacity_ = std::bit_floor(capacity);
85
86 assert(capacity_ > 0 && "buffer capacity must be non-zero after alignment");
87 std::size_t level = std::countr_zero(capacity_);
88 pushFront(reinterpret_cast<BuddyBlock*>(beginBuffer_), level);
89 }
void pushFront(BuddyBlock *block, std::size_t level) noexcept

References beginBuffer_, capacity_, freeList_, and pushFront().

Member Function Documentation

◆ allocateImp()

virtual void * flow::BuddyMemoryResource::allocateImp ( std::size_t bytes,
std::size_t alignment )
inlineoverridevirtual

Implements flow::MemoryResource.

Definition at line 91 of file flow_buddy_memory_resource.h.

91 {
92 std::size_t requiredLevel = std::countr_zero(std::bit_ceil(std::max(bytes, alignment)));
93
94 // Find the smallest available block.
95 std::size_t level = requiredLevel;
96 while (level < kMaxLevel && isEmpty(level)) {
97 ++level;
98 }
99
100 // All blocks are not big enough.
101 if (level >= kMaxLevel) {
102 throw std::bad_alloc();
103 }
104
105 BuddyBlock* block = popFront(level);
106 while (level > requiredLevel) {
107 --level;
108 const std::size_t levelSize = getLevelSize(level);
109
110 BuddyBlock* secondHalf = reinterpret_cast<BuddyBlock*>(reinterpret_cast<std::byte*>(block) + levelSize);
111 pushFront(secondHalf, level);
112 }
113
114 return block;
115 }
bool isEmpty(std::size_t level) const noexcept
BuddyBlock * popFront(std::size_t level) noexcept
static constexpr std::size_t kMaxLevel
std::size_t getLevelSize(std::size_t level) const noexcept

References getLevelSize(), isEmpty(), kMaxLevel, popFront(), and pushFront().

◆ deallocateImp()

virtual void flow::BuddyMemoryResource::deallocateImp ( void * address,
std::size_t bytes,
std::size_t alignment )
inlineoverridevirtual

Implements flow::MemoryResource.

Definition at line 117 of file flow_buddy_memory_resource.h.

117 {
118 if (!address) {
119 return;
120 }
121
122 std::size_t level = std::countr_zero(std::bit_ceil(std::max(bytes, alignment)));
123 for (; level < kMaxLevel; ++level) {
124 BuddyBlock* buddy = getBuddy(static_cast<BuddyBlock*>(address), getLevelSize(level));
125 if (buddy && eraseBlock(buddy, level)) {
126 // Coalesce two blocks.
127 address = std::min(address, static_cast<void*>(buddy));
128 } else {
129 // Push it to the free list.
130 pushFront(static_cast<BuddyBlock*>(address), level);
131 break;
132 }
133 }
134 }
bool eraseBlock(BuddyBlock *block, std::size_t level) noexcept
BuddyBlock * getBuddy(BuddyBlock *block, std::size_t blockSize) const noexcept

References eraseBlock(), getBuddy(), getLevelSize(), kMaxLevel, and pushFront().

◆ eraseBlock()

bool flow::BuddyMemoryResource::eraseBlock ( BuddyBlock * block,
std::size_t level )
inlineprivatenoexcept

Definition at line 56 of file flow_buddy_memory_resource.h.

56 {
57 BuddyBlock* curr = &freeList_[level];
58 while (curr->next) {
59 BuddyBlock* child = curr->next;
60 if (child == block) {
61 curr->next = child->next;
62 return true;
63 }
64 curr = child;
65 }
66 return false;
67 }

References freeList_, and flow::BuddyMemoryResource::BuddyBlock::next.

Referenced by deallocateImp().

◆ getBuddy()

BuddyBlock * flow::BuddyMemoryResource::getBuddy ( BuddyBlock * block,
std::size_t blockSize ) const
inlineprivatenoexcept

Definition at line 45 of file flow_buddy_memory_resource.h.

45 {
46 std::size_t index = reinterpret_cast<std::byte*>(block) - beginBuffer_;
47 std::size_t buddyIndex = index ^ blockSize;
48 if (buddyIndex >= capacity_) {
49 return nullptr;
50 }
51
52 BuddyBlock* buddyBlock = reinterpret_cast<BuddyBlock*>(beginBuffer_ + buddyIndex);
53 return buddyBlock;
54 }

References beginBuffer_, and capacity_.

Referenced by deallocateImp().

◆ getLevelSize()

std::size_t flow::BuddyMemoryResource::getLevelSize ( std::size_t level) const
inlineprivatenoexcept

Definition at line 24 of file flow_buddy_memory_resource.h.

24 {
25 return 1ull << level;
26 }

Referenced by allocateImp(), and deallocateImp().

◆ isEmpty()

bool flow::BuddyMemoryResource::isEmpty ( std::size_t level) const
inlineprivatenoexcept

Definition at line 41 of file flow_buddy_memory_resource.h.

41 {
42 return !freeList_[level].next;
43 }

References freeList_.

Referenced by allocateImp().

◆ popFront()

BuddyBlock * flow::BuddyMemoryResource::popFront ( std::size_t level)
inlineprivatenoexcept

Definition at line 28 of file flow_buddy_memory_resource.h.

28 {
29 assert(freeList_[level].next != nullptr && "pop front from an empty list");
30 BuddyBlock* block = freeList_[level].next;
31 freeList_[level].next = block->next;
32 return block;
33 }

References freeList_, and flow::BuddyMemoryResource::BuddyBlock::next.

Referenced by allocateImp().

◆ pushFront()

void flow::BuddyMemoryResource::pushFront ( BuddyBlock * block,
std::size_t level )
inlineprivatenoexcept

Definition at line 35 of file flow_buddy_memory_resource.h.

35 {
36 assert(level < kMaxLevel && "level is larger than the maximum possible level");
37 block->next = freeList_[level].next;
38 freeList_[level].next = block;
39 }

References freeList_, and kMaxLevel.

Referenced by allocateImp(), BuddyMemoryResource(), and deallocateImp().

Member Data Documentation

◆ beginBuffer_

std::byte* flow::BuddyMemoryResource::beginBuffer_
private

Definition at line 20 of file flow_buddy_memory_resource.h.

Referenced by BuddyMemoryResource(), and getBuddy().

◆ capacity_

std::size_t flow::BuddyMemoryResource::capacity_
private

Definition at line 21 of file flow_buddy_memory_resource.h.

Referenced by BuddyMemoryResource(), and getBuddy().

◆ freeList_

BuddyBlock flow::BuddyMemoryResource::freeList_[kMaxLevel]
private

◆ kMaxLevel

std::size_t flow::BuddyMemoryResource::kMaxLevel = 64
staticconstexprprivate

Definition at line 18 of file flow_buddy_memory_resource.h.

Referenced by allocateImp(), deallocateImp(), and pushFront().


The documentation for this class was generated from the following file: