[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:
2020-07-30 19:41:41 -07:00
parent 4ffd4949ca
commit 73221dfe34
2 changed files with 55 additions and 54 deletions

View File

@@ -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;

View File

@@ -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;