summaryrefslogtreecommitdiff
path: root/src/memory.cpp
blob: ee99fc86a3212a940afd78aa3f6f66483200ab15 (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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125

#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<char *>(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<char *>(Pke_New(bucketBytes * newIncrement));
		std::memcpy(newBuckets, buckets, bucketBytes * bucketIncrementer);
		Pke_Delete(buckets, bucketBytes * bucketIncrementer);
		buckets = newBuckets;
		bucketIncrementer = newIncrement;
	}

	return newHandle;
}