add util::SmallHeap

This commit is contained in:
MihailRis 2024-08-12 22:07:25 +03:00
parent 1a50e69769
commit cf99996b24
2 changed files with 157 additions and 0 deletions

102
src/util/SmallHeap.hpp Normal file
View File

@ -0,0 +1,102 @@
#pragma once
#include <cstdint>
#include <cstring>
#include <vector>
#include <stdexcept>
namespace util {
template <typename Tindex, typename Tsize>
class SmallHeap {
std::vector<uint8_t> buffer;
Tindex entriesCount;
public:
SmallHeap() : entriesCount(0) {}
uint8_t* find(Tindex index) {
auto data = buffer.data();
for (size_t i = 0; i < entriesCount; i++) {
auto nextIndex = *reinterpret_cast<Tindex*>(data);
data += sizeof(Tindex);
auto nextSize = *reinterpret_cast<Tsize*>(data);
data += sizeof(Tsize);
if (nextIndex == index) {
return data;
} else if (nextIndex > index) {
return nullptr;
}
data += nextSize;
}
return nullptr;
}
void free(uint8_t* ptr) {
if (ptr == nullptr) {
return;
}
auto entrySize = sizeOf(ptr);
auto begin =
buffer.begin() +
((ptr - sizeof(Tsize) - sizeof(Tindex)) - buffer.data());
buffer.erase(
begin, begin + entrySize + sizeof(Tsize) + sizeof(Tindex)
);
entriesCount--;
}
uint8_t* allocate(Tindex index, Tsize size) {
if (size == 0) {
throw std::runtime_error("size is 0");
}
ptrdiff_t offset = 0;
if (auto found = find(index)) {
auto entrySize = sizeOf(found);
if (size == entrySize) {
std::memset(found, 0, entrySize);
return found;
}
this->free(found);
return allocate(index, size);
}
for (size_t i = 0; i < entriesCount; i++) {
auto data = buffer.data() + offset;
auto nextIndex = *reinterpret_cast<Tindex*>(data);
data += sizeof(Tindex);
auto nextSize = *reinterpret_cast<Tsize*>(data);
data += sizeof(Tsize);
if (nextIndex > index) {
break;
}
data += nextSize;
offset = data - buffer.data();
}
buffer.insert(
buffer.begin() + offset,
size + sizeof(Tindex) + sizeof(Tsize),
0
);
entriesCount++;
auto data = buffer.data() + offset;
*reinterpret_cast<Tindex*>(data) = index;
data += sizeof(Tindex);
*reinterpret_cast<Tsize*>(data) = size;
return data + sizeof(Tsize);
}
Tsize sizeOf(uint8_t* ptr) const {
if (ptr == nullptr) {
return 0;
}
return *(reinterpret_cast<Tsize*>(ptr)-1);
}
Tindex count() const {
return entriesCount;
}
size_t size() const {
return buffer.size();
}
};
}

55
test/util/SmallHeap.cpp Normal file
View File

@ -0,0 +1,55 @@
#include <gtest/gtest.h>
#include "util/SmallHeap.hpp"
using namespace util;
TEST(SmallHeap, Allocation) {
auto index = 0;
auto size = 4;
SmallHeap<uint16_t, uint8_t> map;
auto ptr = map.allocate(index, size);
EXPECT_EQ(map.sizeOf(ptr), size);
EXPECT_EQ(ptr, map.find(index));
}
TEST(SmallHeap, MultipleAllocation) {
SmallHeap<uint16_t, uint8_t> map;
map.allocate(32, 4);
map.allocate(1, 5);
EXPECT_EQ(map.sizeOf(map.find(32)), 4);
EXPECT_EQ(map.sizeOf(map.find(1)), 5);
}
TEST(SmallHeap, Free) {
SmallHeap<uint16_t, uint8_t> map;
map.free(map.allocate(5, 4));
EXPECT_EQ(map.find(5), nullptr);
}
TEST(SmallHeap, ReAllocationSame) {
SmallHeap<uint16_t, uint8_t> map;
auto ptr1 = map.allocate(1, 2);
auto ptr2 = map.allocate(1, 2);
EXPECT_EQ(ptr1, ptr2);
}
TEST(SmallHeap, ReAllocationDifferent) {
SmallHeap<uint16_t, uint8_t> map;
map.allocate(1, 34);
map.allocate(1, 2);
EXPECT_EQ(map.sizeOf(map.find(1)), 2);
}
TEST(SmallHeap, RandomFill) {
SmallHeap<uint16_t, uint8_t> map;
int n = 3'000;
map.allocate(n, 123);
for (int i = 0; i < n; i++) {
int index = rand() % n;
int size = rand() % 254 + 1;
map.allocate(index, size);
}
EXPECT_EQ(map.sizeOf(map.find(n)), 123);
}