add util::SmallHeap
This commit is contained in:
parent
1a50e69769
commit
cf99996b24
102
src/util/SmallHeap.hpp
Normal file
102
src/util/SmallHeap.hpp
Normal 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
55
test/util/SmallHeap.cpp
Normal 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);
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user