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