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
= 32000;
29 static const char* pszSubVer
= "";
30 static const bool VERSION_IS_BETA
= true;
37 /////////////////////////////////////////////////////////////////
39 // Templates for serializing to anything that looks like a stream,
40 // i.e. anything that supports .read(char*, int) and .write(char*, int)
46 SER_NETWORK
= (1 << 0),
48 SER_GETHASH
= (1 << 2),
51 SER_SKIPSIG
= (1 << 16),
52 SER_BLOCKHEADERONLY
= (1 << 17),
55 #define IMPLEMENT_SERIALIZE(statements) \
56 unsigned int GetSerializeSize(int nType=0, int nVersion=VERSION) const \
58 CSerActionGetSerializeSize ser_action; \
59 const bool fGetSize = true; \
60 const bool fWrite = false; \
61 const bool fRead = false; \
62 unsigned int nSerSize = 0; \
63 ser_streamplaceholder s; \
65 s.nVersion = nVersion; \
69 template<typename Stream> \
70 void Serialize(Stream& s, int nType=0, int nVersion=VERSION) const \
72 CSerActionSerialize ser_action; \
73 const bool fGetSize = false; \
74 const bool fWrite = true; \
75 const bool fRead = false; \
76 unsigned int nSerSize = 0; \
79 template<typename Stream> \
80 void Unserialize(Stream& s, int nType=0, int nVersion=VERSION) \
82 CSerActionUnserialize ser_action; \
83 const bool fGetSize = false; \
84 const bool fWrite = false; \
85 const bool fRead = true; \
86 unsigned int nSerSize = 0; \
90 #define READWRITE(obj) (nSerSize += ::SerReadWrite(s, (obj), nType, nVersion, ser_action))
100 #define WRITEDATA(s, obj) s.write((char*)&(obj), sizeof(obj))
101 #define READDATA(s, obj) s.read((char*)&(obj), sizeof(obj))
103 inline unsigned int GetSerializeSize(char a
, int, int=0) { return sizeof(a
); }
104 inline unsigned int GetSerializeSize(signed char a
, int, int=0) { return sizeof(a
); }
105 inline unsigned int GetSerializeSize(unsigned char a
, int, int=0) { return sizeof(a
); }
106 inline unsigned int GetSerializeSize(signed short a
, int, int=0) { return sizeof(a
); }
107 inline unsigned int GetSerializeSize(unsigned short a
, int, int=0) { return sizeof(a
); }
108 inline unsigned int GetSerializeSize(signed int a
, int, int=0) { return sizeof(a
); }
109 inline unsigned int GetSerializeSize(unsigned int a
, int, int=0) { return sizeof(a
); }
110 inline unsigned int GetSerializeSize(signed long a
, int, int=0) { return sizeof(a
); }
111 inline unsigned int GetSerializeSize(unsigned long a
, int, int=0) { return sizeof(a
); }
112 inline unsigned int GetSerializeSize(int64 a
, int, int=0) { return sizeof(a
); }
113 inline unsigned int GetSerializeSize(uint64 a
, int, int=0) { return sizeof(a
); }
114 inline unsigned int GetSerializeSize(float a
, int, int=0) { return sizeof(a
); }
115 inline unsigned int GetSerializeSize(double a
, int, int=0) { return sizeof(a
); }
117 template<typename Stream
> inline void Serialize(Stream
& s
, char a
, int, int=0) { WRITEDATA(s
, a
); }
118 template<typename Stream
> inline void Serialize(Stream
& s
, signed char a
, int, int=0) { WRITEDATA(s
, a
); }
119 template<typename Stream
> inline void Serialize(Stream
& s
, unsigned char a
, int, int=0) { WRITEDATA(s
, a
); }
120 template<typename Stream
> inline void Serialize(Stream
& s
, signed short a
, int, int=0) { WRITEDATA(s
, a
); }
121 template<typename Stream
> inline void Serialize(Stream
& s
, unsigned short a
, int, int=0) { WRITEDATA(s
, a
); }
122 template<typename Stream
> inline void Serialize(Stream
& s
, signed int a
, int, int=0) { WRITEDATA(s
, a
); }
123 template<typename Stream
> inline void Serialize(Stream
& s
, unsigned int a
, int, int=0) { WRITEDATA(s
, a
); }
124 template<typename Stream
> inline void Serialize(Stream
& s
, signed long a
, int, int=0) { WRITEDATA(s
, a
); }
125 template<typename Stream
> inline void Serialize(Stream
& s
, unsigned long a
, int, int=0) { WRITEDATA(s
, a
); }
126 template<typename Stream
> inline void Serialize(Stream
& s
, int64 a
, int, int=0) { WRITEDATA(s
, a
); }
127 template<typename Stream
> inline void Serialize(Stream
& s
, uint64 a
, int, int=0) { WRITEDATA(s
, a
); }
128 template<typename Stream
> inline void Serialize(Stream
& s
, float a
, int, int=0) { WRITEDATA(s
, a
); }
129 template<typename Stream
> inline void Serialize(Stream
& s
, double a
, int, int=0) { WRITEDATA(s
, a
); }
131 template<typename Stream
> inline void Unserialize(Stream
& s
, char& a
, int, int=0) { READDATA(s
, a
); }
132 template<typename Stream
> inline void Unserialize(Stream
& s
, signed char& a
, int, int=0) { READDATA(s
, a
); }
133 template<typename Stream
> inline void Unserialize(Stream
& s
, unsigned char& a
, int, int=0) { READDATA(s
, a
); }
134 template<typename Stream
> inline void Unserialize(Stream
& s
, signed short& a
, int, int=0) { READDATA(s
, a
); }
135 template<typename Stream
> inline void Unserialize(Stream
& s
, unsigned short& a
, int, int=0) { READDATA(s
, a
); }
136 template<typename Stream
> inline void Unserialize(Stream
& s
, signed int& a
, int, int=0) { READDATA(s
, a
); }
137 template<typename Stream
> inline void Unserialize(Stream
& s
, unsigned int& a
, int, int=0) { READDATA(s
, a
); }
138 template<typename Stream
> inline void Unserialize(Stream
& s
, signed long& a
, int, int=0) { READDATA(s
, a
); }
139 template<typename Stream
> inline void Unserialize(Stream
& s
, unsigned long& a
, int, int=0) { READDATA(s
, a
); }
140 template<typename Stream
> inline void Unserialize(Stream
& s
, int64
& a
, int, int=0) { READDATA(s
, a
); }
141 template<typename Stream
> inline void Unserialize(Stream
& s
, uint64
& a
, int, int=0) { READDATA(s
, a
); }
142 template<typename Stream
> inline void Unserialize(Stream
& s
, float& a
, int, int=0) { READDATA(s
, a
); }
143 template<typename Stream
> inline void Unserialize(Stream
& s
, double& a
, int, int=0) { READDATA(s
, a
); }
145 inline unsigned int GetSerializeSize(bool a
, int, int=0) { return sizeof(char); }
146 template<typename Stream
> inline void Serialize(Stream
& s
, bool a
, int, int=0) { char f
=a
; WRITEDATA(s
, f
); }
147 template<typename Stream
> inline void Unserialize(Stream
& s
, bool& a
, int, int=0) { char f
; READDATA(s
, f
); a
=f
; }
156 // size < 253 -- 1 byte
157 // size <= USHRT_MAX -- 3 bytes (253 + 2 bytes)
158 // size <= UINT_MAX -- 5 bytes (254 + 4 bytes)
159 // size > UINT_MAX -- 9 bytes (255 + 8 bytes)
161 inline unsigned int GetSizeOfCompactSize(uint64 nSize
)
163 if (nSize
< 253) return sizeof(unsigned char);
164 else if (nSize
<= USHRT_MAX
) return sizeof(unsigned char) + sizeof(unsigned short);
165 else if (nSize
<= UINT_MAX
) return sizeof(unsigned char) + sizeof(unsigned int);
166 else return sizeof(unsigned char) + sizeof(uint64
);
169 template<typename Stream
>
170 void WriteCompactSize(Stream
& os
, uint64 nSize
)
174 unsigned char chSize
= nSize
;
175 WRITEDATA(os
, chSize
);
177 else if (nSize
<= USHRT_MAX
)
179 unsigned char chSize
= 253;
180 unsigned short xSize
= nSize
;
181 WRITEDATA(os
, chSize
);
182 WRITEDATA(os
, xSize
);
184 else if (nSize
<= UINT_MAX
)
186 unsigned char chSize
= 254;
187 unsigned int xSize
= nSize
;
188 WRITEDATA(os
, chSize
);
189 WRITEDATA(os
, xSize
);
193 unsigned char chSize
= 255;
194 uint64 xSize
= nSize
;
195 WRITEDATA(os
, chSize
);
196 WRITEDATA(os
, xSize
);
201 template<typename Stream
>
202 uint64
ReadCompactSize(Stream
& is
)
204 unsigned char chSize
;
205 READDATA(is
, chSize
);
211 else if (chSize
== 253)
213 unsigned short xSize
;
217 else if (chSize
== 254)
229 if (nSizeRet
> (uint64
)MAX_SIZE
)
230 throw std::ios_base::failure("ReadCompactSize() : size too large");
237 // Wrapper for serializing arrays and POD
238 // There's a clever template way to make arrays serialize normally, but MSVC6 doesn't support it
240 #define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj)))
247 CFlatData(void* pbeginIn
, void* pendIn
) : pbegin((char*)pbeginIn
), pend((char*)pendIn
) { }
248 char* begin() { return pbegin
; }
249 const char* begin() const { return pbegin
; }
250 char* end() { return pend
; }
251 const char* end() const { return pend
; }
253 unsigned int GetSerializeSize(int, int=0) const
255 return pend
- pbegin
;
258 template<typename Stream
>
259 void Serialize(Stream
& s
, int, int=0) const
261 s
.write(pbegin
, pend
- pbegin
);
264 template<typename Stream
>
265 void Unserialize(Stream
& s
, int, int=0)
267 s
.read(pbegin
, pend
- pbegin
);
274 // string stored as a fixed length field
276 template<std::size_t LEN
>
277 class CFixedFieldString
283 explicit CFixedFieldString(const string
& str
) : pcstr(&str
), pstr(NULL
) { }
284 explicit CFixedFieldString(string
& str
) : pcstr(&str
), pstr(&str
) { }
286 unsigned int GetSerializeSize(int, int=0) const
291 template<typename Stream
>
292 void Serialize(Stream
& s
, int, int=0) const
295 strncpy(pszBuf
, pcstr
->c_str(), LEN
);
296 s
.write(pszBuf
, LEN
);
299 template<typename Stream
>
300 void Unserialize(Stream
& s
, int, int=0)
303 throw std::ios_base::failure("CFixedFieldString::Unserialize : trying to unserialize to const string");
316 // Forward declarations
320 template<typename C
> unsigned int GetSerializeSize(const basic_string
<C
>& str
, int, int=0);
321 template<typename Stream
, typename C
> void Serialize(Stream
& os
, const basic_string
<C
>& str
, int, int=0);
322 template<typename Stream
, typename C
> void Unserialize(Stream
& is
, basic_string
<C
>& str
, int, int=0);
325 template<typename T
, typename A
> unsigned int GetSerializeSize_impl(const std::vector
<T
, A
>& v
, int nType
, int nVersion
, const boost::true_type
&);
326 template<typename T
, typename A
> unsigned int GetSerializeSize_impl(const std::vector
<T
, A
>& v
, int nType
, int nVersion
, const boost::false_type
&);
327 template<typename T
, typename A
> inline unsigned int GetSerializeSize(const std::vector
<T
, A
>& v
, int nType
, int nVersion
=VERSION
);
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::true_type
&);
329 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
&);
330 template<typename Stream
, typename T
, typename A
> inline void Serialize(Stream
& os
, const std::vector
<T
, A
>& v
, int nType
, int nVersion
=VERSION
);
331 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
&);
332 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
&);
333 template<typename Stream
, typename T
, typename A
> inline void Unserialize(Stream
& is
, std::vector
<T
, A
>& v
, int nType
, int nVersion
=VERSION
);
335 // others derived from vector
336 extern inline unsigned int GetSerializeSize(const CScript
& v
, int nType
, int nVersion
=VERSION
);
337 template<typename Stream
> void Serialize(Stream
& os
, const CScript
& v
, int nType
, int nVersion
=VERSION
);
338 template<typename Stream
> void Unserialize(Stream
& is
, CScript
& v
, int nType
, int nVersion
=VERSION
);
341 template<typename K
, typename T
> unsigned int GetSerializeSize(const std::pair
<K
, T
>& item
, int nType
, int nVersion
=VERSION
);
342 template<typename Stream
, typename K
, typename T
> void Serialize(Stream
& os
, const std::pair
<K
, T
>& item
, int nType
, int nVersion
=VERSION
);
343 template<typename Stream
, typename K
, typename T
> void Unserialize(Stream
& is
, std::pair
<K
, T
>& item
, int nType
, int nVersion
=VERSION
);
346 template<typename T0
, typename T1
, typename T2
> unsigned int GetSerializeSize(const boost::tuple
<T0
, T1
, T2
>& item
, int nType
, int nVersion
=VERSION
);
347 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
);
348 template<typename Stream
, typename T0
, typename T1
, typename T2
> void Unserialize(Stream
& is
, boost::tuple
<T0
, T1
, T2
>& item
, int nType
, int nVersion
=VERSION
);
351 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
);
352 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
);
353 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
);
356 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
);
357 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
);
358 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
);
361 template<typename K
, typename Pred
, typename A
> unsigned int GetSerializeSize(const std::set
<K
, Pred
, A
>& m
, int nType
, int nVersion
=VERSION
);
362 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
);
363 template<typename Stream
, typename K
, typename Pred
, typename A
> void Unserialize(Stream
& is
, std::set
<K
, Pred
, A
>& m
, int nType
, int nVersion
=VERSION
);
370 // If none of the specialized versions above matched, default to calling member function.
371 // "int nType" is changed to "long nType" to keep from getting an ambiguous overload error.
372 // The compiler will only cast int to long if none of the other templates matched.
373 // Thanks to Boost serialization for this idea.
376 inline unsigned int GetSerializeSize(const T
& a
, long nType
, int nVersion
=VERSION
)
378 return a
.GetSerializeSize((int)nType
, nVersion
);
381 template<typename Stream
, typename T
>
382 inline void Serialize(Stream
& os
, const T
& a
, long nType
, int nVersion
=VERSION
)
384 a
.Serialize(os
, (int)nType
, nVersion
);
387 template<typename Stream
, typename T
>
388 inline void Unserialize(Stream
& is
, T
& a
, long nType
, int nVersion
=VERSION
)
390 a
.Unserialize(is
, (int)nType
, nVersion
);
401 unsigned int GetSerializeSize(const basic_string
<C
>& str
, int, int)
403 return GetSizeOfCompactSize(str
.size()) + str
.size() * sizeof(str
[0]);
406 template<typename Stream
, typename C
>
407 void Serialize(Stream
& os
, const basic_string
<C
>& str
, int, int)
409 WriteCompactSize(os
, str
.size());
411 os
.write((char*)&str
[0], str
.size() * sizeof(str
[0]));
414 template<typename Stream
, typename C
>
415 void Unserialize(Stream
& is
, basic_string
<C
>& str
, int, int)
417 unsigned int nSize
= ReadCompactSize(is
);
420 is
.read((char*)&str
[0], nSize
* sizeof(str
[0]));
428 template<typename T
, typename A
>
429 unsigned int GetSerializeSize_impl(const std::vector
<T
, A
>& v
, int nType
, int nVersion
, const boost::true_type
&)
431 return (GetSizeOfCompactSize(v
.size()) + v
.size() * sizeof(T
));
434 template<typename T
, typename A
>
435 unsigned int GetSerializeSize_impl(const std::vector
<T
, A
>& v
, int nType
, int nVersion
, const boost::false_type
&)
437 unsigned int nSize
= GetSizeOfCompactSize(v
.size());
438 for (typename
std::vector
<T
, A
>::const_iterator vi
= v
.begin(); vi
!= v
.end(); ++vi
)
439 nSize
+= GetSerializeSize((*vi
), nType
, nVersion
);
443 template<typename T
, typename A
>
444 inline unsigned int GetSerializeSize(const std::vector
<T
, A
>& v
, int nType
, int nVersion
)
446 return GetSerializeSize_impl(v
, nType
, nVersion
, boost::is_fundamental
<T
>());
450 template<typename Stream
, typename T
, typename A
>
451 void Serialize_impl(Stream
& os
, const std::vector
<T
, A
>& v
, int nType
, int nVersion
, const boost::true_type
&)
453 WriteCompactSize(os
, v
.size());
455 os
.write((char*)&v
[0], v
.size() * sizeof(T
));
458 template<typename Stream
, typename T
, typename A
>
459 void Serialize_impl(Stream
& os
, const std::vector
<T
, A
>& v
, int nType
, int nVersion
, const boost::false_type
&)
461 WriteCompactSize(os
, v
.size());
462 for (typename
std::vector
<T
, A
>::const_iterator vi
= v
.begin(); vi
!= v
.end(); ++vi
)
463 ::Serialize(os
, (*vi
), nType
, nVersion
);
466 template<typename Stream
, typename T
, typename A
>
467 inline void Serialize(Stream
& os
, const std::vector
<T
, A
>& v
, int nType
, int nVersion
)
469 Serialize_impl(os
, v
, nType
, nVersion
, boost::is_fundamental
<T
>());
473 template<typename Stream
, typename T
, typename A
>
474 void Unserialize_impl(Stream
& is
, std::vector
<T
, A
>& v
, int nType
, int nVersion
, const boost::true_type
&)
476 //unsigned int nSize = ReadCompactSize(is);
478 //is.read((char*)&v[0], nSize * sizeof(T));
480 // Limit size per read so bogus size value won't cause out of memory
482 unsigned int nSize
= ReadCompactSize(is
);
486 unsigned int blk
= min(nSize
- i
, (unsigned int)(1 + 4999999 / sizeof(T
)));
488 is
.read((char*)&v
[i
], blk
* sizeof(T
));
493 template<typename Stream
, typename T
, typename A
>
494 void Unserialize_impl(Stream
& is
, std::vector
<T
, A
>& v
, int nType
, int nVersion
, const boost::false_type
&)
496 //unsigned int nSize = ReadCompactSize(is);
498 //for (std::vector<T, A>::iterator vi = v.begin(); vi != v.end(); ++vi)
499 // Unserialize(is, (*vi), nType, nVersion);
502 unsigned int nSize
= ReadCompactSize(is
);
504 unsigned int nMid
= 0;
507 nMid
+= 5000000 / sizeof(T
);
511 for (; i
< nMid
; i
++)
512 Unserialize(is
, v
[i
], nType
, nVersion
);
516 template<typename Stream
, typename T
, typename A
>
517 inline void Unserialize(Stream
& is
, std::vector
<T
, A
>& v
, int nType
, int nVersion
)
519 Unserialize_impl(is
, v
, nType
, nVersion
, boost::is_fundamental
<T
>());
525 // others derived from vector
527 inline unsigned int GetSerializeSize(const CScript
& v
, int nType
, int nVersion
)
529 return GetSerializeSize((const vector
<unsigned char>&)v
, nType
, nVersion
);
532 template<typename Stream
>
533 void Serialize(Stream
& os
, const CScript
& v
, int nType
, int nVersion
)
535 Serialize(os
, (const vector
<unsigned char>&)v
, nType
, nVersion
);
538 template<typename Stream
>
539 void Unserialize(Stream
& is
, CScript
& v
, int nType
, int nVersion
)
541 Unserialize(is
, (vector
<unsigned char>&)v
, nType
, nVersion
);
549 template<typename K
, typename T
>
550 unsigned int GetSerializeSize(const std::pair
<K
, T
>& item
, int nType
, int nVersion
)
552 return GetSerializeSize(item
.first
, nType
, nVersion
) + GetSerializeSize(item
.second
, nType
, nVersion
);
555 template<typename Stream
, typename K
, typename T
>
556 void Serialize(Stream
& os
, const std::pair
<K
, T
>& item
, int nType
, int nVersion
)
558 Serialize(os
, item
.first
, nType
, nVersion
);
559 Serialize(os
, item
.second
, nType
, nVersion
);
562 template<typename Stream
, typename K
, typename T
>
563 void Unserialize(Stream
& is
, std::pair
<K
, T
>& item
, int nType
, int nVersion
)
565 Unserialize(is
, item
.first
, nType
, nVersion
);
566 Unserialize(is
, item
.second
, nType
, nVersion
);
574 template<typename T0
, typename T1
, typename T2
>
575 unsigned int GetSerializeSize(const boost::tuple
<T0
, T1
, T2
>& item
, int nType
, int nVersion
)
577 unsigned int nSize
= 0;
578 nSize
+= GetSerializeSize(get
<0>(item
), nType
, nVersion
);
579 nSize
+= GetSerializeSize(get
<1>(item
), nType
, nVersion
);
580 nSize
+= GetSerializeSize(get
<2>(item
), nType
, nVersion
);
584 template<typename Stream
, typename T0
, typename T1
, typename T2
>
585 void Serialize(Stream
& os
, const boost::tuple
<T0
, T1
, T2
>& item
, int nType
, int nVersion
)
587 Serialize(os
, get
<0>(item
), nType
, nVersion
);
588 Serialize(os
, get
<1>(item
), nType
, nVersion
);
589 Serialize(os
, get
<2>(item
), nType
, nVersion
);
592 template<typename Stream
, typename T0
, typename T1
, typename T2
>
593 void Unserialize(Stream
& is
, boost::tuple
<T0
, T1
, T2
>& item
, int nType
, int nVersion
)
595 Unserialize(is
, get
<0>(item
), nType
, nVersion
);
596 Unserialize(is
, get
<1>(item
), nType
, nVersion
);
597 Unserialize(is
, get
<2>(item
), nType
, nVersion
);
605 template<typename T0
, typename T1
, typename T2
, typename T3
>
606 unsigned int GetSerializeSize(const boost::tuple
<T0
, T1
, T2
, T3
>& item
, int nType
, int nVersion
)
608 unsigned int nSize
= 0;
609 nSize
+= GetSerializeSize(get
<0>(item
), nType
, nVersion
);
610 nSize
+= GetSerializeSize(get
<1>(item
), nType
, nVersion
);
611 nSize
+= GetSerializeSize(get
<2>(item
), nType
, nVersion
);
612 nSize
+= GetSerializeSize(get
<3>(item
), nType
, nVersion
);
616 template<typename Stream
, typename T0
, typename T1
, typename T2
, typename T3
>
617 void Serialize(Stream
& os
, const boost::tuple
<T0
, T1
, T2
, T3
>& item
, int nType
, int nVersion
)
619 Serialize(os
, get
<0>(item
), nType
, nVersion
);
620 Serialize(os
, get
<1>(item
), nType
, nVersion
);
621 Serialize(os
, get
<2>(item
), nType
, nVersion
);
622 Serialize(os
, get
<3>(item
), nType
, nVersion
);
625 template<typename Stream
, typename T0
, typename T1
, typename T2
, typename T3
>
626 void Unserialize(Stream
& is
, boost::tuple
<T0
, T1
, T2
, T3
>& item
, int nType
, int nVersion
)
628 Unserialize(is
, get
<0>(item
), nType
, nVersion
);
629 Unserialize(is
, get
<1>(item
), nType
, nVersion
);
630 Unserialize(is
, get
<2>(item
), nType
, nVersion
);
631 Unserialize(is
, get
<3>(item
), nType
, nVersion
);
639 template<typename K
, typename T
, typename Pred
, typename A
>
640 unsigned int GetSerializeSize(const std::map
<K
, T
, Pred
, A
>& m
, int nType
, int nVersion
)
642 unsigned int nSize
= GetSizeOfCompactSize(m
.size());
643 for (typename
std::map
<K
, T
, Pred
, A
>::const_iterator mi
= m
.begin(); mi
!= m
.end(); ++mi
)
644 nSize
+= GetSerializeSize((*mi
), nType
, nVersion
);
648 template<typename Stream
, typename K
, typename T
, typename Pred
, typename A
>
649 void Serialize(Stream
& os
, const std::map
<K
, T
, Pred
, A
>& m
, int nType
, int nVersion
)
651 WriteCompactSize(os
, m
.size());
652 for (typename
std::map
<K
, T
, Pred
, A
>::const_iterator mi
= m
.begin(); mi
!= m
.end(); ++mi
)
653 Serialize(os
, (*mi
), nType
, nVersion
);
656 template<typename Stream
, typename K
, typename T
, typename Pred
, typename A
>
657 void Unserialize(Stream
& is
, std::map
<K
, T
, Pred
, A
>& m
, int nType
, int nVersion
)
660 unsigned int nSize
= ReadCompactSize(is
);
661 typename
std::map
<K
, T
, Pred
, A
>::iterator mi
= m
.begin();
662 for (unsigned int i
= 0; i
< nSize
; i
++)
665 Unserialize(is
, item
, nType
, nVersion
);
666 mi
= m
.insert(mi
, item
);
675 template<typename K
, typename Pred
, typename A
>
676 unsigned int GetSerializeSize(const std::set
<K
, Pred
, A
>& m
, int nType
, int nVersion
)
678 unsigned int nSize
= GetSizeOfCompactSize(m
.size());
679 for (typename
std::set
<K
, Pred
, A
>::const_iterator it
= m
.begin(); it
!= m
.end(); ++it
)
680 nSize
+= GetSerializeSize((*it
), nType
, nVersion
);
684 template<typename Stream
, typename K
, typename Pred
, typename A
>
685 void Serialize(Stream
& os
, const std::set
<K
, Pred
, A
>& m
, int nType
, int nVersion
)
687 WriteCompactSize(os
, m
.size());
688 for (typename
std::set
<K
, Pred
, A
>::const_iterator it
= m
.begin(); it
!= m
.end(); ++it
)
689 Serialize(os
, (*it
), nType
, nVersion
);
692 template<typename Stream
, typename K
, typename Pred
, typename A
>
693 void Unserialize(Stream
& is
, std::set
<K
, Pred
, A
>& m
, int nType
, int nVersion
)
696 unsigned int nSize
= ReadCompactSize(is
);
697 typename
std::set
<K
, Pred
, A
>::iterator it
= m
.begin();
698 for (unsigned int i
= 0; i
< nSize
; i
++)
701 Unserialize(is
, key
, nType
, nVersion
);
702 it
= m
.insert(it
, key
);
709 // Support for IMPLEMENT_SERIALIZE and READWRITE macro
711 class CSerActionGetSerializeSize
{ };
712 class CSerActionSerialize
{ };
713 class CSerActionUnserialize
{ };
715 template<typename Stream
, typename T
>
716 inline unsigned int SerReadWrite(Stream
& s
, const T
& obj
, int nType
, int nVersion
, CSerActionGetSerializeSize ser_action
)
718 return ::GetSerializeSize(obj
, nType
, nVersion
);
721 template<typename Stream
, typename T
>
722 inline unsigned int SerReadWrite(Stream
& s
, const T
& obj
, int nType
, int nVersion
, CSerActionSerialize ser_action
)
724 ::Serialize(s
, obj
, nType
, nVersion
);
728 template<typename Stream
, typename T
>
729 inline unsigned int SerReadWrite(Stream
& s
, T
& obj
, int nType
, int nVersion
, CSerActionUnserialize ser_action
)
731 ::Unserialize(s
, obj
, nType
, nVersion
);
735 struct ser_streamplaceholder
750 // Allocator that clears its contents before deletion
753 struct secure_allocator
: public std::allocator
<T
>
755 // MSVC8 default copy constructor is broken
756 typedef std::allocator
<T
> base
;
757 typedef typename
base::size_type size_type
;
758 typedef typename
base::difference_type difference_type
;
759 typedef typename
base::pointer pointer
;
760 typedef typename
base::const_pointer const_pointer
;
761 typedef typename
base::reference reference
;
762 typedef typename
base::const_reference const_reference
;
763 typedef typename
base::value_type value_type
;
764 secure_allocator() throw() {}
765 secure_allocator(const secure_allocator
& a
) throw() : base(a
) {}
766 ~secure_allocator() throw() {}
767 template<typename _Other
> struct rebind
768 { typedef secure_allocator
<_Other
> other
; };
770 void deallocate(T
* p
, std::size_t n
)
773 memset(p
, 0, sizeof(T
) * n
);
774 allocator
<T
>::deallocate(p
, n
);
781 // Double ended buffer combining vector and stream-like interfaces.
782 // >> and << read and write unformatted data using the above serialization templates.
783 // Fills with data in linear time; some stringstream implementations take N^2 time.
788 typedef vector
<char, secure_allocator
<char> > vector_type
;
790 unsigned int nReadPos
;
797 typedef vector_type::allocator_type allocator_type
;
798 typedef vector_type::size_type size_type
;
799 typedef vector_type::difference_type difference_type
;
800 typedef vector_type::reference reference
;
801 typedef vector_type::const_reference const_reference
;
802 typedef vector_type::value_type value_type
;
803 typedef vector_type::iterator iterator
;
804 typedef vector_type::const_iterator const_iterator
;
805 typedef vector_type::reverse_iterator reverse_iterator
;
807 explicit CDataStream(int nTypeIn
=SER_NETWORK
, int nVersionIn
=VERSION
)
809 Init(nTypeIn
, nVersionIn
);
812 CDataStream(const_iterator pbegin
, const_iterator pend
, int nTypeIn
=SER_NETWORK
, int nVersionIn
=VERSION
) : vch(pbegin
, pend
)
814 Init(nTypeIn
, nVersionIn
);
817 #if !defined(_MSC_VER) || _MSC_VER >= 1300
818 CDataStream(const char* pbegin
, const char* pend
, int nTypeIn
=SER_NETWORK
, int nVersionIn
=VERSION
) : vch(pbegin
, pend
)
820 Init(nTypeIn
, nVersionIn
);
824 CDataStream(const vector_type
& vchIn
, int nTypeIn
=SER_NETWORK
, int nVersionIn
=VERSION
) : vch(vchIn
.begin(), vchIn
.end())
826 Init(nTypeIn
, nVersionIn
);
829 CDataStream(const vector
<char>& vchIn
, int nTypeIn
=SER_NETWORK
, int nVersionIn
=VERSION
) : vch(vchIn
.begin(), vchIn
.end())
831 Init(nTypeIn
, nVersionIn
);
834 CDataStream(const vector
<unsigned char>& vchIn
, int nTypeIn
=SER_NETWORK
, int nVersionIn
=VERSION
) : vch((char*)&vchIn
.begin()[0], (char*)&vchIn
.end()[0])
836 Init(nTypeIn
, nVersionIn
);
839 void Init(int nTypeIn
=SER_NETWORK
, int nVersionIn
=VERSION
)
843 nVersion
= nVersionIn
;
845 exceptmask
= ios::badbit
| ios::failbit
;
848 CDataStream
& operator+=(const CDataStream
& b
)
850 vch
.insert(vch
.end(), b
.begin(), b
.end());
854 friend CDataStream
operator+(const CDataStream
& a
, const CDataStream
& b
)
863 return (string(begin(), end()));
870 const_iterator
begin() const { return vch
.begin() + nReadPos
; }
871 iterator
begin() { return vch
.begin() + nReadPos
; }
872 const_iterator
end() const { return vch
.end(); }
873 iterator
end() { return vch
.end(); }
874 size_type
size() const { return vch
.size() - nReadPos
; }
875 bool empty() const { return vch
.size() == nReadPos
; }
876 void resize(size_type n
, value_type c
=0) { vch
.resize(n
+ nReadPos
, c
); }
877 void reserve(size_type n
) { vch
.reserve(n
+ nReadPos
); }
878 const_reference
operator[](size_type pos
) const { return vch
[pos
+ nReadPos
]; }
879 reference
operator[](size_type pos
) { return vch
[pos
+ nReadPos
]; }
880 void clear() { vch
.clear(); nReadPos
= 0; }
881 iterator
insert(iterator it
, const char& x
=char()) { return vch
.insert(it
, x
); }
882 void insert(iterator it
, size_type n
, const char& x
) { vch
.insert(it
, n
, x
); }
884 void insert(iterator it
, const_iterator first
, const_iterator last
)
886 if (it
== vch
.begin() + nReadPos
&& last
- first
<= nReadPos
)
888 // special case for inserting at the front when there's room
889 nReadPos
-= (last
- first
);
890 memcpy(&vch
[nReadPos
], &first
[0], last
- first
);
893 vch
.insert(it
, first
, last
);
896 void insert(iterator it
, vector
<char>::const_iterator first
, vector
<char>::const_iterator last
)
898 if (it
== vch
.begin() + nReadPos
&& last
- first
<= nReadPos
)
900 // special case for inserting at the front when there's room
901 nReadPos
-= (last
- first
);
902 memcpy(&vch
[nReadPos
], &first
[0], last
- first
);
905 vch
.insert(it
, first
, last
);
908 #if !defined(_MSC_VER) || _MSC_VER >= 1300
909 void insert(iterator it
, const char* first
, const char* last
)
911 if (it
== vch
.begin() + nReadPos
&& last
- first
<= nReadPos
)
913 // special case for inserting at the front when there's room
914 nReadPos
-= (last
- first
);
915 memcpy(&vch
[nReadPos
], &first
[0], last
- first
);
918 vch
.insert(it
, first
, last
);
922 iterator
erase(iterator it
)
924 if (it
== vch
.begin() + nReadPos
)
926 // special case for erasing from the front
927 if (++nReadPos
>= vch
.size())
929 // whenever we reach the end, we take the opportunity to clear the buffer
931 return vch
.erase(vch
.begin(), vch
.end());
933 return vch
.begin() + nReadPos
;
936 return vch
.erase(it
);
939 iterator
erase(iterator first
, iterator last
)
941 if (first
== vch
.begin() + nReadPos
)
943 // special case for erasing from the front
944 if (last
== vch
.end())
947 return vch
.erase(vch
.begin(), vch
.end());
951 nReadPos
= (last
- vch
.begin());
956 return vch
.erase(first
, last
);
959 inline void Compact()
961 vch
.erase(vch
.begin(), vch
.begin() + nReadPos
);
965 bool Rewind(size_type n
)
967 // Rewind by n characters if the buffer hasn't been compacted yet
978 void setstate(short bits
, const char* psz
)
981 if (state
& exceptmask
)
982 throw std::ios_base::failure(psz
);
985 bool eof() const { return size() == 0; }
986 bool fail() const { return state
& (ios::badbit
| ios::failbit
); }
987 bool good() const { return !eof() && (state
== 0); }
988 void clear(short n
) { state
= n
; } // name conflict with vector clear()
989 short exceptions() { return exceptmask
; }
990 short exceptions(short mask
) { short prev
= exceptmask
; exceptmask
= mask
; setstate(0, "CDataStream"); return prev
; }
991 CDataStream
* rdbuf() { return this; }
992 int in_avail() { return size(); }
994 void SetType(int n
) { nType
= n
; }
995 int GetType() { return nType
; }
996 void SetVersion(int n
) { nVersion
= n
; }
997 int GetVersion() { return nVersion
; }
998 void ReadVersion() { *this >> nVersion
; }
999 void WriteVersion() { *this << nVersion
; }
1001 CDataStream
& read(char* pch
, int nSize
)
1003 // Read from the beginning of the buffer
1005 unsigned int nReadPosNext
= nReadPos
+ nSize
;
1006 if (nReadPosNext
>= vch
.size())
1008 if (nReadPosNext
> vch
.size())
1010 setstate(ios::failbit
, "CDataStream::read() : end of data");
1011 memset(pch
, 0, nSize
);
1012 nSize
= vch
.size() - nReadPos
;
1014 memcpy(pch
, &vch
[nReadPos
], nSize
);
1019 memcpy(pch
, &vch
[nReadPos
], nSize
);
1020 nReadPos
= nReadPosNext
;
1024 CDataStream
& ignore(int nSize
)
1026 // Ignore from the beginning of the buffer
1028 unsigned int nReadPosNext
= nReadPos
+ nSize
;
1029 if (nReadPosNext
>= vch
.size())
1031 if (nReadPosNext
> vch
.size())
1033 setstate(ios::failbit
, "CDataStream::ignore() : end of data");
1034 nSize
= vch
.size() - nReadPos
;
1040 nReadPos
= nReadPosNext
;
1044 CDataStream
& write(const char* pch
, int nSize
)
1046 // Write to the end of the buffer
1048 vch
.insert(vch
.end(), pch
, pch
+ nSize
);
1052 template<typename Stream
>
1053 void Serialize(Stream
& s
, int nType
=0, int nVersion
=VERSION
) const
1055 // Special case: stream << stream concatenates like stream += stream
1057 s
.write((char*)&vch
[0], vch
.size() * sizeof(vch
[0]));
1060 template<typename T
>
1061 unsigned int GetSerializeSize(const T
& obj
)
1063 // Tells the size of the object if serialized to this stream
1064 return ::GetSerializeSize(obj
, nType
, nVersion
);
1067 template<typename T
>
1068 CDataStream
& operator<<(const T
& obj
)
1070 // Serialize to this stream
1071 ::Serialize(*this, obj
, nType
, nVersion
);
1075 template<typename T
>
1076 CDataStream
& operator>>(T
& obj
)
1078 // Unserialize from this stream
1079 ::Unserialize(*this, obj
, nType
, nVersion
);
1084 #ifdef TESTCDATASTREAM
1091 // n=16000 0 seconds
1092 // n=32000 0 seconds
1093 // n=64000 1 seconds
1094 // n=128000 1 seconds
1095 // n=256000 2 seconds
1096 // n=512000 4 seconds
1097 // n=1024000 8 seconds
1098 // n=2048000 16 seconds
1099 // n=4096000 32 seconds
1103 // n=4000 13 seconds
1104 // n=8000 87 seconds
1105 // n=16000 400 seconds
1106 // n=32000 1660 seconds
1107 // n=64000 6749 seconds
1108 // n=128000 27241 seconds
1109 // n=256000 109804 seconds
1111 int main(int argc
, char *argv
[])
1113 vector
<unsigned char> vch(0xcc, 250);
1114 printf("CDataStream:\n");
1115 for (int n
= 1000; n
<= 4500000; n
*= 2)
1118 time_t nStart
= time(NULL
);
1119 for (int i
= 0; i
< n
; i
++)
1120 ss
.write((char*)&vch
[0], vch
.size());
1121 printf("n=%-10d %d seconds\n", n
, time(NULL
) - nStart
);
1123 printf("stringstream:\n");
1124 for (int n
= 1000; n
<= 4500000; n
*= 2)
1127 time_t nStart
= time(NULL
);
1128 for (int i
= 0; i
< n
; i
++)
1129 ss
.write((char*)&vch
[0], vch
.size());
1130 printf("n=%-10d %d seconds\n", n
, time(NULL
) - nStart
);
1145 // Automatic closing wrapper for FILE*
1146 // - Will automatically close the file when it goes out of scope if not null.
1147 // - If you're returning the file pointer, return file.release().
1148 // - If you need to close the file early, use file.fclose() instead of fclose(file).
1160 typedef FILE element_type
;
1162 CAutoFile(FILE* filenew
=NULL
, int nTypeIn
=SER_DISK
, int nVersionIn
=VERSION
)
1166 nVersion
= nVersionIn
;
1168 exceptmask
= ios::badbit
| ios::failbit
;
1178 if (file
!= NULL
&& file
!= stdin
&& file
!= stdout
&& file
!= stderr
)
1183 FILE* release() { FILE* ret
= file
; file
= NULL
; return ret
; }
1184 operator FILE*() { return file
; }
1185 FILE* operator->() { return file
; }
1186 FILE& operator*() { return *file
; }
1187 FILE** operator&() { return &file
; }
1188 FILE* operator=(FILE* pnew
) { return file
= pnew
; }
1189 bool operator!() { return (file
== NULL
); }
1195 void setstate(short bits
, const char* psz
)
1198 if (state
& exceptmask
)
1199 throw std::ios_base::failure(psz
);
1202 bool fail() const { return state
& (ios::badbit
| ios::failbit
); }
1203 bool good() const { return state
== 0; }
1204 void clear(short n
= 0) { state
= n
; }
1205 short exceptions() { return exceptmask
; }
1206 short exceptions(short mask
) { short prev
= exceptmask
; exceptmask
= mask
; setstate(0, "CAutoFile"); return prev
; }
1208 void SetType(int n
) { nType
= n
; }
1209 int GetType() { return nType
; }
1210 void SetVersion(int n
) { nVersion
= n
; }
1211 int GetVersion() { return nVersion
; }
1212 void ReadVersion() { *this >> nVersion
; }
1213 void WriteVersion() { *this << nVersion
; }
1215 CAutoFile
& read(char* pch
, int nSize
)
1218 throw std::ios_base::failure("CAutoFile::read : file handle is NULL");
1219 if (fread(pch
, 1, nSize
, file
) != nSize
)
1220 setstate(ios::failbit
, feof(file
) ? "CAutoFile::read : end of file" : "CAutoFile::read : fread failed");
1224 CAutoFile
& write(const char* pch
, int nSize
)
1227 throw std::ios_base::failure("CAutoFile::write : file handle is NULL");
1228 if (fwrite(pch
, 1, nSize
, file
) != nSize
)
1229 setstate(ios::failbit
, "CAutoFile::write : write failed");
1233 template<typename T
>
1234 unsigned int GetSerializeSize(const T
& obj
)
1236 // Tells the size of the object if serialized to this stream
1237 return ::GetSerializeSize(obj
, nType
, nVersion
);
1240 template<typename T
>
1241 CAutoFile
& operator<<(const T
& obj
)
1243 // Serialize to this stream
1245 throw std::ios_base::failure("CAutoFile::operator<< : file handle is NULL");
1246 ::Serialize(*this, obj
, nType
, nVersion
);
1250 template<typename T
>
1251 CAutoFile
& operator>>(T
& obj
)
1253 // Unserialize from this stream
1255 throw std::ios_base::failure("CAutoFile::operator>> : file handle is NULL");
1256 ::Unserialize(*this, obj
, nType
, nVersion
);