summaryrefslogtreecommitdiff
path: root/src/memory.cpp
blob: f9197703f675e09c96ab8c5242c9a318692c7837 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107

#include "memory.hpp"

struct pke::MemBucket {
	int64_t size;
	int64_t head;
	int64_t free;
	int64_t allocs;
	bool transient;
	char * ptr;
};

pke::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<char *>(std::malloc(sz));
	return bucketHead++;
}

void DestroyBucket(pke::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::PkeNew(std::size_t sz, pke::MemBucket *bkt) {
	void *ptr = bkt->ptr + bkt->head;
	bkt->head += sz;
	bkt->allocs++;
	return ptr;
}

void *pke::PkeNew(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 PkeNew(sz, bkt);
}

void pke::PkeDelete(const void *ptr, std::size_t sz, pke::MemBucket *bkt) {
	assert(ptr >= bkt->ptr && ptr < bkt->ptr + bkt->size && "pointer not in 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::PkeDelete(const void *ptr, std::size_t sz) {
	pke::MemBucket *bkt = nullptr;
	for (long i = 0; i < bucketHead; ++i) {
		bkt = &buckets[i];
		if (ptr >= bkt->ptr && ptr < bkt->ptr + bkt->size) break;
	}
	if (bkt == nullptr) {
		std::printf("bad pointer %llu", reinterpret_cast<unsigned long long>(ptr));
		throw "bad pointer";
	}
	PkeDelete(ptr, sz, bkt);
}

pke::MemBucket *pke::BeginTransientBucket(int64_t sz) {
	return &buckets[InitNewBucket(sz, true)];
}

void pke::EndTransientBucket(pke::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 pke::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]);
	}
}