summaryrefslogtreecommitdiff
path: root/src/memory.cpp
blob: 87d5eca6807bb424d6724bd72d6e90a71a101eb5 (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
126
127
128
129
130
131
132
133
134
135
136
137
138

#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;
}

void Pke_DebugPrint() {
	printf("Memory Manager printout:\nBucket count: %li\n", bucketHead + 1);
	for (long i = 0; i < bucketHead + 1; ++i) {
		printf("- bucket #%li\n", i);
		printf("\tsize:      %li\n", buckets[i].size);
		printf("\thead:      %li\n", buckets[i].head);
		printf("\tfree:      %li\n", buckets[i].free);
		printf("\tallocs:    %li\n", buckets[i].allocs);
		printf("\ttransient: %i\n", buckets[i].transient);
		printf("\tptr:        %p\n", buckets[i].ptr);
	}
}