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
7#include <algorithm>
8#include <cstdint>
9#include <cstring>
10#include <cassert>
11#include <span>
12#include <tuple>
13
14namespace openmsx {
15
30{
31public:
35
39 void insert(const void* __restrict data, size_t len)
40 {
41#ifdef __GNUC__
42 if (__builtin_constant_p(len)) {
43 if (len == 1) {
44 insertN<1>(data); return;
45 } else if (len == 2) {
46 insertN<2>(data); return;
47 } else if (len == 4) {
48 insertN<4>(data); return;
49 } else if (len == 8) {
50 insertN<8>(data); return;
51 }
52 }
53#endif
54 insertN(data, len);
55 }
56#ifdef __GNUC__
57 template<size_t N> void insertN(const void* __restrict data);
58#endif
59 void insertN(const void* __restrict data, size_t len);
60
66 template<typename TUPLE> ALWAYS_INLINE void insert_tuple_ptr(const TUPLE& tuple)
67 {
68 size_t len = 0;
69 auto accum = [&](auto* p) { len += sizeof(*p); };
70 std::apply([&](auto&&... args) { (accum(args), ...); }, tuple);
71
72 if (const uint8_t* newEnd = end + len; newEnd > buf.end()) [[unlikely]] {
73 grow(len); // reallocates, thus newEnd is no longer valid.
74 }
75
76 uint8_t* dst = end;
77 auto write = [&](auto* src) {
78 memcpy(dst, src, sizeof(*src));
79 dst += sizeof(*src);
80 };
81 std::apply([&](auto&&... args) { (write(args), ...); }, tuple);
82 assert(dst == (end + len));
83
84 end = dst;
85 }
86
87 template<typename T> ALWAYS_INLINE void insert_tuple_ptr(const std::tuple<T*>& tuple)
88 {
89 // single-element tuple -> use insert() because it's better tuned
90 insert(std::get<0>(tuple), sizeof(T));
91 }
92
97 void insertAt(size_t pos, const void* __restrict data, size_t len)
98 {
99 assert(buf.data() + pos + len <= buf.end());
100 memcpy(buf.data() + pos, data, len);
101 }
102
111 [[nodiscard]] std::span<uint8_t> allocate(size_t len)
112 {
113 auto* newEnd = end + len;
114 // Make sure the next OutputBuffer will start with an initial size
115 // that can hold this much space plus some slack.
116 size_t newSize = newEnd - buf.data();
117 lastSize = std::max(lastSize, newSize + 1000);
118 if (newEnd <= buf.end()) {
119 uint8_t* result = end;
120 end = newEnd;
121 return {result, len};
122 } else {
123 return {allocateGrow(len), len};
124 }
125 }
126
138 /*void deallocate(uint8_t* pos)
139 {
140 assert(buf.data() <= pos);
141 assert(pos <= end);
142 end = pos;
143 }*/
144
147 [[nodiscard]] size_t getPosition() const
148 {
149 return end - buf.data();
150 }
151
155 [[nodiscard]] MemBuffer<uint8_t> release() &&;
156
157private:
158 void insertGrow(const void* __restrict data, size_t len);
159 [[nodiscard]] uint8_t* allocateGrow(size_t len);
160 void grow(size_t len);
161
162 MemBuffer<uint8_t> buf; // allocated memory
163 uint8_t* end; // points right after the last used byte
164 // so end - buf == size_in_use
165
166 static inline size_t lastSize = 50000; // initial estimate
167};
168
169
175{
176public:
180 InputBuffer(std::span<const uint8_t> buf_)
181 : buf(buf_) {}
182
187 void read(void* __restrict result, size_t len)
188 {
189 assert(buf.size() >= len);
190 memcpy(result, buf.data(), len);
191 buf = buf.subspan(len);
192 }
193
198 void skip(size_t len)
199 {
200 assert(buf.size() >= len);
201 buf = buf.subspan(len);
202 }
203
209 [[nodiscard]] const uint8_t* getCurrentPos() const { return buf.data(); }
210
211private:
212 std::span<const uint8_t> buf;
213};
214
215} // namespace openmsx
216
217#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.
void skip(size_t len)
Skip the given number of bytes.
InputBuffer(std::span< const uint8_t > buf_)
Construct new InputBuffer, typically the buf_ parameter will come from a MemBuffer object.
This class manages the lifetime of a block of memory.
Definition MemBuffer.hh:32
const T * data() const
Returns pointer to the start of the memory buffer.
Definition MemBuffer.hh:79
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.
std::span< uint8_t > allocate(size_t len)
Reserve space to insert the given number of bytes.
ALWAYS_INLINE void insert_tuple_ptr(const TUPLE &tuple)
Insert all the elements of the given tuple.
MemBuffer< uint8_t > release() &&
Release ownership of the buffer.
size_t getPosition() const
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
This file implemented 3 utility functions:
Definition Autofire.cc:11