1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
9 #include <boost/type_traits/is_fundamental.hpp>
10 #include <boost/tuple/tuple.hpp>
11 #include <boost/tuple/tuple_comparison.hpp>
12 #include <boost/tuple/tuple_io.hpp>
13 #if defined(_MSC_VER) || defined(__BORLANDC__)
14 typedef __int64 int64
;
15 typedef unsigned __int64 uint64
;
17 typedef long long int64
;
18 typedef unsigned long long uint64
;
20 #if defined(_MSC_VER) && _MSC_VER < 1300
21 #define for if (false) ; else for
26 static const unsigned int MAX_SIZE
= 0x02000000;
28 static const int VERSION
= 31704;
29 static const char* pszSubVer
= "";
36 /////////////////////////////////////////////////////////////////
38 // Templates for serializing to anything that looks like a stream,
39 // i.e. anything that supports .read(char*, int) and .write(char*, int)
45 SER_NETWORK
= (1 << 0),
47 SER_GETHASH
= (1 << 2),
50 SER_SKIPSIG
= (1 << 16),
51 SER_BLOCKHEADERONLY
= (1 << 17),
54 #define IMPLEMENT_SERIALIZE(statements) \
55 unsigned int GetSerializeSize(int nType=0, int nVersion=VERSION) const \
57 CSerActionGetSerializeSize ser_action; \
58 const bool fGetSize = true; \
59 const bool fWrite = false; \
60 const bool fRead = false; \
61 unsigned int nSerSize = 0; \
62 ser_streamplaceholder s; \
64 s.nVersion = nVersion; \
68 template<typename Stream> \
69 void Serialize(Stream& s, int nType=0, int nVersion=VERSION) const \
71 CSerActionSerialize ser_action; \
72 const bool fGetSize = false; \
73 const bool fWrite = true; \
74 const bool fRead = false; \
75 unsigned int nSerSize = 0; \
78 template<typename Stream> \
79 void Unserialize(Stream& s, int nType=0, int nVersion=VERSION) \
81 CSerActionUnserialize ser_action; \
82 const bool fGetSize = false; \
83 const bool fWrite = false; \
84 const bool fRead = true; \
85 unsigned int nSerSize = 0; \
89 #define READWRITE(obj) (nSerSize += ::SerReadWrite(s, (obj), nType, nVersion, ser_action))
99 #define WRITEDATA(s, obj) s.write((char*)&(obj), sizeof(obj))
100 #define READDATA(s, obj) s.read((char*)&(obj), sizeof(obj))
102 inline unsigned int GetSerializeSize(char a
, int, int=0) { return sizeof(a
); }
103 inline unsigned int GetSerializeSize(signed char a
, int, int=0) { return sizeof(a
); }
104 inline unsigned int GetSerializeSize(unsigned char a
, int, int=0) { return sizeof(a
); }
105 inline unsigned int GetSerializeSize(signed short a
, int, int=0) { return sizeof(a
); }
106 inline unsigned int GetSerializeSize(unsigned short a
, int, int=0) { return sizeof(a
); }
107 inline unsigned int GetSerializeSize(signed int a
, int, int=0) { return sizeof(a
); }
108 inline unsigned int GetSerializeSize(unsigned int a
, int, int=0) { return sizeof(a
); }
109 inline unsigned int GetSerializeSize(signed long a
, int, int=0) { return sizeof(a
); }
110 inline unsigned int GetSerializeSize(unsigned long a
, int, int=0) { return sizeof(a
); }
111 inline unsigned int GetSerializeSize(int64 a
, int, int=0) { return sizeof(a
); }
112 inline unsigned int GetSerializeSize(uint64 a
, int, int=0) { return sizeof(a
); }
113 inline unsigned int GetSerializeSize(float a
, int, int=0) { return sizeof(a
); }
114 inline unsigned int GetSerializeSize(double a
, int, int=0) { return sizeof(a
); }
116 template<typename Stream
> inline void Serialize(Stream
& s
, char a
, int, int=0) { WRITEDATA(s
, a
); }
117 template<typename Stream
> inline void Serialize(Stream
& s
, signed char a
, int, int=0) { WRITEDATA(s
, a
); }
118 template<typename Stream
> inline void Serialize(Stream
& s
, unsigned char a
, int, int=0) { WRITEDATA(s
, a
); }
119 template<typename Stream
> inline void Serialize(Stream
& s
, signed short a
, int, int=0) { WRITEDATA(s
, a
); }
120 template<typename Stream
> inline void Serialize(Stream
& s
, unsigned short a
, int, int=0) { WRITEDATA(s
, a
); }
121 template<typename Stream
> inline void Serialize(Stream
& s
, signed int a
, int, int=0) { WRITEDATA(s
, a
); }
122 template<typename Stream
> inline void Serialize(Stream
& s
, unsigned int a
, int, int=0) { WRITEDATA(s
, a
); }
123 template<typename Stream
> inline void Serialize(Stream
& s
, signed long a
, int, int=0) { WRITEDATA(s
, a
); }
124 template<typename Stream
> inline void Serialize(Stream
& s
, unsigned long a
, int, int=0) { WRITEDATA(s
, a
); }
125 template<typename Stream
> inline void Serialize(Stream
& s
, int64 a
, int, int=0) { WRITEDATA(s
, a
); }
126 template<typename Stream
> inline void Serialize(Stream
& s
, uint64 a
, int, int=0) { WRITEDATA(s
, a
); }
127 template<typename Stream
> inline void Serialize(Stream
& s
, float a
, int, int=0) { WRITEDATA(s
, a
); }
128 template<typename Stream
> inline void Serialize(Stream
& s
, double a
, int, int=0) { WRITEDATA(s
, a
); }
130 template<typename Stream
> inline void Unserialize(Stream
& s
, char& a
, int, int=0) { READDATA(s
, a
); }
131 template<typename Stream
> inline void Unserialize(Stream
& s
, signed char& a
, int, int=0) { READDATA(s
, a
); }
132 template<typename Stream
> inline void Unserialize(Stream
& s
, unsigned char& a
, int, int=0) { READDATA(s
, a
); }
133 template<typename Stream
> inline void Unserialize(Stream
& s
, signed short& a
, int, int=0) { READDATA(s
, a
); }
134 template<typename Stream
> inline void Unserialize(Stream
& s
, unsigned short& a
, int, int=0) { READDATA(s
, a
); }
135 template<typename Stream
> inline void Unserialize(Stream
& s
, signed int& a
, int, int=0) { READDATA(s
, a
); }
136 template<typename Stream
> inline void Unserialize(Stream
& s
, unsigned int& a
, int, int=0) { READDATA(s
, a
); }
137 template<typename Stream
> inline void Unserialize(Stream
& s
, signed long& a
, int, int=0) { READDATA(s
, a
); }
138 template<typename Stream
> inline void Unserialize(Stream
& s
, unsigned long& a
, int, int=0) { READDATA(s
, a
); }
139 template<typename Stream
> inline void Unserialize(Stream
& s
, int64
& a
, int, int=0) { READDATA(s
, a
); }
140 template<typename Stream
> inline void Unserialize(Stream
& s
, uint64
& a
, int, int=0) { READDATA(s
, a
); }
141 template<typename Stream
> inline void Unserialize(Stream
& s
, float& a
, int, int=0) { READDATA(s
, a
); }
142 template<typename Stream
> inline void Unserialize(Stream
& s
, double& a
, int, int=0) { READDATA(s
, a
); }
144 inline unsigned int GetSerializeSize(bool a
, int, int=0) { return sizeof(char); }
145 template<typename Stream
> inline void Serialize(Stream
& s
, bool a
, int, int=0) { char f
=a
; WRITEDATA(s
, f
); }
146 template<typename Stream
> inline void Unserialize(Stream
& s
, bool& a
, int, int=0) { char f
; READDATA(s
, f
); a
=f
; }
155 // size < 253 -- 1 byte
156 // size <= USHRT_MAX -- 3 bytes (253 + 2 bytes)
157 // size <= UINT_MAX -- 5 bytes (254 + 4 bytes)
158 // size > UINT_MAX -- 9 bytes (255 + 8 bytes)
160 inline unsigned int GetSizeOfCompactSize(uint64 nSize
)
162 if (nSize
< 253) return sizeof(unsigned char);
163 else if (nSize
<= USHRT_MAX
) return sizeof(unsigned char) + sizeof(unsigned short);
164 else if (nSize
<= UINT_MAX
) return sizeof(unsigned char) + sizeof(unsigned int);
165 else return sizeof(unsigned char) + sizeof(uint64
);
168 template<typename Stream
>
169 void WriteCompactSize(Stream
& os
, uint64 nSize
)
173 unsigned char chSize
= nSize
;
174 WRITEDATA(os
, chSize
);
176 else if (nSize
<= USHRT_MAX
)
178 unsigned char chSize
= 253;
179 unsigned short xSize
= nSize
;
180 WRITEDATA(os
, chSize
);
181 WRITEDATA(os
, xSize
);
183 else if (nSize
<= UINT_MAX
)
185 unsigned char chSize
= 254;
186 unsigned int xSize
= nSize
;
187 WRITEDATA(os
, chSize
);
188 WRITEDATA(os
, xSize
);
192 unsigned char chSize
= 255;
193 uint64 xSize
= nSize
;
194 WRITEDATA(os
, chSize
);
195 WRITEDATA(os
, xSize
);
200 template<typename Stream
>
201 uint64
ReadCompactSize(Stream
& is
)
203 unsigned char chSize
;
204 READDATA(is
, chSize
);
210 else if (chSize
== 253)
212 unsigned short xSize
;
216 else if (chSize
== 254)
228 if (nSizeRet
> (uint64
)MAX_SIZE
)
229 throw std::ios_base::failure("ReadCompactSize() : size too large");
236 // Wrapper for serializing arrays and POD
237 // There's a clever template way to make arrays serialize normally, but MSVC6 doesn't support it
239 #define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj)))
246 CFlatData(void* pbeginIn
, void* pendIn
) : pbegin((char*)pbeginIn
), pend((char*)pendIn
) { }
247 char* begin() { return pbegin
; }
248 const char* begin() const { return pbegin
; }
249 char* end() { return pend
; }
250 const char* end() const { return pend
; }
252 unsigned int GetSerializeSize(int, int=0) const
254 return pend
- pbegin
;
257 template<typename Stream
>
258 void Serialize(Stream
& s
, int, int=0) const
260 s
.write(pbegin
, pend
- pbegin
);
263 template<typename Stream
>
264 void Unserialize(Stream
& s
, int, int=0)
266 s
.read(pbegin
, pend
- pbegin
);
273 // string stored as a fixed length field
275 template<std::size_t LEN
>
276 class CFixedFieldString
282 explicit CFixedFieldString(const string
& str
) : pcstr(&str
), pstr(NULL
) { }
283 explicit CFixedFieldString(string
& str
) : pcstr(&str
), pstr(&str
) { }
285 unsigned int GetSerializeSize(int, int=0) const
290 template<typename Stream
>
291 void Serialize(Stream
& s
, int, int=0) const
294 strncpy(pszBuf
, pcstr
->c_str(), LEN
);
295 s
.write(pszBuf
, LEN
);
298 template<typename Stream
>
299 void Unserialize(Stream
& s
, int, int=0)
302 throw std::ios_base::failure("CFixedFieldString::Unserialize : trying to unserialize to const string");
315 // Forward declarations
319 template<typename C
> unsigned int GetSerializeSize(const basic_string
<C
>& str
, int, int=0);
320 template<typename Stream
, typename C
> void Serialize(Stream
& os
, const basic_string
<C
>& str
, int, int=0);
321 template<typename Stream
, typename C
> void Unserialize(Stream
& is
, basic_string
<C
>& str
, int, int=0);
324 template<typename T
, typename A
> unsigned int GetSerializeSize_impl(const std::vector
<T
, A
>& v
, int nType
, int nVersion
, const boost::true_type
&);
325 template<typename T
, typename A
> unsigned int GetSerializeSize_impl(const std::vector
<T
, A
>& v
, int nType
, int nVersion
, const boost::false_type
&);
326 template<typename T
, typename A
> inline unsigned int GetSerializeSize(const std::vector
<T
, A
>& v
, int nType
, int nVersion
=VERSION
);
327 template<typename Stream
, typename T
, typename A
> void Serialize_impl(Stream
& os
, const std::vector
<T
, A
>& v
, int nType
, int nVersion
, const boost::true_type
&);
328 template<typename Stream
, typename T
, typename A
> void Serialize_impl(Stream
& os
, const std::vector
<T
, A
>& v
, int nType
, int nVersion
, const boost::false_type
&);
329 template<typename Stream
, typename T
, typename A
> inline void Serialize(Stream
& os
, const std::vector
<T
, A
>& v
, int nType
, int nVersion
=VERSION
);
330 template<typename Stream
, typename T
, typename A
> void Unserialize_impl(Stream
& is
, std::vector
<T
, A
>& v
, int nType
, int nVersion
, const boost::true_type
&);
331 template<typename Stream
, typename T
, typename A
> void Unserialize_impl(Stream
& is
, std::vector
<T
, A
>& v
, int nType
, int nVersion
, const boost::false_type
&);
332 template<typename Stream
, typename T
, typename A
> inline void Unserialize(Stream
& is
, std::vector
<T
, A
>& v
, int nType
, int nVersion
=VERSION
);
334 // others derived from vector
335 extern inline unsigned int GetSerializeSize(const CScript
& v
, int nType
, int nVersion
=VERSION
);
336 template<typename Stream
> void Serialize(Stream
& os
, const CScript
& v
, int nType
, int nVersion
=VERSION
);
337 template<typename Stream
> void Unserialize(Stream
& is
, CScript
& v
, int nType
, int nVersion
=VERSION
);
340 template<typename K
, typename T
> unsigned int GetSerializeSize(const std::pair
<K
, T
>& item
, int nType
, int nVersion
=VERSION
);
341 template<typename Stream
, typename K
, typename T
> void Serialize(Stream
& os
, const std::pair
<K
, T
>& item
, int nType
, int nVersion
=VERSION
);
342 template<typename Stream
, typename K
, typename T
> void Unserialize(Stream
& is
, std::pair
<K
, T
>& item
, int nType
, int nVersion
=VERSION
);
345 template<typename T0
, typename T1
, typename T2
> unsigned int GetSerializeSize(const boost::tuple
<T0
, T1
, T2
>& item
, int nType
, int nVersion
=VERSION
);
346 template<typename Stream
, typename T0
, typename T1
, typename T2
> void Serialize(Stream
& os
, const boost::tuple
<T0
, T1
, T2
>& item
, int nType
, int nVersion
=VERSION
);
347 template<typename Stream
, typename T0
, typename T1
, typename T2
> void Unserialize(Stream
& is
, boost::tuple
<T0
, T1
, T2
>& item
, int nType
, int nVersion
=VERSION
);
350 template<typename T0
, typename T1
, typename T2
, typename T3
> unsigned int GetSerializeSize(const boost::tuple
<T0
, T1
, T2
, T3
>& item
, int nType
, int nVersion
=VERSION
);
351 template<typename Stream
, typename T0
, typename T1
, typename T2
, typename T3
> void Serialize(Stream
& os
, const boost::tuple
<T0
, T1
, T2
, T3
>& item
, int nType
, int nVersion
=VERSION
);
352 template<typename Stream
, typename T0
, typename T1
, typename T2
, typename T3
> void Unserialize(Stream
& is
, boost::tuple
<T0
, T1
, T2
, T3
>& item
, int nType
, int nVersion
=VERSION
);
355 template<typename K
, typename T
, typename Pred
, typename A
> unsigned int GetSerializeSize(const std::map
<K
, T
, Pred
, A
>& m
, int nType
, int nVersion
=VERSION
);
356 template<typename Stream
, typename K
, typename T
, typename Pred
, typename A
> void Serialize(Stream
& os
, const std::map
<K
, T
, Pred
, A
>& m
, int nType
, int nVersion
=VERSION
);
357 template<typename Stream
, typename K
, typename T
, typename Pred
, typename A
> void Unserialize(Stream
& is
, std::map
<K
, T
, Pred
, A
>& m
, int nType
, int nVersion
=VERSION
);
360 template<typename K
, typename Pred
, typename A
> unsigned int GetSerializeSize(const std::set
<K
, Pred
, A
>& m
, int nType
, int nVersion
=VERSION
);
361 template<typename Stream
, typename K
, typename Pred
, typename A
> void Serialize(Stream
& os
, const std::set
<K
, Pred
, A
>& m
, int nType
, int nVersion
=VERSION
);
362 template<typename Stream
, typename K
, typename Pred
, typename A
> void Unserialize(Stream
& is
, std::set
<K
, Pred
, A
>& m
, int nType
, int nVersion
=VERSION
);
369 // If none of the specialized versions above matched, default to calling member function.
370 // "int nType" is changed to "long nType" to keep from getting an ambiguous overload error.
371 // The compiler will only cast int to long if none of the other templates matched.
372 // Thanks to Boost serialization for this idea.
375 inline unsigned int GetSerializeSize(const T
& a
, long nType
, int nVersion
=VERSION
)
377 return a
.GetSerializeSize((int)nType
, nVersion
);
380 template<typename Stream
, typename T
>
381 inline void Serialize(Stream
& os
, const T
& a
, long nType
, int nVersion
=VERSION
)
383 a
.Serialize(os
, (int)nType
, nVersion
);
386 template<typename Stream
, typename T
>
387 inline void Unserialize(Stream
& is
, T
& a
, long nType
, int nVersion
=VERSION
)
389 a
.Unserialize(is
, (int)nType
, nVersion
);
400 unsigned int GetSerializeSize(const basic_string
<C
>& str
, int, int)
402 return GetSizeOfCompactSize(str
.size()) + str
.size() * sizeof(str
[0]);
405 template<typename Stream
, typename C
>
406 void Serialize(Stream
& os
, const basic_string
<C
>& str
, int, int)
408 WriteCompactSize(os
, str
.size());
410 os
.write((char*)&str
[0], str
.size() * sizeof(str
[0]));
413 template<typename Stream
, typename C
>
414 void Unserialize(Stream
& is
, basic_string
<C
>& str
, int, int)
416 unsigned int nSize
= ReadCompactSize(is
);
419 is
.read((char*)&str
[0], nSize
* sizeof(str
[0]));
427 template<typename T
, typename A
>
428 unsigned int GetSerializeSize_impl(const std::vector
<T
, A
>& v
, int nType
, int nVersion
, const boost::true_type
&)
430 return (GetSizeOfCompactSize(v
.size()) + v
.size() * sizeof(T
));
433 template<typename T
, typename A
>
434 unsigned int GetSerializeSize_impl(const std::vector
<T
, A
>& v
, int nType
, int nVersion
, const boost::false_type
&)
436 unsigned int nSize
= GetSizeOfCompactSize(v
.size());
437 for (typename
std::vector
<T
, A
>::const_iterator vi
= v
.begin(); vi
!= v
.end(); ++vi
)
438 nSize
+= GetSerializeSize((*vi
), nType
, nVersion
);
442 template<typename T
, typename A
>
443 inline unsigned int GetSerializeSize(const std::vector
<T
, A
>& v
, int nType
, int nVersion
)
445 return GetSerializeSize_impl(v
, nType
, nVersion
, boost::is_fundamental
<T
>());
449 template<typename Stream
, typename T
, typename A
>
450 void Serialize_impl(Stream
& os
, const std::vector
<T
, A
>& v
, int nType
, int nVersion
, const boost::true_type
&)
452 WriteCompactSize(os
, v
.size());
454 os
.write((char*)&v
[0], v
.size() * sizeof(T
));
457 template<typename Stream
, typename T
, typename A
>
458 void Serialize_impl(Stream
& os
, const std::vector
<T
, A
>& v
, int nType
, int nVersion
, const boost::false_type
&)
460 WriteCompactSize(os
, v
.size());
461 for (typename
std::vector
<T
, A
>::const_iterator vi
= v
.begin(); vi
!= v
.end(); ++vi
)
462 ::Serialize(os
, (*vi
), nType
, nVersion
);
465 template<typename Stream
, typename T
, typename A
>
466 inline void Serialize(Stream
& os
, const std::vector
<T
, A
>& v
, int nType
, int nVersion
)
468 Serialize_impl(os
, v
, nType
, nVersion
, boost::is_fundamental
<T
>());
472 template<typename Stream
, typename T
, typename A
>
473 void Unserialize_impl(Stream
& is
, std::vector
<T
, A
>& v
, int nType
, int nVersion
, const boost::true_type
&)
475 //unsigned int nSize = ReadCompactSize(is);
477 //is.read((char*)&v[0], nSize * sizeof(T));
479 // Limit size per read so bogus size value won't cause out of memory
481 unsigned int nSize
= ReadCompactSize(is
);
485 unsigned int blk
= min(nSize
- i
, (unsigned int)(1 + 4999999 / sizeof(T
)));
487 is
.read((char*)&v
[i
], blk
* sizeof(T
));
492 template<typename Stream
, typename T
, typename A
>
493 void Unserialize_impl(Stream
& is
, std::vector
<T
, A
>& v
, int nType
, int nVersion
, const boost::false_type
&)
495 //unsigned int nSize = ReadCompactSize(is);
497 //for (std::vector<T, A>::iterator vi = v.begin(); vi != v.end(); ++vi)
498 // Unserialize(is, (*vi), nType, nVersion);
501 unsigned int nSize
= ReadCompactSize(is
);
503 unsigned int nMid
= 0;
506 nMid
+= 5000000 / sizeof(T
);
510 for (; i
< nMid
; i
++)
511 Unserialize(is
, v
[i
], nType
, nVersion
);
515 template<typename Stream
, typename T
, typename A
>
516 inline void Unserialize(Stream
& is
, std::vector
<T
, A
>& v
, int nType
, int nVersion
)
518 Unserialize_impl(is
, v
, nType
, nVersion
, boost::is_fundamental
<T
>());
524 // others derived from vector
526 inline unsigned int GetSerializeSize(const CScript
& v
, int nType
, int nVersion
)
528 return GetSerializeSize((const vector
<unsigned char>&)v
, nType
, nVersion
);
531 template<typename Stream
>
532 void Serialize(Stream
& os
, const CScript
& v
, int nType
, int nVersion
)
534 Serialize(os
, (const vector
<unsigned char>&)v
, nType
, nVersion
);
537 template<typename Stream
>
538 void Unserialize(Stream
& is
, CScript
& v
, int nType
, int nVersion
)
540 Unserialize(is
, (vector
<unsigned char>&)v
, nType
, nVersion
);
548 template<typename K
, typename T
>
549 unsigned int GetSerializeSize(const std::pair
<K
, T
>& item
, int nType
, int nVersion
)
551 return GetSerializeSize(item
.first
, nType
, nVersion
) + GetSerializeSize(item
.second
, nType
, nVersion
);
554 template<typename Stream
, typename K
, typename T
>
555 void Serialize(Stream
& os
, const std::pair
<K
, T
>& item
, int nType
, int nVersion
)
557 Serialize(os
, item
.first
, nType
, nVersion
);
558 Serialize(os
, item
.second
, nType
, nVersion
);
561 template<typename Stream
, typename K
, typename T
>
562 void Unserialize(Stream
& is
, std::pair
<K
, T
>& item
, int nType
, int nVersion
)
564 Unserialize(is
, item
.first
, nType
, nVersion
);
565 Unserialize(is
, item
.second
, nType
, nVersion
);
573 template<typename T0
, typename T1
, typename T2
>
574 unsigned int GetSerializeSize(const boost::tuple
<T0
, T1
, T2
>& item
, int nType
, int nVersion
)
576 unsigned int nSize
= 0;
577 nSize
+= GetSerializeSize(get
<0>(item
), nType
, nVersion
);
578 nSize
+= GetSerializeSize(get
<1>(item
), nType
, nVersion
);
579 nSize
+= GetSerializeSize(get
<2>(item
), nType
, nVersion
);
583 template<typename Stream
, typename T0
, typename T1
, typename T2
>
584 void Serialize(Stream
& os
, const boost::tuple
<T0
, T1
, T2
>& item
, int nType
, int nVersion
)
586 Serialize(os
, get
<0>(item
), nType
, nVersion
);
587 Serialize(os
, get
<1>(item
), nType
, nVersion
);
588 Serialize(os
, get
<2>(item
), nType
, nVersion
);
591 template<typename Stream
, typename T0
, typename T1
, typename T2
>
592 void Unserialize(Stream
& is
, boost::tuple
<T0
, T1
, T2
>& item
, int nType
, int nVersion
)
594 Unserialize(is
, get
<0>(item
), nType
, nVersion
);
595 Unserialize(is
, get
<1>(item
), nType
, nVersion
);
596 Unserialize(is
, get
<2>(item
), nType
, nVersion
);
604 template<typename T0
, typename T1
, typename T2
, typename T3
>
605 unsigned int GetSerializeSize(const boost::tuple
<T0
, T1
, T2
, T3
>& item
, int nType
, int nVersion
)
607 unsigned int nSize
= 0;
608 nSize
+= GetSerializeSize(get
<0>(item
), nType
, nVersion
);
609 nSize
+= GetSerializeSize(get
<1>(item
), nType
, nVersion
);
610 nSize
+= GetSerializeSize(get
<2>(item
), nType
, nVersion
);
611 nSize
+= GetSerializeSize(get
<3>(item
), nType
, nVersion
);
615 template<typename Stream
, typename T0
, typename T1
, typename T2
, typename T3
>
616 void Serialize(Stream
& os
, const boost::tuple
<T0
, T1
, T2
, T3
>& item
, int nType
, int nVersion
)
618 Serialize(os
, get
<0>(item
), nType
, nVersion
);
619 Serialize(os
, get
<1>(item
), nType
, nVersion
);
620 Serialize(os
, get
<2>(item
), nType
, nVersion
);
621 Serialize(os
, get
<3>(item
), nType
, nVersion
);
624 template<typename Stream
, typename T0
, typename T1
, typename T2
, typename T3
>
625 void Unserialize(Stream
& is
, boost::tuple
<T0
, T1
, T2
, T3
>& item
, int nType
, int nVersion
)
627 Unserialize(is
, get
<0>(item
), nType
, nVersion
);
628 Unserialize(is
, get
<1>(item
), nType
, nVersion
);
629 Unserialize(is
, get
<2>(item
), nType
, nVersion
);
630 Unserialize(is
, get
<3>(item
), nType
, nVersion
);
638 template<typename K
, typename T
, typename Pred
, typename A
>
639 unsigned int GetSerializeSize(const std::map
<K
, T
, Pred
, A
>& m
, int nType
, int nVersion
)
641 unsigned int nSize
= GetSizeOfCompactSize(m
.size());
642 for (typename
std::map
<K
, T
, Pred
, A
>::const_iterator mi
= m
.begin(); mi
!= m
.end(); ++mi
)
643 nSize
+= GetSerializeSize((*mi
), nType
, nVersion
);
647 template<typename Stream
, typename K
, typename T
, typename Pred
, typename A
>
648 void Serialize(Stream
& os
, const std::map
<K
, T
, Pred
, A
>& m
, int nType
, int nVersion
)
650 WriteCompactSize(os
, m
.size());
651 for (typename
std::map
<K
, T
, Pred
, A
>::const_iterator mi
= m
.begin(); mi
!= m
.end(); ++mi
)
652 Serialize(os
, (*mi
), nType
, nVersion
);
655 template<typename Stream
, typename K
, typename T
, typename Pred
, typename A
>
656 void Unserialize(Stream
& is
, std::map
<K
, T
, Pred
, A
>& m
, int nType
, int nVersion
)
659 unsigned int nSize
= ReadCompactSize(is
);
660 typename
std::map
<K
, T
, Pred
, A
>::iterator mi
= m
.begin();
661 for (unsigned int i
= 0; i
< nSize
; i
++)
664 Unserialize(is
, item
, nType
, nVersion
);
665 mi
= m
.insert(mi
, item
);
674 template<typename K
, typename Pred
, typename A
>
675 unsigned int GetSerializeSize(const std::set
<K
, Pred
, A
>& m
, int nType
, int nVersion
)
677 unsigned int nSize
= GetSizeOfCompactSize(m
.size());
678 for (typename
std::set
<K
, Pred
, A
>::const_iterator it
= m
.begin(); it
!= m
.end(); ++it
)
679 nSize
+= GetSerializeSize((*it
), nType
, nVersion
);
683 template<typename Stream
, typename K
, typename Pred
, typename A
>
684 void Serialize(Stream
& os
, const std::set
<K
, Pred
, A
>& m
, int nType
, int nVersion
)
686 WriteCompactSize(os
, m
.size());
687 for (typename
std::set
<K
, Pred
, A
>::const_iterator it
= m
.begin(); it
!= m
.end(); ++it
)
688 Serialize(os
, (*it
), nType
, nVersion
);
691 template<typename Stream
, typename K
, typename Pred
, typename A
>
692 void Unserialize(Stream
& is
, std::set
<K
, Pred
, A
>& m
, int nType
, int nVersion
)
695 unsigned int nSize
= ReadCompactSize(is
);
696 typename
std::set
<K
, Pred
, A
>::iterator it
= m
.begin();
697 for (unsigned int i
= 0; i
< nSize
; i
++)
700 Unserialize(is
, key
, nType
, nVersion
);
701 it
= m
.insert(it
, key
);
708 // Support for IMPLEMENT_SERIALIZE and READWRITE macro
710 class CSerActionGetSerializeSize
{ };
711 class CSerActionSerialize
{ };
712 class CSerActionUnserialize
{ };
714 template<typename Stream
, typename T
>
715 inline unsigned int SerReadWrite(Stream
& s
, const T
& obj
, int nType
, int nVersion
, CSerActionGetSerializeSize ser_action
)
717 return ::GetSerializeSize(obj
, nType
, nVersion
);
720 template<typename Stream
, typename T
>
721 inline unsigned int SerReadWrite(Stream
& s
, const T
& obj
, int nType
, int nVersion
, CSerActionSerialize ser_action
)
723 ::Serialize(s
, obj
, nType
, nVersion
);
727 template<typename Stream
, typename T
>
728 inline unsigned int SerReadWrite(Stream
& s
, T
& obj
, int nType
, int nVersion
, CSerActionUnserialize ser_action
)
730 ::Unserialize(s
, obj
, nType
, nVersion
);
734 struct ser_streamplaceholder
749 // Allocator that clears its contents before deletion
752 struct secure_allocator
: public std::allocator
<T
>
754 // MSVC8 default copy constructor is broken
755 typedef std::allocator
<T
> base
;
756 typedef typename
base::size_type size_type
;
757 typedef typename
base::difference_type difference_type
;
758 typedef typename
base::pointer pointer
;
759 typedef typename
base::const_pointer const_pointer
;
760 typedef typename
base::reference reference
;
761 typedef typename
base::const_reference const_reference
;
762 typedef typename
base::value_type value_type
;
763 secure_allocator() throw() {}
764 secure_allocator(const secure_allocator
& a
) throw() : base(a
) {}
765 ~secure_allocator() throw() {}
766 template<typename _Other
> struct rebind
767 { typedef secure_allocator
<_Other
> other
; };
769 void deallocate(T
* p
, std::size_t n
)
772 memset(p
, 0, sizeof(T
) * n
);
773 allocator
<T
>::deallocate(p
, n
);
780 // Double ended buffer combining vector and stream-like interfaces.
781 // >> and << read and write unformatted data using the above serialization templates.
782 // Fills with data in linear time; some stringstream implementations take N^2 time.
787 typedef vector
<char, secure_allocator
<char> > vector_type
;
789 unsigned int nReadPos
;
796 typedef vector_type::allocator_type allocator_type
;
797 typedef vector_type::size_type size_type
;
798 typedef vector_type::difference_type difference_type
;
799 typedef vector_type::reference reference
;
800 typedef vector_type::const_reference const_reference
;
801 typedef vector_type::value_type value_type
;
802 typedef vector_type::iterator iterator
;
803 typedef vector_type::const_iterator const_iterator
;
804 typedef vector_type::reverse_iterator reverse_iterator
;
806 explicit CDataStream(int nTypeIn
=SER_NETWORK
, int nVersionIn
=VERSION
)
808 Init(nTypeIn
, nVersionIn
);
811 CDataStream(const_iterator pbegin
, const_iterator pend
, int nTypeIn
=SER_NETWORK
, int nVersionIn
=VERSION
) : vch(pbegin
, pend
)
813 Init(nTypeIn
, nVersionIn
);
816 #if !defined(_MSC_VER) || _MSC_VER >= 1300
817 CDataStream(const char* pbegin
, const char* pend
, int nTypeIn
=SER_NETWORK
, int nVersionIn
=VERSION
) : vch(pbegin
, pend
)
819 Init(nTypeIn
, nVersionIn
);
823 CDataStream(const vector_type
& vchIn
, int nTypeIn
=SER_NETWORK
, int nVersionIn
=VERSION
) : vch(vchIn
.begin(), vchIn
.end())
825 Init(nTypeIn
, nVersionIn
);
828 CDataStream(const vector
<char>& vchIn
, int nTypeIn
=SER_NETWORK
, int nVersionIn
=VERSION
) : vch(vchIn
.begin(), vchIn
.end())
830 Init(nTypeIn
, nVersionIn
);
833 CDataStream(const vector
<unsigned char>& vchIn
, int nTypeIn
=SER_NETWORK
, int nVersionIn
=VERSION
) : vch((char*)&vchIn
.begin()[0], (char*)&vchIn
.end()[0])
835 Init(nTypeIn
, nVersionIn
);
838 void Init(int nTypeIn
=SER_NETWORK
, int nVersionIn
=VERSION
)
842 nVersion
= nVersionIn
;
844 exceptmask
= ios::badbit
| ios::failbit
;
847 CDataStream
& operator+=(const CDataStream
& b
)
849 vch
.insert(vch
.end(), b
.begin(), b
.end());
853 friend CDataStream
operator+(const CDataStream
& a
, const CDataStream
& b
)
862 return (string(begin(), end()));
869 const_iterator
begin() const { return vch
.begin() + nReadPos
; }
870 iterator
begin() { return vch
.begin() + nReadPos
; }
871 const_iterator
end() const { return vch
.end(); }
872 iterator
end() { return vch
.end(); }
873 size_type
size() const { return vch
.size() - nReadPos
; }
874 bool empty() const { return vch
.size() == nReadPos
; }
875 void resize(size_type n
, value_type c
=0) { vch
.resize(n
+ nReadPos
, c
); }
876 void reserve(size_type n
) { vch
.reserve(n
+ nReadPos
); }
877 const_reference
operator[](size_type pos
) const { return vch
[pos
+ nReadPos
]; }
878 reference
operator[](size_type pos
) { return vch
[pos
+ nReadPos
]; }
879 void clear() { vch
.clear(); nReadPos
= 0; }
880 iterator
insert(iterator it
, const char& x
=char()) { return vch
.insert(it
, x
); }
881 void insert(iterator it
, size_type n
, const char& x
) { vch
.insert(it
, n
, x
); }
883 void insert(iterator it
, const_iterator first
, const_iterator last
)
885 if (it
== vch
.begin() + nReadPos
&& last
- first
<= nReadPos
)
887 // special case for inserting at the front when there's room
888 nReadPos
-= (last
- first
);
889 memcpy(&vch
[nReadPos
], &first
[0], last
- first
);
892 vch
.insert(it
, first
, last
);
895 void insert(iterator it
, vector
<char>::const_iterator first
, vector
<char>::const_iterator last
)
897 if (it
== vch
.begin() + nReadPos
&& last
- first
<= nReadPos
)
899 // special case for inserting at the front when there's room
900 nReadPos
-= (last
- first
);
901 memcpy(&vch
[nReadPos
], &first
[0], last
- first
);
904 vch
.insert(it
, first
, last
);
907 #if !defined(_MSC_VER) || _MSC_VER >= 1300
908 void insert(iterator it
, const char* first
, const char* last
)
910 if (it
== vch
.begin() + nReadPos
&& last
- first
<= nReadPos
)
912 // special case for inserting at the front when there's room
913 nReadPos
-= (last
- first
);
914 memcpy(&vch
[nReadPos
], &first
[0], last
- first
);
917 vch
.insert(it
, first
, last
);
921 iterator
erase(iterator it
)
923 if (it
== vch
.begin() + nReadPos
)
925 // special case for erasing from the front
926 if (++nReadPos
>= vch
.size())
928 // whenever we reach the end, we take the opportunity to clear the buffer
930 return vch
.erase(vch
.begin(), vch
.end());
932 return vch
.begin() + nReadPos
;
935 return vch
.erase(it
);
938 iterator
erase(iterator first
, iterator last
)
940 if (first
== vch
.begin() + nReadPos
)
942 // special case for erasing from the front
943 if (last
== vch
.end())
946 return vch
.erase(vch
.begin(), vch
.end());
950 nReadPos
= (last
- vch
.begin());
955 return vch
.erase(first
, last
);
958 inline void Compact()
960 vch
.erase(vch
.begin(), vch
.begin() + nReadPos
);
964 bool Rewind(size_type n
)
966 // Rewind by n characters if the buffer hasn't been compacted yet
977 void setstate(short bits
, const char* psz
)
980 if (state
& exceptmask
)
981 throw std::ios_base::failure(psz
);
984 bool eof() const { return size() == 0; }
985 bool fail() const { return state
& (ios::badbit
| ios::failbit
); }
986 bool good() const { return !eof() && (state
== 0); }
987 void clear(short n
) { state
= n
; } // name conflict with vector clear()
988 short exceptions() { return exceptmask
; }
989 short exceptions(short mask
) { short prev
= exceptmask
; exceptmask
= mask
; setstate(0, "CDataStream"); return prev
; }
990 CDataStream
* rdbuf() { return this; }
991 int in_avail() { return size(); }
993 void SetType(int n
) { nType
= n
; }
994 int GetType() { return nType
; }
995 void SetVersion(int n
) { nVersion
= n
; }
996 int GetVersion() { return nVersion
; }
997 void ReadVersion() { *this >> nVersion
; }
998 void WriteVersion() { *this << nVersion
; }
1000 CDataStream
& read(char* pch
, int nSize
)
1002 // Read from the beginning of the buffer
1004 unsigned int nReadPosNext
= nReadPos
+ nSize
;
1005 if (nReadPosNext
>= vch
.size())
1007 if (nReadPosNext
> vch
.size())
1009 setstate(ios::failbit
, "CDataStream::read() : end of data");
1010 memset(pch
, 0, nSize
);
1011 nSize
= vch
.size() - nReadPos
;
1013 memcpy(pch
, &vch
[nReadPos
], nSize
);
1018 memcpy(pch
, &vch
[nReadPos
], nSize
);
1019 nReadPos
= nReadPosNext
;
1023 CDataStream
& ignore(int nSize
)
1025 // Ignore from the beginning of the buffer
1027 unsigned int nReadPosNext
= nReadPos
+ nSize
;
1028 if (nReadPosNext
>= vch
.size())
1030 if (nReadPosNext
> vch
.size())
1032 setstate(ios::failbit
, "CDataStream::ignore() : end of data");
1033 nSize
= vch
.size() - nReadPos
;
1039 nReadPos
= nReadPosNext
;
1043 CDataStream
& write(const char* pch
, int nSize
)
1045 // Write to the end of the buffer
1047 vch
.insert(vch
.end(), pch
, pch
+ nSize
);
1051 template<typename Stream
>
1052 void Serialize(Stream
& s
, int nType
=0, int nVersion
=VERSION
) const
1054 // Special case: stream << stream concatenates like stream += stream
1056 s
.write((char*)&vch
[0], vch
.size() * sizeof(vch
[0]));
1059 template<typename T
>
1060 unsigned int GetSerializeSize(const T
& obj
)
1062 // Tells the size of the object if serialized to this stream
1063 return ::GetSerializeSize(obj
, nType
, nVersion
);
1066 template<typename T
>
1067 CDataStream
& operator<<(const T
& obj
)
1069 // Serialize to this stream
1070 ::Serialize(*this, obj
, nType
, nVersion
);
1074 template<typename T
>
1075 CDataStream
& operator>>(T
& obj
)
1077 // Unserialize from this stream
1078 ::Unserialize(*this, obj
, nType
, nVersion
);
1083 #ifdef TESTCDATASTREAM
1090 // n=16000 0 seconds
1091 // n=32000 0 seconds
1092 // n=64000 1 seconds
1093 // n=128000 1 seconds
1094 // n=256000 2 seconds
1095 // n=512000 4 seconds
1096 // n=1024000 8 seconds
1097 // n=2048000 16 seconds
1098 // n=4096000 32 seconds
1102 // n=4000 13 seconds
1103 // n=8000 87 seconds
1104 // n=16000 400 seconds
1105 // n=32000 1660 seconds
1106 // n=64000 6749 seconds
1107 // n=128000 27241 seconds
1108 // n=256000 109804 seconds
1110 int main(int argc
, char *argv
[])
1112 vector
<unsigned char> vch(0xcc, 250);
1113 printf("CDataStream:\n");
1114 for (int n
= 1000; n
<= 4500000; n
*= 2)
1117 time_t nStart
= time(NULL
);
1118 for (int i
= 0; i
< n
; i
++)
1119 ss
.write((char*)&vch
[0], vch
.size());
1120 printf("n=%-10d %d seconds\n", n
, time(NULL
) - nStart
);
1122 printf("stringstream:\n");
1123 for (int n
= 1000; n
<= 4500000; n
*= 2)
1126 time_t nStart
= time(NULL
);
1127 for (int i
= 0; i
< n
; i
++)
1128 ss
.write((char*)&vch
[0], vch
.size());
1129 printf("n=%-10d %d seconds\n", n
, time(NULL
) - nStart
);
1144 // Automatic closing wrapper for FILE*
1145 // - Will automatically close the file when it goes out of scope if not null.
1146 // - If you're returning the file pointer, return file.release().
1147 // - If you need to close the file early, use file.fclose() instead of fclose(file).
1159 typedef FILE element_type
;
1161 CAutoFile(FILE* filenew
=NULL
, int nTypeIn
=SER_DISK
, int nVersionIn
=VERSION
)
1165 nVersion
= nVersionIn
;
1167 exceptmask
= ios::badbit
| ios::failbit
;
1177 if (file
!= NULL
&& file
!= stdin
&& file
!= stdout
&& file
!= stderr
)
1182 FILE* release() { FILE* ret
= file
; file
= NULL
; return ret
; }
1183 operator FILE*() { return file
; }
1184 FILE* operator->() { return file
; }
1185 FILE& operator*() { return *file
; }
1186 FILE** operator&() { return &file
; }
1187 FILE* operator=(FILE* pnew
) { return file
= pnew
; }
1188 bool operator!() { return (file
== NULL
); }
1194 void setstate(short bits
, const char* psz
)
1197 if (state
& exceptmask
)
1198 throw std::ios_base::failure(psz
);
1201 bool fail() const { return state
& (ios::badbit
| ios::failbit
); }
1202 bool good() const { return state
== 0; }
1203 void clear(short n
= 0) { state
= n
; }
1204 short exceptions() { return exceptmask
; }
1205 short exceptions(short mask
) { short prev
= exceptmask
; exceptmask
= mask
; setstate(0, "CAutoFile"); return prev
; }
1207 void SetType(int n
) { nType
= n
; }
1208 int GetType() { return nType
; }
1209 void SetVersion(int n
) { nVersion
= n
; }
1210 int GetVersion() { return nVersion
; }
1211 void ReadVersion() { *this >> nVersion
; }
1212 void WriteVersion() { *this << nVersion
; }
1214 CAutoFile
& read(char* pch
, int nSize
)
1217 throw std::ios_base::failure("CAutoFile::read : file handle is NULL");
1218 if (fread(pch
, 1, nSize
, file
) != nSize
)
1219 setstate(ios::failbit
, feof(file
) ? "CAutoFile::read : end of file" : "CAutoFile::read : fread failed");
1223 CAutoFile
& write(const char* pch
, int nSize
)
1226 throw std::ios_base::failure("CAutoFile::write : file handle is NULL");
1227 if (fwrite(pch
, 1, nSize
, file
) != nSize
)
1228 setstate(ios::failbit
, "CAutoFile::write : write failed");
1232 template<typename T
>
1233 unsigned int GetSerializeSize(const T
& obj
)
1235 // Tells the size of the object if serialized to this stream
1236 return ::GetSerializeSize(obj
, nType
, nVersion
);
1239 template<typename T
>
1240 CAutoFile
& operator<<(const T
& obj
)
1242 // Serialize to this stream
1244 throw std::ios_base::failure("CAutoFile::operator<< : file handle is NULL");
1245 ::Serialize(*this, obj
, nType
, nVersion
);
1249 template<typename T
>
1250 CAutoFile
& operator>>(T
& obj
)
1252 // Unserialize from this stream
1254 throw std::ios_base::failure("CAutoFile::operator>> : file handle is NULL");
1255 ::Unserialize(*this, obj
, nType
, nVersion
);