openMSX
SerializeBuffer.cc
Go to the documentation of this file.
1 #include "SerializeBuffer.hh"
2 #include <cstdlib>
3 #include <utility>
4 
5 namespace openmsx {
6 
7 // class OutputBuffer
8 
10  : buf(lastSize)
11  , end(buf.data())
12  , finish(buf.data() + lastSize)
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 <= finish) [[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 <= finish) [[likely]] {
52  memcpy(end, data, len);
53  end = newEnd;
54  } else {
55  insertGrow(data, len);
56  }
57 }
58 
60 {
61  size = end - buf.data();
62 
63  // Deallocate unused buffer space.
64  buf.resize(size);
65 
66  end = finish = nullptr;
67  return std::move(buf);
68 }
69 
70 void OutputBuffer::grow(size_t len)
71 {
72  size_t oldSize = end - buf.data();
73  size_t newSize = std::max(oldSize + len, oldSize + oldSize / 2);
74  buf.resize(newSize);
75  end = buf.data() + oldSize;
76  finish = buf.data() + newSize;
77 }
78 
79 uint8_t* OutputBuffer::allocateGrow(size_t len)
80 {
81  grow(len);
82  auto* result = end;
83  end += len;
84  return result;
85 }
86 
87 void OutputBuffer::insertGrow(const void* __restrict data, size_t len)
88 {
89  uint8_t* pos = allocateGrow(len);
90  memcpy(pos, data, len);
91 }
92 
93 
94 
95 // class InputBuffer
96 
97 InputBuffer::InputBuffer(const uint8_t* data, size_t size)
98  : buf(data)
99 #ifndef NDEBUG
100  , finish(buf + size)
101 #endif
102 {
103  (void)size;
104 }
105 
106 } // namespace openmsx
InputBuffer(const uint8_t *data, size_t size)
Construct new InputBuffer, typically the data and size parameters will come from a MemBuffer object.
const T * data() const
Returns pointer to the start of the memory buffer.
Definition: MemBuffer.hh:81
void resize(size_t size)
Grow or shrink the memory block.
Definition: MemBuffer.hh:111
void insertN(const void *data, size_t len)
OutputBuffer()
Create an empty output buffer.
MemBuffer< uint8_t > release(size_t &size)
Release ownership of the buffer.
constexpr vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:283
This file implemented 3 utility functions:
Definition: Autofire.cc:9
size_t size(std::string_view utf8)
constexpr auto end(const zstring_view &x)