]>
Commit | Line | Data |
---|---|---|
0a61b0df | 1 | // Copyright (c) 2009-2010 Satoshi Nakamoto |
88216419 | 2 | // Copyright (c) 2009-2012 The Bitcoin developers |
0a61b0df | 3 | // Distributed under the MIT/X11 software license, see the accompanying |
3a25a2b9 | 4 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
223b6f1b WL |
5 | #ifndef BITCOIN_SERIALIZE_H |
6 | #define BITCOIN_SERIALIZE_H | |
0a61b0df | 7 | |
d743f035 | 8 | #include <string> |
0a61b0df | 9 | #include <vector> |
10 | #include <map> | |
d743f035 | 11 | #include <set> |
223b6f1b | 12 | #include <cassert> |
0e87f34b | 13 | #include <limits> |
223b6f1b WL |
14 | #include <cstring> |
15 | #include <cstdio> | |
16 | ||
0a61b0df | 17 | #include <boost/type_traits/is_fundamental.hpp> |
84d7c981 | 18 | #include <boost/tuple/tuple.hpp> |
19 | #include <boost/tuple/tuple_comparison.hpp> | |
20 | #include <boost/tuple/tuple_io.hpp> | |
223b6f1b | 21 | |
6cb6d623 | 22 | #include "allocators.h" |
b87c0fc4 | 23 | #include "version.h" |
6cb6d623 | 24 | |
bde280b9 WL |
25 | typedef long long int64; |
26 | typedef unsigned long long uint64; | |
27 | ||
0a61b0df | 28 | class CScript; |
29 | class CDataStream; | |
30 | class CAutoFile; | |
0a61b0df | 31 | static const unsigned int MAX_SIZE = 0x02000000; |
32 | ||
82dc6426 GS |
33 | // Used to bypass the rule against non-const reference to temporary |
34 | // where it makes sense with wrappers such as CFlatData or CTxDB | |
35 | template<typename T> | |
36 | inline T& REF(const T& val) | |
37 | { | |
38 | return const_cast<T&>(val); | |
39 | } | |
0a61b0df | 40 | |
41 | ///////////////////////////////////////////////////////////////// | |
42 | // | |
43 | // Templates for serializing to anything that looks like a stream, | |
44 | // i.e. anything that supports .read(char*, int) and .write(char*, int) | |
45 | // | |
46 | ||
47 | enum | |
48 | { | |
49 | // primary actions | |
50 | SER_NETWORK = (1 << 0), | |
51 | SER_DISK = (1 << 1), | |
52 | SER_GETHASH = (1 << 2), | |
53 | ||
54 | // modifiers | |
55 | SER_SKIPSIG = (1 << 16), | |
56 | SER_BLOCKHEADERONLY = (1 << 17), | |
57 | }; | |
58 | ||
59 | #define IMPLEMENT_SERIALIZE(statements) \ | |
6b6aaa16 | 60 | unsigned int GetSerializeSize(int nType, int nVersion) const \ |
0a61b0df | 61 | { \ |
62 | CSerActionGetSerializeSize ser_action; \ | |
63 | const bool fGetSize = true; \ | |
64 | const bool fWrite = false; \ | |
65 | const bool fRead = false; \ | |
66 | unsigned int nSerSize = 0; \ | |
67 | ser_streamplaceholder s; \ | |
a1de57a0 | 68 | assert(fGetSize||fWrite||fRead); /* suppress warning */ \ |
0a61b0df | 69 | s.nType = nType; \ |
70 | s.nVersion = nVersion; \ | |
71 | {statements} \ | |
72 | return nSerSize; \ | |
73 | } \ | |
74 | template<typename Stream> \ | |
6b6aaa16 | 75 | void Serialize(Stream& s, int nType, int nVersion) const \ |
0a61b0df | 76 | { \ |
77 | CSerActionSerialize ser_action; \ | |
78 | const bool fGetSize = false; \ | |
79 | const bool fWrite = true; \ | |
80 | const bool fRead = false; \ | |
81 | unsigned int nSerSize = 0; \ | |
a1de57a0 | 82 | assert(fGetSize||fWrite||fRead); /* suppress warning */ \ |
0a61b0df | 83 | {statements} \ |
84 | } \ | |
85 | template<typename Stream> \ | |
6b6aaa16 | 86 | void Unserialize(Stream& s, int nType, int nVersion) \ |
0a61b0df | 87 | { \ |
88 | CSerActionUnserialize ser_action; \ | |
89 | const bool fGetSize = false; \ | |
90 | const bool fWrite = false; \ | |
91 | const bool fRead = true; \ | |
92 | unsigned int nSerSize = 0; \ | |
a1de57a0 | 93 | assert(fGetSize||fWrite||fRead); /* suppress warning */ \ |
0a61b0df | 94 | {statements} \ |
95 | } | |
96 | ||
97 | #define READWRITE(obj) (nSerSize += ::SerReadWrite(s, (obj), nType, nVersion, ser_action)) | |
98 | ||
0a61b0df | 99 | |
100 | ||
101 | ||
102 | ||
103 | ||
104 | // | |
105 | // Basic types | |
106 | // | |
107 | #define WRITEDATA(s, obj) s.write((char*)&(obj), sizeof(obj)) | |
108 | #define READDATA(s, obj) s.read((char*)&(obj), sizeof(obj)) | |
109 | ||
110 | inline unsigned int GetSerializeSize(char a, int, int=0) { return sizeof(a); } | |
111 | inline unsigned int GetSerializeSize(signed char a, int, int=0) { return sizeof(a); } | |
112 | inline unsigned int GetSerializeSize(unsigned char a, int, int=0) { return sizeof(a); } | |
113 | inline unsigned int GetSerializeSize(signed short a, int, int=0) { return sizeof(a); } | |
114 | inline unsigned int GetSerializeSize(unsigned short a, int, int=0) { return sizeof(a); } | |
115 | inline unsigned int GetSerializeSize(signed int a, int, int=0) { return sizeof(a); } | |
116 | inline unsigned int GetSerializeSize(unsigned int a, int, int=0) { return sizeof(a); } | |
117 | inline unsigned int GetSerializeSize(signed long a, int, int=0) { return sizeof(a); } | |
118 | inline unsigned int GetSerializeSize(unsigned long a, int, int=0) { return sizeof(a); } | |
bde280b9 WL |
119 | inline unsigned int GetSerializeSize(int64 a, int, int=0) { return sizeof(a); } |
120 | inline unsigned int GetSerializeSize(uint64 a, int, int=0) { return sizeof(a); } | |
0a61b0df | 121 | inline unsigned int GetSerializeSize(float a, int, int=0) { return sizeof(a); } |
122 | inline unsigned int GetSerializeSize(double a, int, int=0) { return sizeof(a); } | |
123 | ||
124 | template<typename Stream> inline void Serialize(Stream& s, char a, int, int=0) { WRITEDATA(s, a); } | |
125 | template<typename Stream> inline void Serialize(Stream& s, signed char a, int, int=0) { WRITEDATA(s, a); } | |
126 | template<typename Stream> inline void Serialize(Stream& s, unsigned char a, int, int=0) { WRITEDATA(s, a); } | |
127 | template<typename Stream> inline void Serialize(Stream& s, signed short a, int, int=0) { WRITEDATA(s, a); } | |
128 | template<typename Stream> inline void Serialize(Stream& s, unsigned short a, int, int=0) { WRITEDATA(s, a); } | |
129 | template<typename Stream> inline void Serialize(Stream& s, signed int a, int, int=0) { WRITEDATA(s, a); } | |
130 | template<typename Stream> inline void Serialize(Stream& s, unsigned int a, int, int=0) { WRITEDATA(s, a); } | |
131 | template<typename Stream> inline void Serialize(Stream& s, signed long a, int, int=0) { WRITEDATA(s, a); } | |
132 | template<typename Stream> inline void Serialize(Stream& s, unsigned long a, int, int=0) { WRITEDATA(s, a); } | |
bde280b9 WL |
133 | template<typename Stream> inline void Serialize(Stream& s, int64 a, int, int=0) { WRITEDATA(s, a); } |
134 | template<typename Stream> inline void Serialize(Stream& s, uint64 a, int, int=0) { WRITEDATA(s, a); } | |
0a61b0df | 135 | template<typename Stream> inline void Serialize(Stream& s, float a, int, int=0) { WRITEDATA(s, a); } |
136 | template<typename Stream> inline void Serialize(Stream& s, double a, int, int=0) { WRITEDATA(s, a); } | |
137 | ||
138 | template<typename Stream> inline void Unserialize(Stream& s, char& a, int, int=0) { READDATA(s, a); } | |
139 | template<typename Stream> inline void Unserialize(Stream& s, signed char& a, int, int=0) { READDATA(s, a); } | |
140 | template<typename Stream> inline void Unserialize(Stream& s, unsigned char& a, int, int=0) { READDATA(s, a); } | |
141 | template<typename Stream> inline void Unserialize(Stream& s, signed short& a, int, int=0) { READDATA(s, a); } | |
142 | template<typename Stream> inline void Unserialize(Stream& s, unsigned short& a, int, int=0) { READDATA(s, a); } | |
143 | template<typename Stream> inline void Unserialize(Stream& s, signed int& a, int, int=0) { READDATA(s, a); } | |
144 | template<typename Stream> inline void Unserialize(Stream& s, unsigned int& a, int, int=0) { READDATA(s, a); } | |
145 | template<typename Stream> inline void Unserialize(Stream& s, signed long& a, int, int=0) { READDATA(s, a); } | |
146 | template<typename Stream> inline void Unserialize(Stream& s, unsigned long& a, int, int=0) { READDATA(s, a); } | |
bde280b9 WL |
147 | template<typename Stream> inline void Unserialize(Stream& s, int64& a, int, int=0) { READDATA(s, a); } |
148 | template<typename Stream> inline void Unserialize(Stream& s, uint64& a, int, int=0) { READDATA(s, a); } | |
0a61b0df | 149 | template<typename Stream> inline void Unserialize(Stream& s, float& a, int, int=0) { READDATA(s, a); } |
150 | template<typename Stream> inline void Unserialize(Stream& s, double& a, int, int=0) { READDATA(s, a); } | |
151 | ||
152 | inline unsigned int GetSerializeSize(bool a, int, int=0) { return sizeof(char); } | |
153 | template<typename Stream> inline void Serialize(Stream& s, bool a, int, int=0) { char f=a; WRITEDATA(s, f); } | |
154 | template<typename Stream> inline void Unserialize(Stream& s, bool& a, int, int=0) { char f; READDATA(s, f); a=f; } | |
155 | ||
156 | ||
157 | ||
158 | ||
159 | ||
160 | ||
161 | // | |
162 | // Compact size | |
163 | // size < 253 -- 1 byte | |
164 | // size <= USHRT_MAX -- 3 bytes (253 + 2 bytes) | |
165 | // size <= UINT_MAX -- 5 bytes (254 + 4 bytes) | |
166 | // size > UINT_MAX -- 9 bytes (255 + 8 bytes) | |
167 | // | |
bde280b9 | 168 | inline unsigned int GetSizeOfCompactSize(uint64 nSize) |
0a61b0df | 169 | { |
a790fa46 | 170 | if (nSize < 253) return sizeof(unsigned char); |
26ce92b3 GA |
171 | else if (nSize <= std::numeric_limits<unsigned short>::max()) return sizeof(unsigned char) + sizeof(unsigned short); |
172 | else if (nSize <= std::numeric_limits<unsigned int>::max()) return sizeof(unsigned char) + sizeof(unsigned int); | |
bde280b9 | 173 | else return sizeof(unsigned char) + sizeof(uint64); |
0a61b0df | 174 | } |
175 | ||
176 | template<typename Stream> | |
bde280b9 | 177 | void WriteCompactSize(Stream& os, uint64 nSize) |
0a61b0df | 178 | { |
a790fa46 | 179 | if (nSize < 253) |
0a61b0df | 180 | { |
181 | unsigned char chSize = nSize; | |
182 | WRITEDATA(os, chSize); | |
183 | } | |
26ce92b3 | 184 | else if (nSize <= std::numeric_limits<unsigned short>::max()) |
0a61b0df | 185 | { |
a790fa46 | 186 | unsigned char chSize = 253; |
0a61b0df | 187 | unsigned short xSize = nSize; |
188 | WRITEDATA(os, chSize); | |
189 | WRITEDATA(os, xSize); | |
190 | } | |
26ce92b3 | 191 | else if (nSize <= std::numeric_limits<unsigned int>::max()) |
0a61b0df | 192 | { |
a790fa46 | 193 | unsigned char chSize = 254; |
0a61b0df | 194 | unsigned int xSize = nSize; |
195 | WRITEDATA(os, chSize); | |
196 | WRITEDATA(os, xSize); | |
197 | } | |
198 | else | |
199 | { | |
a790fa46 | 200 | unsigned char chSize = 255; |
bde280b9 | 201 | uint64 xSize = nSize; |
0a61b0df | 202 | WRITEDATA(os, chSize); |
a790fa46 | 203 | WRITEDATA(os, xSize); |
0a61b0df | 204 | } |
205 | return; | |
206 | } | |
207 | ||
208 | template<typename Stream> | |
bde280b9 | 209 | uint64 ReadCompactSize(Stream& is) |
0a61b0df | 210 | { |
211 | unsigned char chSize; | |
212 | READDATA(is, chSize); | |
bde280b9 | 213 | uint64 nSizeRet = 0; |
a790fa46 | 214 | if (chSize < 253) |
0a61b0df | 215 | { |
216 | nSizeRet = chSize; | |
217 | } | |
a790fa46 | 218 | else if (chSize == 253) |
0a61b0df | 219 | { |
a790fa46 | 220 | unsigned short xSize; |
221 | READDATA(is, xSize); | |
222 | nSizeRet = xSize; | |
0a61b0df | 223 | } |
a790fa46 | 224 | else if (chSize == 254) |
0a61b0df | 225 | { |
a790fa46 | 226 | unsigned int xSize; |
227 | READDATA(is, xSize); | |
228 | nSizeRet = xSize; | |
0a61b0df | 229 | } |
230 | else | |
231 | { | |
bde280b9 | 232 | uint64 xSize; |
a790fa46 | 233 | READDATA(is, xSize); |
234 | nSizeRet = xSize; | |
0a61b0df | 235 | } |
bde280b9 | 236 | if (nSizeRet > (uint64)MAX_SIZE) |
0a61b0df | 237 | throw std::ios_base::failure("ReadCompactSize() : size too large"); |
238 | return nSizeRet; | |
239 | } | |
240 | ||
241 | ||
242 | ||
0a61b0df | 243 | #define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj))) |
6b8de05d PW |
244 | |
245 | /** Wrapper for serializing arrays and POD. | |
246 | * There's a clever template way to make arrays serialize normally, but MSVC6 doesn't support it. | |
247 | */ | |
0a61b0df | 248 | class CFlatData |
249 | { | |
250 | protected: | |
251 | char* pbegin; | |
252 | char* pend; | |
253 | public: | |
254 | CFlatData(void* pbeginIn, void* pendIn) : pbegin((char*)pbeginIn), pend((char*)pendIn) { } | |
255 | char* begin() { return pbegin; } | |
256 | const char* begin() const { return pbegin; } | |
257 | char* end() { return pend; } | |
258 | const char* end() const { return pend; } | |
259 | ||
260 | unsigned int GetSerializeSize(int, int=0) const | |
261 | { | |
262 | return pend - pbegin; | |
263 | } | |
264 | ||
265 | template<typename Stream> | |
266 | void Serialize(Stream& s, int, int=0) const | |
267 | { | |
268 | s.write(pbegin, pend - pbegin); | |
269 | } | |
270 | ||
271 | template<typename Stream> | |
272 | void Unserialize(Stream& s, int, int=0) | |
273 | { | |
274 | s.read(pbegin, pend - pbegin); | |
275 | } | |
276 | }; | |
277 | ||
0a61b0df | 278 | // |
279 | // Forward declarations | |
280 | // | |
281 | ||
282 | // string | |
223b6f1b WL |
283 | template<typename C> unsigned int GetSerializeSize(const std::basic_string<C>& str, int, int=0); |
284 | template<typename Stream, typename C> void Serialize(Stream& os, const std::basic_string<C>& str, int, int=0); | |
285 | template<typename Stream, typename C> void Unserialize(Stream& is, std::basic_string<C>& str, int, int=0); | |
0a61b0df | 286 | |
287 | // vector | |
288 | template<typename T, typename A> unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&); | |
289 | template<typename T, typename A> unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&); | |
6b6aaa16 | 290 | template<typename T, typename A> inline unsigned int GetSerializeSize(const std::vector<T, A>& v, int nType, int nVersion); |
0a61b0df | 291 | 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&); |
292 | 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&); | |
6b6aaa16 | 293 | template<typename Stream, typename T, typename A> inline void Serialize(Stream& os, const std::vector<T, A>& v, int nType, int nVersion); |
0a61b0df | 294 | 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&); |
295 | 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&); | |
6b6aaa16 | 296 | template<typename Stream, typename T, typename A> inline void Unserialize(Stream& is, std::vector<T, A>& v, int nType, int nVersion); |
0a61b0df | 297 | |
298 | // others derived from vector | |
6b6aaa16 PW |
299 | extern inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion); |
300 | template<typename Stream> void Serialize(Stream& os, const CScript& v, int nType, int nVersion); | |
301 | template<typename Stream> void Unserialize(Stream& is, CScript& v, int nType, int nVersion); | |
0a61b0df | 302 | |
303 | // pair | |
6b6aaa16 PW |
304 | template<typename K, typename T> unsigned int GetSerializeSize(const std::pair<K, T>& item, int nType, int nVersion); |
305 | template<typename Stream, typename K, typename T> void Serialize(Stream& os, const std::pair<K, T>& item, int nType, int nVersion); | |
306 | template<typename Stream, typename K, typename T> void Unserialize(Stream& is, std::pair<K, T>& item, int nType, int nVersion); | |
0a61b0df | 307 | |
84d7c981 | 308 | // 3 tuple |
6b6aaa16 PW |
309 | template<typename T0, typename T1, typename T2> unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2>& item, int nType, int nVersion); |
310 | template<typename Stream, typename T0, typename T1, typename T2> void Serialize(Stream& os, const boost::tuple<T0, T1, T2>& item, int nType, int nVersion); | |
311 | template<typename Stream, typename T0, typename T1, typename T2> void Unserialize(Stream& is, boost::tuple<T0, T1, T2>& item, int nType, int nVersion); | |
84d7c981 | 312 | |
313 | // 4 tuple | |
6b6aaa16 PW |
314 | template<typename T0, typename T1, typename T2, typename T3> unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion); |
315 | 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); | |
316 | 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); | |
84d7c981 | 317 | |
0a61b0df | 318 | // map |
6b6aaa16 PW |
319 | template<typename K, typename T, typename Pred, typename A> unsigned int GetSerializeSize(const std::map<K, T, Pred, A>& m, int nType, int nVersion); |
320 | 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); | |
321 | 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); | |
0a61b0df | 322 | |
323 | // set | |
6b6aaa16 PW |
324 | template<typename K, typename Pred, typename A> unsigned int GetSerializeSize(const std::set<K, Pred, A>& m, int nType, int nVersion); |
325 | template<typename Stream, typename K, typename Pred, typename A> void Serialize(Stream& os, const std::set<K, Pred, A>& m, int nType, int nVersion); | |
326 | template<typename Stream, typename K, typename Pred, typename A> void Unserialize(Stream& is, std::set<K, Pred, A>& m, int nType, int nVersion); | |
0a61b0df | 327 | |
328 | ||
329 | ||
330 | ||
331 | ||
332 | // | |
333 | // If none of the specialized versions above matched, default to calling member function. | |
334 | // "int nType" is changed to "long nType" to keep from getting an ambiguous overload error. | |
335 | // The compiler will only cast int to long if none of the other templates matched. | |
336 | // Thanks to Boost serialization for this idea. | |
337 | // | |
338 | template<typename T> | |
6b6aaa16 | 339 | inline unsigned int GetSerializeSize(const T& a, long nType, int nVersion) |
0a61b0df | 340 | { |
341 | return a.GetSerializeSize((int)nType, nVersion); | |
342 | } | |
343 | ||
344 | template<typename Stream, typename T> | |
6b6aaa16 | 345 | inline void Serialize(Stream& os, const T& a, long nType, int nVersion) |
0a61b0df | 346 | { |
347 | a.Serialize(os, (int)nType, nVersion); | |
348 | } | |
349 | ||
350 | template<typename Stream, typename T> | |
6b6aaa16 | 351 | inline void Unserialize(Stream& is, T& a, long nType, int nVersion) |
0a61b0df | 352 | { |
353 | a.Unserialize(is, (int)nType, nVersion); | |
354 | } | |
355 | ||
356 | ||
357 | ||
358 | ||
359 | ||
360 | // | |
361 | // string | |
362 | // | |
363 | template<typename C> | |
223b6f1b | 364 | unsigned int GetSerializeSize(const std::basic_string<C>& str, int, int) |
0a61b0df | 365 | { |
366 | return GetSizeOfCompactSize(str.size()) + str.size() * sizeof(str[0]); | |
367 | } | |
368 | ||
369 | template<typename Stream, typename C> | |
223b6f1b | 370 | void Serialize(Stream& os, const std::basic_string<C>& str, int, int) |
0a61b0df | 371 | { |
372 | WriteCompactSize(os, str.size()); | |
373 | if (!str.empty()) | |
374 | os.write((char*)&str[0], str.size() * sizeof(str[0])); | |
375 | } | |
376 | ||
377 | template<typename Stream, typename C> | |
223b6f1b | 378 | void Unserialize(Stream& is, std::basic_string<C>& str, int, int) |
0a61b0df | 379 | { |
380 | unsigned int nSize = ReadCompactSize(is); | |
381 | str.resize(nSize); | |
382 | if (nSize != 0) | |
383 | is.read((char*)&str[0], nSize * sizeof(str[0])); | |
384 | } | |
385 | ||
386 | ||
387 | ||
388 | // | |
389 | // vector | |
390 | // | |
391 | template<typename T, typename A> | |
392 | unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&) | |
393 | { | |
394 | return (GetSizeOfCompactSize(v.size()) + v.size() * sizeof(T)); | |
395 | } | |
396 | ||
397 | template<typename T, typename A> | |
398 | unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&) | |
399 | { | |
400 | unsigned int nSize = GetSizeOfCompactSize(v.size()); | |
401 | for (typename std::vector<T, A>::const_iterator vi = v.begin(); vi != v.end(); ++vi) | |
402 | nSize += GetSerializeSize((*vi), nType, nVersion); | |
403 | return nSize; | |
404 | } | |
405 | ||
406 | template<typename T, typename A> | |
407 | inline unsigned int GetSerializeSize(const std::vector<T, A>& v, int nType, int nVersion) | |
408 | { | |
409 | return GetSerializeSize_impl(v, nType, nVersion, boost::is_fundamental<T>()); | |
410 | } | |
411 | ||
412 | ||
413 | template<typename Stream, typename T, typename A> | |
414 | void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&) | |
415 | { | |
416 | WriteCompactSize(os, v.size()); | |
417 | if (!v.empty()) | |
418 | os.write((char*)&v[0], v.size() * sizeof(T)); | |
419 | } | |
420 | ||
421 | template<typename Stream, typename T, typename A> | |
422 | void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&) | |
423 | { | |
424 | WriteCompactSize(os, v.size()); | |
425 | for (typename std::vector<T, A>::const_iterator vi = v.begin(); vi != v.end(); ++vi) | |
426 | ::Serialize(os, (*vi), nType, nVersion); | |
427 | } | |
428 | ||
429 | template<typename Stream, typename T, typename A> | |
430 | inline void Serialize(Stream& os, const std::vector<T, A>& v, int nType, int nVersion) | |
431 | { | |
432 | Serialize_impl(os, v, nType, nVersion, boost::is_fundamental<T>()); | |
433 | } | |
434 | ||
435 | ||
436 | template<typename Stream, typename T, typename A> | |
437 | void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&) | |
438 | { | |
0a61b0df | 439 | // Limit size per read so bogus size value won't cause out of memory |
440 | v.clear(); | |
441 | unsigned int nSize = ReadCompactSize(is); | |
442 | unsigned int i = 0; | |
443 | while (i < nSize) | |
444 | { | |
223b6f1b | 445 | unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T))); |
0a61b0df | 446 | v.resize(i + blk); |
447 | is.read((char*)&v[i], blk * sizeof(T)); | |
448 | i += blk; | |
449 | } | |
450 | } | |
451 | ||
452 | template<typename Stream, typename T, typename A> | |
453 | void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&) | |
454 | { | |
0a61b0df | 455 | v.clear(); |
456 | unsigned int nSize = ReadCompactSize(is); | |
457 | unsigned int i = 0; | |
458 | unsigned int nMid = 0; | |
459 | while (nMid < nSize) | |
460 | { | |
461 | nMid += 5000000 / sizeof(T); | |
462 | if (nMid > nSize) | |
463 | nMid = nSize; | |
464 | v.resize(nMid); | |
465 | for (; i < nMid; i++) | |
466 | Unserialize(is, v[i], nType, nVersion); | |
467 | } | |
468 | } | |
469 | ||
470 | template<typename Stream, typename T, typename A> | |
471 | inline void Unserialize(Stream& is, std::vector<T, A>& v, int nType, int nVersion) | |
472 | { | |
473 | Unserialize_impl(is, v, nType, nVersion, boost::is_fundamental<T>()); | |
474 | } | |
475 | ||
476 | ||
477 | ||
478 | // | |
479 | // others derived from vector | |
480 | // | |
481 | inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion) | |
482 | { | |
223b6f1b | 483 | return GetSerializeSize((const std::vector<unsigned char>&)v, nType, nVersion); |
0a61b0df | 484 | } |
485 | ||
486 | template<typename Stream> | |
487 | void Serialize(Stream& os, const CScript& v, int nType, int nVersion) | |
488 | { | |
223b6f1b | 489 | Serialize(os, (const std::vector<unsigned char>&)v, nType, nVersion); |
0a61b0df | 490 | } |
491 | ||
492 | template<typename Stream> | |
493 | void Unserialize(Stream& is, CScript& v, int nType, int nVersion) | |
494 | { | |
223b6f1b | 495 | Unserialize(is, (std::vector<unsigned char>&)v, nType, nVersion); |
0a61b0df | 496 | } |
497 | ||
498 | ||
499 | ||
500 | // | |
501 | // pair | |
502 | // | |
503 | template<typename K, typename T> | |
504 | unsigned int GetSerializeSize(const std::pair<K, T>& item, int nType, int nVersion) | |
505 | { | |
506 | return GetSerializeSize(item.first, nType, nVersion) + GetSerializeSize(item.second, nType, nVersion); | |
507 | } | |
508 | ||
509 | template<typename Stream, typename K, typename T> | |
510 | void Serialize(Stream& os, const std::pair<K, T>& item, int nType, int nVersion) | |
511 | { | |
512 | Serialize(os, item.first, nType, nVersion); | |
513 | Serialize(os, item.second, nType, nVersion); | |
514 | } | |
515 | ||
516 | template<typename Stream, typename K, typename T> | |
517 | void Unserialize(Stream& is, std::pair<K, T>& item, int nType, int nVersion) | |
518 | { | |
519 | Unserialize(is, item.first, nType, nVersion); | |
520 | Unserialize(is, item.second, nType, nVersion); | |
521 | } | |
522 | ||
523 | ||
524 | ||
84d7c981 | 525 | // |
526 | // 3 tuple | |
527 | // | |
528 | template<typename T0, typename T1, typename T2> | |
529 | unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2>& item, int nType, int nVersion) | |
530 | { | |
531 | unsigned int nSize = 0; | |
223b6f1b WL |
532 | nSize += GetSerializeSize(boost::get<0>(item), nType, nVersion); |
533 | nSize += GetSerializeSize(boost::get<1>(item), nType, nVersion); | |
534 | nSize += GetSerializeSize(boost::get<2>(item), nType, nVersion); | |
84d7c981 | 535 | return nSize; |
536 | } | |
537 | ||
538 | template<typename Stream, typename T0, typename T1, typename T2> | |
539 | void Serialize(Stream& os, const boost::tuple<T0, T1, T2>& item, int nType, int nVersion) | |
540 | { | |
223b6f1b WL |
541 | Serialize(os, boost::get<0>(item), nType, nVersion); |
542 | Serialize(os, boost::get<1>(item), nType, nVersion); | |
543 | Serialize(os, boost::get<2>(item), nType, nVersion); | |
84d7c981 | 544 | } |
545 | ||
546 | template<typename Stream, typename T0, typename T1, typename T2> | |
547 | void Unserialize(Stream& is, boost::tuple<T0, T1, T2>& item, int nType, int nVersion) | |
548 | { | |
223b6f1b WL |
549 | Unserialize(is, boost::get<0>(item), nType, nVersion); |
550 | Unserialize(is, boost::get<1>(item), nType, nVersion); | |
551 | Unserialize(is, boost::get<2>(item), nType, nVersion); | |
84d7c981 | 552 | } |
553 | ||
554 | ||
555 | ||
556 | // | |
557 | // 4 tuple | |
558 | // | |
559 | template<typename T0, typename T1, typename T2, typename T3> | |
560 | unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion) | |
561 | { | |
562 | unsigned int nSize = 0; | |
223b6f1b WL |
563 | nSize += GetSerializeSize(boost::get<0>(item), nType, nVersion); |
564 | nSize += GetSerializeSize(boost::get<1>(item), nType, nVersion); | |
565 | nSize += GetSerializeSize(boost::get<2>(item), nType, nVersion); | |
566 | nSize += GetSerializeSize(boost::get<3>(item), nType, nVersion); | |
84d7c981 | 567 | return nSize; |
568 | } | |
569 | ||
570 | template<typename Stream, typename T0, typename T1, typename T2, typename T3> | |
571 | void Serialize(Stream& os, const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion) | |
572 | { | |
223b6f1b WL |
573 | Serialize(os, boost::get<0>(item), nType, nVersion); |
574 | Serialize(os, boost::get<1>(item), nType, nVersion); | |
575 | Serialize(os, boost::get<2>(item), nType, nVersion); | |
576 | Serialize(os, boost::get<3>(item), nType, nVersion); | |
84d7c981 | 577 | } |
578 | ||
579 | template<typename Stream, typename T0, typename T1, typename T2, typename T3> | |
580 | void Unserialize(Stream& is, boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion) | |
581 | { | |
223b6f1b WL |
582 | Unserialize(is, boost::get<0>(item), nType, nVersion); |
583 | Unserialize(is, boost::get<1>(item), nType, nVersion); | |
584 | Unserialize(is, boost::get<2>(item), nType, nVersion); | |
585 | Unserialize(is, boost::get<3>(item), nType, nVersion); | |
84d7c981 | 586 | } |
587 | ||
588 | ||
589 | ||
0a61b0df | 590 | // |
591 | // map | |
592 | // | |
593 | template<typename K, typename T, typename Pred, typename A> | |
594 | unsigned int GetSerializeSize(const std::map<K, T, Pred, A>& m, int nType, int nVersion) | |
595 | { | |
596 | unsigned int nSize = GetSizeOfCompactSize(m.size()); | |
597 | for (typename std::map<K, T, Pred, A>::const_iterator mi = m.begin(); mi != m.end(); ++mi) | |
598 | nSize += GetSerializeSize((*mi), nType, nVersion); | |
599 | return nSize; | |
600 | } | |
601 | ||
602 | template<typename Stream, typename K, typename T, typename Pred, typename A> | |
603 | void Serialize(Stream& os, const std::map<K, T, Pred, A>& m, int nType, int nVersion) | |
604 | { | |
605 | WriteCompactSize(os, m.size()); | |
606 | for (typename std::map<K, T, Pred, A>::const_iterator mi = m.begin(); mi != m.end(); ++mi) | |
607 | Serialize(os, (*mi), nType, nVersion); | |
608 | } | |
609 | ||
610 | template<typename Stream, typename K, typename T, typename Pred, typename A> | |
611 | void Unserialize(Stream& is, std::map<K, T, Pred, A>& m, int nType, int nVersion) | |
612 | { | |
613 | m.clear(); | |
614 | unsigned int nSize = ReadCompactSize(is); | |
615 | typename std::map<K, T, Pred, A>::iterator mi = m.begin(); | |
616 | for (unsigned int i = 0; i < nSize; i++) | |
617 | { | |
223b6f1b | 618 | std::pair<K, T> item; |
0a61b0df | 619 | Unserialize(is, item, nType, nVersion); |
620 | mi = m.insert(mi, item); | |
621 | } | |
622 | } | |
623 | ||
624 | ||
625 | ||
626 | // | |
627 | // set | |
628 | // | |
629 | template<typename K, typename Pred, typename A> | |
630 | unsigned int GetSerializeSize(const std::set<K, Pred, A>& m, int nType, int nVersion) | |
631 | { | |
632 | unsigned int nSize = GetSizeOfCompactSize(m.size()); | |
633 | for (typename std::set<K, Pred, A>::const_iterator it = m.begin(); it != m.end(); ++it) | |
634 | nSize += GetSerializeSize((*it), nType, nVersion); | |
635 | return nSize; | |
636 | } | |
637 | ||
638 | template<typename Stream, typename K, typename Pred, typename A> | |
639 | void Serialize(Stream& os, const std::set<K, Pred, A>& m, int nType, int nVersion) | |
640 | { | |
641 | WriteCompactSize(os, m.size()); | |
642 | for (typename std::set<K, Pred, A>::const_iterator it = m.begin(); it != m.end(); ++it) | |
643 | Serialize(os, (*it), nType, nVersion); | |
644 | } | |
645 | ||
646 | template<typename Stream, typename K, typename Pred, typename A> | |
647 | void Unserialize(Stream& is, std::set<K, Pred, A>& m, int nType, int nVersion) | |
648 | { | |
649 | m.clear(); | |
650 | unsigned int nSize = ReadCompactSize(is); | |
651 | typename std::set<K, Pred, A>::iterator it = m.begin(); | |
652 | for (unsigned int i = 0; i < nSize; i++) | |
653 | { | |
654 | K key; | |
655 | Unserialize(is, key, nType, nVersion); | |
656 | it = m.insert(it, key); | |
657 | } | |
658 | } | |
659 | ||
660 | ||
661 | ||
662 | // | |
663 | // Support for IMPLEMENT_SERIALIZE and READWRITE macro | |
664 | // | |
665 | class CSerActionGetSerializeSize { }; | |
666 | class CSerActionSerialize { }; | |
667 | class CSerActionUnserialize { }; | |
668 | ||
669 | template<typename Stream, typename T> | |
670 | inline unsigned int SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionGetSerializeSize ser_action) | |
671 | { | |
672 | return ::GetSerializeSize(obj, nType, nVersion); | |
673 | } | |
674 | ||
675 | template<typename Stream, typename T> | |
676 | inline unsigned int SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionSerialize ser_action) | |
677 | { | |
678 | ::Serialize(s, obj, nType, nVersion); | |
679 | return 0; | |
680 | } | |
681 | ||
682 | template<typename Stream, typename T> | |
683 | inline unsigned int SerReadWrite(Stream& s, T& obj, int nType, int nVersion, CSerActionUnserialize ser_action) | |
684 | { | |
685 | ::Unserialize(s, obj, nType, nVersion); | |
686 | return 0; | |
687 | } | |
688 | ||
689 | struct ser_streamplaceholder | |
690 | { | |
691 | int nType; | |
692 | int nVersion; | |
693 | }; | |
694 | ||
695 | ||
696 | ||
697 | ||
698 | ||
699 | ||
700 | ||
701 | ||
702 | ||
f7a9a113 MC |
703 | |
704 | ||
0a61b0df | 705 | |
6b8de05d PW |
706 | /** Double ended buffer combining vector and stream-like interfaces. |
707 | * | |
708 | * >> and << read and write unformatted data using the above serialization templates. | |
709 | * Fills with data in linear time; some stringstream implementations take N^2 time. | |
710 | */ | |
0a61b0df | 711 | class CDataStream |
712 | { | |
713 | protected: | |
f7a9a113 | 714 | typedef std::vector<char, zero_after_free_allocator<char> > vector_type; |
0a61b0df | 715 | vector_type vch; |
716 | unsigned int nReadPos; | |
717 | short state; | |
718 | short exceptmask; | |
719 | public: | |
720 | int nType; | |
721 | int nVersion; | |
722 | ||
723 | typedef vector_type::allocator_type allocator_type; | |
724 | typedef vector_type::size_type size_type; | |
725 | typedef vector_type::difference_type difference_type; | |
726 | typedef vector_type::reference reference; | |
727 | typedef vector_type::const_reference const_reference; | |
728 | typedef vector_type::value_type value_type; | |
729 | typedef vector_type::iterator iterator; | |
730 | typedef vector_type::const_iterator const_iterator; | |
731 | typedef vector_type::reverse_iterator reverse_iterator; | |
732 | ||
6b6aaa16 | 733 | explicit CDataStream(int nTypeIn, int nVersionIn) |
0a61b0df | 734 | { |
735 | Init(nTypeIn, nVersionIn); | |
736 | } | |
737 | ||
6b6aaa16 | 738 | CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend) |
0a61b0df | 739 | { |
740 | Init(nTypeIn, nVersionIn); | |
741 | } | |
742 | ||
743 | #if !defined(_MSC_VER) || _MSC_VER >= 1300 | |
6b6aaa16 | 744 | CDataStream(const char* pbegin, const char* pend, int nTypeIn, int nVersionIn) : vch(pbegin, pend) |
0a61b0df | 745 | { |
746 | Init(nTypeIn, nVersionIn); | |
747 | } | |
748 | #endif | |
749 | ||
6b6aaa16 | 750 | CDataStream(const vector_type& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end()) |
0a61b0df | 751 | { |
752 | Init(nTypeIn, nVersionIn); | |
753 | } | |
754 | ||
6b6aaa16 | 755 | CDataStream(const std::vector<char>& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end()) |
0a61b0df | 756 | { |
757 | Init(nTypeIn, nVersionIn); | |
758 | } | |
759 | ||
6b6aaa16 | 760 | CDataStream(const std::vector<unsigned char>& vchIn, int nTypeIn, int nVersionIn) : vch((char*)&vchIn.begin()[0], (char*)&vchIn.end()[0]) |
0a61b0df | 761 | { |
762 | Init(nTypeIn, nVersionIn); | |
763 | } | |
764 | ||
6b6aaa16 | 765 | void Init(int nTypeIn, int nVersionIn) |
0a61b0df | 766 | { |
767 | nReadPos = 0; | |
768 | nType = nTypeIn; | |
769 | nVersion = nVersionIn; | |
770 | state = 0; | |
223b6f1b | 771 | exceptmask = std::ios::badbit | std::ios::failbit; |
0a61b0df | 772 | } |
773 | ||
774 | CDataStream& operator+=(const CDataStream& b) | |
775 | { | |
776 | vch.insert(vch.end(), b.begin(), b.end()); | |
777 | return *this; | |
778 | } | |
779 | ||
780 | friend CDataStream operator+(const CDataStream& a, const CDataStream& b) | |
781 | { | |
782 | CDataStream ret = a; | |
783 | ret += b; | |
784 | return (ret); | |
785 | } | |
786 | ||
223b6f1b | 787 | std::string str() const |
0a61b0df | 788 | { |
223b6f1b | 789 | return (std::string(begin(), end())); |
0a61b0df | 790 | } |
791 | ||
792 | ||
793 | // | |
794 | // Vector subset | |
795 | // | |
796 | const_iterator begin() const { return vch.begin() + nReadPos; } | |
797 | iterator begin() { return vch.begin() + nReadPos; } | |
798 | const_iterator end() const { return vch.end(); } | |
799 | iterator end() { return vch.end(); } | |
800 | size_type size() const { return vch.size() - nReadPos; } | |
801 | bool empty() const { return vch.size() == nReadPos; } | |
802 | void resize(size_type n, value_type c=0) { vch.resize(n + nReadPos, c); } | |
803 | void reserve(size_type n) { vch.reserve(n + nReadPos); } | |
804 | const_reference operator[](size_type pos) const { return vch[pos + nReadPos]; } | |
805 | reference operator[](size_type pos) { return vch[pos + nReadPos]; } | |
806 | void clear() { vch.clear(); nReadPos = 0; } | |
807 | iterator insert(iterator it, const char& x=char()) { return vch.insert(it, x); } | |
808 | void insert(iterator it, size_type n, const char& x) { vch.insert(it, n, x); } | |
809 | ||
810 | void insert(iterator it, const_iterator first, const_iterator last) | |
811 | { | |
812 | if (it == vch.begin() + nReadPos && last - first <= nReadPos) | |
813 | { | |
814 | // special case for inserting at the front when there's room | |
815 | nReadPos -= (last - first); | |
816 | memcpy(&vch[nReadPos], &first[0], last - first); | |
817 | } | |
818 | else | |
819 | vch.insert(it, first, last); | |
820 | } | |
821 | ||
223b6f1b | 822 | void insert(iterator it, std::vector<char>::const_iterator first, std::vector<char>::const_iterator last) |
0a61b0df | 823 | { |
824 | if (it == vch.begin() + nReadPos && last - first <= nReadPos) | |
825 | { | |
826 | // special case for inserting at the front when there's room | |
827 | nReadPos -= (last - first); | |
828 | memcpy(&vch[nReadPos], &first[0], last - first); | |
829 | } | |
830 | else | |
831 | vch.insert(it, first, last); | |
832 | } | |
833 | ||
834 | #if !defined(_MSC_VER) || _MSC_VER >= 1300 | |
835 | void insert(iterator it, const char* first, const char* last) | |
836 | { | |
837 | if (it == vch.begin() + nReadPos && last - first <= nReadPos) | |
838 | { | |
839 | // special case for inserting at the front when there's room | |
840 | nReadPos -= (last - first); | |
841 | memcpy(&vch[nReadPos], &first[0], last - first); | |
842 | } | |
843 | else | |
844 | vch.insert(it, first, last); | |
845 | } | |
846 | #endif | |
847 | ||
848 | iterator erase(iterator it) | |
849 | { | |
850 | if (it == vch.begin() + nReadPos) | |
851 | { | |
852 | // special case for erasing from the front | |
853 | if (++nReadPos >= vch.size()) | |
854 | { | |
855 | // whenever we reach the end, we take the opportunity to clear the buffer | |
856 | nReadPos = 0; | |
857 | return vch.erase(vch.begin(), vch.end()); | |
858 | } | |
859 | return vch.begin() + nReadPos; | |
860 | } | |
861 | else | |
862 | return vch.erase(it); | |
863 | } | |
864 | ||
865 | iterator erase(iterator first, iterator last) | |
866 | { | |
867 | if (first == vch.begin() + nReadPos) | |
868 | { | |
869 | // special case for erasing from the front | |
870 | if (last == vch.end()) | |
871 | { | |
872 | nReadPos = 0; | |
873 | return vch.erase(vch.begin(), vch.end()); | |
874 | } | |
875 | else | |
876 | { | |
877 | nReadPos = (last - vch.begin()); | |
878 | return last; | |
879 | } | |
880 | } | |
881 | else | |
882 | return vch.erase(first, last); | |
883 | } | |
884 | ||
885 | inline void Compact() | |
886 | { | |
887 | vch.erase(vch.begin(), vch.begin() + nReadPos); | |
888 | nReadPos = 0; | |
889 | } | |
890 | ||
891 | bool Rewind(size_type n) | |
892 | { | |
893 | // Rewind by n characters if the buffer hasn't been compacted yet | |
894 | if (n > nReadPos) | |
895 | return false; | |
896 | nReadPos -= n; | |
897 | return true; | |
898 | } | |
899 | ||
900 | ||
901 | // | |
902 | // Stream subset | |
903 | // | |
904 | void setstate(short bits, const char* psz) | |
905 | { | |
906 | state |= bits; | |
907 | if (state & exceptmask) | |
908 | throw std::ios_base::failure(psz); | |
909 | } | |
910 | ||
911 | bool eof() const { return size() == 0; } | |
223b6f1b | 912 | bool fail() const { return state & (std::ios::badbit | std::ios::failbit); } |
0a61b0df | 913 | bool good() const { return !eof() && (state == 0); } |
914 | void clear(short n) { state = n; } // name conflict with vector clear() | |
915 | short exceptions() { return exceptmask; } | |
916 | short exceptions(short mask) { short prev = exceptmask; exceptmask = mask; setstate(0, "CDataStream"); return prev; } | |
917 | CDataStream* rdbuf() { return this; } | |
918 | int in_avail() { return size(); } | |
919 | ||
920 | void SetType(int n) { nType = n; } | |
921 | int GetType() { return nType; } | |
922 | void SetVersion(int n) { nVersion = n; } | |
923 | int GetVersion() { return nVersion; } | |
924 | void ReadVersion() { *this >> nVersion; } | |
925 | void WriteVersion() { *this << nVersion; } | |
926 | ||
927 | CDataStream& read(char* pch, int nSize) | |
928 | { | |
929 | // Read from the beginning of the buffer | |
930 | assert(nSize >= 0); | |
931 | unsigned int nReadPosNext = nReadPos + nSize; | |
932 | if (nReadPosNext >= vch.size()) | |
933 | { | |
934 | if (nReadPosNext > vch.size()) | |
935 | { | |
223b6f1b | 936 | setstate(std::ios::failbit, "CDataStream::read() : end of data"); |
0a61b0df | 937 | memset(pch, 0, nSize); |
938 | nSize = vch.size() - nReadPos; | |
939 | } | |
940 | memcpy(pch, &vch[nReadPos], nSize); | |
941 | nReadPos = 0; | |
942 | vch.clear(); | |
943 | return (*this); | |
944 | } | |
945 | memcpy(pch, &vch[nReadPos], nSize); | |
946 | nReadPos = nReadPosNext; | |
947 | return (*this); | |
948 | } | |
949 | ||
950 | CDataStream& ignore(int nSize) | |
951 | { | |
952 | // Ignore from the beginning of the buffer | |
953 | assert(nSize >= 0); | |
954 | unsigned int nReadPosNext = nReadPos + nSize; | |
955 | if (nReadPosNext >= vch.size()) | |
956 | { | |
957 | if (nReadPosNext > vch.size()) | |
958 | { | |
223b6f1b | 959 | setstate(std::ios::failbit, "CDataStream::ignore() : end of data"); |
0a61b0df | 960 | nSize = vch.size() - nReadPos; |
961 | } | |
962 | nReadPos = 0; | |
963 | vch.clear(); | |
964 | return (*this); | |
965 | } | |
966 | nReadPos = nReadPosNext; | |
967 | return (*this); | |
968 | } | |
969 | ||
970 | CDataStream& write(const char* pch, int nSize) | |
971 | { | |
972 | // Write to the end of the buffer | |
973 | assert(nSize >= 0); | |
974 | vch.insert(vch.end(), pch, pch + nSize); | |
975 | return (*this); | |
976 | } | |
977 | ||
978 | template<typename Stream> | |
6b6aaa16 | 979 | void Serialize(Stream& s, int nType, int nVersion) const |
0a61b0df | 980 | { |
981 | // Special case: stream << stream concatenates like stream += stream | |
982 | if (!vch.empty()) | |
983 | s.write((char*)&vch[0], vch.size() * sizeof(vch[0])); | |
984 | } | |
985 | ||
986 | template<typename T> | |
987 | unsigned int GetSerializeSize(const T& obj) | |
988 | { | |
989 | // Tells the size of the object if serialized to this stream | |
990 | return ::GetSerializeSize(obj, nType, nVersion); | |
991 | } | |
992 | ||
993 | template<typename T> | |
994 | CDataStream& operator<<(const T& obj) | |
995 | { | |
996 | // Serialize to this stream | |
997 | ::Serialize(*this, obj, nType, nVersion); | |
998 | return (*this); | |
999 | } | |
1000 | ||
1001 | template<typename T> | |
1002 | CDataStream& operator>>(T& obj) | |
1003 | { | |
1004 | // Unserialize from this stream | |
1005 | ::Unserialize(*this, obj, nType, nVersion); | |
1006 | return (*this); | |
1007 | } | |
1008 | }; | |
1009 | ||
1010 | #ifdef TESTCDATASTREAM | |
1011 | // VC6sp6 | |
1012 | // CDataStream: | |
1013 | // n=1000 0 seconds | |
1014 | // n=2000 0 seconds | |
1015 | // n=4000 0 seconds | |
1016 | // n=8000 0 seconds | |
1017 | // n=16000 0 seconds | |
1018 | // n=32000 0 seconds | |
1019 | // n=64000 1 seconds | |
1020 | // n=128000 1 seconds | |
1021 | // n=256000 2 seconds | |
1022 | // n=512000 4 seconds | |
1023 | // n=1024000 8 seconds | |
1024 | // n=2048000 16 seconds | |
1025 | // n=4096000 32 seconds | |
1026 | // stringstream: | |
1027 | // n=1000 1 seconds | |
1028 | // n=2000 1 seconds | |
1029 | // n=4000 13 seconds | |
1030 | // n=8000 87 seconds | |
1031 | // n=16000 400 seconds | |
1032 | // n=32000 1660 seconds | |
1033 | // n=64000 6749 seconds | |
1034 | // n=128000 27241 seconds | |
1035 | // n=256000 109804 seconds | |
1036 | #include <iostream> | |
1037 | int main(int argc, char *argv[]) | |
1038 | { | |
1039 | vector<unsigned char> vch(0xcc, 250); | |
1040 | printf("CDataStream:\n"); | |
1041 | for (int n = 1000; n <= 4500000; n *= 2) | |
1042 | { | |
1043 | CDataStream ss; | |
1044 | time_t nStart = time(NULL); | |
1045 | for (int i = 0; i < n; i++) | |
1046 | ss.write((char*)&vch[0], vch.size()); | |
1047 | printf("n=%-10d %d seconds\n", n, time(NULL) - nStart); | |
1048 | } | |
1049 | printf("stringstream:\n"); | |
1050 | for (int n = 1000; n <= 4500000; n *= 2) | |
1051 | { | |
1052 | stringstream ss; | |
1053 | time_t nStart = time(NULL); | |
1054 | for (int i = 0; i < n; i++) | |
1055 | ss.write((char*)&vch[0], vch.size()); | |
1056 | printf("n=%-10d %d seconds\n", n, time(NULL) - nStart); | |
1057 | } | |
1058 | } | |
1059 | #endif | |
1060 | ||
1061 | ||
1062 | ||
1063 | ||
1064 | ||
1065 | ||
1066 | ||
1067 | ||
1068 | ||
1069 | ||
6b8de05d PW |
1070 | /** RAII wrapper for FILE*. |
1071 | * | |
1072 | * Will automatically close the file when it goes out of scope if not null. | |
1073 | * If you're returning the file pointer, return file.release(). | |
1074 | * If you need to close the file early, use file.fclose() instead of fclose(file). | |
1075 | */ | |
0a61b0df | 1076 | class CAutoFile |
1077 | { | |
1078 | protected: | |
1079 | FILE* file; | |
1080 | short state; | |
1081 | short exceptmask; | |
1082 | public: | |
1083 | int nType; | |
1084 | int nVersion; | |
1085 | ||
6b6aaa16 | 1086 | CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn) |
0a61b0df | 1087 | { |
1088 | file = filenew; | |
1089 | nType = nTypeIn; | |
1090 | nVersion = nVersionIn; | |
1091 | state = 0; | |
223b6f1b | 1092 | exceptmask = std::ios::badbit | std::ios::failbit; |
0a61b0df | 1093 | } |
1094 | ||
1095 | ~CAutoFile() | |
1096 | { | |
1097 | fclose(); | |
1098 | } | |
1099 | ||
1100 | void fclose() | |
1101 | { | |
1102 | if (file != NULL && file != stdin && file != stdout && file != stderr) | |
1103 | ::fclose(file); | |
1104 | file = NULL; | |
1105 | } | |
1106 | ||
1107 | FILE* release() { FILE* ret = file; file = NULL; return ret; } | |
1108 | operator FILE*() { return file; } | |
1109 | FILE* operator->() { return file; } | |
1110 | FILE& operator*() { return *file; } | |
1111 | FILE** operator&() { return &file; } | |
1112 | FILE* operator=(FILE* pnew) { return file = pnew; } | |
1113 | bool operator!() { return (file == NULL); } | |
1114 | ||
1115 | ||
1116 | // | |
1117 | // Stream subset | |
1118 | // | |
1119 | void setstate(short bits, const char* psz) | |
1120 | { | |
1121 | state |= bits; | |
1122 | if (state & exceptmask) | |
1123 | throw std::ios_base::failure(psz); | |
1124 | } | |
1125 | ||
223b6f1b | 1126 | bool fail() const { return state & (std::ios::badbit | std::ios::failbit); } |
0a61b0df | 1127 | bool good() const { return state == 0; } |
1128 | void clear(short n = 0) { state = n; } | |
1129 | short exceptions() { return exceptmask; } | |
1130 | short exceptions(short mask) { short prev = exceptmask; exceptmask = mask; setstate(0, "CAutoFile"); return prev; } | |
1131 | ||
1132 | void SetType(int n) { nType = n; } | |
1133 | int GetType() { return nType; } | |
1134 | void SetVersion(int n) { nVersion = n; } | |
1135 | int GetVersion() { return nVersion; } | |
1136 | void ReadVersion() { *this >> nVersion; } | |
1137 | void WriteVersion() { *this << nVersion; } | |
1138 | ||
c3fad835 | 1139 | CAutoFile& read(char* pch, size_t nSize) |
0a61b0df | 1140 | { |
1141 | if (!file) | |
1142 | throw std::ios_base::failure("CAutoFile::read : file handle is NULL"); | |
1143 | if (fread(pch, 1, nSize, file) != nSize) | |
223b6f1b | 1144 | setstate(std::ios::failbit, feof(file) ? "CAutoFile::read : end of file" : "CAutoFile::read : fread failed"); |
0a61b0df | 1145 | return (*this); |
1146 | } | |
1147 | ||
c3fad835 | 1148 | CAutoFile& write(const char* pch, size_t nSize) |
0a61b0df | 1149 | { |
1150 | if (!file) | |
1151 | throw std::ios_base::failure("CAutoFile::write : file handle is NULL"); | |
1152 | if (fwrite(pch, 1, nSize, file) != nSize) | |
223b6f1b | 1153 | setstate(std::ios::failbit, "CAutoFile::write : write failed"); |
0a61b0df | 1154 | return (*this); |
1155 | } | |
1156 | ||
1157 | template<typename T> | |
1158 | unsigned int GetSerializeSize(const T& obj) | |
1159 | { | |
1160 | // Tells the size of the object if serialized to this stream | |
1161 | return ::GetSerializeSize(obj, nType, nVersion); | |
1162 | } | |
1163 | ||
1164 | template<typename T> | |
1165 | CAutoFile& operator<<(const T& obj) | |
1166 | { | |
1167 | // Serialize to this stream | |
1168 | if (!file) | |
1169 | throw std::ios_base::failure("CAutoFile::operator<< : file handle is NULL"); | |
1170 | ::Serialize(*this, obj, nType, nVersion); | |
1171 | return (*this); | |
1172 | } | |
1173 | ||
1174 | template<typename T> | |
1175 | CAutoFile& operator>>(T& obj) | |
1176 | { | |
1177 | // Unserialize from this stream | |
1178 | if (!file) | |
1179 | throw std::ios_base::failure("CAutoFile::operator>> : file handle is NULL"); | |
1180 | ::Unserialize(*this, obj, nType, nVersion); | |
1181 | return (*this); | |
1182 | } | |
1183 | }; | |
223b6f1b WL |
1184 | |
1185 | #endif |