Bitcoin ABC 0.32.5
P2P Digital Currency
serialize.h
Go to the documentation of this file.
1// Copyright (c) 2009-2010 Satoshi Nakamoto
2// Copyright (c) 2009-2016 The Bitcoin Core developers
3// Distributed under the MIT software license, see the accompanying
4// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6#ifndef BITCOIN_SERIALIZE_H
7#define BITCOIN_SERIALIZE_H
8
9#include <attributes.h>
10#include <compat/assumptions.h>
11#include <compat/endian.h>
12#include <prevector.h>
13#include <rcu.h>
14#include <span.h>
15
16#include <algorithm>
17#include <array>
18#include <concepts>
19#include <cstdint>
20#include <cstring>
21#include <ios>
22#include <limits>
23#include <map>
24#include <memory>
25#include <set>
26#include <string>
27#include <utility>
28#include <vector>
29
34static constexpr uint64_t MAX_SIZE = 0x02000000;
35
40static const unsigned int MAX_VECTOR_ALLOCATE = 5000000;
41
54
58template <typename Stream> inline void ser_writedata8(Stream &s, uint8_t obj) {
59 s.write(AsBytes(Span{&obj, 1}));
60}
61template <typename Stream>
62inline void ser_writedata16(Stream &s, uint16_t obj) {
63 obj = htole16_internal(obj);
64 s.write(AsBytes(Span{&obj, 1}));
65}
66template <typename Stream>
67inline void ser_writedata16be(Stream &s, uint16_t obj) {
68 obj = htobe16_internal(obj);
69 s.write(AsBytes(Span{&obj, 1}));
70}
71template <typename Stream>
72inline void ser_writedata32(Stream &s, uint32_t obj) {
73 obj = htole32_internal(obj);
74 s.write(AsBytes(Span{&obj, 1}));
75}
76template <typename Stream>
77inline void ser_writedata32be(Stream &s, uint32_t obj) {
78 obj = htobe32_internal(obj);
79 s.write(AsBytes(Span{&obj, 1}));
80}
81template <typename Stream>
82inline void ser_writedata64(Stream &s, uint64_t obj) {
83 obj = htole64_internal(obj);
84 s.write(AsBytes(Span{&obj, 1}));
85}
86template <typename Stream> inline uint8_t ser_readdata8(Stream &s) {
87 uint8_t obj;
88 s.read(AsWritableBytes(Span{&obj, 1}));
89 return obj;
90}
91template <typename Stream> inline uint16_t ser_readdata16(Stream &s) {
92 uint16_t obj;
93 s.read(AsWritableBytes(Span{&obj, 1}));
94 return le16toh_internal(obj);
95}
96template <typename Stream> inline uint16_t ser_readdata16be(Stream &s) {
97 uint16_t obj;
98 s.read(AsWritableBytes(Span{&obj, 1}));
99 return be16toh_internal(obj);
100}
101template <typename Stream> inline uint32_t ser_readdata32(Stream &s) {
102 uint32_t obj;
103 s.read(AsWritableBytes(Span{&obj, 1}));
104 return le32toh_internal(obj);
105}
106template <typename Stream> inline uint32_t ser_readdata32be(Stream &s) {
107 uint32_t obj;
108 s.read(AsWritableBytes(Span{&obj, 1}));
109 return be32toh_internal(obj);
110}
111template <typename Stream> inline uint64_t ser_readdata64(Stream &s) {
112 uint64_t obj;
113 s.read(AsWritableBytes(Span{&obj, 1}));
114 return le64toh_internal(obj);
115}
116inline uint64_t ser_double_to_uint64(double x) {
117 uint64_t tmp;
118 std::memcpy(&tmp, &x, sizeof(x));
119 static_assert(sizeof(tmp) == sizeof(x),
120 "double and uint64_t assumed to have the same size");
121 return tmp;
122}
123inline uint32_t ser_float_to_uint32(float x) {
124 uint32_t tmp;
125 std::memcpy(&tmp, &x, sizeof(x));
126 static_assert(sizeof(tmp) == sizeof(x),
127 "float and uint32_t assumed to have the same size");
128 return tmp;
129}
130inline double ser_uint64_to_double(uint64_t y) {
131 double tmp;
132 std::memcpy(&tmp, &y, sizeof(y));
133 static_assert(sizeof(tmp) == sizeof(y),
134 "double and uint64_t assumed to have the same size");
135 return tmp;
136}
137inline float ser_uint32_to_float(uint32_t y) {
138 float tmp;
139 std::memcpy(&tmp, &y, sizeof(y));
140 static_assert(sizeof(tmp) == sizeof(y),
141 "float and uint32_t assumed to have the same size");
142 return tmp;
143}
144
146//
147// Templates for serializing to anything that looks like a stream,
148// i.e. anything that supports .read(Span<std::byte>) and .write(Span<const
149// std::byte>)
150//
151class CSizeComputer;
152
153enum {
154 // primary actions
155 SER_NETWORK = (1 << 0),
156 SER_DISK = (1 << 1),
157 SER_GETHASH = (1 << 2),
158};
159
180template <class Out, class In> Out &AsBase(In &x) {
181 static_assert(std::is_base_of_v<Out, In>);
182 return x;
183}
184template <class Out, class In> const Out &AsBase(const In &x) {
185 static_assert(std::is_base_of_v<Out, In>);
186 return x;
187}
188
189#define READWRITE(...) (::SerReadWriteMany(s, ser_action, __VA_ARGS__))
190#define SER_READ(obj, code) \
191 ::SerRead( \
192 s, ser_action, obj, \
193 [&](Stream &s, typename std::remove_const<Type>::type &obj) { code; })
194#define SER_WRITE(obj, code) \
195 ::SerWrite(s, ser_action, obj, [&](Stream &s, const Type &obj) { code; })
196
215#define FORMATTER_METHODS(cls, obj) \
216 template <typename Stream> static void Ser(Stream &s, const cls &obj) { \
217 SerializationOps(obj, s, ActionSerialize()); \
218 } \
219 template <typename Stream> static void Unser(Stream &s, cls &obj) { \
220 SerializationOps(obj, s, ActionUnserialize()); \
221 } \
222 template <typename Stream, typename Type, typename Operation> \
223 static void SerializationOps(Type &obj, Stream &s, Operation ser_action)
224
258#define FORMATTER_METHODS_PARAMS(cls, obj, paramcls, paramobj) \
259 template <typename Stream> static void Ser(Stream &s, const cls &obj) { \
260 SerializationOps(obj, s, ActionSerialize{}, s.GetParams()); \
261 } \
262 template <typename Stream> static void Unser(Stream &s, cls &obj) { \
263 SerializationOps(obj, s, ActionUnserialize{}, s.GetParams()); \
264 } \
265 template <typename Stream, typename Type, typename Operation> \
266 static void SerializationOps(Type &obj, Stream &s, Operation ser_action, \
267 const paramcls &paramobj)
268
269#define BASE_SERIALIZE_METHODS(cls) \
270 template <typename Stream> void Serialize(Stream &s) const { \
271 static_assert(std::is_same<const cls &, decltype(*this)>::value, \
272 "Serialize type mismatch"); \
273 Ser(s, *this); \
274 } \
275 template <typename Stream> void Unserialize(Stream &s) { \
276 static_assert(std::is_same<cls &, decltype(*this)>::value, \
277 "Unserialize type mismatch"); \
278 Unser(s, *this); \
279 }
280
289#define SERIALIZE_METHODS(cls, obj) \
290 BASE_SERIALIZE_METHODS(cls) \
291 FORMATTER_METHODS(cls, obj)
292
298#define SERIALIZE_METHODS_PARAMS(cls, obj, paramcls, paramobj) \
299 BASE_SERIALIZE_METHODS(cls) \
300 FORMATTER_METHODS_PARAMS(cls, obj, paramcls, paramobj)
301
302// Typically int8_t and char are distinct types, but some systems may define
303// int8_t in terms of char. Forbid serialization of char in the typical case,
304// but allow it if it's the only way to describe an int8_t.
305template <class T>
306concept CharNotInt8 = std::same_as<T, char> && !std::same_as<T, int8_t>;
307
308// char serialization forbidden. Use uint8_t or int8_t
309template <typename Stream, CharNotInt8 V> void Serialize(Stream &, V) = delete;
310template <typename Stream> void Serialize(Stream &s, std::byte a) {
311 ser_writedata8(s, uint8_t(a));
312}
313template <typename Stream> inline void Serialize(Stream &s, int8_t a) {
314 ser_writedata8(s, a);
315}
316template <typename Stream> inline void Serialize(Stream &s, uint8_t a) {
317 ser_writedata8(s, a);
318}
319template <typename Stream> inline void Serialize(Stream &s, int16_t a) {
320 ser_writedata16(s, a);
321}
322template <typename Stream> inline void Serialize(Stream &s, uint16_t a) {
323 ser_writedata16(s, a);
324}
325template <typename Stream> inline void Serialize(Stream &s, int32_t a) {
326 ser_writedata32(s, a);
327}
328template <typename Stream> inline void Serialize(Stream &s, uint32_t a) {
329 ser_writedata32(s, a);
330}
331template <typename Stream> inline void Serialize(Stream &s, int64_t a) {
332 ser_writedata64(s, a);
333}
334template <typename Stream> inline void Serialize(Stream &s, uint64_t a) {
335 ser_writedata64(s, a);
336}
337template <typename Stream> inline void Serialize(Stream &s, float a) {
339}
340template <typename Stream> inline void Serialize(Stream &s, double a) {
342}
343template <typename Stream, size_t N>
344inline void Serialize(Stream &s, const int8_t (&a)[N]) {
345 s.write(a, N);
346}
347template <typename Stream, BasicByte B, size_t N>
348void Serialize(Stream &s, const B (&a)[N]) {
349 s.write(MakeByteSpan(a));
350}
351template <typename Stream, size_t N>
352inline void Serialize(Stream &s, const std::array<int8_t, N> &a) {
353 s.write(a.data(), N);
354}
355template <typename Stream, size_t N>
356inline void Serialize(Stream &s, const std::array<uint8_t, N> &a) {
357 s.write(MakeByteSpan(a));
358}
359template <typename Stream, BasicByte B, std::size_t N>
360void Serialize(Stream &s, const std::array<B, N> &a) {
361 s.write(MakeByteSpan(a));
362}
363template <typename Stream, BasicByte B>
364void Serialize(Stream &s, Span<B> span) {
365 s.write(AsBytes(span));
366}
367
368// char serialization forbidden. Use uint8_t or int8_t
369template <typename Stream, CharNotInt8 V>
370void Unserialize(Stream &, V) = delete;
371template <typename Stream> void Unserialize(Stream &s, std::byte &a) {
372 a = std::byte{ser_readdata8(s)};
373}
374template <typename Stream> inline void Unserialize(Stream &s, int8_t &a) {
375 a = ser_readdata8(s);
376}
377template <typename Stream> inline void Unserialize(Stream &s, uint8_t &a) {
378 a = ser_readdata8(s);
379}
380template <typename Stream> inline void Unserialize(Stream &s, int16_t &a) {
381 a = ser_readdata16(s);
382}
383template <typename Stream> inline void Unserialize(Stream &s, uint16_t &a) {
384 a = ser_readdata16(s);
385}
386template <typename Stream> inline void Unserialize(Stream &s, int32_t &a) {
387 a = ser_readdata32(s);
388}
389template <typename Stream> inline void Unserialize(Stream &s, uint32_t &a) {
390 a = ser_readdata32(s);
391}
392template <typename Stream> inline void Unserialize(Stream &s, int64_t &a) {
393 a = ser_readdata64(s);
394}
395template <typename Stream> inline void Unserialize(Stream &s, uint64_t &a) {
396 a = ser_readdata64(s);
397}
398template <typename Stream> inline void Unserialize(Stream &s, float &a) {
400}
401template <typename Stream> inline void Unserialize(Stream &s, double &a) {
403}
404template <typename Stream, size_t N>
405inline void Unserialize(Stream &s, int8_t (&a)[N]) {
406 s.read(MakeWritableByteSpan(a));
407}
408template <typename Stream, BasicByte B, size_t N>
409void Unserialize(Stream &s, B (&a)[N]) {
410 s.read(MakeWritableByteSpan(a));
411}
412
413template <typename Stream> inline void Serialize(Stream &s, bool a) {
414 char f = a;
415 ser_writedata8(s, f);
416}
417template <typename Stream> inline void Unserialize(Stream &s, bool &a) {
418 char f = ser_readdata8(s);
419 a = f;
420}
421template <typename Stream, BasicByte B, std::size_t N>
422void Unserialize(Stream &s, std::array<B, N> &a) {
423 s.read(MakeWritableByteSpan(a));
424}
425template <typename Stream, BasicByte B>
426void Unserialize(Stream &s, Span<B> span) {
427 s.read(AsWritableBytes(span));
428}
429
437inline uint32_t GetSizeOfCompactSize(uint64_t nSize) {
438 if (nSize < 253) {
439 return sizeof(uint8_t);
440 }
441 if (nSize <= std::numeric_limits<uint16_t>::max()) {
442 return sizeof(uint8_t) + sizeof(uint16_t);
443 }
444 if (nSize <= std::numeric_limits<uint32_t>::max()) {
445 return sizeof(uint8_t) + sizeof(uint32_t);
446 }
447
448 return sizeof(uint8_t) + sizeof(uint64_t);
449}
450
451inline void WriteCompactSize(CSizeComputer &os, uint64_t nSize);
452
453template <typename Stream> void WriteCompactSize(Stream &os, uint64_t nSize) {
454 if (nSize < 253) {
456 } else if (nSize <= std::numeric_limits<uint16_t>::max()) {
457 ser_writedata8(os, 253);
459 } else if (nSize <= std::numeric_limits<uint32_t>::max()) {
460 ser_writedata8(os, 254);
462 } else {
463 ser_writedata8(os, 255);
465 }
466 return;
467}
468
476template <typename Stream>
477uint64_t ReadCompactSize(Stream &is, bool range_check = true) {
478 uint8_t chSize = ser_readdata8(is);
479 uint64_t nSizeRet = 0;
480 if (chSize < 253) {
481 nSizeRet = chSize;
482 } else if (chSize == 253) {
483 nSizeRet = ser_readdata16(is);
484 if (nSizeRet < 253) {
485 throw std::ios_base::failure("non-canonical ReadCompactSize()");
486 }
487 } else if (chSize == 254) {
488 nSizeRet = ser_readdata32(is);
489 if (nSizeRet < 0x10000u) {
490 throw std::ios_base::failure("non-canonical ReadCompactSize()");
491 }
492 } else {
493 nSizeRet = ser_readdata64(is);
494 if (nSizeRet < 0x100000000ULL) {
495 throw std::ios_base::failure("non-canonical ReadCompactSize()");
496 }
497 }
498 if (range_check && nSizeRet > MAX_SIZE) {
499 throw std::ios_base::failure("ReadCompactSize(): size too large");
500 }
501 return nSizeRet;
502}
503
539
540template <VarIntMode Mode, typename I> struct CheckVarIntMode {
541 constexpr CheckVarIntMode() {
542 static_assert(Mode != VarIntMode::DEFAULT || std::is_unsigned<I>::value,
543 "Unsigned type required with mode DEFAULT.");
544 static_assert(Mode != VarIntMode::NONNEGATIVE_SIGNED ||
545 std::is_signed<I>::value,
546 "Signed type required with mode NONNEGATIVE_SIGNED.");
547 }
548};
549
550template <VarIntMode Mode, typename I>
551inline unsigned int GetSizeOfVarInt(I n) {
553 int nRet = 0;
554 while (true) {
555 nRet++;
556 if (n <= 0x7F) {
557 return nRet;
558 }
559 n = (n >> 7) - 1;
560 }
561}
562
563template <typename I> inline void WriteVarInt(CSizeComputer &os, I n);
564
565template <typename Stream, VarIntMode Mode, typename I>
566void WriteVarInt(Stream &os, I n) {
568 uint8_t tmp[(sizeof(n) * 8 + 6) / 7];
569 int len = 0;
570 while (true) {
571 tmp[len] = (n & 0x7F) | (len ? 0x80 : 0x00);
572 if (n <= 0x7F) {
573 break;
574 }
575 n = (n >> 7) - 1;
576 len++;
577 }
578 do {
579 ser_writedata8(os, tmp[len]);
580 } while (len--);
581}
582
583template <typename Stream, VarIntMode Mode, typename I>
584I ReadVarInt(Stream &is) {
586 I n = 0;
587 while (true) {
588 uint8_t chData = ser_readdata8(is);
589 if (n > (std::numeric_limits<I>::max() >> 7)) {
590 throw std::ios_base::failure("ReadVarInt(): size too large");
591 }
592 n = (n << 7) | (chData & 0x7F);
593 if ((chData & 0x80) == 0) {
594 return n;
595 }
596 if (n == std::numeric_limits<I>::max()) {
597 throw std::ios_base::failure("ReadVarInt(): size too large");
598 }
599 n++;
600 }
601}
602
607template <typename Formatter, typename T> class Wrapper {
608 static_assert(std::is_lvalue_reference<T>::value,
609 "Wrapper needs an lvalue reference type T");
610
611protected:
613
614public:
615 explicit Wrapper(T obj) : m_object(obj) {}
616 template <typename Stream> void Serialize(Stream &s) const {
617 Formatter().Ser(s, m_object);
618 }
619 template <typename Stream> void Unserialize(Stream &s) {
620 Formatter().Unser(s, m_object);
621 }
622};
623
637template <typename Formatter, typename T>
638static inline Wrapper<Formatter, T &> Using(T &&t) {
639 return Wrapper<Formatter, T &>(t);
640}
641
642#define VARINT_MODE(obj, mode) Using<VarIntFormatter<mode>>(obj)
643#define VARINT(obj) Using<VarIntFormatter<VarIntMode::DEFAULT>>(obj)
644#define COMPACTSIZE(obj) Using<CompactSizeFormatter<true>>(obj)
645#define LIMITED_STRING(obj, n) Using<LimitedStringFormatter<n>>(obj)
646
650template <VarIntMode Mode> struct VarIntFormatter {
651 template <typename Stream, typename I> void Ser(Stream &s, I v) {
652 WriteVarInt<Stream, Mode, typename std::remove_cv<I>::type>(s, v);
653 }
654
655 template <typename Stream, typename I> void Unser(Stream &s, I &v) {
656 v = ReadVarInt<Stream, Mode, typename std::remove_cv<I>::type>(s);
657 }
658};
659
670template <int Bytes, bool BigEndian = false> struct CustomUintFormatter {
671 static_assert(Bytes > 0 && Bytes <= 8,
672 "CustomUintFormatter Bytes out of range");
673 static constexpr uint64_t MAX = 0xffffffffffffffff >> (8 * (8 - Bytes));
674
675 template <typename Stream, typename I> void Ser(Stream &s, I v) {
676 if (v < 0 || v > MAX) {
677 throw std::ios_base::failure(
678 "CustomUintFormatter value out of range");
679 }
680 if (BigEndian) {
681 uint64_t raw = htobe64_internal(v);
682 s.write({BytePtr(&raw) + 8 - Bytes, Bytes});
683 } else {
684 uint64_t raw = htole64_internal(v);
685 s.write({BytePtr(&raw), Bytes});
686 }
687 }
688
689 template <typename Stream, typename I> void Unser(Stream &s, I &v) {
690 using U = typename std::conditional<std::is_enum<I>::value,
691 std::underlying_type<I>,
692 std::common_type<I>>::type::type;
693 static_assert(std::numeric_limits<U>::max() >= MAX &&
694 std::numeric_limits<U>::min() <= 0,
695 "Assigned type too small");
696 uint64_t raw = 0;
697 if (BigEndian) {
698 s.read({BytePtr(&raw) + 8 - Bytes, Bytes});
699 v = static_cast<I>(be64toh_internal(raw));
700 } else {
701 s.read({BytePtr(&raw), Bytes});
702 v = static_cast<I>(le64toh_internal(raw));
703 }
704 }
705};
706
707template <int Bytes>
709
711template <bool RangeCheck> struct CompactSizeFormatter {
712 template <typename Stream, typename I> void Unser(Stream &s, I &v) {
713 uint64_t n = ReadCompactSize<Stream>(s, RangeCheck);
714 if (n < std::numeric_limits<I>::min() ||
715 n > std::numeric_limits<I>::max()) {
716 throw std::ios_base::failure("CompactSize exceeds limit of type");
717 }
718 v = n;
719 }
720
721 template <typename Stream, typename I> void Ser(Stream &s, I v) {
722 static_assert(std::is_unsigned<I>::value,
723 "CompactSize only supported for unsigned integers");
724 static_assert(std::numeric_limits<I>::max() <=
725 std::numeric_limits<uint64_t>::max(),
726 "CompactSize only supports 64-bit integers and below");
727
728 WriteCompactSize<Stream>(s, v);
729 }
730};
731
732template <typename U, bool LOSSY = false> struct ChronoFormatter {
733 template <typename Stream, typename Tp> void Unser(Stream &s, Tp &tp) {
734 U u;
735 s >> u;
736 // Lossy deserialization does not make sense, so force Wnarrowing
737 tp = Tp{typename Tp::duration{typename Tp::duration::rep{u}}};
738 }
739 template <typename Stream, typename Tp> void Ser(Stream &s, Tp tp) {
740 if constexpr (LOSSY) {
741 s << U(tp.time_since_epoch().count());
742 } else {
743 s << U{tp.time_since_epoch().count()};
744 }
745 }
746};
747template <typename U> using LossyChronoFormatter = ChronoFormatter<U, true>;
748
749template <size_t Limit> struct LimitedStringFormatter {
750 template <typename Stream> void Unser(Stream &s, std::string &v) {
751 size_t size = ReadCompactSize(s);
752 if (size > Limit) {
753 throw std::ios_base::failure("String length limit exceeded");
754 }
755 v.resize(size);
756 if (size != 0) {
757 s.read(MakeWritableByteSpan(v));
758 }
759 }
760
761 template <typename Stream> void Ser(Stream &s, const std::string &v) {
762 s << v;
763 }
764};
765
782template <class Formatter> struct VectorFormatter {
783 template <typename Stream, typename V> void Ser(Stream &s, const V &v) {
784 Formatter formatter;
785 WriteCompactSize(s, v.size());
786 for (const typename V::value_type &elem : v) {
787 formatter.Ser(s, elem);
788 }
789 }
790
791 template <typename Stream, typename V> void Unser(Stream &s, V &v) {
792 Formatter formatter;
793 v.clear();
794 size_t size = ReadCompactSize(s);
795 size_t allocated = 0;
796 while (allocated < size) {
797 // For DoS prevention, do not blindly allocate as much as the stream
798 // claims to contain. Instead, allocate in 5MiB batches, so that an
799 // attacker actually needs to provide X MiB of data to make us
800 // allocate X+5 Mib.
801 static_assert(sizeof(typename V::value_type) <= MAX_VECTOR_ALLOCATE,
802 "Vector element size too large");
803 allocated =
804 std::min(size, allocated + MAX_VECTOR_ALLOCATE /
805 sizeof(typename V::value_type));
806 v.reserve(allocated);
807 while (v.size() < allocated) {
808 v.emplace_back();
809 formatter.Unser(s, v.back());
810 }
811 }
812 };
813};
814
826 uint64_t m_shift = 0;
827
828public:
829 template <typename Stream, typename I> void Ser(Stream &s, I v) {
830 if (v < m_shift || v >= std::numeric_limits<uint64_t>::max()) {
831 throw std::ios_base::failure("differential value overflow");
832 }
834 m_shift = uint64_t(v) + 1;
835 }
836 template <typename Stream, typename I> void Unser(Stream &s, I &v) {
837 uint64_t n = ReadCompactSize(s);
838 m_shift += n;
839 if (m_shift < n || m_shift >= std::numeric_limits<uint64_t>::max() ||
840 m_shift < std::numeric_limits<I>::min() ||
841 m_shift > std::numeric_limits<I>::max()) {
842 throw std::ios_base::failure("differential value overflow");
843 }
844 v = I(m_shift++);
845 }
846};
847
859 template <typename Stream, typename T> void Ser(Stream &s, T v) {
860 DifferenceFormatter::Ser(s, v.index);
861 v.SerData(s);
862 }
863
864 template <typename Stream, typename T> void Unser(Stream &s, T &v) {
865 DifferenceFormatter::Unser(s, v.index);
866 v.UnserData(s);
867 }
868};
869
877template <typename Stream, typename C>
878void Serialize(Stream &os, const std::basic_string<C> &str);
879template <typename Stream, typename C>
880void Unserialize(Stream &is, std::basic_string<C> &str);
881
885template <typename Stream, unsigned int N, typename T>
886inline void Serialize(Stream &os, const prevector<N, T> &v);
887template <typename Stream, unsigned int N, typename T>
888inline void Unserialize(Stream &is, prevector<N, T> &v);
889
893template <typename Stream, typename T, typename A>
894inline void Serialize(Stream &os, const std::vector<T, A> &v);
895template <typename Stream, typename T, typename A>
896inline void Unserialize(Stream &is, std::vector<T, A> &v);
897
901template <typename Stream, typename K, typename T>
902void Serialize(Stream &os, const std::pair<K, T> &item);
903template <typename Stream, typename K, typename T>
904void Unserialize(Stream &is, std::pair<K, T> &item);
905
909template <typename Stream, typename K, typename T, typename Pred, typename A>
910void Serialize(Stream &os, const std::map<K, T, Pred, A> &m);
911template <typename Stream, typename K, typename T, typename Pred, typename A>
912void Unserialize(Stream &is, std::map<K, T, Pred, A> &m);
913
917template <typename Stream, typename K, typename Pred, typename A>
918void Serialize(Stream &os, const std::set<K, Pred, A> &m);
919template <typename Stream, typename K, typename Pred, typename A>
920void Unserialize(Stream &is, std::set<K, Pred, A> &m);
921
925template <typename Stream, typename T>
926void Serialize(Stream &os, const std::shared_ptr<const T> &p);
927template <typename Stream, typename T>
928void Unserialize(Stream &os, std::shared_ptr<const T> &p);
929
933template <typename Stream, typename T>
934void Serialize(Stream &os, const std::unique_ptr<const T> &p);
935template <typename Stream, typename T>
936void Unserialize(Stream &os, std::unique_ptr<const T> &p);
937
941template <typename Stream, typename T>
942void Serialize(Stream &os, const RCUPtr<const T> &p);
943template <typename Stream, typename T>
944void Unserialize(Stream &os, RCUPtr<const T> &p);
945
950template <class T, class Stream>
951concept Serializable = requires(T a, Stream s) { a.Serialize(s); };
952template <typename Stream, typename T>
954void Serialize(Stream &os, const T &a) {
955 a.Serialize(os);
956}
957
958template <class T, class Stream>
959concept Unserializable = requires(T a, Stream s) { a.Unserialize(s); };
960template <typename Stream, typename T>
962void Unserialize(Stream &is, T &&a) {
963 a.Unserialize(is);
964}
965
973 template <typename Stream, typename T>
974 static void Ser(Stream &s, const T &t) {
975 Serialize(s, t);
976 }
977
978 template <typename Stream, typename T> static void Unser(Stream &s, T &t) {
979 Unserialize(s, t);
980 }
981};
982
986template <typename Stream, typename C>
987void Serialize(Stream &os, const std::basic_string<C> &str) {
988 WriteCompactSize(os, str.size());
989 if (!str.empty()) {
990 os.write(MakeByteSpan(str));
991 }
992}
993
994template <typename Stream, typename C>
995void Unserialize(Stream &is, std::basic_string<C> &str) {
996 size_t nSize = ReadCompactSize(is);
997 str.resize(nSize);
998 if (nSize != 0) {
999 is.read(MakeWritableByteSpan(str));
1000 }
1001}
1002
1006template <typename Stream, unsigned int N, typename T>
1007void Serialize(Stream &os, const prevector<N, T> &v) {
1008 if constexpr (BasicByte<T>) {
1009 // Use optimized version for unformatted basic bytes
1010 WriteCompactSize(os, v.size());
1011 if (!v.empty()) os.write(MakeByteSpan(v));
1012 } else {
1014 }
1015}
1016
1017template <typename Stream, unsigned int N, typename T>
1018void Unserialize(Stream &is, prevector<N, T> &v) {
1019 if constexpr (BasicByte<T>) {
1020 // Use optimized version for unformatted basic bytes
1021 // Limit size per read so bogus size value won't cause out of memory
1022 v.clear();
1023 size_t nSize = ReadCompactSize(is);
1024 size_t i = 0;
1025 while (i < nSize) {
1026 size_t blk = std::min(nSize - i, size_t(1 + 4999999 / sizeof(T)));
1027 v.resize_uninitialized(i + blk);
1028 is.read(AsWritableBytes(Span{&v[i], blk}));
1029 i += blk;
1030 }
1031 } else {
1033 }
1034}
1035
1039template <typename Stream, typename T, typename A>
1040void Serialize(Stream &os, const std::vector<T, A> &v) {
1041 if constexpr (BasicByte<T>) {
1042 // Use optimized version for unformatted basic bytes
1043 WriteCompactSize(os, v.size());
1044 if (!v.empty()) {
1045 os.write(MakeByteSpan(v));
1046 }
1047 } else if constexpr (std::is_same_v<T, bool>) {
1048 // A special case for std::vector<bool>, as dereferencing
1049 // std::vector<bool>::const_iterator does not result in a const bool&
1050 // due to std::vector's special casing for bool arguments.
1051 WriteCompactSize(os, v.size());
1052 for (bool elem : v) {
1053 ::Serialize(os, elem);
1054 }
1055 } else {
1057 }
1058}
1059
1060template <typename Stream, typename T, typename A>
1061void Unserialize(Stream &is, std::vector<T, A> &v) {
1062 if constexpr (BasicByte<T>) {
1063 // Use optimized version for unformatted basic bytes
1064 // Limit size per read so bogus size value won't cause out of memory
1065 v.clear();
1066 size_t nSize = ReadCompactSize(is);
1067 size_t i = 0;
1068 while (i < nSize) {
1069 size_t blk = std::min(nSize - i, size_t(1 + 4999999 / sizeof(T)));
1070 v.resize(i + blk);
1071 is.read(AsWritableBytes(Span{&v[i], blk}));
1072 i += blk;
1073 }
1074 } else {
1076 }
1077}
1078
1082template <typename Stream, typename K, typename T>
1083void Serialize(Stream &os, const std::pair<K, T> &item) {
1084 Serialize(os, item.first);
1085 Serialize(os, item.second);
1086}
1087
1088template <typename Stream, typename K, typename T>
1089void Unserialize(Stream &is, std::pair<K, T> &item) {
1090 Unserialize(is, item.first);
1091 Unserialize(is, item.second);
1092}
1093
1097template <typename Stream, typename K, typename T, typename Pred, typename A>
1098void Serialize(Stream &os, const std::map<K, T, Pred, A> &m) {
1099 WriteCompactSize(os, m.size());
1100 for (const auto &entry : m) {
1101 Serialize(os, entry);
1102 }
1103}
1104
1105template <typename Stream, typename K, typename T, typename Pred, typename A>
1106void Unserialize(Stream &is, std::map<K, T, Pred, A> &m) {
1107 m.clear();
1108 size_t nSize = ReadCompactSize(is);
1109 typename std::map<K, T, Pred, A>::iterator mi = m.begin();
1110 for (size_t i = 0; i < nSize; i++) {
1111 std::pair<K, T> item;
1112 Unserialize(is, item);
1113 mi = m.insert(mi, item);
1114 }
1115}
1116
1120template <typename Stream, typename K, typename Pred, typename A>
1121void Serialize(Stream &os, const std::set<K, Pred, A> &m) {
1122 WriteCompactSize(os, m.size());
1123 for (const K &i : m) {
1124 Serialize(os, i);
1125 }
1126}
1127
1128template <typename Stream, typename K, typename Pred, typename A>
1129void Unserialize(Stream &is, std::set<K, Pred, A> &m) {
1130 m.clear();
1131 size_t nSize = ReadCompactSize(is);
1132 typename std::set<K, Pred, A>::iterator it = m.begin();
1133 for (size_t i = 0; i < nSize; i++) {
1134 K key;
1135 Unserialize(is, key);
1136 it = m.insert(it, key);
1137 }
1138}
1139
1143template <typename Stream, typename T>
1144void Serialize(Stream &os, const std::unique_ptr<const T> &p) {
1145 Serialize(os, *p);
1146}
1147
1148template <typename Stream, typename T>
1149void Unserialize(Stream &is, std::unique_ptr<const T> &p) {
1150 p.reset(new T(deserialize, is));
1151}
1152
1156template <typename Stream, typename T>
1157void Serialize(Stream &os, const std::shared_ptr<const T> &p) {
1158 Serialize(os, *p);
1159}
1160
1161template <typename Stream, typename T>
1162void Unserialize(Stream &is, std::shared_ptr<const T> &p) {
1163 p = std::make_shared<const T>(deserialize, is);
1164}
1165
1169template <typename Stream, typename T>
1170void Serialize(Stream &os, const RCUPtr<const T> &p) {
1171 Serialize(os, *p);
1172}
1173
1174template <typename Stream, typename T>
1175void Unserialize(Stream &is, RCUPtr<const T> &p) {
1177}
1178
1184 constexpr bool ForRead() const { return false; }
1185};
1187 constexpr bool ForRead() const { return true; }
1188};
1189
1203protected:
1204 size_t nSize;
1205
1206 const int nVersion;
1207
1208public:
1209 explicit CSizeComputer(int nVersionIn) : nSize(0), nVersion(nVersionIn) {}
1210
1211 void write(Span<const std::byte> src) { this->nSize += src.size(); }
1212
1214 void seek(size_t _nSize) { this->nSize += _nSize; }
1215
1216 template <typename T> CSizeComputer &operator<<(const T &obj) {
1217 ::Serialize(*this, obj);
1218 return (*this);
1219 }
1220
1221 size_t size() const { return nSize; }
1222
1223 int GetVersion() const { return nVersion; }
1224};
1225
1226template <typename Stream> void SerializeMany(Stream &s) {}
1227
1228template <typename Stream, typename Arg, typename... Args>
1229void SerializeMany(Stream &s, const Arg &arg, const Args &...args) {
1230 ::Serialize(s, arg);
1231 ::SerializeMany(s, args...);
1232}
1233
1234template <typename Stream> inline void UnserializeMany(Stream &s) {}
1235
1236template <typename Stream, typename Arg, typename... Args>
1237inline void UnserializeMany(Stream &s, Arg &&arg, Args &&...args) {
1238 ::Unserialize(s, arg);
1239 ::UnserializeMany(s, args...);
1240}
1241
1242template <typename Stream, typename... Args>
1243inline void SerReadWriteMany(Stream &s, ActionSerialize ser_action,
1244 const Args &...args) {
1245 ::SerializeMany(s, args...);
1246}
1247
1248template <typename Stream, typename... Args>
1249inline void SerReadWriteMany(Stream &s, ActionUnserialize ser_action,
1250 Args &&...args) {
1251 ::UnserializeMany(s, args...);
1252}
1253
1254template <typename Stream, typename Type, typename Fn>
1255inline void SerRead(Stream &s, ActionSerialize ser_action, Type &&, Fn &&) {}
1256
1257template <typename Stream, typename Type, typename Fn>
1258inline void SerRead(Stream &s, ActionUnserialize ser_action, Type &&obj,
1259 Fn &&fn) {
1260 fn(s, std::forward<Type>(obj));
1261}
1262
1263template <typename Stream, typename Type, typename Fn>
1264inline void SerWrite(Stream &s, ActionSerialize ser_action, Type &&obj,
1265 Fn &&fn) {
1266 fn(s, std::forward<Type>(obj));
1267}
1268
1269template <typename Stream, typename Type, typename Fn>
1270inline void SerWrite(Stream &s, ActionUnserialize ser_action, Type &&, Fn &&) {}
1271
1272template <typename I> inline void WriteVarInt(CSizeComputer &s, I n) {
1273 s.seek(GetSizeOfVarInt<I>(n));
1274}
1275
1276inline void WriteCompactSize(CSizeComputer &s, uint64_t nSize) {
1277 s.seek(GetSizeOfCompactSize(nSize));
1278}
1279
1280template <typename T> size_t GetSerializeSize(const T &t, int nVersion = 0) {
1281 return (CSizeComputer(nVersion) << t).size();
1282}
1283
1284template <typename... T>
1285size_t GetSerializeSizeMany(int nVersion, const T &...t) {
1286 CSizeComputer sc(nVersion);
1287 SerializeMany(sc, t...);
1288 return sc.size();
1289}
1290
1295template <typename Params, typename SubStream> class ParamsStream {
1297 // private to avoid leaking version/type into serialization code that
1298 // shouldn't see it
1299 SubStream &m_substream;
1300
1301public:
1303 SubStream &substream LIFETIMEBOUND)
1304 : m_params{params}, m_substream{substream} {}
1305 template <typename U> ParamsStream &operator<<(const U &obj) {
1306 ::Serialize(*this, obj);
1307 return *this;
1308 }
1309 template <typename U> ParamsStream &operator>>(U &&obj) {
1310 ::Unserialize(*this, obj);
1311 return *this;
1312 }
1313 void write(Span<const std::byte> src) { m_substream.write(src); }
1314 void read(Span<std::byte> dst) { m_substream.read(dst); }
1315 void ignore(size_t num) { m_substream.ignore(num); }
1316 bool eof() const { return m_substream.eof(); }
1317 size_t size() const { return m_substream.size(); }
1318 const Params &GetParams() const { return m_params; }
1319 // Deprecated with Params usage
1320 int GetVersion() = delete;
1321 // Deprecated with Params usage
1322 int GetType() = delete;
1323};
1324
1326template <typename Params, typename T> class ParamsWrapper {
1327 static_assert(std::is_lvalue_reference<T>::value,
1328 "ParamsWrapper needs an lvalue reference type T");
1331
1332public:
1333 explicit ParamsWrapper(const Params &params, T obj)
1334 : m_params{params}, m_object{obj} {}
1335
1336 template <typename Stream> void Serialize(Stream &s) const {
1337 ParamsStream ss{m_params, s};
1338 ::Serialize(ss, m_object);
1339 }
1340 template <typename Stream> void Unserialize(Stream &s) {
1341 ParamsStream ss{m_params, s};
1343 }
1344};
1345
1353template <typename Params, typename T>
1354static auto WithParams(const Params &params, T &&t) {
1355 return ParamsWrapper<Params, T &>{params, t};
1356}
1357
1358#endif // BITCOIN_SERIALIZE_H
#define LIFETIMEBOUND
Definition: attributes.h:16
const CChainParams & Params()
Return the currently selected parameters.
Definition: chainparams.cpp:21
GetSerializeSize implementations
Definition: serialize.h:1202
CSizeComputer & operator<<(const T &obj)
Definition: serialize.h:1216
void write(Span< const std::byte > src)
Definition: serialize.h:1211
CSizeComputer(int nVersionIn)
Definition: serialize.h:1209
size_t nSize
Definition: serialize.h:1204
size_t size() const
Definition: serialize.h:1221
const int nVersion
Definition: serialize.h:1206
void seek(size_t _nSize)
Pretend _nSize bytes are written, without specifying them.
Definition: serialize.h:1214
int GetVersion() const
Definition: serialize.h:1223
Helper for differentially encoded Compact Size integers in lists.
Definition: serialize.h:825
void Unser(Stream &s, I &v)
Definition: serialize.h:836
void Ser(Stream &s, I v)
Definition: serialize.h:829
Wrapper that overrides the GetParams() function of a stream (and hides GetVersion/GetType).
Definition: serialize.h:1295
const Params & m_params
Definition: serialize.h:1296
void ignore(size_t num)
Definition: serialize.h:1315
ParamsStream(const Params &params LIFETIMEBOUND, SubStream &substream LIFETIMEBOUND)
Definition: serialize.h:1302
void write(Span< const std::byte > src)
Definition: serialize.h:1313
int GetVersion()=delete
ParamsStream & operator<<(const U &obj)
Definition: serialize.h:1305
void read(Span< std::byte > dst)
Definition: serialize.h:1314
bool eof() const
Definition: serialize.h:1316
const Params & GetParams() const
Definition: serialize.h:1318
ParamsStream & operator>>(U &&obj)
Definition: serialize.h:1309
size_t size() const
Definition: serialize.h:1317
SubStream & m_substream
Definition: serialize.h:1299
int GetType()=delete
Wrapper that serializes objects with the specified parameters.
Definition: serialize.h:1326
const Params & m_params
Definition: serialize.h:1329
void Unserialize(Stream &s)
Definition: serialize.h:1340
void Serialize(Stream &s) const
Definition: serialize.h:1336
ParamsWrapper(const Params &params, T obj)
Definition: serialize.h:1333
Definition: rcu.h:85
static RCUPtr make(Args &&...args)
Construct a new object that is owned by the pointer.
Definition: rcu.h:112
A Span is an object that can refer to a contiguous sequence of objects.
Definition: span.h:94
constexpr std::size_t size() const noexcept
Definition: span.h:210
Simple wrapper class to serialize objects using a formatter; used by Using().
Definition: serialize.h:607
Wrapper(T obj)
Definition: serialize.h:615
T m_object
Definition: serialize.h:612
void Serialize(Stream &s) const
Definition: serialize.h:616
void Unserialize(Stream &s)
Definition: serialize.h:619
Implements a drop-in replacement for std::vector<T> which stores up to N elements directly (without h...
Definition: prevector.h:38
bool empty() const
Definition: prevector.h:398
void clear()
Definition: prevector.h:451
size_type size() const
Definition: prevector.h:396
void resize_uninitialized(size_type new_size)
Definition: prevector.h:492
If none of the specialized versions above matched, default to calling member function.
Definition: serialize.h:951
BSWAP_CONSTEXPR uint32_t be32toh_internal(uint32_t big_endian_32bits)
Definition: endian.h:56
BSWAP_CONSTEXPR uint16_t be16toh_internal(uint16_t big_endian_16bits)
Definition: endian.h:27
BSWAP_CONSTEXPR uint64_t htobe64_internal(uint64_t host_64bits)
Definition: endian.h:71
BSWAP_CONSTEXPR uint16_t htobe16_internal(uint16_t host_16bits)
Definition: endian.h:13
BSWAP_CONSTEXPR uint32_t htole32_internal(uint32_t host_32bits)
Definition: endian.h:49
BSWAP_CONSTEXPR uint16_t htole16_internal(uint16_t host_16bits)
Definition: endian.h:20
BSWAP_CONSTEXPR uint64_t be64toh_internal(uint64_t big_endian_64bits)
Definition: endian.h:85
BSWAP_CONSTEXPR uint16_t le16toh_internal(uint16_t little_endian_16bits)
Definition: endian.h:35
BSWAP_CONSTEXPR uint64_t htole64_internal(uint64_t host_64bits)
Definition: endian.h:78
BSWAP_CONSTEXPR uint64_t le64toh_internal(uint64_t little_endian_64bits)
Definition: endian.h:93
BSWAP_CONSTEXPR uint32_t le32toh_internal(uint32_t little_endian_32bits)
Definition: endian.h:64
BSWAP_CONSTEXPR uint32_t htobe32_internal(uint32_t host_32bits)
Definition: endian.h:42
void Serialize(Stream &, V)=delete
void SerRead(Stream &s, ActionSerialize ser_action, Type &&, Fn &&)
Definition: serialize.h:1255
void SerializeMany(Stream &s)
Definition: serialize.h:1226
static const unsigned int MAX_VECTOR_ALLOCATE
Maximum amount of memory (in bytes) to allocate at once when deserializing vectors.
Definition: serialize.h:40
uint8_t ser_readdata8(Stream &s)
Definition: serialize.h:86
float ser_uint32_to_float(uint32_t y)
Definition: serialize.h:137
I ReadVarInt(Stream &is)
Definition: serialize.h:584
void ser_writedata32be(Stream &s, uint32_t obj)
Definition: serialize.h:77
void WriteVarInt(CSizeComputer &os, I n)
Definition: serialize.h:1272
VarIntMode
Variable-length integers: bytes are a MSB base-128 encoding of the number.
Definition: serialize.h:538
@ NONNEGATIVE_SIGNED
void ser_writedata32(Stream &s, uint32_t obj)
Definition: serialize.h:72
size_t GetSerializeSizeMany(int nVersion, const T &...t)
Definition: serialize.h:1285
uint32_t GetSizeOfCompactSize(uint64_t nSize)
Compact Size size < 253 – 1 byte size <= USHRT_MAX – 3 bytes (253 + 2 bytes) size <= UINT_MAX – 5 byt...
Definition: serialize.h:437
static constexpr uint64_t MAX_SIZE
The maximum size of a serialized object in bytes or number of elements (for eg vectors) when the size...
Definition: serialize.h:34
constexpr deserialize_type deserialize
Definition: serialize.h:53
void ser_writedata16(Stream &s, uint16_t obj)
Definition: serialize.h:62
uint32_t ser_float_to_uint32(float x)
Definition: serialize.h:123
@ SER_DISK
Definition: serialize.h:156
@ SER_NETWORK
Definition: serialize.h:155
@ SER_GETHASH
Definition: serialize.h:157
void Unserialize(Stream &, V)=delete
Out & AsBase(In &x)
Convert any argument to a reference to X, maintaining constness.
Definition: serialize.h:180
static auto WithParams(const Params &params, T &&t)
Return a wrapper around t that (de)serializes it with specified parameter params.
Definition: serialize.h:1354
void ser_writedata16be(Stream &s, uint16_t obj)
Definition: serialize.h:67
void SerReadWriteMany(Stream &s, ActionSerialize ser_action, const Args &...args)
Definition: serialize.h:1243
uint16_t ser_readdata16(Stream &s)
Definition: serialize.h:91
uint64_t ser_readdata64(Stream &s)
Definition: serialize.h:111
double ser_uint64_to_double(uint64_t y)
Definition: serialize.h:130
void ser_writedata8(Stream &s, uint8_t obj)
Lowest-level serialization and conversion.
Definition: serialize.h:58
uint64_t ReadCompactSize(Stream &is, bool range_check=true)
Decode a CompactSize-encoded variable-length integer.
Definition: serialize.h:477
void SerWrite(Stream &s, ActionSerialize ser_action, Type &&obj, Fn &&fn)
Definition: serialize.h:1264
static Wrapper< Formatter, T & > Using(T &&t)
Cause serialization/deserialization of an object to be done using a specified formatter class.
Definition: serialize.h:638
unsigned int GetSizeOfVarInt(I n)
Definition: serialize.h:551
uint32_t ser_readdata32(Stream &s)
Definition: serialize.h:101
uint16_t ser_readdata16be(Stream &s)
Definition: serialize.h:96
size_t GetSerializeSize(const T &t, int nVersion=0)
Definition: serialize.h:1280
void UnserializeMany(Stream &s)
Definition: serialize.h:1234
uint64_t ser_double_to_uint64(double x)
Definition: serialize.h:116
void ser_writedata64(Stream &s, uint64_t obj)
Definition: serialize.h:82
uint32_t ser_readdata32be(Stream &s)
Definition: serialize.h:106
void WriteCompactSize(CSizeComputer &os, uint64_t nSize)
Definition: serialize.h:1276
Span< std::byte > AsWritableBytes(Span< T > s) noexcept
Definition: span.h:298
const std::byte * BytePtr(const void *data)
Convert a data pointer to a std::byte data pointer.
Definition: span.h:287
Span< const std::byte > MakeByteSpan(V &&v) noexcept
Definition: span.h:302
Span< const std::byte > AsBytes(Span< T > s) noexcept
Definition: span.h:295
Span< std::byte > MakeWritableByteSpan(V &&v) noexcept
Definition: span.h:305
Support for all macros providing or using the ser_action parameter of the SerializationOps method.
Definition: serialize.h:1183
constexpr bool ForRead() const
Definition: serialize.h:1184
constexpr bool ForRead() const
Definition: serialize.h:1187
constexpr CheckVarIntMode()
Definition: serialize.h:541
void Unser(Stream &s, Tp &tp)
Definition: serialize.h:733
void Ser(Stream &s, Tp tp)
Definition: serialize.h:739
Formatter for integers in CompactSize format.
Definition: serialize.h:711
void Unser(Stream &s, I &v)
Definition: serialize.h:712
void Ser(Stream &s, I v)
Definition: serialize.h:721
Serialization wrapper class for custom integers and enums.
Definition: serialize.h:670
static constexpr uint64_t MAX
Definition: serialize.h:673
void Ser(Stream &s, I v)
Definition: serialize.h:675
void Unser(Stream &s, I &v)
Definition: serialize.h:689
Default formatter.
Definition: serialize.h:972
static void Ser(Stream &s, const T &t)
Definition: serialize.h:974
static void Unser(Stream &s, T &t)
Definition: serialize.h:978
Helper for a list of items containing a differentially encoded index as their first member.
Definition: serialize.h:858
void Unser(Stream &s, T &v)
Definition: serialize.h:864
void Ser(Stream &s, T v)
Definition: serialize.h:859
void Unser(Stream &s, std::string &v)
Definition: serialize.h:750
void Ser(Stream &s, const std::string &v)
Definition: serialize.h:761
Serialization wrapper class for integers in VarInt format.
Definition: serialize.h:650
void Ser(Stream &s, I v)
Definition: serialize.h:651
void Unser(Stream &s, I &v)
Definition: serialize.h:655
Formatter to serialize/deserialize vector elements using another formatter.
Definition: serialize.h:782
void Unser(Stream &s, V &v)
Definition: serialize.h:791
void Ser(Stream &s, const V &v)
Definition: serialize.h:783
Dummy data type to identify deserializing constructors.
Definition: serialize.h:52