]>
Commit | Line | Data |
---|---|---|
0a61b0df | 1 | // Copyright (c) 2009-2010 Satoshi Nakamoto |
f914f1a7 | 2 | // Copyright (c) 2009-2014 The Bitcoin Core developers |
1c0aa911 | 3 | // Distributed under the MIT software license, see the accompanying |
bc909a7a | 4 | // file COPYING or https://www.opensource.org/licenses/mit-license.php . |
51ed9ec9 | 5 | |
223b6f1b WL |
6 | #ifndef BITCOIN_SERIALIZE_H |
7 | #define BITCOIN_SERIALIZE_H | |
0a61b0df | 8 | |
5207f33f PK |
9 | #include "compat/endian.h" |
10 | ||
51ed9ec9 | 11 | #include <algorithm> |
a6bbb26e | 12 | #include <array> |
51ed9ec9 | 13 | #include <assert.h> |
51ed9ec9 | 14 | #include <ios> |
611116d4 | 15 | #include <limits> |
be74c80d | 16 | #include <list> |
0a61b0df | 17 | #include <map> |
40cc9aa7 | 18 | #include <memory> |
d743f035 | 19 | #include <set> |
51ed9ec9 BD |
20 | #include <stdint.h> |
21 | #include <string> | |
22 | #include <string.h> | |
23 | #include <utility> | |
24 | #include <vector> | |
223b6f1b | 25 | |
291b191b | 26 | #include <boost/optional.hpp> |
5884044b | 27 | |
29a8ade7 | 28 | #include "prevector.h" |
51ed9ec9 | 29 | |
0a61b0df | 30 | static const unsigned int MAX_SIZE = 0x02000000; |
31 | ||
40cc9aa7 PW |
32 | /** |
33 | * Dummy data type to identify deserializing constructors. | |
34 | * | |
35 | * By convention, a constructor of a type T with signature | |
36 | * | |
37 | * template <typename Stream> T::T(deserialize_type, Stream& s) | |
38 | * | |
39 | * is a deserializing constructor, which builds the type by | |
40 | * deserializing it from s. If T contains const fields, this | |
41 | * is likely the only way to do so. | |
42 | */ | |
43 | struct deserialize_type {}; | |
44 | constexpr deserialize_type deserialize {}; | |
45 | ||
1c0aa911 MF |
46 | /** |
47 | * Used to bypass the rule against non-const reference to temporary | |
48 | * where it makes sense with wrappers such as CFlatData or CTxDB | |
49 | */ | |
82dc6426 GS |
50 | template<typename T> |
51 | inline T& REF(const T& val) | |
52 | { | |
53 | return const_cast<T&>(val); | |
54 | } | |
0a61b0df | 55 | |
1c0aa911 MF |
56 | /** |
57 | * Used to acquire a non-const pointer "this" to generate bodies | |
58 | * of const serialization operations from a template | |
59 | */ | |
3d796f89 | 60 | template<typename T> |
84881f8c | 61 | inline T* NCONST_PTR(const T* val) |
3d796f89 | 62 | { |
84881f8c | 63 | return const_cast<T*>(val); |
3d796f89 KD |
64 | } |
65 | ||
1c0aa911 MF |
66 | /** |
67 | * Get begin pointer of vector (non-const version). | |
fa126eff WL |
68 | * @note These functions avoid the undefined case of indexing into an empty |
69 | * vector, as well as that of indexing after the end of the vector. | |
70 | */ | |
29a8ade7 PW |
71 | template <typename V> |
72 | inline typename V::value_type* begin_ptr(V& v) | |
fa126eff WL |
73 | { |
74 | return v.empty() ? NULL : &v[0]; | |
75 | } | |
76 | /** Get begin pointer of vector (const version) */ | |
29a8ade7 PW |
77 | template <typename V> |
78 | inline const typename V::value_type* begin_ptr(const V& v) | |
fa126eff WL |
79 | { |
80 | return v.empty() ? NULL : &v[0]; | |
81 | } | |
82 | /** Get end pointer of vector (non-const version) */ | |
29a8ade7 PW |
83 | template <typename V> |
84 | inline typename V::value_type* end_ptr(V& v) | |
fa126eff WL |
85 | { |
86 | return v.empty() ? NULL : (&v[0] + v.size()); | |
87 | } | |
88 | /** Get end pointer of vector (const version) */ | |
29a8ade7 PW |
89 | template <typename V> |
90 | inline const typename V::value_type* end_ptr(const V& v) | |
fa126eff WL |
91 | { |
92 | return v.empty() ? NULL : (&v[0] + v.size()); | |
93 | } | |
94 | ||
01f9c344 WL |
95 | /* |
96 | * Lowest-level serialization and conversion. | |
97 | * @note Sizes of these types are verified in the tests | |
98 | */ | |
99 | template<typename Stream> inline void ser_writedata8(Stream &s, uint8_t obj) | |
100 | { | |
101 | s.write((char*)&obj, 1); | |
102 | } | |
103 | template<typename Stream> inline void ser_writedata16(Stream &s, uint16_t obj) | |
104 | { | |
105 | obj = htole16(obj); | |
106 | s.write((char*)&obj, 2); | |
107 | } | |
b2a98c42 MT |
108 | template<typename Stream> inline void ser_writedata16be(Stream &s, uint16_t obj) |
109 | { | |
110 | obj = htobe16(obj); | |
111 | s.write((char*)&obj, 2); | |
112 | } | |
01f9c344 WL |
113 | template<typename Stream> inline void ser_writedata32(Stream &s, uint32_t obj) |
114 | { | |
115 | obj = htole32(obj); | |
116 | s.write((char*)&obj, 4); | |
117 | } | |
8b78a819 T |
118 | template<typename Stream> inline void ser_writedata32be(Stream &s, uint32_t obj) |
119 | { | |
120 | obj = htobe32(obj); | |
121 | s.write((char*)&obj, 4); | |
122 | } | |
01f9c344 WL |
123 | template<typename Stream> inline void ser_writedata64(Stream &s, uint64_t obj) |
124 | { | |
125 | obj = htole64(obj); | |
126 | s.write((char*)&obj, 8); | |
127 | } | |
b2a98c42 MT |
128 | template<typename Stream> inline void ser_writedata64be(Stream &s, uint64_t obj) |
129 | { | |
130 | obj = htobe64(obj); | |
131 | s.write((char*)&obj, 8); | |
132 | } | |
01f9c344 WL |
133 | template<typename Stream> inline uint8_t ser_readdata8(Stream &s) |
134 | { | |
135 | uint8_t obj; | |
136 | s.read((char*)&obj, 1); | |
137 | return obj; | |
138 | } | |
139 | template<typename Stream> inline uint16_t ser_readdata16(Stream &s) | |
140 | { | |
141 | uint16_t obj; | |
142 | s.read((char*)&obj, 2); | |
143 | return le16toh(obj); | |
144 | } | |
b2a98c42 MT |
145 | template<typename Stream> inline uint16_t ser_readdata16be(Stream &s) |
146 | { | |
147 | uint16_t obj; | |
148 | s.read((char*)&obj, 2); | |
149 | return be16toh(obj); | |
150 | } | |
01f9c344 WL |
151 | template<typename Stream> inline uint32_t ser_readdata32(Stream &s) |
152 | { | |
153 | uint32_t obj; | |
154 | s.read((char*)&obj, 4); | |
155 | return le32toh(obj); | |
156 | } | |
8b78a819 T |
157 | template<typename Stream> inline uint32_t ser_readdata32be(Stream &s) |
158 | { | |
159 | uint32_t obj; | |
160 | s.read((char*)&obj, 4); | |
161 | return be32toh(obj); | |
162 | } | |
01f9c344 WL |
163 | template<typename Stream> inline uint64_t ser_readdata64(Stream &s) |
164 | { | |
165 | uint64_t obj; | |
166 | s.read((char*)&obj, 8); | |
167 | return le64toh(obj); | |
168 | } | |
b2a98c42 MT |
169 | template<typename Stream> inline uint64_t ser_readdata64be(Stream &s) |
170 | { | |
171 | uint64_t obj; | |
172 | s.read((char*)&obj, 8); | |
173 | return be64toh(obj); | |
174 | } | |
01f9c344 WL |
175 | inline uint64_t ser_double_to_uint64(double x) |
176 | { | |
177 | union { double x; uint64_t y; } tmp; | |
178 | tmp.x = x; | |
179 | return tmp.y; | |
180 | } | |
181 | inline uint32_t ser_float_to_uint32(float x) | |
182 | { | |
183 | union { float x; uint32_t y; } tmp; | |
184 | tmp.x = x; | |
185 | return tmp.y; | |
186 | } | |
187 | inline double ser_uint64_to_double(uint64_t y) | |
188 | { | |
189 | union { double x; uint64_t y; } tmp; | |
190 | tmp.y = y; | |
191 | return tmp.x; | |
192 | } | |
193 | inline float ser_uint32_to_float(uint32_t y) | |
194 | { | |
195 | union { float x; uint32_t y; } tmp; | |
196 | tmp.y = y; | |
197 | return tmp.x; | |
198 | } | |
199 | ||
200 | ||
0a61b0df | 201 | ///////////////////////////////////////////////////////////////// |
202 | // | |
203 | // Templates for serializing to anything that looks like a stream, | |
8695a393 | 204 | // i.e. anything that supports .read(char*, size_t) and .write(char*, size_t) |
0a61b0df | 205 | // |
206 | ||
09891705 PW |
207 | class CSizeComputer; |
208 | ||
0a61b0df | 209 | enum |
210 | { | |
211 | // primary actions | |
212 | SER_NETWORK = (1 << 0), | |
213 | SER_DISK = (1 << 1), | |
214 | SER_GETHASH = (1 << 2), | |
0a61b0df | 215 | }; |
216 | ||
242f1421 PW |
217 | #define READWRITE(obj) (::SerReadWrite(s, (obj), ser_action)) |
218 | #define READWRITEMANY(...) (::SerReadWriteMany(s, ser_action, __VA_ARGS__)) | |
0a61b0df | 219 | |
1c0aa911 MF |
220 | /** |
221 | * Implement three methods for serializable objects. These are actually wrappers over | |
3d796f89 | 222 | * "SerializationOp" template, which implements the body of each class' serialization |
3f6540ad | 223 | * code. Adding "ADD_SERIALIZE_METHODS" in the body of the class causes these wrappers to be |
1c0aa911 MF |
224 | * added as members. |
225 | */ | |
242f1421 PW |
226 | #define ADD_SERIALIZE_METHODS \ |
227 | template<typename Stream> \ | |
228 | void Serialize(Stream& s) const { \ | |
229 | NCONST_PTR(this)->SerializationOp(s, CSerActionSerialize()); \ | |
230 | } \ | |
231 | template<typename Stream> \ | |
232 | void Unserialize(Stream& s) { \ | |
233 | SerializationOp(s, CSerActionUnserialize()); \ | |
0a61b0df | 234 | } |
235 | ||
242f1421 PW |
236 | template<typename Stream> inline void Serialize(Stream& s, char a ) { ser_writedata8(s, a); } // TODO Get rid of bare char |
237 | template<typename Stream> inline void Serialize(Stream& s, int8_t a ) { ser_writedata8(s, a); } | |
238 | template<typename Stream> inline void Serialize(Stream& s, uint8_t a ) { ser_writedata8(s, a); } | |
239 | template<typename Stream> inline void Serialize(Stream& s, int16_t a ) { ser_writedata16(s, a); } | |
240 | template<typename Stream> inline void Serialize(Stream& s, uint16_t a) { ser_writedata16(s, a); } | |
241 | template<typename Stream> inline void Serialize(Stream& s, int32_t a ) { ser_writedata32(s, a); } | |
242 | template<typename Stream> inline void Serialize(Stream& s, uint32_t a) { ser_writedata32(s, a); } | |
243 | template<typename Stream> inline void Serialize(Stream& s, int64_t a ) { ser_writedata64(s, a); } | |
244 | template<typename Stream> inline void Serialize(Stream& s, uint64_t a) { ser_writedata64(s, a); } | |
245 | template<typename Stream> inline void Serialize(Stream& s, float a ) { ser_writedata32(s, ser_float_to_uint32(a)); } | |
246 | template<typename Stream> inline void Serialize(Stream& s, double a ) { ser_writedata64(s, ser_double_to_uint64(a)); } | |
01f9c344 | 247 | |
242f1421 PW |
248 | template<typename Stream> inline void Unserialize(Stream& s, char& a ) { a = ser_readdata8(s); } // TODO Get rid of bare char |
249 | template<typename Stream> inline void Unserialize(Stream& s, int8_t& a ) { a = ser_readdata8(s); } | |
250 | template<typename Stream> inline void Unserialize(Stream& s, uint8_t& a ) { a = ser_readdata8(s); } | |
251 | template<typename Stream> inline void Unserialize(Stream& s, int16_t& a ) { a = ser_readdata16(s); } | |
252 | template<typename Stream> inline void Unserialize(Stream& s, uint16_t& a) { a = ser_readdata16(s); } | |
253 | template<typename Stream> inline void Unserialize(Stream& s, int32_t& a ) { a = ser_readdata32(s); } | |
254 | template<typename Stream> inline void Unserialize(Stream& s, uint32_t& a) { a = ser_readdata32(s); } | |
255 | template<typename Stream> inline void Unserialize(Stream& s, int64_t& a ) { a = ser_readdata64(s); } | |
256 | template<typename Stream> inline void Unserialize(Stream& s, uint64_t& a) { a = ser_readdata64(s); } | |
257 | template<typename Stream> inline void Unserialize(Stream& s, float& a ) { a = ser_uint32_to_float(ser_readdata32(s)); } | |
258 | template<typename Stream> inline void Unserialize(Stream& s, double& a ) { a = ser_uint64_to_double(ser_readdata64(s)); } | |
0a61b0df | 259 | |
242f1421 PW |
260 | template<typename Stream> inline void Serialize(Stream& s, bool a) { char f=a; ser_writedata8(s, f); } |
261 | template<typename Stream> inline void Unserialize(Stream& s, bool& a) { char f=ser_readdata8(s); a=f; } | |
0a61b0df | 262 | |
263 | ||
264 | ||
265 | ||
266 | ||
267 | ||
1c0aa911 MF |
268 | /** |
269 | * Compact Size | |
270 | * size < 253 -- 1 byte | |
d76ed723 DH |
271 | * size <= 0xFFFF -- 3 bytes (253 + 2 bytes) |
272 | * size <= 0xFFFFFFFF -- 5 bytes (254 + 4 bytes) | |
273 | * size > 0xFFFFFFFF -- 9 bytes (255 + 8 bytes) | |
1c0aa911 | 274 | */ |
51ed9ec9 | 275 | inline unsigned int GetSizeOfCompactSize(uint64_t nSize) |
0a61b0df | 276 | { |
d76ed723 DH |
277 | if (nSize < 253) return 1; |
278 | else if (nSize <= 0xFFFFu) return 3; | |
279 | else if (nSize <= 0xFFFFFFFFu) return 5; | |
280 | else return 9; | |
0a61b0df | 281 | } |
282 | ||
09891705 PW |
283 | inline void WriteCompactSize(CSizeComputer& os, uint64_t nSize); |
284 | ||
0a61b0df | 285 | template<typename Stream> |
51ed9ec9 | 286 | void WriteCompactSize(Stream& os, uint64_t nSize) |
0a61b0df | 287 | { |
a790fa46 | 288 | if (nSize < 253) |
0a61b0df | 289 | { |
01f9c344 | 290 | ser_writedata8(os, nSize); |
0a61b0df | 291 | } |
d76ed723 | 292 | else if (nSize <= 0xFFFFu) |
0a61b0df | 293 | { |
01f9c344 WL |
294 | ser_writedata8(os, 253); |
295 | ser_writedata16(os, nSize); | |
0a61b0df | 296 | } |
d76ed723 | 297 | else if (nSize <= 0xFFFFFFFFu) |
0a61b0df | 298 | { |
01f9c344 WL |
299 | ser_writedata8(os, 254); |
300 | ser_writedata32(os, nSize); | |
0a61b0df | 301 | } |
302 | else | |
303 | { | |
01f9c344 WL |
304 | ser_writedata8(os, 255); |
305 | ser_writedata64(os, nSize); | |
0a61b0df | 306 | } |
0a61b0df | 307 | } |
308 | ||
309 | template<typename Stream> | |
51ed9ec9 | 310 | uint64_t ReadCompactSize(Stream& is) |
0a61b0df | 311 | { |
01f9c344 | 312 | uint8_t chSize = ser_readdata8(is); |
51ed9ec9 | 313 | uint64_t nSizeRet = 0; |
a790fa46 | 314 | if (chSize < 253) |
0a61b0df | 315 | { |
316 | nSizeRet = chSize; | |
317 | } | |
a790fa46 | 318 | else if (chSize == 253) |
0a61b0df | 319 | { |
01f9c344 | 320 | nSizeRet = ser_readdata16(is); |
8dc206a1 GA |
321 | if (nSizeRet < 253) |
322 | throw std::ios_base::failure("non-canonical ReadCompactSize()"); | |
0a61b0df | 323 | } |
a790fa46 | 324 | else if (chSize == 254) |
0a61b0df | 325 | { |
01f9c344 | 326 | nSizeRet = ser_readdata32(is); |
8dc206a1 GA |
327 | if (nSizeRet < 0x10000u) |
328 | throw std::ios_base::failure("non-canonical ReadCompactSize()"); | |
0a61b0df | 329 | } |
330 | else | |
331 | { | |
01f9c344 | 332 | nSizeRet = ser_readdata64(is); |
775b7b8d | 333 | if (nSizeRet < 0x100000000ULL) |
8dc206a1 | 334 | throw std::ios_base::failure("non-canonical ReadCompactSize()"); |
0a61b0df | 335 | } |
51ed9ec9 | 336 | if (nSizeRet > (uint64_t)MAX_SIZE) |
5262fde0 | 337 | throw std::ios_base::failure("ReadCompactSize(): size too large"); |
0a61b0df | 338 | return nSizeRet; |
339 | } | |
340 | ||
1c0aa911 MF |
341 | /** |
342 | * Variable-length integers: bytes are a MSB base-128 encoding of the number. | |
343 | * The high bit in each byte signifies whether another digit follows. To make | |
344 | * sure the encoding is one-to-one, one is subtracted from all but the last digit. | |
345 | * Thus, the byte sequence a[] with length len, where all but the last byte | |
346 | * has bit 128 set, encodes the number: | |
347 | * | |
348 | * (a[len-1] & 0x7F) + sum(i=1..len-1, 128^i*((a[len-i-1] & 0x7F)+1)) | |
349 | * | |
350 | * Properties: | |
351 | * * Very small (0-127: 1 byte, 128-16511: 2 bytes, 16512-2113663: 3 bytes) | |
352 | * * Every integer has exactly one encoding | |
353 | * * Encoding does not depend on size of original integer type | |
354 | * * No redundancy: every (infinite) byte sequence corresponds to a list | |
355 | * of encoded integers. | |
356 | * | |
357 | * 0: [0x00] 256: [0x81 0x00] | |
358 | * 1: [0x01] 16383: [0xFE 0x7F] | |
359 | * 127: [0x7F] 16384: [0xFF 0x00] | |
360 | * 128: [0x80 0x00] 16511: [0x80 0xFF 0x7F] | |
361 | * 255: [0x80 0x7F] 65535: [0x82 0xFD 0x7F] | |
362 | * 2^32: [0x8E 0xFE 0xFE 0xFF 0x00] | |
363 | */ | |
4d6144f9 PW |
364 | |
365 | template<typename I> | |
366 | inline unsigned int GetSizeOfVarInt(I n) | |
367 | { | |
368 | int nRet = 0; | |
369 | while(true) { | |
370 | nRet++; | |
371 | if (n <= 0x7F) | |
372 | break; | |
373 | n = (n >> 7) - 1; | |
374 | } | |
375 | return nRet; | |
376 | } | |
377 | ||
09891705 PW |
378 | template<typename I> |
379 | inline void WriteVarInt(CSizeComputer& os, I n); | |
380 | ||
4d6144f9 PW |
381 | template<typename Stream, typename I> |
382 | void WriteVarInt(Stream& os, I n) | |
383 | { | |
384 | unsigned char tmp[(sizeof(n)*8+6)/7]; | |
385 | int len=0; | |
386 | while(true) { | |
387 | tmp[len] = (n & 0x7F) | (len ? 0x80 : 0x00); | |
388 | if (n <= 0x7F) | |
389 | break; | |
390 | n = (n >> 7) - 1; | |
391 | len++; | |
392 | } | |
393 | do { | |
01f9c344 | 394 | ser_writedata8(os, tmp[len]); |
4d6144f9 PW |
395 | } while(len--); |
396 | } | |
0a61b0df | 397 | |
4d6144f9 PW |
398 | template<typename Stream, typename I> |
399 | I ReadVarInt(Stream& is) | |
400 | { | |
401 | I n = 0; | |
402 | while(true) { | |
01f9c344 | 403 | unsigned char chData = ser_readdata8(is); |
4d6144f9 PW |
404 | n = (n << 7) | (chData & 0x7F); |
405 | if (chData & 0x80) | |
406 | n++; | |
407 | else | |
408 | return n; | |
409 | } | |
410 | } | |
0a61b0df | 411 | |
216e9a44 PW |
412 | #define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj))) |
413 | #define VARINT(obj) REF(WrapVarInt(REF(obj))) | |
c803fa10 | 414 | #define COMPACTSIZE(obj) REF(CCompactSize(REF(obj))) |
216e9a44 | 415 | #define LIMITED_STRING(obj,n) REF(LimitedString< n >(REF(obj))) |
6b8de05d | 416 | |
1c0aa911 MF |
417 | /** |
418 | * Wrapper for serializing arrays and POD. | |
6b8de05d | 419 | */ |
0a61b0df | 420 | class CFlatData |
421 | { | |
422 | protected: | |
423 | char* pbegin; | |
424 | char* pend; | |
425 | public: | |
426 | CFlatData(void* pbeginIn, void* pendIn) : pbegin((char*)pbeginIn), pend((char*)pendIn) { } | |
fa126eff WL |
427 | template <class T, class TAl> |
428 | explicit CFlatData(std::vector<T,TAl> &v) | |
429 | { | |
430 | pbegin = (char*)begin_ptr(v); | |
431 | pend = (char*)end_ptr(v); | |
432 | } | |
29a8ade7 PW |
433 | template <unsigned int N, typename T, typename S, typename D> |
434 | explicit CFlatData(prevector<N, T, S, D> &v) | |
435 | { | |
436 | pbegin = (char*)begin_ptr(v); | |
437 | pend = (char*)end_ptr(v); | |
438 | } | |
0a61b0df | 439 | char* begin() { return pbegin; } |
440 | const char* begin() const { return pbegin; } | |
441 | char* end() { return pend; } | |
442 | const char* end() const { return pend; } | |
443 | ||
0a61b0df | 444 | template<typename Stream> |
242f1421 | 445 | void Serialize(Stream& s) const |
0a61b0df | 446 | { |
447 | s.write(pbegin, pend - pbegin); | |
448 | } | |
449 | ||
450 | template<typename Stream> | |
242f1421 | 451 | void Unserialize(Stream& s) |
0a61b0df | 452 | { |
453 | s.read(pbegin, pend - pbegin); | |
454 | } | |
455 | }; | |
456 | ||
4d6144f9 PW |
457 | template<typename I> |
458 | class CVarInt | |
459 | { | |
460 | protected: | |
461 | I &n; | |
462 | public: | |
463 | CVarInt(I& nIn) : n(nIn) { } | |
464 | ||
4d6144f9 | 465 | template<typename Stream> |
242f1421 | 466 | void Serialize(Stream &s) const { |
4d6144f9 PW |
467 | WriteVarInt<Stream,I>(s, n); |
468 | } | |
469 | ||
470 | template<typename Stream> | |
242f1421 | 471 | void Unserialize(Stream& s) { |
4d6144f9 PW |
472 | n = ReadVarInt<Stream,I>(s); |
473 | } | |
474 | }; | |
475 | ||
c803fa10 MC |
476 | class CCompactSize |
477 | { | |
478 | protected: | |
479 | uint64_t &n; | |
480 | public: | |
481 | CCompactSize(uint64_t& nIn) : n(nIn) { } | |
482 | ||
c803fa10 | 483 | template<typename Stream> |
242f1421 | 484 | void Serialize(Stream &s) const { |
c803fa10 MC |
485 | WriteCompactSize<Stream>(s, n); |
486 | } | |
487 | ||
488 | template<typename Stream> | |
242f1421 | 489 | void Unserialize(Stream& s) { |
c803fa10 MC |
490 | n = ReadCompactSize<Stream>(s); |
491 | } | |
492 | }; | |
493 | ||
216e9a44 PW |
494 | template<size_t Limit> |
495 | class LimitedString | |
496 | { | |
497 | protected: | |
498 | std::string& string; | |
499 | public: | |
9b228f03 | 500 | LimitedString(std::string& _string) : string(_string) {} |
216e9a44 PW |
501 | |
502 | template<typename Stream> | |
242f1421 | 503 | void Unserialize(Stream& s) |
216e9a44 PW |
504 | { |
505 | size_t size = ReadCompactSize(s); | |
506 | if (size > Limit) { | |
507 | throw std::ios_base::failure("String length limit exceeded"); | |
508 | } | |
509 | string.resize(size); | |
510 | if (size != 0) | |
511 | s.read((char*)&string[0], size); | |
512 | } | |
513 | ||
514 | template<typename Stream> | |
242f1421 | 515 | void Serialize(Stream& s) const |
216e9a44 PW |
516 | { |
517 | WriteCompactSize(s, string.size()); | |
518 | if (!string.empty()) | |
519 | s.write((char*)&string[0], string.size()); | |
520 | } | |
216e9a44 PW |
521 | }; |
522 | ||
4d6144f9 PW |
523 | template<typename I> |
524 | CVarInt<I> WrapVarInt(I& n) { return CVarInt<I>(n); } | |
525 | ||
1c0aa911 MF |
526 | /** |
527 | * Forward declarations | |
528 | */ | |
0a61b0df | 529 | |
1c0aa911 MF |
530 | /** |
531 | * string | |
532 | */ | |
242f1421 PW |
533 | template<typename Stream, typename C> void Serialize(Stream& os, const std::basic_string<C>& str); |
534 | template<typename Stream, typename C> void Unserialize(Stream& is, std::basic_string<C>& str); | |
0a61b0df | 535 | |
1c0aa911 | 536 | /** |
29a8ade7 PW |
537 | * prevector |
538 | * prevectors of unsigned char are a special case and are intended to be serialized as a single opaque blob. | |
1c0aa911 | 539 | */ |
242f1421 PW |
540 | template<typename Stream, unsigned int N, typename T> void Serialize_impl(Stream& os, const prevector<N, T>& v, const unsigned char&); |
541 | template<typename Stream, unsigned int N, typename T, typename V> void Serialize_impl(Stream& os, const prevector<N, T>& v, const V&); | |
542 | template<typename Stream, unsigned int N, typename T> inline void Serialize(Stream& os, const prevector<N, T>& v); | |
543 | template<typename Stream, unsigned int N, typename T> void Unserialize_impl(Stream& is, prevector<N, T>& v, const unsigned char&); | |
544 | template<typename Stream, unsigned int N, typename T, typename V> void Unserialize_impl(Stream& is, prevector<N, T>& v, const V&); | |
545 | template<typename Stream, unsigned int N, typename T> inline void Unserialize(Stream& is, prevector<N, T>& v); | |
0a61b0df | 546 | |
1c0aa911 | 547 | /** |
1c0aa911 MF |
548 | * vector |
549 | * vectors of unsigned char are a special case and are intended to be serialized as a single opaque blob. | |
1c0aa911 | 550 | */ |
242f1421 PW |
551 | template<typename Stream, typename T, typename A> void Serialize_impl(Stream& os, const std::vector<T, A>& v, const unsigned char&); |
552 | template<typename Stream, typename T, typename A, typename V> void Serialize_impl(Stream& os, const std::vector<T, A>& v, const V&); | |
553 | template<typename Stream, typename T, typename A> inline void Serialize(Stream& os, const std::vector<T, A>& v); | |
554 | template<typename Stream, typename T, typename A> void Unserialize_impl(Stream& is, std::vector<T, A>& v, const unsigned char&); | |
555 | template<typename Stream, typename T, typename A, typename V> void Unserialize_impl(Stream& is, std::vector<T, A>& v, const V&); | |
556 | template<typename Stream, typename T, typename A> inline void Unserialize(Stream& is, std::vector<T, A>& v); | |
0a61b0df | 557 | |
291b191b SB |
558 | /** |
559 | * optional | |
560 | */ | |
68a1a592 JG |
561 | template<typename Stream, typename T> void Serialize(Stream& os, const boost::optional<T>& item); |
562 | template<typename Stream, typename T> void Unserialize(Stream& is, boost::optional<T>& item); | |
291b191b | 563 | |
5884044b SB |
564 | /** |
565 | * array | |
566 | */ | |
a6bbb26e JG |
567 | template<typename Stream, typename T, std::size_t N> void Serialize(Stream& os, const std::array<T, N>& item); |
568 | template<typename Stream, typename T, std::size_t N> void Unserialize(Stream& is, std::array<T, N>& item); | |
5884044b | 569 | |
1c0aa911 MF |
570 | /** |
571 | * pair | |
572 | */ | |
242f1421 PW |
573 | template<typename Stream, typename K, typename T> void Serialize(Stream& os, const std::pair<K, T>& item); |
574 | template<typename Stream, typename K, typename T> void Unserialize(Stream& is, std::pair<K, T>& item); | |
0a61b0df | 575 | |
1c0aa911 MF |
576 | /** |
577 | * map | |
578 | */ | |
242f1421 PW |
579 | template<typename Stream, typename K, typename T, typename Pred, typename A> void Serialize(Stream& os, const std::map<K, T, Pred, A>& m); |
580 | template<typename Stream, typename K, typename T, typename Pred, typename A> void Unserialize(Stream& is, std::map<K, T, Pred, A>& m); | |
0a61b0df | 581 | |
1c0aa911 MF |
582 | /** |
583 | * set | |
584 | */ | |
242f1421 PW |
585 | template<typename Stream, typename K, typename Pred, typename A> void Serialize(Stream& os, const std::set<K, Pred, A>& m); |
586 | template<typename Stream, typename K, typename Pred, typename A> void Unserialize(Stream& is, std::set<K, Pred, A>& m); | |
0a61b0df | 587 | |
be74c80d JG |
588 | /** |
589 | * list | |
590 | */ | |
68a1a592 JG |
591 | template<typename Stream, typename T, typename A> void Serialize(Stream& os, const std::list<T, A>& m); |
592 | template<typename Stream, typename T, typename A> void Unserialize(Stream& is, std::list<T, A>& m); | |
be74c80d | 593 | |
40cc9aa7 PW |
594 | /** |
595 | * shared_ptr | |
596 | */ | |
597 | template<typename Stream, typename T> void Serialize(Stream& os, const std::shared_ptr<const T>& p); | |
598 | template<typename Stream, typename T> void Unserialize(Stream& os, std::shared_ptr<const T>& p); | |
0a61b0df | 599 | |
40cc9aa7 PW |
600 | /** |
601 | * unique_ptr | |
602 | */ | |
603 | template<typename Stream, typename T> void Serialize(Stream& os, const std::unique_ptr<const T>& p); | |
604 | template<typename Stream, typename T> void Unserialize(Stream& os, std::unique_ptr<const T>& p); | |
0a61b0df | 605 | |
606 | ||
607 | ||
1c0aa911 MF |
608 | /** |
609 | * If none of the specialized versions above matched, default to calling member function. | |
1c0aa911 | 610 | */ |
0a61b0df | 611 | template<typename Stream, typename T> |
242f1421 | 612 | inline void Serialize(Stream& os, const T& a) |
0a61b0df | 613 | { |
242f1421 | 614 | a.Serialize(os); |
0a61b0df | 615 | } |
616 | ||
617 | template<typename Stream, typename T> | |
242f1421 | 618 | inline void Unserialize(Stream& is, T& a) |
0a61b0df | 619 | { |
242f1421 | 620 | a.Unserialize(is); |
0a61b0df | 621 | } |
622 | ||
623 | ||
624 | ||
625 | ||
626 | ||
1c0aa911 MF |
627 | /** |
628 | * string | |
629 | */ | |
0a61b0df | 630 | template<typename Stream, typename C> |
242f1421 | 631 | void Serialize(Stream& os, const std::basic_string<C>& str) |
0a61b0df | 632 | { |
633 | WriteCompactSize(os, str.size()); | |
634 | if (!str.empty()) | |
635 | os.write((char*)&str[0], str.size() * sizeof(str[0])); | |
636 | } | |
637 | ||
638 | template<typename Stream, typename C> | |
242f1421 | 639 | void Unserialize(Stream& is, std::basic_string<C>& str) |
0a61b0df | 640 | { |
641 | unsigned int nSize = ReadCompactSize(is); | |
642 | str.resize(nSize); | |
643 | if (nSize != 0) | |
644 | is.read((char*)&str[0], nSize * sizeof(str[0])); | |
645 | } | |
646 | ||
647 | ||
648 | ||
1c0aa911 | 649 | /** |
29a8ade7 | 650 | * prevector |
1c0aa911 | 651 | */ |
29a8ade7 | 652 | template<typename Stream, unsigned int N, typename T> |
242f1421 | 653 | void Serialize_impl(Stream& os, const prevector<N, T>& v, const unsigned char&) |
29a8ade7 PW |
654 | { |
655 | WriteCompactSize(os, v.size()); | |
656 | if (!v.empty()) | |
657 | os.write((char*)&v[0], v.size() * sizeof(T)); | |
658 | } | |
659 | ||
660 | template<typename Stream, unsigned int N, typename T, typename V> | |
242f1421 | 661 | void Serialize_impl(Stream& os, const prevector<N, T>& v, const V&) |
0a61b0df | 662 | { |
29a8ade7 PW |
663 | WriteCompactSize(os, v.size()); |
664 | for (typename prevector<N, T>::const_iterator vi = v.begin(); vi != v.end(); ++vi) | |
242f1421 | 665 | ::Serialize(os, (*vi)); |
0a61b0df | 666 | } |
667 | ||
29a8ade7 | 668 | template<typename Stream, unsigned int N, typename T> |
242f1421 | 669 | inline void Serialize(Stream& os, const prevector<N, T>& v) |
0a61b0df | 670 | { |
242f1421 | 671 | Serialize_impl(os, v, T()); |
29a8ade7 PW |
672 | } |
673 | ||
674 | ||
675 | template<typename Stream, unsigned int N, typename T> | |
242f1421 | 676 | void Unserialize_impl(Stream& is, prevector<N, T>& v, const unsigned char&) |
29a8ade7 PW |
677 | { |
678 | // Limit size per read so bogus size value won't cause out of memory | |
679 | v.clear(); | |
680 | unsigned int nSize = ReadCompactSize(is); | |
681 | unsigned int i = 0; | |
682 | while (i < nSize) | |
683 | { | |
684 | unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T))); | |
685 | v.resize(i + blk); | |
686 | is.read((char*)&v[i], blk * sizeof(T)); | |
687 | i += blk; | |
688 | } | |
689 | } | |
690 | ||
691 | template<typename Stream, unsigned int N, typename T, typename V> | |
242f1421 | 692 | void Unserialize_impl(Stream& is, prevector<N, T>& v, const V&) |
29a8ade7 PW |
693 | { |
694 | v.clear(); | |
695 | unsigned int nSize = ReadCompactSize(is); | |
696 | unsigned int i = 0; | |
697 | unsigned int nMid = 0; | |
698 | while (nMid < nSize) | |
699 | { | |
700 | nMid += 5000000 / sizeof(T); | |
701 | if (nMid > nSize) | |
702 | nMid = nSize; | |
703 | v.resize(nMid); | |
704 | for (; i < nMid; i++) | |
242f1421 | 705 | Unserialize(is, v[i]); |
29a8ade7 | 706 | } |
0a61b0df | 707 | } |
708 | ||
29a8ade7 | 709 | template<typename Stream, unsigned int N, typename T> |
242f1421 | 710 | inline void Unserialize(Stream& is, prevector<N, T>& v) |
0a61b0df | 711 | { |
242f1421 | 712 | Unserialize_impl(is, v, T()); |
0a61b0df | 713 | } |
714 | ||
715 | ||
29a8ade7 | 716 | |
1c0aa911 MF |
717 | /** |
718 | * vector | |
719 | */ | |
0a61b0df | 720 | template<typename Stream, typename T, typename A> |
242f1421 | 721 | void Serialize_impl(Stream& os, const std::vector<T, A>& v, const unsigned char&) |
0a61b0df | 722 | { |
723 | WriteCompactSize(os, v.size()); | |
724 | if (!v.empty()) | |
725 | os.write((char*)&v[0], v.size() * sizeof(T)); | |
726 | } | |
727 | ||
1d9b86d5 | 728 | template<typename Stream, typename T, typename A, typename V> |
242f1421 | 729 | void Serialize_impl(Stream& os, const std::vector<T, A>& v, const V&) |
0a61b0df | 730 | { |
731 | WriteCompactSize(os, v.size()); | |
732 | for (typename std::vector<T, A>::const_iterator vi = v.begin(); vi != v.end(); ++vi) | |
242f1421 | 733 | ::Serialize(os, (*vi)); |
0a61b0df | 734 | } |
735 | ||
736 | template<typename Stream, typename T, typename A> | |
242f1421 | 737 | inline void Serialize(Stream& os, const std::vector<T, A>& v) |
0a61b0df | 738 | { |
242f1421 | 739 | Serialize_impl(os, v, T()); |
0a61b0df | 740 | } |
741 | ||
742 | ||
743 | template<typename Stream, typename T, typename A> | |
242f1421 | 744 | void Unserialize_impl(Stream& is, std::vector<T, A>& v, const unsigned char&) |
0a61b0df | 745 | { |
0a61b0df | 746 | // Limit size per read so bogus size value won't cause out of memory |
747 | v.clear(); | |
748 | unsigned int nSize = ReadCompactSize(is); | |
749 | unsigned int i = 0; | |
750 | while (i < nSize) | |
751 | { | |
223b6f1b | 752 | unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T))); |
0a61b0df | 753 | v.resize(i + blk); |
754 | is.read((char*)&v[i], blk * sizeof(T)); | |
755 | i += blk; | |
756 | } | |
757 | } | |
758 | ||
1d9b86d5 | 759 | template<typename Stream, typename T, typename A, typename V> |
242f1421 | 760 | void Unserialize_impl(Stream& is, std::vector<T, A>& v, const V&) |
0a61b0df | 761 | { |
0a61b0df | 762 | v.clear(); |
763 | unsigned int nSize = ReadCompactSize(is); | |
764 | unsigned int i = 0; | |
765 | unsigned int nMid = 0; | |
766 | while (nMid < nSize) | |
767 | { | |
768 | nMid += 5000000 / sizeof(T); | |
769 | if (nMid > nSize) | |
770 | nMid = nSize; | |
771 | v.resize(nMid); | |
772 | for (; i < nMid; i++) | |
242f1421 | 773 | Unserialize(is, v[i]); |
0a61b0df | 774 | } |
775 | } | |
776 | ||
777 | template<typename Stream, typename T, typename A> | |
242f1421 | 778 | inline void Unserialize(Stream& is, std::vector<T, A>& v) |
0a61b0df | 779 | { |
242f1421 | 780 | Unserialize_impl(is, v, T()); |
0a61b0df | 781 | } |
782 | ||
783 | ||
291b191b SB |
784 | |
785 | /** | |
786 | * optional | |
787 | */ | |
291b191b | 788 | template<typename Stream, typename T> |
68a1a592 | 789 | void Serialize(Stream& os, const boost::optional<T>& item) |
291b191b SB |
790 | { |
791 | // If the value is there, put 0x01 and then serialize the value. | |
792 | // If it's not, put 0x00. | |
793 | if (item) { | |
794 | unsigned char discriminant = 0x01; | |
68a1a592 JG |
795 | Serialize(os, discriminant); |
796 | Serialize(os, *item); | |
291b191b SB |
797 | } else { |
798 | unsigned char discriminant = 0x00; | |
68a1a592 | 799 | Serialize(os, discriminant); |
291b191b SB |
800 | } |
801 | } | |
802 | ||
803 | template<typename Stream, typename T> | |
68a1a592 | 804 | void Unserialize(Stream& is, boost::optional<T>& item) |
291b191b SB |
805 | { |
806 | unsigned char discriminant = 0x00; | |
68a1a592 | 807 | Unserialize(is, discriminant); |
291b191b SB |
808 | |
809 | if (discriminant == 0x00) { | |
810 | item = boost::none; | |
e1ff849d | 811 | } else if (discriminant == 0x01) { |
291b191b | 812 | T object; |
68a1a592 | 813 | Unserialize(is, object); |
291b191b | 814 | item = object; |
e1ff849d SB |
815 | } else { |
816 | throw std::ios_base::failure("non-canonical optional discriminant"); | |
291b191b SB |
817 | } |
818 | } | |
819 | ||
820 | ||
821 | ||
5884044b SB |
822 | /** |
823 | * array | |
824 | */ | |
5884044b | 825 | template<typename Stream, typename T, std::size_t N> |
a6bbb26e | 826 | void Serialize(Stream& os, const std::array<T, N>& item) |
5884044b SB |
827 | { |
828 | for (size_t i = 0; i < N; i++) { | |
68a1a592 | 829 | Serialize(os, item[i]); |
5884044b SB |
830 | } |
831 | } | |
832 | ||
833 | template<typename Stream, typename T, std::size_t N> | |
a6bbb26e | 834 | void Unserialize(Stream& is, std::array<T, N>& item) |
5884044b SB |
835 | { |
836 | for (size_t i = 0; i < N; i++) { | |
68a1a592 | 837 | Unserialize(is, item[i]); |
5884044b SB |
838 | } |
839 | } | |
840 | ||
0a61b0df | 841 | |
1c0aa911 MF |
842 | /** |
843 | * pair | |
844 | */ | |
0a61b0df | 845 | template<typename Stream, typename K, typename T> |
242f1421 | 846 | void Serialize(Stream& os, const std::pair<K, T>& item) |
0a61b0df | 847 | { |
242f1421 PW |
848 | Serialize(os, item.first); |
849 | Serialize(os, item.second); | |
0a61b0df | 850 | } |
851 | ||
852 | template<typename Stream, typename K, typename T> | |
242f1421 | 853 | void Unserialize(Stream& is, std::pair<K, T>& item) |
0a61b0df | 854 | { |
242f1421 PW |
855 | Unserialize(is, item.first); |
856 | Unserialize(is, item.second); | |
0a61b0df | 857 | } |
858 | ||
859 | ||
860 | ||
1c0aa911 MF |
861 | /** |
862 | * map | |
863 | */ | |
0a61b0df | 864 | template<typename Stream, typename K, typename T, typename Pred, typename A> |
242f1421 | 865 | void Serialize(Stream& os, const std::map<K, T, Pred, A>& m) |
0a61b0df | 866 | { |
867 | WriteCompactSize(os, m.size()); | |
868 | for (typename std::map<K, T, Pred, A>::const_iterator mi = m.begin(); mi != m.end(); ++mi) | |
242f1421 | 869 | Serialize(os, (*mi)); |
0a61b0df | 870 | } |
871 | ||
872 | template<typename Stream, typename K, typename T, typename Pred, typename A> | |
242f1421 | 873 | void Unserialize(Stream& is, std::map<K, T, Pred, A>& m) |
0a61b0df | 874 | { |
875 | m.clear(); | |
876 | unsigned int nSize = ReadCompactSize(is); | |
877 | typename std::map<K, T, Pred, A>::iterator mi = m.begin(); | |
878 | for (unsigned int i = 0; i < nSize; i++) | |
879 | { | |
223b6f1b | 880 | std::pair<K, T> item; |
242f1421 | 881 | Unserialize(is, item); |
0a61b0df | 882 | mi = m.insert(mi, item); |
883 | } | |
884 | } | |
885 | ||
886 | ||
887 | ||
1c0aa911 MF |
888 | /** |
889 | * set | |
890 | */ | |
0a61b0df | 891 | template<typename Stream, typename K, typename Pred, typename A> |
242f1421 | 892 | void Serialize(Stream& os, const std::set<K, Pred, A>& m) |
0a61b0df | 893 | { |
894 | WriteCompactSize(os, m.size()); | |
895 | for (typename std::set<K, Pred, A>::const_iterator it = m.begin(); it != m.end(); ++it) | |
242f1421 | 896 | Serialize(os, (*it)); |
0a61b0df | 897 | } |
898 | ||
899 | template<typename Stream, typename K, typename Pred, typename A> | |
242f1421 | 900 | void Unserialize(Stream& is, std::set<K, Pred, A>& m) |
0a61b0df | 901 | { |
902 | m.clear(); | |
903 | unsigned int nSize = ReadCompactSize(is); | |
904 | typename std::set<K, Pred, A>::iterator it = m.begin(); | |
905 | for (unsigned int i = 0; i < nSize; i++) | |
906 | { | |
907 | K key; | |
242f1421 | 908 | Unserialize(is, key); |
0a61b0df | 909 | it = m.insert(it, key); |
910 | } | |
911 | } | |
912 | ||
913 | ||
914 | ||
be74c80d JG |
915 | /** |
916 | * list | |
917 | */ | |
be74c80d | 918 | template<typename Stream, typename T, typename A> |
68a1a592 | 919 | void Serialize(Stream& os, const std::list<T, A>& l) |
be74c80d JG |
920 | { |
921 | WriteCompactSize(os, l.size()); | |
922 | for (typename std::list<T, A>::const_iterator it = l.begin(); it != l.end(); ++it) | |
68a1a592 | 923 | Serialize(os, (*it)); |
be74c80d JG |
924 | } |
925 | ||
926 | template<typename Stream, typename T, typename A> | |
68a1a592 | 927 | void Unserialize(Stream& is, std::list<T, A>& l) |
be74c80d JG |
928 | { |
929 | l.clear(); | |
930 | unsigned int nSize = ReadCompactSize(is); | |
931 | typename std::list<T, A>::iterator it = l.begin(); | |
932 | for (unsigned int i = 0; i < nSize; i++) | |
933 | { | |
934 | T item; | |
68a1a592 | 935 | Unserialize(is, item); |
be74c80d JG |
936 | l.push_back(item); |
937 | } | |
938 | } | |
939 | ||
940 | ||
941 | ||
40cc9aa7 PW |
942 | /** |
943 | * unique_ptr | |
944 | */ | |
945 | template<typename Stream, typename T> void | |
946 | Serialize(Stream& os, const std::unique_ptr<const T>& p) | |
947 | { | |
948 | Serialize(os, *p); | |
949 | } | |
950 | ||
951 | template<typename Stream, typename T> | |
952 | void Unserialize(Stream& is, std::unique_ptr<const T>& p) | |
953 | { | |
954 | p.reset(new T(deserialize, is)); | |
955 | } | |
956 | ||
957 | ||
958 | ||
959 | /** | |
960 | * shared_ptr | |
961 | */ | |
962 | template<typename Stream, typename T> void | |
963 | Serialize(Stream& os, const std::shared_ptr<const T>& p) | |
964 | { | |
965 | Serialize(os, *p); | |
966 | } | |
967 | ||
968 | template<typename Stream, typename T> | |
969 | void Unserialize(Stream& is, std::shared_ptr<const T>& p) | |
970 | { | |
971 | p = std::make_shared<const T>(deserialize, is); | |
972 | } | |
973 | ||
974 | ||
975 | ||
1c0aa911 MF |
976 | /** |
977 | * Support for ADD_SERIALIZE_METHODS and READWRITE macro | |
978 | */ | |
31e9a838 | 979 | struct CSerActionSerialize |
0a61b0df | 980 | { |
93aaf4fc | 981 | constexpr bool ForRead() const { return false; } |
31e9a838 PW |
982 | }; |
983 | struct CSerActionUnserialize | |
984 | { | |
93aaf4fc | 985 | constexpr bool ForRead() const { return true; } |
31e9a838 | 986 | }; |
0a61b0df | 987 | |
988 | template<typename Stream, typename T> | |
242f1421 | 989 | inline void SerReadWrite(Stream& s, const T& obj, CSerActionSerialize ser_action) |
0a61b0df | 990 | { |
242f1421 | 991 | ::Serialize(s, obj); |
0a61b0df | 992 | } |
993 | ||
994 | template<typename Stream, typename T> | |
242f1421 | 995 | inline void SerReadWrite(Stream& s, T& obj, CSerActionUnserialize ser_action) |
0a61b0df | 996 | { |
242f1421 | 997 | ::Unserialize(s, obj); |
0a61b0df | 998 | } |
999 | ||
0a61b0df | 1000 | |
1001 | ||
1002 | ||
1003 | ||
1004 | ||
1005 | ||
f7a9a113 MC |
1006 | |
1007 | ||
09891705 PW |
1008 | /* ::GetSerializeSize implementations |
1009 | * | |
1010 | * Computing the serialized size of objects is done through a special stream | |
1011 | * object of type CSizeComputer, which only records the number of bytes written | |
1012 | * to it. | |
1013 | * | |
1014 | * If your Serialize or SerializationOp method has non-trivial overhead for | |
1015 | * serialization, it may be worthwhile to implement a specialized version for | |
1016 | * CSizeComputer, which uses the s.seek() method to record bytes that would | |
1017 | * be written instead. | |
1018 | */ | |
b069750d PW |
1019 | class CSizeComputer |
1020 | { | |
1021 | protected: | |
1022 | size_t nSize; | |
1023 | ||
7f4acac4 PW |
1024 | const int nType; |
1025 | const int nVersion; | |
b069750d | 1026 | public: |
b069750d PW |
1027 | CSizeComputer(int nTypeIn, int nVersionIn) : nSize(0), nType(nTypeIn), nVersion(nVersionIn) {} |
1028 | ||
9b228f03 | 1029 | void write(const char *psz, size_t _nSize) |
b069750d | 1030 | { |
9b228f03 | 1031 | this->nSize += _nSize; |
b069750d PW |
1032 | } |
1033 | ||
09891705 PW |
1034 | /** Pretend _nSize bytes are written, without specifying them. */ |
1035 | void seek(size_t _nSize) | |
1036 | { | |
1037 | this->nSize += _nSize; | |
b069750d PW |
1038 | } |
1039 | ||
1040 | template<typename T> | |
1041 | CSizeComputer& operator<<(const T& obj) | |
1042 | { | |
242f1421 | 1043 | ::Serialize(*this, obj); |
b069750d PW |
1044 | return (*this); |
1045 | } | |
1046 | ||
1047 | size_t size() const { | |
1048 | return nSize; | |
1049 | } | |
242f1421 PW |
1050 | |
1051 | int GetVersion() const { return nVersion; } | |
1052 | int GetType() const { return nType; } | |
b069750d PW |
1053 | }; |
1054 | ||
d1c9ef86 | 1055 | template<typename Stream> |
242f1421 | 1056 | void SerializeMany(Stream& s) |
d1c9ef86 CF |
1057 | { |
1058 | } | |
1059 | ||
1060 | template<typename Stream, typename Arg> | |
242f1421 | 1061 | void SerializeMany(Stream& s, Arg&& arg) |
d1c9ef86 | 1062 | { |
242f1421 | 1063 | ::Serialize(s, std::forward<Arg>(arg)); |
d1c9ef86 CF |
1064 | } |
1065 | ||
1066 | template<typename Stream, typename Arg, typename... Args> | |
242f1421 | 1067 | void SerializeMany(Stream& s, Arg&& arg, Args&&... args) |
d1c9ef86 | 1068 | { |
242f1421 PW |
1069 | ::Serialize(s, std::forward<Arg>(arg)); |
1070 | ::SerializeMany(s, std::forward<Args>(args)...); | |
d1c9ef86 CF |
1071 | } |
1072 | ||
1073 | template<typename Stream> | |
242f1421 | 1074 | inline void UnserializeMany(Stream& s) |
d1c9ef86 CF |
1075 | { |
1076 | } | |
1077 | ||
1078 | template<typename Stream, typename Arg> | |
242f1421 | 1079 | inline void UnserializeMany(Stream& s, Arg& arg) |
d1c9ef86 | 1080 | { |
242f1421 | 1081 | ::Unserialize(s, arg); |
d1c9ef86 CF |
1082 | } |
1083 | ||
1084 | template<typename Stream, typename Arg, typename... Args> | |
242f1421 | 1085 | inline void UnserializeMany(Stream& s, Arg& arg, Args&... args) |
d1c9ef86 | 1086 | { |
242f1421 PW |
1087 | ::Unserialize(s, arg); |
1088 | ::UnserializeMany(s, args...); | |
d1c9ef86 CF |
1089 | } |
1090 | ||
1091 | template<typename Stream, typename... Args> | |
242f1421 | 1092 | inline void SerReadWriteMany(Stream& s, CSerActionSerialize ser_action, Args&&... args) |
d1c9ef86 | 1093 | { |
242f1421 | 1094 | ::SerializeMany(s, std::forward<Args>(args)...); |
d1c9ef86 CF |
1095 | } |
1096 | ||
1097 | template<typename Stream, typename... Args> | |
242f1421 | 1098 | inline void SerReadWriteMany(Stream& s, CSerActionUnserialize ser_action, Args&... args) |
d1c9ef86 | 1099 | { |
242f1421 | 1100 | ::UnserializeMany(s, args...); |
d1c9ef86 CF |
1101 | } |
1102 | ||
09891705 PW |
1103 | template<typename I> |
1104 | inline void WriteVarInt(CSizeComputer &s, I n) | |
1105 | { | |
1106 | s.seek(GetSizeOfVarInt<I>(n)); | |
1107 | } | |
1108 | ||
1109 | inline void WriteCompactSize(CSizeComputer &s, uint64_t nSize) | |
1110 | { | |
1111 | s.seek(GetSizeOfCompactSize(nSize)); | |
1112 | } | |
1113 | ||
b8a65793 PW |
1114 | template <typename T> |
1115 | size_t GetSerializeSize(const T& t, int nType, int nVersion = 0) | |
1116 | { | |
1117 | return (CSizeComputer(nType, nVersion) << t).size(); | |
1118 | } | |
1119 | ||
1120 | template <typename S, typename T> | |
1121 | size_t GetSerializeSize(const S& s, const T& t) | |
1122 | { | |
1123 | return (CSizeComputer(s.GetType(), s.GetVersion()) << t).size(); | |
1124 | } | |
1125 | ||
093303a8 | 1126 | #endif // BITCOIN_SERIALIZE_H |