64 lines
1.8 KiB
C++
64 lines
1.8 KiB
C++
|
// Copyright (c) Vitaliy Filippov, 2023+
|
||
|
// License: VNPL-1.1 or GNU GPL-2.0+ (see README.md for details)
|
||
|
|
||
|
#include <assert.h>
|
||
|
#include "freelist.h"
|
||
|
|
||
|
uint64_t freelist_allocator_t::alloc(uint64_t data_size)
|
||
|
{
|
||
|
for (int i = 0; i < freelist.size(); i++)
|
||
|
{
|
||
|
if (freelist[i].size >= data_size)
|
||
|
{
|
||
|
uint64_t r = freelist[i].start;
|
||
|
freelist[i].start += data_size;
|
||
|
freelist[i].size -= data_size;
|
||
|
return r;
|
||
|
}
|
||
|
}
|
||
|
return UINT64_MAX;
|
||
|
}
|
||
|
|
||
|
void freelist_allocator_t::free(uint64_t start, uint64_t size)
|
||
|
{
|
||
|
int min = 0, max = freelist.size();
|
||
|
if (max && freelist[freelist.size()-1].start < start)
|
||
|
{
|
||
|
min = max;
|
||
|
}
|
||
|
if (max && freelist[0].start >= start)
|
||
|
{
|
||
|
max = 0;
|
||
|
}
|
||
|
while (max-min > 1)
|
||
|
{
|
||
|
int mid = (min+max)/2;
|
||
|
if (freelist[mid].start >= start)
|
||
|
max = mid;
|
||
|
else
|
||
|
min = mid;
|
||
|
}
|
||
|
// max = the first item where freelist[max].start >= start
|
||
|
if (max > 0 && freelist[max-1].start+freelist[max-1].size >= start)
|
||
|
{
|
||
|
assert(freelist[max-1].start+freelist[max-1].size == start);
|
||
|
freelist[max-1].size += size;
|
||
|
}
|
||
|
else if (max < freelist.size() && freelist[max].start <= size+start)
|
||
|
{
|
||
|
assert(freelist[max].start == size+start);
|
||
|
freelist[max].start -= size;
|
||
|
freelist[max].size += size;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
freelist.insert(freelist.begin()+min, (freelist_item_t){ .start = start, .size = size });
|
||
|
max = min; // to skip the if below
|
||
|
}
|
||
|
if (min != max && max < freelist.size() && freelist[max].start == freelist[min].start+freelist[min].size)
|
||
|
{
|
||
|
freelist[min].size += freelist[max].size;
|
||
|
freelist.erase(freelist.begin()+max, freelist.begin()+max+1);
|
||
|
}
|
||
|
}
|