This repository has been archived on 2022-05-21. You can view files and clone it, but cannot push or open issues or pull requests.
glyphs-juke/LinearAllocator.h
2021-08-21 17:29:58 +09:00

97 lines
2.6 KiB
C++

#pragma once
#include <cassert>
#include <cstddef>
#include <cstdint>
#include "common.h"
#include "iAllocator.h"
namespace gj {
class LinearAllocator : public iAllocator {
public:
using iAllocator::Alloc;
using iAllocator::MakeUnique;
LinearAllocator() = delete;
LinearAllocator(LinearAllocator&&) = delete;
LinearAllocator(const LinearAllocator&) = delete;
LinearAllocator& operator=(LinearAllocator&&) = delete;
LinearAllocator& operator=(const LinearAllocator&) = delete;
LinearAllocator(void* ptr, const size_t size) :
ptr_(static_cast<uint8_t*>(ptr)) {
assert(size >= sizeof(Header)*2);
auto head = reinterpret_cast<Header*>(ptr_);
head->prev = 0;
head->next = size - sizeof(Header);
head->size = sizeof(Header);
auto tail = reinterpret_cast<Header*>(ptr_+head->next);
tail->prev = head->next;
tail->next = 0;
tail->size = sizeof(Header);
}
void* Alloc(const size_t size) override {
const size_t aligned_size = (((size >> 3) + !!(size & 0b111))) << 3;
const size_t whole_size = sizeof(Header) + aligned_size;
assert(aligned_size >= size);
auto h = reinterpret_cast<Header*>(ptr_);
while (h->next) {
const size_t remain = h->next - h->size;
if (remain >= whole_size) {
auto hprev = h;
auto hnext = reinterpret_cast<Header*>(reinterpret_cast<uint8_t*>(hprev) + hprev->next);
h = reinterpret_cast<Header*>(reinterpret_cast<uint8_t*>(hprev) + hprev->size);
h->prev = hprev->size;
h->next = remain;
h->size = whole_size;
hprev->next = h->prev;
hnext->prev = h->next;
return h + 1;
}
h = reinterpret_cast<Header*>(reinterpret_cast<uint8_t*>(h) + h->next);
}
Abort("LinearAllocator Allocation Failure");
}
void Free(void* ptr) override {
if (!ptr) return;
uint8_t* uptr = reinterpret_cast<uint8_t*>(ptr) - sizeof(Header);
auto h = reinterpret_cast<Header*>(uptr);
auto hprev = reinterpret_cast<Header*>(uptr - h->prev);
auto hnext = reinterpret_cast<Header*>(uptr + h->next);
hprev->next += h->next;
hnext->prev += h->prev;
}
private:
/* |------prev--------||--------next--------| */
/* |----size-----| */
/* memory: HHAAAAAAAAAAAAAAAAUUHHAAAAAAAAAAAAAUUUUUUUHHAAAAA */
/* H: header, A: allocated area, U: unused area */
struct Header {
size_t prev;
size_t next;
size_t size;
};
static_assert(sizeof(Header) == sizeof(size_t)*3, "padding detected in memory header");
uint8_t* const ptr_;
};
}