openMSX
SerializeBuffer.hh
Go to the documentation of this file.
1#ifndef SERIALIZEBUFFER_HH
2#define SERIALIZEBUFFER_HH
3
4#include "MemBuffer.hh"
5#include "inline.hh"
6#include <algorithm>
7#include <cstdint>
8#include <cstring>
9#include <cassert>
10#include <tuple>
11
12namespace openmsx {
13
28{
29public:
33
37 void insert(const void* __restrict data, size_t len)
38 {
39#ifdef __GNUC__
40 if (__builtin_constant_p(len)) {
41 if (len == 1) {
42 insertN<1>(data); return;
43 } else if (len == 2) {
44 insertN<2>(data); return;
45 } else if (len == 4) {
46 insertN<4>(data); return;
47 } else if (len == 8) {
48 insertN<8>(data); return;
49 }
50 }
51#endif
52 insertN(data, len);
53 }
54#ifdef __GNUC__
55 template<size_t N> void insertN(const void* __restrict data);
56#endif
57 void insertN(const void* __restrict data, size_t len);
58
64 template<typename TUPLE> ALWAYS_INLINE void insert_tuple_ptr(const TUPLE& tuple)
65 {
66 size_t len = 0;
67 auto accum = [&](auto* p) { len += sizeof(*p); };
68 std::apply([&](auto&&... args) { (accum(args), ...); }, tuple);
69
70 uint8_t* newEnd = end + len;
71 if (newEnd > finish) [[unlikely]] {
72 grow(len); // reallocates, thus newEnd is no longer valid.
73 }
74
75 uint8_t* dst = end;
76 auto write = [&](auto* src) {
77 memcpy(dst, src, sizeof(*src));
78 dst += sizeof(*src);
79 };
80 std::apply([&](auto&&... args) { (write(args), ...); }, tuple);
81 assert(dst == (end + len));
82
83 end = dst;
84 }
85
86 template<typename T> ALWAYS_INLINE void insert_tuple_ptr(const std::tuple<T*>& tuple)
87 {
88 // single-element tuple -> use insert() because it's better tuned
89 insert(std::get<0>(tuple), sizeof(T));
90 }
91
96 void insertAt(size_t pos, const void* __restrict data, size_t len)
97 {
98 assert(buf.data() + pos + len <= finish);
99 memcpy(buf.data() + pos, data, len);
100 }
101
110 [[nodiscard]] uint8_t* allocate(size_t len)
111 {
112 auto* newEnd = end + len;
113 // Make sure the next OutputBuffer will start with an initial size
114 // that can hold this much space plus some slack.
115 size_t newSize = newEnd - buf.data();
116 lastSize = std::max(lastSize, newSize + 1000);
117 if (newEnd <= finish) {
118 uint8_t* result = end;
119 end = newEnd;
120 return result;
121 } else {
122 return allocateGrow(len);
123 }
124 }
125
137 void deallocate(uint8_t* pos)
138 {
139 assert(buf.data() <= pos);
140 assert(pos <= end);
141 end = pos;
142 }
143
146 [[nodiscard]] size_t getPosition() const
147 {
148 return end - buf.data();
149 }
150
154 [[nodiscard]] MemBuffer<uint8_t> release(size_t& size);
155
156private:
157 void insertGrow(const void* __restrict data, size_t len);
158 [[nodiscard]] uint8_t* allocateGrow(size_t len);
159 void grow(size_t len);
160
161 MemBuffer<uint8_t> buf; // begin of allocated memory
162 uint8_t* end; // points right after the last used byte
163 // so end - buf == size
164 uint8_t* finish; // points right after the last allocated byte
165 // so finish - buf == capacity
166
167 static inline size_t lastSize = 50000; // initial estimate
168};
169
170
176{
177public:
181 InputBuffer(const uint8_t* data, size_t size);
182
187 void read(void* __restrict result, size_t len) __restrict
188 {
189 memcpy(result, buf, len);
190 buf += len;
191 assert(buf <= finish);
192 }
193
198 void skip(size_t len)
199 {
200 buf += len;
201 assert(buf <= finish);
202 }
203
209 [[nodiscard]] const uint8_t* getCurrentPos() const { return buf; }
210
211private:
212 const uint8_t* buf;
213#ifndef NDEBUG
214 const uint8_t* finish; // only used to check asserts
215#endif
216};
217
218} // namespace openmsx
219
220#endif
This class is complementary to the OutputBuffer class.
void read(void *result, size_t len)
Read the given number of bytes.
const uint8_t * getCurrentPos() const
Return a pointer to the current position in the buffer.
InputBuffer(const uint8_t *data, size_t size)
Construct new InputBuffer, typically the data and size parameters will come from a MemBuffer object.
void skip(size_t len)
Skip the given number of bytes.
const T * data() const
Returns pointer to the start of the memory buffer.
Definition: MemBuffer.hh:81
Memory output buffer.
void insertAt(size_t pos, const void *data, size_t len)
Insert data at a given position.
ALWAYS_INLINE void insert_tuple_ptr(const std::tuple< T * > &tuple)
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.
ALWAYS_INLINE void insert_tuple_ptr(const TUPLE &tuple)
Insert all the elements of the given tuple.
size_t getPosition() const
Get the current size of the buffer.
uint8_t * allocate(size_t len)
Reserve space to insert the given number of bytes.
void deallocate(uint8_t *pos)
Free part of a previously allocated buffer.
void insert(const void *data, size_t len)
Insert data at the end of this buffer.
#define ALWAYS_INLINE
Definition: inline.hh:16
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)