VirtualC64 v5.0 beta
Commodore 64 Emulator
Loading...
Searching...
No Matches
Serializable.h
1// -----------------------------------------------------------------------------
2// This file is part of VirtualC64
3//
4// Copyright (C) Dirk W. Hoffmann. www.dirkwhoffmann.de
5// This FILE is dual-licensed. You are free to choose between:
6//
7// - The GNU General Public License v3 (or any later version)
8// - The Mozilla Public License v2
9//
10// SPDX-License-Identifier: GPL-3.0-or-later OR MPL-2.0
11// -----------------------------------------------------------------------------
12
13#pragma once
14
15#include "Macros.h"
16#include "MemUtils.h"
17#include "Buffer.h"
18#include <vector>
19
20namespace vc64 {
21
22class Serializable {
23
24public:
25
26 virtual ~Serializable() = default;
27
28 // Serialization operators (to be implemented by the subclass)
29 virtual void operator << (class SerCounter &worker) = 0;
30 virtual void operator << (class SerChecker &worker) = 0;
31 virtual void operator << (class SerResetter &worker) = 0;
32 virtual void operator << (class SerReader &worker) = 0;
33 virtual void operator << (class SerWriter &worker) = 0;
34
35 // Zeroes out all items
36 void hardReset();
37 void softReset();
38
39 // Calculates the snapshot size
40 isize size();
41
42 // Computes a checksum
43 u64 checksum();
44
45 // Recreates the component from a buffer
46 isize load(const u8 *buffer);
47
48 // Serializes the component into a buffer
49 isize save(u8 *buffer);
50};
51
52
53//
54// Basic memory buffer I/O
55//
56
57inline u8 read8(const u8 *& buf)
58{
59 u8 result = R8BE(buf);
60 buf += 1;
61 return result;
62}
63
64inline u16 read16(const u8 *& buf)
65{
66 u16 result = R16BE(buf);
67 buf += 2;
68 return result;
69}
70
71inline u32 read32(const u8 *& buf)
72{
73 u32 result = R32BE(buf);
74 buf += 4;
75 return result;
76}
77
78inline u64 read64(const u8 *& buf)
79{
80 u32 hi = read32(buf);
81 u32 lo = read32(buf);
82 return ((u64)hi << 32) | lo;
83}
84
85inline double readDouble(const u8 *& buf)
86{
87 double result = 0;
88 for (isize i = 0; i < 8; i++) ((u8 *)&result)[i] = read8(buf);
89 return result;
90}
91
92inline string readString(const u8 *& buf)
93{
94 u8 len = read8(buf);
95 string result = string((const char *)buf, len);
96 buf += len;
97 return result;
98}
99
100inline void write8(u8 *& buf, u8 value)
101{
102 W8BE(buf, value);
103 buf += 1;
104}
105
106inline void write16(u8 *& buf, u16 value)
107{
108 W16BE(buf, value);
109 buf += 2;
110}
111
112inline void write32(u8 *& buf, u32 value)
113{
114 W32BE(buf, value);
115 buf += 4;
116}
117
118inline void write64(u8 *& buf, u64 value)
119{
120 write32(buf, (u32)(value >> 32));
121 write32(buf, (u32)(value));
122}
123
124inline void writeDouble(u8 *& buf, double value)
125{
126 for (isize i = 0; i < 8; i++) write8(buf, ((u8 *)&value)[i]);
127}
128
129inline void writeString(u8 *& buf, string value)
130{
131 auto len = value.length();
132 write8(buf, u8(len));
133 value.copy((char *)buf, len);
134 buf += len;
135}
136
137
138//
139// Counter (determines the state size)
140//
141
142#define COUNT(type,size) \
143auto& operator<<(type& v) \
144{ \
145count += size; \
146return *this; \
147}
148
149#define COUNT8(type) static_assert(sizeof(type) == 1); COUNT(type,1)
150#define COUNT16(type) static_assert(sizeof(type) == 2); COUNT(type,2)
151#define COUNT64(type) static_assert(sizeof(type) <= 8); COUNT(type,8)
152#define COUNTD(type) static_assert(sizeof(type) <= 8); COUNT(type,8)
153
154class SerCounter
155{
156public:
157
158 isize count;
159
160 SerCounter() { count = 0; }
161
162 COUNT8(const bool)
163 COUNT8(const char)
164 COUNT8(const signed char)
165 COUNT8(const unsigned char)
166 COUNT16(const short)
167 COUNT16(const unsigned short)
168 COUNT64(const int)
169 COUNT64(const unsigned int)
170 COUNT64(const long)
171 COUNT64(const unsigned long)
172 COUNT64(const long long)
173 COUNT64(const unsigned long long)
174 COUNTD(const float)
175 COUNTD(const double)
176
177 template <class T>
178 auto& operator<<(util::Allocator<T> &a)
179 {
180 count += 8 + a.size;
181 return *this;
182 }
183
184 auto& operator<<(string &v)
185 {
186 auto len = v.length();
187 count += 1 + isize(len);
188 return *this;
189 }
190
191 template <class T>
192 auto& operator<<(std::vector <T> &v)
193 {
194 auto len = v.size();
195 for(usize i = 0; i < len; i++) *this << v[i];
196 count += 8;
197 return *this;
198 }
199
200 template <class T, isize N>
201 SerCounter& operator<<(T (&v)[N])
202 {
203 for(isize i = 0; i < N; ++i) {
204 *this << v[i];
205 }
206 return *this;
207 }
208
209 template <class E, class = std::enable_if_t<std::is_enum<E>{}>>
210 SerCounter& operator<<(E &v)
211 {
212 count += sizeof(long);
213 return *this;
214 }
215
216 template <std::derived_from<Serializable> T>
217 SerCounter& operator<<(T &v)
218 {
219 v << *this;
220 return *this;
221 }
222};
223
224
225//
226// Checksum generator
227//
228
229#define CHECK(type) \
230auto& operator<<(type& v) \
231{ \
232hash = util::fnvIt64(hash, (u64)v); \
233return *this; \
234}
235
236class SerChecker
237{
238public:
239
240 u64 hash;
241
242 SerChecker() { hash = util::fnvInit64(); }
243
244 CHECK(const bool)
245 CHECK(const char)
246 CHECK(const signed char)
247 CHECK(const unsigned char)
248 CHECK(const short)
249 CHECK(const unsigned short)
250 CHECK(const int)
251 CHECK(const unsigned int)
252 CHECK(const long)
253 CHECK(const unsigned long)
254 CHECK(const long long)
255 CHECK(const unsigned long long)
256 CHECK(const float)
257 CHECK(const double)
258
259 template <class T>
260 auto& operator<<(util::Allocator<T> &a)
261 {
262 hash = util::fnvIt64(hash, a.fnv64());
263 return *this;
264 }
265
266 auto& operator<<(string &v)
267 {
268 auto len = v.length();
269 for (usize i = 0; i < len; i++) {
270 hash = util::fnvIt64(hash, v[i]);
271 }
272 return *this;
273 }
274
275 template <class T>
276 auto& operator<<(std::vector <T> &v)
277 {
278 isize len = isize(v.size());
279 for (isize i = 0; i < len; i++) {
280 *this << v[i];
281 }
282 return *this;
283 }
284
285 template <class T, isize N>
286 SerChecker& operator<<(T (&v)[N])
287 {
288 for(isize i = 0; i < N; ++i) {
289 *this << v[i];
290 }
291 return *this;
292 }
293
294 template <class E, class = std::enable_if_t<std::is_enum<E>{}>>
295 SerChecker& operator<<(E &v)
296 {
297 hash = util::fnvIt64(hash, v);
298 return *this;
299 }
300
301 template <std::derived_from<Serializable> T>
302 SerChecker& operator<<(T &v)
303 {
304 v << *this;
305 return *this;
306 }
307};
308
309
310//
311// Reader (Deserializer)
312//
313
314#define DESERIALIZE(type,function) \
315SerReader& operator<<(type& v) \
316{ \
317v = (type)function(ptr); \
318return *this; \
319}
320
321#define DESERIALIZE8(type) static_assert(sizeof(type) == 1); DESERIALIZE(type,read8)
322#define DESERIALIZE16(type) static_assert(sizeof(type) == 2); DESERIALIZE(type,read16)
323#define DESERIALIZE64(type) static_assert(sizeof(type) <= 8); DESERIALIZE(type,read64)
324#define DESERIALIZED(type) static_assert(sizeof(type) <= 8); DESERIALIZE(type,readDouble)
325
326class SerReader
327{
328public:
329
330 const u8 *ptr;
331
332 SerReader(const u8 *p) : ptr(p)
333 {
334 }
335
336 DESERIALIZE8(bool)
337 DESERIALIZE8(char)
338 DESERIALIZE8(signed char)
339 DESERIALIZE8(unsigned char)
340 DESERIALIZE16(short)
341 DESERIALIZE16(unsigned short)
342 DESERIALIZE64(int)
343 DESERIALIZE64(unsigned int)
344 DESERIALIZE64(long)
345 DESERIALIZE64(unsigned long)
346 DESERIALIZE64(long long)
347 DESERIALIZE64(unsigned long long)
348 DESERIALIZED(float)
349 DESERIALIZED(double)
350
351 template <class T>
352 auto& operator<<(util::Allocator<T> &a)
353 {
354 i64 len;
355 *this << len;
356 a.init(ptr, isize(len));
357 ptr += len;
358 return *this;
359 }
360
361 auto& operator<<(string &v)
362 {
363 v = readString(ptr);
364 return *this;
365 }
366
367 template <class T>
368 auto& operator<<(std::vector <T> &v)
369 {
370 i64 len;
371 *this << len;
372 v.clear();
373 v.reserve(len);
374 for (isize i = 0; i < len; i++) {
375 v.push_back(T());
376 *this << v.back();
377 }
378 return *this;
379 }
380
381 template <class T, isize N>
382 SerReader& operator<<(T (&v)[N])
383 {
384 for(isize i = 0; i < N; ++i) {
385 *this << v[i];
386 }
387 return *this;
388 }
389
390 void copy(void *dst, isize n)
391 {
392 std::memcpy(dst, (void *)ptr, n);
393 ptr += n;
394 }
395
396 template <class E, class = std::enable_if_t<std::is_enum<E>{}>>
397 SerReader& operator<<(E &v)
398 {
399 v = (E)read64(ptr);
400 return *this;
401 }
402
403 template <std::derived_from<Serializable> T>
404 SerReader& operator<<(T &v)
405 {
406 v << *this;
407 return *this;
408 }
409};
410
411
412//
413// Writer (Serializer)
414//
415
416#define SERIALIZE(type,function,cast) \
417SerWriter& operator<<(type& v) \
418{ \
419function(ptr, (cast)v); \
420return *this; \
421}
422
423#define SERIALIZE8(type) static_assert(sizeof(type) == 1); SERIALIZE(type,write8,u8)
424#define SERIALIZE16(type) static_assert(sizeof(type) == 2); SERIALIZE(type,write16,u16)
425#define SERIALIZE64(type) static_assert(sizeof(type) <= 8); SERIALIZE(type,write64,u64)
426#define SERIALIZED(type) static_assert(sizeof(type) <= 8); SERIALIZE(type,writeDouble,double)
427
428class SerWriter
429{
430public:
431
432 u8 *ptr;
433
434 SerWriter(u8 *p) : ptr(p)
435 {
436 }
437
438 SERIALIZE8(const bool)
439 SERIALIZE8(const char)
440 SERIALIZE8(const signed char)
441 SERIALIZE8(const unsigned char)
442 SERIALIZE16(const short)
443 SERIALIZE16(const unsigned short)
444 SERIALIZE64(const int)
445 SERIALIZE64(const unsigned int)
446 SERIALIZE64(const long)
447 SERIALIZE64(const unsigned long)
448 SERIALIZE64(const long long)
449 SERIALIZE64(const unsigned long long)
450 SERIALIZED(const float)
451 SERIALIZED(const double)
452
453 template <class T>
454 auto& operator<<(util::Allocator<T> &a)
455 {
456 *this << i64(a.size);
457 a.copy(ptr);
458 ptr += a.size;
459 return *this;
460 }
461
462 auto& operator<<(const string &v)
463 {
464 writeString(ptr, v);
465 return *this;
466 }
467
468 template <class T>
469 auto& operator<<(std::vector <T> &v)
470 {
471 auto len = v.size();
472 *this << i64(len);
473 for (usize i = 0; i < len; i++) {
474 *this << v[i];
475 }
476 return *this;
477 }
478
479 template <class T, isize N>
480 SerWriter& operator<<(T (&v)[N])
481 {
482 for(isize i = 0; i < N; ++i) {
483 *this << v[i];
484 }
485 return *this;
486 }
487
488 template <class E, class = std::enable_if_t<std::is_enum<E>{}>>
489 SerWriter& operator<<(E &v)
490 {
491 write64(ptr, (long)v);
492 return *this;
493 }
494
495 template <std::derived_from<Serializable> T>
496 SerWriter& operator<<(T &v)
497 {
498 v << *this;
499 return *this;
500 }
501
502 void copy(const void *src, isize n)
503 {
504 std::memcpy((void *)ptr, src, n);
505 ptr += n;
506 }
507};
508
509
510//
511// Resetter
512//
513
514#define RESET(type) \
515SerResetter & operator<<(type& v) \
516{ \
517v = (type)0; \
518return *this; \
519}
520
521class SerResetter
522{
523protected:
524
525 SerResetter() { }
526 virtual ~SerResetter() = default;
527
528public:
529
530 RESET(bool)
531 RESET(char)
532 RESET(signed char)
533 RESET(unsigned char)
534 RESET(short)
535 RESET(unsigned short)
536 RESET(int)
537 RESET(unsigned int)
538 RESET(long)
539 RESET(unsigned long)
540 RESET(long long)
541 RESET(unsigned long long)
542 RESET(float)
543 RESET(double)
544
545 template <class T>
546 auto& operator<<(util::Allocator<T> &a)
547 {
548 a.clear();
549 return *this;
550 }
551
552 auto& operator<<(string &v)
553 {
554 v = "";
555 return *this;
556 }
557
558 template <class T>
559 auto& operator<<(std::vector <T> &v)
560 {
561 v.clear();
562 return *this;
563 }
564
565 template <class T, isize N>
566 SerResetter & operator<<(T (&v)[N])
567 {
568 for(isize i = 0; i < N; ++i) {
569 *this << v[i];
570 }
571 return *this;
572 }
573
574 template <class E, class = std::enable_if_t<std::is_enum<E>{}>>
575 SerResetter& operator<<(E &v)
576 {
577 v = (E)0;
578 return *this;
579 }
580
581 template <std::derived_from<Serializable> T>
582 SerResetter & operator<<(T &v)
583 {
584 v << *this;
585 return *this;
586 }
587};
588
589class SerSoftResetter : public SerResetter
590{
591public:
592 SerSoftResetter() { }
593};
594
595class SerHardResetter : public SerResetter
596{
597public:
598 SerHardResetter() { }
599};
600
601template <class T>
602static constexpr bool isSoftResetter(T &worker) {
603
604 auto &id = typeid(worker);
605 return id == typeid(SerSoftResetter);
606}
607
608template <class T>
609static constexpr bool isHardResetter(T &worker) {
610
611 auto &id = typeid(worker);
612 return id == typeid(SerHardResetter);
613}
614
615template <class T>
616static constexpr bool isResetter(T &worker) {
617 return isSoftResetter(worker) || isHardResetter(worker);
618}
619
620template <class T>
621static constexpr bool isChecker(T &worker) {
622 return typeid(worker) == typeid(SerChecker);
623}
624
625}
626
627#define SERIALIZERS(fn) \
628void operator << (SerChecker &worker) override { fn(worker); } \
629void operator << (SerCounter &worker) override { fn(worker); } \
630void operator << (SerResetter &worker) override { fn(worker); } \
631void operator << (SerReader &worker) override { fn(worker); } \
632void operator << (SerWriter &worker) override { fn(worker); }
633
634#define CARTRIDGE_SERIALIZERS(fn) \
635void operator << (SerChecker &worker) override { Cartridge::operator<<(worker); fn(worker); } \
636void operator << (SerCounter &worker) override { Cartridge::operator<<(worker); fn(worker); } \
637void operator << (SerResetter &worker) override { Cartridge::operator<<(worker); fn(worker); } \
638void operator << (SerReader &worker) override { Cartridge::operator<<(worker); fn(worker); } \
639void operator << (SerWriter &worker) override { Cartridge::operator<<(worker); fn(worker); }
640
641#define CLONE(x) x = other.x;
642#define CLONE_ARRAY(x) std::copy(std::begin(other.x), std::end(other.x), std::begin(x));
VirtualC64 project namespace.
Definition CmdQueue.cpp:16