OXYGENHUB
◆ main openmsx / src / utils / SerializeBuffer.cc
2.3 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#include "SerializeBuffer.hh"
2
3
#include <cstdlib>
4
#include <utility>
5
6
namespace openmsx {
7
8
// class OutputBuffer
9
10
OutputBuffer::OutputBuffer()
11
	: buf(lastSize)
12
	, end(buf.data())
13
{
14
	// We've allocated a buffer with an estimated initial size. This
15
	// estimate is based on the largest intermediate size of the previously
16
	// required buffers.
17
	// For correctness this initial size doesn't matter (we could even not
18
	// allocate any initial buffer at all). But it can make a difference in
19
	// performance. If later we discover the buffer is too small, we have
20
	// to reallocate (and thus make a copy). In profiling this reallocation
21
	// step was noticeable.
22
23
	// Slowly drop the estimated required size. This makes sure that when
24
	// we've overestimated the size once, we don't forever keep this too
25
	// high value. For performance an overestimation is less bad than an
26
	// underestimation.
27
	lastSize -= lastSize >> 7;
28
}
29
30
#ifdef __GNUC__
31
template<size_t LEN> void OutputBuffer::insertN(const void* __restrict data)
32
{
33
	uint8_t* newEnd = end + LEN;
34
	if (newEnd <= buf.end()) [[likely]] {
35
		memcpy(end, data, LEN);
36
		end = newEnd;
37
	} else {
38
		insertGrow(data, LEN);
39
	}
40
}
41
// Force template instantiation
42
template void OutputBuffer::insertN<1>(const void* __restrict data);
43
template void OutputBuffer::insertN<2>(const void* __restrict data);
44
template void OutputBuffer::insertN<4>(const void* __restrict data);
45
template void OutputBuffer::insertN<8>(const void* __restrict data);
46
#endif
47
48
void OutputBuffer::insertN(const void* __restrict data, size_t len)
49
{
50
	uint8_t* newEnd = end + len;
51
	if (newEnd <= buf.end()) [[likely]] {
52
		memcpy(end, data, len);
53
		end = newEnd;
54
	} else {
55
		insertGrow(data, len);
56
	}
57
}
58
59
MemBuffer<uint8_t> OutputBuffer::release() &&
60
{
61
	// Deallocate unused buffer space.
62
	size_t size = end - buf.data();
63
	buf.resize(size);
64
65
	end = nullptr;
66
	return std::move(buf);
67
}
68
69
void OutputBuffer::grow(size_t len)
70
{
71
	size_t oldSize = end - buf.data();
72
	size_t newSize = std::max(oldSize + len, oldSize + oldSize / 2);
73
	buf.resize(newSize);
74
	end    = buf.data() + oldSize;
75
}
76
77
uint8_t* OutputBuffer::allocateGrow(size_t len)
78
{
79
	grow(len);
80
	auto* result = end;
81
	end += len;
82
	return result;
83
}
84
85
void OutputBuffer::insertGrow(const void* __restrict data, size_t len)
86
{
87
	uint8_t* pos = allocateGrow(len);
88
	memcpy(pos, data, len);
89
}
90
91
} // namespace openmsx