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