OXYGENHUB
◆ main openmsx / src / utils / monotonic_allocator.hh
1.8 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
#ifndef MEMORY_RESOURCE
2
#define MEMORY_RESOURCE
3
4
#include <algorithm>
5
#include <cassert>
6
#include <cstddef>
7
#include <cstdlib>
8
#include <memory>
9
#include <new>
10
11
// A minimal re-implementation of std::monotonic_buffer_resource.
12
// Because libc++ doesn't have this yet, even though it's part of c++17.
13
14
class monotonic_allocator
15
{
16
public:
17
	monotonic_allocator() = default;
18
19
	explicit monotonic_allocator(size_t initialSize)
20
		: nextSize(initialSize)
21
	{
22
		assert(initialSize != 0);
23
	}
24
25
	monotonic_allocator(void* buffer, size_t bufferSize)
26
		: current(buffer)
27
		, available(bufferSize)
28
		, nextSize(2 * bufferSize)
29
	{
30
		assert(buffer || bufferSize == 0);
31
	}
32
33
	monotonic_allocator(const monotonic_allocator&) = delete;
34
	monotonic_allocator(monotonic_allocator&&) = delete;
35
	monotonic_allocator& operator=(const monotonic_allocator&) = delete;
36
	monotonic_allocator& operator=(monotonic_allocator&&) = delete;
37
38
	~monotonic_allocator()
39
	{
40
		void* p = head;
41
		while (p) {
42
			void* next = *static_cast<void**>(p);
43
			free(p);
44
			p = next;
45
		}
46
	}
47
48
	[[nodiscard]] void* allocate(size_t bytes, size_t alignment)
49
	{
50
		assert(alignment <= alignof(max_align_t));
51
52
		if (bytes == 0) bytes = 1;
53
		void* p = std::align(alignment, bytes, current, available);
54
		if (!p) {
55
			newBuffer(bytes);
56
			p = current;
57
		}
58
		current = static_cast<char*>(current) + bytes;
59
		available -= bytes;
60
		return p;
61
	}
62
63
private:
64
	void newBuffer(size_t bytes)
65
	{
66
		size_t n = std::max(nextSize, bytes);
67
		void* newBuf = malloc(n + sizeof(void*));
68
		if (!newBuf) {
69
			throw std::bad_alloc();
70
		}
71
72
		auto** p = static_cast<void**>(newBuf);
73
		p[0] = head;
74
75
		current = static_cast<void*>(&p[1]);
76
		available = n;
77
		nextSize = 2 * n;
78
		head = newBuf;
79
	}
80
81
private:
82
	void* current = nullptr;
83
	size_t available = 0;
84
	size_t nextSize = 1024;
85
	void* head = nullptr;
86
};
87
88
#endif