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