Cogs.Core
MemoryBuffer.cpp
1#include "MemoryBuffer.h"
2
3#include "../StringView.h"
4
5#include <algorithm>
6#include <cstring>
7
11std::string Cogs::Memory::MemToHexString(const void* memory, size_t size) {
12 const char* digits = "0123456789ABCDEF";
13 std::string output;
14 const uint8_t* ptr = static_cast<const uint8_t*>(memory);
15 constexpr size_t bytesPerLine = 32;
16 uint32_t offset = 0;
17 char buffer[16];
18
19 output.reserve(size * 4);
20
21 for (; size >= bytesPerLine; size -= bytesPerLine, offset += bytesPerLine) {
22 snprintf(buffer, sizeof(buffer), "0x%08X: ", offset);
23 output += buffer;
24
25 for (size_t count = 0; count++ < bytesPerLine; ) {
26 output += digits[*ptr >> 4];
27 output += digits[*ptr++ & 0x0F];
28 output += " ";
29
30 if (!(count & 0x03)) {
31 output += " ";
32 }
33 }
34 output += "\n";
35 }
36 if (size) {
37 snprintf(buffer, sizeof(buffer), "0x%08X: ", offset);
38 output += buffer;
39
40 for (size_t count = 0; size--; ) {
41 output += digits[*ptr >> 4];
42 output += digits[*ptr++ & 0x0F];
43 output += " ";
44
45 if (!(++count & 0x03)) {
46 output += " ";
47 }
48 }
49 output += "\n";
50 }
51 return output;
52}
53
54Cogs::Memory::MemoryBuffer::MemoryBuffer(const void* memory, size_t size) {
55 buffer = const_cast<void*>(memory);
56 currentSize = size;
57 storageSize = 0;
58 currentPos = 0;
59 allocator = nullptr;
60}
61
62void Cogs::Memory::MemoryBuffer::reset(size_t size, Allocator * allocator)
63{
64 if (allocator == this->allocator) {
65 resize(size, false, false);
66 }
67 else {
68 release();
69 this->allocator = allocator;
70 resize(size, false, false);
71 }
72}
73
74bool Cogs::Memory::MemoryBuffer::resize(size_t size, bool keep, bool forceRealloc) {
75 assert(allocator);
76
77 if (currentSize == size) {
78 return true;
79 }
80
81 if (forceRealloc || (size > storageSize)) {
82 void* newBuffer = nullptr;
83
84 if (size) {
85 newBuffer = allocator->allocate(size, 0, type);
86
87 if (!newBuffer) {
88 return false;
89 }
90 if (buffer && keep) {
91 std::memcpy(newBuffer, buffer, std::min(size, currentSize));
92 }
93 }
94 release();
95
96 storageSize = size;
97 buffer = newBuffer;
98 }
99 currentSize = size;
100 currentPos = std::min(currentPos, currentSize);
101 return true;
102}
103
104bool Cogs::Memory::MemoryBuffer::reserve(size_t size) {
105 assert(allocator);
106
107 if (size > storageSize) {
108 void* newBuffer = allocator->allocate(size, 0, type);
109
110 if (!newBuffer) {
111 return false;
112 }
113 if (buffer) {
114 std::memcpy(newBuffer, buffer, currentSize);
115 allocator->deallocate(buffer, storageSize, type);
116 }
117 storageSize = size;
118 buffer = newBuffer;
119 }
120 return true;
121}
122
123void Cogs::Memory::MemoryBuffer::copy(const MemoryBuffer & other) {
124 resize(other.size(), false);
125
126 if (size()) {
127 std::memcpy(buffer, other.buffer, currentSize);
128 }
129 type = other.type;
130}
131
132void Cogs::Memory::MemoryBuffer::swap(MemoryBuffer & other) {
133 std::swap(buffer, other.buffer);
134 std::swap(storageSize, other.storageSize);
135 std::swap(currentSize, other.currentSize);
136 std::swap(currentPos, other.currentPos);
137 std::swap(allocator, other.allocator);
138 std::swap(type, other.type);
139}
140
141size_t Cogs::Memory::MemoryBuffer::read(void* dest, size_t noofbytes) {
142 size_t bytesRead = std::min(noofbytes, unreadSize());
143
144 std::memcpy(dest, static_cast<uint8_t*>(buffer) + currentPos, bytesRead);
145 currentPos += bytesRead;
146
147 return bytesRead;
148}
149
150glm::vec2 Cogs::Memory::MemoryBuffer::readFloat2() {
151 glm::vec2 v;
152
153 v.x = readFloat();
154 v.y = readFloat();
155 return v;
156}
157
158glm::vec3 Cogs::Memory::MemoryBuffer::readFloat3() {
159 glm::vec3 v;
160
161 for (int i = 0; i < 3; ++i) {
162 v[i] = readFloat();
163 }
164 return v;
165}
166
167glm::vec4 Cogs::Memory::MemoryBuffer::readFloat4() {
168 glm::vec4 v;
169
170 for (int i = 0; i < 4; ++i) {
171 v[i] = readFloat();
172 }
173 return v;
174}
175
176glm::quat Cogs::Memory::MemoryBuffer::readQuaternion() {
177 glm::quat q;
178
179 for (int i = 0; i < 4; ++i) {
180 q[i] = readFloat();
181 }
182 return q;
183}
184
185glm::mat4 Cogs::Memory::MemoryBuffer::readMatrix() {
186 glm::mat4 m;
187
188 for (int col = 0; col < 4; ++col) {
189 m[col] = readFloat4();
190 }
191 return m;
192}
193
194std::string Cogs::Memory::MemoryBuffer::readString() {
195 size_t length = read32();
196 std::string str;
197
198 if (length) {
199 str.resize(--length);
200 read(str.data(), length);
201
202 // Historically strings were written to MemoryBuffer with null-terminators. For backwards compatibility
203 // with older versions of ProximityView this functionality needs to be kept. So skip over the null-
204 // terminator we didn't read above.
205 ++currentPos;
206 }
207 return str;
208}
209
210bool Cogs::Memory::MemoryBuffer::write(const void* src, size_t bytes) {
211 if (!allocator) {
212 return false;
213 }
214 if ((currentSize + bytes) > storageSize) {
215 if (!reserve(std::max<size_t>(1024, std::max<size_t>(currentSize + bytes, storageSize * 3 / 2)))) {
216 return false;
217 }
218 }
219 memcpy(static_cast<uint8_t*>(buffer) + currentPos, src, bytes);
220 currentPos += bytes;
221 currentSize = currentPos;
222 return true;
223}
224
225bool Cogs::Memory::MemoryBuffer::writeFloat2(const glm::vec2& value) {
226 bool result = true;
227
228 result &= writeFloat(value.x);
229 result &= writeFloat(value.y);
230
231 return result;
232}
233
234bool Cogs::Memory::MemoryBuffer::writeFloat3(const glm::vec3& value) {
235 bool result = true;
236
237 for (int i = 0; i < 3; ++i) {
238 result &= writeFloat(value[i]);
239 }
240 return result;
241}
242
243bool Cogs::Memory::MemoryBuffer::writeFloat4(const glm::vec4& value) {
244 bool result = true;
245
246 for (int i = 0; i < 4; ++i) {
247 result &= writeFloat(value[i]);
248 }
249 return result;
250}
251
252bool Cogs::Memory::MemoryBuffer::writeQuaternion(const glm::quat& value) {
253 bool result = true;
254
255 for (int i = 0; i < 4; ++i) {
256 result &= writeFloat(value[i]);
257 }
258 return result;
259}
260
261bool Cogs::Memory::MemoryBuffer::writeMatrix(const glm::mat4& value) {
262 bool result = true;
263
264 for (int col = 0; col < 4; ++col) {
265 result &= writeFloat4(value[col]);
266 }
267 return result;
268}
269
270bool Cogs::Memory::MemoryBuffer::writeString(const StringView& str) {
271 size_t length = str.size();
272 bool success = true;
273
274 // Strings, unfortunately, need to be written with null-terminators to ensure newer versions
275 // of ProximityView are binary compatible with older versions installed on customer vessels.
276 success &= write32(static_cast<uint32_t>(length + 1));
277 success &= write(str.data(), length);
278 success &= write8(0);
279
280 return success;
281}
282
283void Cogs::Memory::MemoryBuffer::seek(int64_t offset, Anchor from) {
284 switch (from) {
285 case Anchor::Start: currentPos = offset; break;
286 case Anchor::Current: currentPos += offset; break;
287 case Anchor::End: currentPos = currentSize + offset; break;
288 }
289 currentPos = std::clamp<int64_t>(currentPos, 0, currentSize);
290}
291
292bool Cogs::Memory::MemoryBuffer::areContentsEqual(const MemoryBuffer& rhs) const {
293 if (size() == rhs.size()) {
294 return !memcmp(data(), rhs.data(), size());
295 }
296 return false;
297}
298
299void Cogs::Memory::MemoryBuffer::release() {
300 if (buffer) {
301 if (allocator) {
302 allocator->deallocate(buffer, storageSize, type);
303 }
304 buffer = nullptr;
305 storageSize = 0;
306 currentSize = 0;
307 }
308}
309
310void Cogs::Memory::MemoryBuffer::changeType(MemBlockType newType)
311{
312 if (buffer && allocator) {
313 allocator->changeType(buffer, storageSize, type, newType);
314 }
315 type = newType;
316}