[kutil] Rename 'size' to 'order' when meaning 2^N
Heap allocator is a buddy allocator that deals with power-of-two block sizes. Previously it referred to both a number of bytes and an order of magnitude as a 'size'. Rename functions and variables referring to orders of magnitude to 'order'. Tags: pedantry
This commit is contained in:
@@ -7,15 +7,15 @@ namespace kutil {
|
|||||||
|
|
||||||
struct heap_allocator::mem_header
|
struct heap_allocator::mem_header
|
||||||
{
|
{
|
||||||
mem_header(mem_header *prev, mem_header *next, uint8_t size) :
|
mem_header(mem_header *prev, mem_header *next, uint8_t order) :
|
||||||
m_prev(prev), m_next(next)
|
m_prev(prev), m_next(next)
|
||||||
{
|
{
|
||||||
set_size(size);
|
set_order(order);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void set_size(uint8_t size) {
|
inline void set_order(uint8_t order) {
|
||||||
m_prev = reinterpret_cast<mem_header *>(
|
m_prev = reinterpret_cast<mem_header *>(
|
||||||
reinterpret_cast<uintptr_t>(prev()) | (size & 0x3f));
|
reinterpret_cast<uintptr_t>(prev()) | (order & 0x3f));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void set_used(bool used) {
|
inline void set_used(bool used) {
|
||||||
@@ -30,9 +30,9 @@ struct heap_allocator::mem_header
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline void set_prev(mem_header *prev) {
|
inline void set_prev(mem_header *prev) {
|
||||||
uint8_t s = size();
|
uint8_t s = order();
|
||||||
m_prev = prev;
|
m_prev = prev;
|
||||||
set_size(s);
|
set_order(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove() {
|
void remove() {
|
||||||
@@ -47,12 +47,12 @@ struct heap_allocator::mem_header
|
|||||||
|
|
||||||
inline mem_header * buddy() const {
|
inline mem_header * buddy() const {
|
||||||
return reinterpret_cast<mem_header *>(
|
return reinterpret_cast<mem_header *>(
|
||||||
reinterpret_cast<uintptr_t>(this) ^ (1 << size()));
|
reinterpret_cast<uintptr_t>(this) ^ (1 << order()));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool eldest() const { return this < buddy(); }
|
inline bool eldest() const { return this < buddy(); }
|
||||||
|
|
||||||
inline uint8_t size() const { return reinterpret_cast<uintptr_t>(m_prev) & 0x3f; }
|
inline uint8_t order() const { return reinterpret_cast<uintptr_t>(m_prev) & 0x3f; }
|
||||||
inline bool used() const { return reinterpret_cast<uintptr_t>(m_next) & 0x1; }
|
inline bool used() const { return reinterpret_cast<uintptr_t>(m_next) & 0x1; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -73,16 +73,17 @@ void *
|
|||||||
heap_allocator::allocate(size_t length)
|
heap_allocator::allocate(size_t length)
|
||||||
{
|
{
|
||||||
size_t total = length + sizeof(mem_header);
|
size_t total = length + sizeof(mem_header);
|
||||||
unsigned size = min_size;
|
|
||||||
while (total > (1 << size)) size++;
|
|
||||||
|
|
||||||
kassert(size <= max_size, "Tried to allocate a block bigger than max_size");
|
unsigned order = min_order;
|
||||||
if (size > max_size)
|
while (total > (1 << order)) order++;
|
||||||
|
|
||||||
|
kassert(order <= max_order, "Tried to allocate a block bigger than max_order");
|
||||||
|
if (order > max_order)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
mem_header *header = pop_free(size);
|
mem_header *header = pop_free(order);
|
||||||
header->set_used(true);
|
header->set_used(true);
|
||||||
m_allocated_size += (1 << size);
|
m_allocated_size += (1 << order);
|
||||||
return header + 1;
|
return header + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,66 +95,66 @@ heap_allocator::free(void *p)
|
|||||||
mem_header *header = reinterpret_cast<mem_header *>(p);
|
mem_header *header = reinterpret_cast<mem_header *>(p);
|
||||||
header -= 1; // p points after the header
|
header -= 1; // p points after the header
|
||||||
header->set_used(false);
|
header->set_used(false);
|
||||||
m_allocated_size -= (1 << header->size());
|
m_allocated_size -= (1 << header->order());
|
||||||
|
|
||||||
while (header->size() != max_size) {
|
while (header->order() != max_order) {
|
||||||
auto size = header->size();
|
auto order = header->order();
|
||||||
|
|
||||||
mem_header *buddy = header->buddy();
|
mem_header *buddy = header->buddy();
|
||||||
if (buddy->used() || buddy->size() != size)
|
if (buddy->used() || buddy->order() != order)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (get_free(size) == buddy)
|
if (get_free(order) == buddy)
|
||||||
get_free(size) = buddy->next();
|
get_free(order) = buddy->next();
|
||||||
|
|
||||||
buddy->remove();
|
buddy->remove();
|
||||||
|
|
||||||
header = header->eldest() ? header : buddy;
|
header = header->eldest() ? header : buddy;
|
||||||
header->set_size(size + 1);
|
header->set_order(order + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t size = header->size();
|
uint8_t order = header->order();
|
||||||
header->set_next(get_free(size));
|
header->set_next(get_free(order));
|
||||||
get_free(size) = header;
|
get_free(order) = header;
|
||||||
if (header->next())
|
if (header->next())
|
||||||
header->next()->set_prev(header);
|
header->next()->set_prev(header);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
heap_allocator::ensure_block(unsigned size)
|
heap_allocator::ensure_block(unsigned order)
|
||||||
{
|
{
|
||||||
if (get_free(size) != nullptr)
|
if (get_free(order) != nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (size == max_size) {
|
if (order == max_order) {
|
||||||
size_t bytes = (1 << max_size);
|
size_t bytes = (1 << max_order);
|
||||||
if (bytes <= m_size) {
|
if (bytes <= m_size) {
|
||||||
mem_header *next = reinterpret_cast<mem_header *>(m_next);
|
mem_header *next = reinterpret_cast<mem_header *>(m_next);
|
||||||
new (next) mem_header(nullptr, nullptr, size);
|
new (next) mem_header(nullptr, nullptr, order);
|
||||||
get_free(size) = next;
|
get_free(order) = next;
|
||||||
m_next += bytes;
|
m_next += bytes;
|
||||||
m_size -= bytes;
|
m_size -= bytes;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mem_header *orig = pop_free(size + 1);
|
mem_header *orig = pop_free(order + 1);
|
||||||
if (orig) {
|
if (orig) {
|
||||||
mem_header *next = kutil::offset_pointer(orig, 1 << size);
|
mem_header *next = kutil::offset_pointer(orig, 1 << order);
|
||||||
new (next) mem_header(orig, nullptr, size);
|
new (next) mem_header(orig, nullptr, order);
|
||||||
|
|
||||||
orig->set_next(next);
|
orig->set_next(next);
|
||||||
orig->set_size(size);
|
orig->set_order(order);
|
||||||
get_free(size) = orig;
|
get_free(order) = orig;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_allocator::mem_header *
|
heap_allocator::mem_header *
|
||||||
heap_allocator::pop_free(unsigned size)
|
heap_allocator::pop_free(unsigned order)
|
||||||
{
|
{
|
||||||
ensure_block(size);
|
ensure_block(order);
|
||||||
mem_header *block = get_free(size);
|
mem_header *block = get_free(order);
|
||||||
if (block) {
|
if (block) {
|
||||||
get_free(size) = block->next();
|
get_free(order) = block->next();
|
||||||
block->remove();
|
block->remove();
|
||||||
}
|
}
|
||||||
return block;
|
return block;
|
||||||
|
|||||||
@@ -29,32 +29,32 @@ public:
|
|||||||
/// \arg p A pointer previously retuned by allocate()
|
/// \arg p A pointer previously retuned by allocate()
|
||||||
virtual void free(void *p);
|
virtual void free(void *p);
|
||||||
|
|
||||||
/// Minimum block size is (2^min_size). Must be at least 6.
|
/// Minimum block size is (2^min_order). Must be at least 6.
|
||||||
static const unsigned min_size = 6;
|
static const unsigned min_order = 6;
|
||||||
|
|
||||||
/// Maximum block size is (2^max_size). Must be less than 64.
|
/// Maximum block size is (2^max_order). Must be less than 64.
|
||||||
static const unsigned max_size = 22;
|
static const unsigned max_order = 22;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
class mem_header;
|
class mem_header;
|
||||||
|
|
||||||
/// Ensure there is a block of a given size, recursively splitting
|
/// Ensure there is a block of a given order, recursively splitting
|
||||||
/// \arg size Size category of the block we want
|
/// \arg order Order (2^N) of the block we want
|
||||||
void ensure_block(unsigned size);
|
void ensure_block(unsigned order);
|
||||||
|
|
||||||
/// Helper accessor for the list of blocks of a given size
|
/// Helper accessor for the list of blocks of a given order
|
||||||
/// \arg size Size category of the block we want
|
/// \arg order Order (2^N) of the block we want
|
||||||
/// \returns A mutable reference to the head of the list
|
/// \returns A mutable reference to the head of the list
|
||||||
mem_header *& get_free(unsigned size) { return m_free[size - min_size]; }
|
mem_header *& get_free(unsigned order) { return m_free[order - min_order]; }
|
||||||
|
|
||||||
/// Helper to get a block of the given size, growing if necessary
|
/// Helper to get a block of the given order, growing if necessary
|
||||||
/// \arg size Size category of the block we want
|
/// \arg order Order (2^N) of the block we want
|
||||||
/// \returns A detached block of the given size
|
/// \returns A detached block of the given order
|
||||||
mem_header * pop_free(unsigned size);
|
mem_header * pop_free(unsigned order);
|
||||||
|
|
||||||
uintptr_t m_next;
|
uintptr_t m_next;
|
||||||
size_t m_size;
|
size_t m_size;
|
||||||
mem_header *m_free[max_size - min_size + 1];
|
mem_header *m_free[max_order - min_order + 1];
|
||||||
size_t m_allocated_size;
|
size_t m_allocated_size;
|
||||||
|
|
||||||
heap_allocator(const heap_allocator &) = delete;
|
heap_allocator(const heap_allocator &) = delete;
|
||||||
|
|||||||
Reference in New Issue
Block a user