#include "memory.hpp" struct MemBucket { int64_t size; int64_t head; int64_t free; int64_t allocs; bool transient; char * ptr; }; MemBucket buckets[128]; int64_t bucketHead = 0; int64_t InitNewBucket(int64_t sz, bool transient = false) { buckets[bucketHead].size = sz; buckets[bucketHead].head = 0; buckets[bucketHead].free = 0; buckets[bucketHead].allocs = 0; buckets[bucketHead].transient = transient; buckets[bucketHead].ptr = reinterpret_cast(std::malloc(sz)); return bucketHead++; } void DestroyBucket(MemBucket *bkt) { std::free(bkt->ptr); bkt->size = 0; bkt->head = 0; bkt->free = 0; bkt->allocs = 0; bkt->transient = false; bkt->ptr = CAFE_BABE(char); } void *Pke_New(std::size_t sz, MemBucket *bkt) { assert(bkt->head + sz <= bkt->size && "memory bucket specified, but full"); void *ptr = bkt->ptr + bkt->head; bkt->head += sz; bkt->allocs++; return ptr; } void *Pke_New(std::size_t sz) { MemBucket *bkt = nullptr; for (long i = 0; i < bucketHead; ++i) { if (buckets[i].transient == false && buckets[i].size - buckets[i].head > sz) { bkt = &buckets[i]; } } if (bkt == nullptr) { bkt = &buckets[InitNewBucket(DEFAULT_BUCKET_SIZE)]; } return Pke_New(sz, bkt); } void Pke_Delete(const void *ptr, std::size_t sz, MemBucket *bkt) { assert(ptr >= bkt->ptr && ptr < bkt->ptr + bkt->size && "pointer not in memory bucket range"); bkt->allocs--; bkt->free += sz; if (ptr == bkt->ptr + bkt->head - sz) bkt->head -= sz; if (bkt->allocs == 0) { bkt->head = 0; bkt->free = 0; } } void Pke_Delete(const void *ptr, std::size_t sz) { MemBucket *bkt = nullptr; for (long i = 0; i < bucketHead; ++i) { bkt = &buckets[i]; if (ptr >= bkt->ptr && ptr < bkt->ptr + bkt->size) break; } assert(bkt != nullptr && "failed to determine correct memory bucket"); Pke_Delete(ptr, sz, bkt); } MemBucket *BeginTransientBucket(int64_t sz) { return &buckets[InitNewBucket(sz, true)]; } void EndTransientBucket(MemBucket *bkt) { int64_t foundIndex = -1; for (int64_t i = 0; i < bucketHead; ++i) { if (&buckets[i] == bkt) { foundIndex = i; DestroyBucket(&buckets[i]); break; } } if (foundIndex == bucketHead) { bucketHead--; } } void Flush() { for (long i = bucketHead - 2; i > -1; --i) { if (buckets[i].head != 0) break; if (buckets[i+1].head != 0) break; if (buckets[i].transient == true) break; if (buckets[i+1].transient == true) break; bucketHead--; DestroyBucket(&buckets[i + 1]); } } uint64_t Buckets_NewHandle(std::size_t bucketBytes, uint64_t bucketItemCount, uint64_t &bucketIncrementer, uint64_t &bucketCounter, uint64_t &itemCounter, void*& buckets) { uint64_t newHandle{itemCounter | bucketCounter}; itemCounter += uint64_t{1ULL << 32}; if (itemCounter > uint64_t{(bucketItemCount - 1) << 32}) { itemCounter = 0ULL; bucketCounter += 1; } if (bucketCounter > bucketIncrementer) { int64_t newIncrement = bucketIncrementer * 1.5; char * newBuckets = reinterpret_cast(Pke_New(bucketBytes * newIncrement)); std::memcpy(newBuckets, buckets, bucketBytes * bucketIncrementer); Pke_Delete(buckets, bucketBytes * bucketIncrementer); buckets = newBuckets; bucketIncrementer = newIncrement; } return newHandle; } void Pke_DebugPrint() { printf("Memory Manager printout:\nBucket count: %li\n", bucketHead + 1); for (long i = 0; i <= bucketHead; ++i) { printf("- bucket #%li\n", i); printf("\tsize: %li\n", buckets[i].size); printf("\thead: %li\n", buckets[i].head); printf("\tfree: %li\n", buckets[i].free); printf("\tallocs: %li\n", buckets[i].allocs); printf("\ttransient: %i\n", buckets[i].transient); printf("\tptr: %p\n", buckets[i].ptr); } }