diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -224,8 +224,6 @@ -Wunused-parameter -Wmissing-braces -Wthread-safety - -Wshadow - -Wshadow-field -Wrange-loop-analysis -Wredundant-decls -Wunreachable-code-loop-increment @@ -235,6 +233,16 @@ -Wredundant-move ) +if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + # GCC has no flag variant which is granular enough to avoid raising the clang + # -Wshadow-uncaptured-local equivalent. This is causing a lot of warnings + # on serialize.h which cannot be disabled locally, so drop the flag. + add_compiler_flags( + -Wshadow + -Wshadow-field + ) +endif() + option(EXTRA_WARNINGS "Enable extra warnings" OFF) if(EXTRA_WARNINGS) add_cxx_compiler_flags(-Wsuggest-override) diff --git a/src/bench/prevector.cpp b/src/bench/prevector.cpp --- a/src/bench/prevector.cpp +++ b/src/bench/prevector.cpp @@ -20,11 +20,7 @@ struct nontrivial_t { int x; nontrivial_t() : x(-1) {} - ADD_SERIALIZE_METHODS - template - inline void SerializationOp(Stream &s, Operation ser_action) { - READWRITE(x); - } + SERIALIZE_METHODS(nontrivial_t, obj) { READWRITE(obj.x); } }; static_assert(!IS_TRIVIALLY_CONSTRUCTIBLE::value, "expected nontrivial_t to not be trivially constructible"); diff --git a/src/blockencodings.h b/src/blockencodings.h --- a/src/blockencodings.h +++ b/src/blockencodings.h @@ -99,13 +99,13 @@ friend class PartiallyDownloadedBlock; - static const int SHORTTXIDS_LENGTH = 6; - protected: std::vector shorttxids; std::vector prefilledtxn; public: + static constexpr int SHORTTXIDS_LENGTH = 6; + CBlockHeader header; // Dummy for deserialization diff --git a/src/bloom.h b/src/bloom.h --- a/src/bloom.h +++ b/src/bloom.h @@ -68,14 +68,8 @@ const uint32_t nTweak, uint8_t nFlagsIn); CBloomFilter() : nHashFuncs(0), nTweak(0), nFlags(0) {} - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream &s, Operation ser_action) { - READWRITE(vData); - READWRITE(nHashFuncs); - READWRITE(nTweak); - READWRITE(nFlags); + SERIALIZE_METHODS(CBloomFilter, obj) { + READWRITE(obj.vData, obj.nHashFuncs, obj.nTweak, obj.nFlags); } void insert(const std::vector &vKey); diff --git a/src/flatfile.h b/src/flatfile.h --- a/src/flatfile.h +++ b/src/flatfile.h @@ -15,12 +15,9 @@ int nFile; unsigned int nPos; - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream &s, Operation ser_action) { - READWRITE(VARINT_MODE(nFile, VarIntMode::NONNEGATIVE_SIGNED)); - READWRITE(VARINT(nPos)); + SERIALIZE_METHODS(FlatFilePos, obj) { + READWRITE(VARINT_MODE(obj.nFile, VarIntMode::NONNEGATIVE_SIGNED), + VARINT(obj.nPos)); } FlatFilePos() : nFile(-1), nPos(0) {} diff --git a/src/index/blockfilterindex.cpp b/src/index/blockfilterindex.cpp --- a/src/index/blockfilterindex.cpp +++ b/src/index/blockfilterindex.cpp @@ -55,14 +55,7 @@ uint256 header; FlatFilePos pos; - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream &s, Operation ser_action) { - READWRITE(hash); - READWRITE(header); - READWRITE(pos); - } + SERIALIZE_METHODS(DBVal, obj) { READWRITE(obj.hash, obj.header, obj.pos); } }; struct DBHeightKey { diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp --- a/src/index/txindex.cpp +++ b/src/index/txindex.cpp @@ -23,12 +23,9 @@ struct CDiskTxPos : public FlatFilePos { unsigned int nTxOffset; // after header - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream &s, Operation ser_action) { - READWRITEAS(FlatFilePos, *this); - READWRITE(VARINT(nTxOffset)); + SERIALIZE_METHODS(CDiskTxPos, obj) { + READWRITEAS(FlatFilePos, obj); + READWRITE(VARINT(obj.nTxOffset)); } CDiskTxPos(const FlatFilePos &blockIn, unsigned int nTxOffsetIn) diff --git a/src/merkleblock.h b/src/merkleblock.h --- a/src/merkleblock.h +++ b/src/merkleblock.h @@ -13,6 +13,10 @@ #include +// Helper functions for serialization. +std::vector BitsToBytes(const std::vector &bits); +std::vector BytesToBits(const std::vector &bytes); + /** * Data structure that represents a partial merkle tree. * @@ -95,29 +99,13 @@ std::vector &vnIndex); public: - /** serialization implementation */ - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream &s, Operation ser_action) { - READWRITE(nTransactions); - READWRITE(vHash); - std::vector vBytes; - if (ser_action.ForRead()) { - READWRITE(vBytes); - CPartialMerkleTree &us = *(const_cast(this)); - us.vBits.resize(vBytes.size() * 8); - for (size_t p = 0; p < us.vBits.size(); p++) { - us.vBits[p] = (vBytes[p / 8] & (1 << (p % 8))) != 0; - } - us.fBad = false; - } else { - vBytes.resize((vBits.size() + 7) / 8); - for (size_t p = 0; p < vBits.size(); p++) { - vBytes[p / 8] |= vBits[p] << (p % 8); - } - READWRITE(vBytes); - } + SERIALIZE_METHODS(CPartialMerkleTree, obj) { + READWRITE(obj.nTransactions, obj.vHash); + std::vector bytes; + SER_WRITE(obj, bytes = BitsToBytes(obj.vBits)); + READWRITE(bytes); + SER_READ(obj, obj.vBits = BytesToBits(bytes)); + SER_READ(obj, obj.fBad = false); } /** @@ -186,13 +174,7 @@ CMerkleBlock() {} - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream &s, Operation ser_action) { - READWRITE(header); - READWRITE(txn); - } + SERIALIZE_METHODS(CMerkleBlock, obj) { READWRITE(obj.header, obj.txn); } private: /** diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp --- a/src/merkleblock.cpp +++ b/src/merkleblock.cpp @@ -8,6 +8,22 @@ #include #include +std::vector BitsToBytes(const std::vector &bits) { + std::vector ret((bits.size() + 7) / 8); + for (unsigned int p = 0; p < bits.size(); p++) { + ret[p / 8] |= bits[p] << (p % 8); + } + return ret; +} + +std::vector BytesToBits(const std::vector &bytes) { + std::vector ret(bytes.size() * 8); + for (unsigned int p = 0; p < ret.size(); p++) { + ret[p] = (bytes[p / 8] & (1 << (p % 8))) != 0; + } + return ret; +} + CMerkleBlock::CMerkleBlock(const CBlock &block, CBloomFilter *filter, const std::set *txids) { header = block.GetBlockHeader(); diff --git a/src/netaddress.h b/src/netaddress.h --- a/src/netaddress.h +++ b/src/netaddress.h @@ -127,12 +127,7 @@ } friend bool operator<(const CNetAddr &a, const CNetAddr &b); - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream &s, Operation ser_action) { - READWRITE(ip); - } + SERIALIZE_METHODS(CNetAddr, obj) { READWRITE(obj.ip); } friend class CSubNet; }; @@ -165,13 +160,8 @@ } friend bool operator<(const CSubNet &a, const CSubNet &b); - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream &s, Operation ser_action) { - READWRITE(network); - READWRITE(netmask); - READWRITE(valid); + SERIALIZE_METHODS(CSubNet, obj) { + READWRITE(obj.network, obj.netmask, obj.valid); } }; @@ -202,12 +192,8 @@ CService(const struct in6_addr &ipv6Addr, unsigned short port); explicit CService(const struct sockaddr_in6 &addr); - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream &s, Operation ser_action) { - READWRITE(ip); - READWRITE(WrapBigEndian(port)); + SERIALIZE_METHODS(CService, obj) { + READWRITE(obj.ip, Using>(obj.port)); } }; diff --git a/src/node/utxo_snapshot.h b/src/node/utxo_snapshot.h --- a/src/node/utxo_snapshot.h +++ b/src/node/utxo_snapshot.h @@ -31,13 +31,8 @@ : m_base_blockhash(base_blockhash), m_coins_count(coins_count), m_nchaintx(nchaintx) {} - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream &s, Operation ser_action) { - READWRITE(m_base_blockhash); - READWRITE(m_coins_count); - READWRITE(m_nchaintx); + SERIALIZE_METHODS(SnapshotMetadata, obj) { + READWRITE(obj.m_base_blockhash, obj.m_coins_count, obj.m_nchaintx); } }; diff --git a/src/primitives/block.h b/src/primitives/block.h --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -31,16 +31,9 @@ CBlockHeader() { SetNull(); } - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream &s, Operation ser_action) { - READWRITE(this->nVersion); - READWRITE(hashPrevBlock); - READWRITE(hashMerkleRoot); - READWRITE(nTime); - READWRITE(nBits); - READWRITE(nNonce); + SERIALIZE_METHODS(CBlockHeader, obj) { + READWRITE(obj.nVersion, obj.hashPrevBlock, obj.hashMerkleRoot, + obj.nTime, obj.nBits, obj.nNonce); } void SetNull() { @@ -74,12 +67,9 @@ *(static_cast(this)) = header; } - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream &s, Operation ser_action) { - READWRITEAS(CBlockHeader, *this); - READWRITE(vtx); + SERIALIZE_METHODS(CBlock, obj) { + READWRITEAS(CBlockHeader, obj); + READWRITE(obj.vtx); } void SetNull() { @@ -115,15 +105,12 @@ explicit CBlockLocator(const std::vector &vHaveIn) : vHave(vHaveIn) {} - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream &s, Operation ser_action) { + SERIALIZE_METHODS(CBlockLocator, obj) { int nVersion = s.GetVersion(); if (!(s.GetType() & SER_GETHASH)) { READWRITE(nVersion); } - READWRITE(vHave); + READWRITE(obj.vHave); } void SetNull() { vHave.clear(); } diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -30,13 +30,7 @@ COutPoint() : txid(), n(NULL_INDEX) {} COutPoint(TxId txidIn, uint32_t nIn) : txid(txidIn), n(nIn) {} - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream &s, Operation ser_action) { - READWRITE(txid); - READWRITE(n); - } + SERIALIZE_METHODS(COutPoint, obj) { READWRITE(obj.txid, obj.n); } bool IsNull() const { return txid.IsNull() && n == NULL_INDEX; } @@ -115,13 +109,8 @@ uint32_t nSequenceIn = SEQUENCE_FINAL) : CTxIn(COutPoint(prevTxId, nOut), scriptSigIn, nSequenceIn) {} - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream &s, Operation ser_action) { - READWRITE(prevout); - READWRITE(scriptSig); - READWRITE(nSequence); + SERIALIZE_METHODS(CTxIn, obj) { + READWRITE(obj.prevout, obj.scriptSig, obj.nSequence); } friend bool operator==(const CTxIn &a, const CTxIn &b) { @@ -148,13 +137,7 @@ CTxOut(Amount nValueIn, CScript scriptPubKeyIn) : nValue(nValueIn), scriptPubKey(scriptPubKeyIn) {} - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream &s, Operation ser_action) { - READWRITE(nValue); - READWRITE(scriptPubKey); - } + SERIALIZE_METHODS(CTxOut, obj) { READWRITE(obj.nValue, obj.scriptPubKey); } void SetNull() { nValue = -SATOSHI; diff --git a/src/protocol.h b/src/protocol.h --- a/src/protocol.h +++ b/src/protocol.h @@ -64,14 +64,9 @@ bool IsValidWithoutConfig(const MessageMagic &magic) const; bool IsOversized(const Config &config) const; - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream &s, Operation ser_action) { - READWRITE(pchMessageStart); - READWRITE(pchCommand); - READWRITE(nMessageSize); - READWRITE(pchChecksum); + SERIALIZE_METHODS(CMessageHeader, obj) { + READWRITE(obj.pchMessageStart, obj.pchCommand, obj.nMessageSize, + obj.pchChecksum); } MessageMagic pchMessageStart; @@ -431,13 +426,8 @@ void Init(); - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream &s, Operation ser_action) { - if (ser_action.ForRead()) { - Init(); - } + SERIALIZE_METHODS(CAddress, obj) { + SER_READ(obj, obj.Init()); int nVersion = s.GetVersion(); if (s.GetType() & SER_DISK) { READWRITE(nVersion); @@ -450,12 +440,10 @@ // After the version handshake, serialization version is >= // MIN_PEER_PROTO_VERSION and all ADDR messages are serialized with // nTime. - READWRITE(nTime); + READWRITE(obj.nTime); } - uint64_t nServicesInt = nServices; - READWRITE(nServicesInt); - nServices = static_cast(nServicesInt); - READWRITEAS(CService, *this); + READWRITE(Using>(obj.nServices)); + READWRITEAS(CService, obj); } ServiceFlags nServices; @@ -496,13 +484,7 @@ CInv() : type(0), hash() {} CInv(uint32_t typeIn, const uint256 &hashIn) : type(typeIn), hash(hashIn) {} - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream &s, Operation ser_action) { - READWRITE(type); - READWRITE(hash); - } + SERIALIZE_METHODS(CInv, obj) { READWRITE(obj.type, obj.hash); } friend bool operator<(const CInv &a, const CInv &b) { return a.type < b.type || (a.type == b.type && a.hash < b.hash); diff --git a/src/rest.cpp b/src/rest.cpp --- a/src/rest.cpp +++ b/src/rest.cpp @@ -56,14 +56,9 @@ explicit CCoin(Coin in) : nHeight(in.GetHeight()), out(std::move(in.GetTxOut())) {} - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream &s, Operation ser_action) { + SERIALIZE_METHODS(CCoin, obj) { uint32_t nTxVerDummy = 0; - READWRITE(nTxVerDummy); - READWRITE(nHeight); - READWRITE(out); + READWRITE(nTxVerDummy, obj.nHeight, obj.out); } }; diff --git a/src/script/keyorigin.h b/src/script/keyorigin.h --- a/src/script/keyorigin.h +++ b/src/script/keyorigin.h @@ -19,11 +19,8 @@ a.path == b.path; } - ADD_SERIALIZE_METHODS; - template - inline void SerializationOp(Stream &s, Operation ser_action) { - READWRITE(fingerprint); - READWRITE(path); + SERIALIZE_METHODS(KeyOriginInfo, obj) { + READWRITE(obj.fingerprint, obj.path); } void clear() { diff --git a/src/script/script.h b/src/script/script.h --- a/src/script/script.h +++ b/src/script/script.h @@ -450,12 +450,7 @@ CScript(const uint8_t *pbegin, const uint8_t *pend) : CScriptBase(pbegin, pend) {} - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream &s, Operation ser_action) { - READWRITEAS(CScriptBase, *this); - } + SERIALIZE_METHODS(CScript, obj) { READWRITEAS(CScriptBase, obj); } explicit CScript(int64_t b) { operator<<(b); } explicit CScript(opcodetype b) { operator<<(b); } diff --git a/src/serialize.h b/src/serialize.h --- a/src/serialize.h +++ b/src/serialize.h @@ -191,6 +191,12 @@ #define READWRITE(...) (::SerReadWriteMany(s, ser_action, __VA_ARGS__)) #define READWRITEAS(type, obj) \ (::SerReadWriteMany(s, ser_action, ReadWriteAsHelper(obj))) +#define SER_READ(obj, code) \ + ::SerRead( \ + s, ser_action, obj, \ + [&](Stream &s, typename std::remove_const::type &obj) { code; }) +#define SER_WRITE(obj, code) \ + ::SerWrite(s, ser_action, obj, [&](Stream &s, const Type &obj) { code; }) /** * Implement three methods for serializable objects. These are actually wrappers @@ -622,7 +628,17 @@ } }; -template struct CustomUintFormatter { +/** + * Serialization wrapper class for custom integers and enums. + * + * It permits specifying the serialized size (1 to 8 bytes) and endianness. + * + * Use the big endian mode for values that are stored in memory in native + * byte order, but serialized in big endian notation. This is only intended + * to implement serializers that are compatible with existing formats, and + * its use is not recommended for new data structures. + */ +template struct CustomUintFormatter { static_assert(Bytes > 0 && Bytes <= 8, "CustomUintFormatter Bytes out of range"); static constexpr uint64_t MAX = 0xffffffffffffffff >> (8 * (8 - Bytes)); @@ -632,51 +648,35 @@ throw std::ios_base::failure( "CustomUintFormatter value out of range"); } - uint64_t raw = htole64(v); - s.write((const char *)&raw, Bytes); + if (BigEndian) { + uint64_t raw = htobe64(v); + s.write(((const char *)&raw) + 8 - Bytes, Bytes); + } else { + uint64_t raw = htole64(v); + s.write((const char *)&raw, Bytes); + } } template void Unser(Stream &s, I &v) { - static_assert(std::numeric_limits::max() >= MAX && - std::numeric_limits::min() <= 0, - "CustomUintFormatter type too small"); + using U = typename std::conditional::value, + std::underlying_type, + std::common_type>::type::type; + static_assert(std::numeric_limits::max() >= MAX && + std::numeric_limits::min() <= 0, + "Assigned type too small"); uint64_t raw = 0; - s.read((char *)&raw, Bytes); - v = le64toh(raw); + if (BigEndian) { + s.read(((char *)&raw) + 8 - Bytes, Bytes); + v = static_cast(be64toh(raw)); + } else { + s.read((char *)&raw, Bytes); + v = static_cast(le64toh(raw)); + } } }; -/** Serialization wrapper class for big-endian integers. - * - * Use this wrapper around integer types that are stored in memory in native - * byte order, but serialized in big endian notation. This is only intended - * to implement serializers that are compatible with existing formats, and - * its use is not recommended for new data structures. - * - * Only 16-bit types are supported for now. - */ -template class BigEndian { -protected: - I &m_val; - -public: - explicit BigEndian(I &val) : m_val(val) { - static_assert(std::is_unsigned::value, - "BigEndian type must be unsigned integer"); - static_assert(sizeof(I) == 2 && std::numeric_limits::min() == 0 && - std::numeric_limits::max() == - std::numeric_limits::max(), - "Unsupported BigEndian size"); - } - - template void Serialize(Stream &s) const { - ser_writedata16be(s, m_val); - } - - template void Unserialize(Stream &s) { - m_val = ser_readdata16be(s); - } -}; +template +using BigEndianFormatter = CustomUintFormatter; /** Formatter for integers in CompactSize format. */ struct CompactSizeFormatter { @@ -726,10 +726,6 @@ } }; -template BigEndian WrapBigEndian(I &n) { - return BigEndian(n); -} - /** * Formatter to serialize/deserialize vector elements using another formatter * @@ -1182,6 +1178,26 @@ ::UnserializeMany(s, args...); } +template +inline void SerRead(Stream &s, CSerActionSerialize ser_action, Type &&, Fn &&) { +} + +template +inline void SerRead(Stream &s, CSerActionUnserialize ser_action, Type &&obj, + Fn &&fn) { + fn(s, std::forward(obj)); +} + +template +inline void SerWrite(Stream &s, CSerActionSerialize ser_action, Type &&obj, + Fn &&fn) { + fn(s, std::forward(obj)); +} + +template +inline void SerWrite(Stream &s, CSerActionUnserialize ser_action, Type &&, + Fn &&) {} + template inline void WriteVarInt(CSizeComputer &s, I n) { s.seek(GetSizeOfVarInt(n)); } diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp --- a/src/test/blockencodings_tests.cpp +++ b/src/test/blockencodings_tests.cpp @@ -166,23 +166,12 @@ return base.GetShortID(txhash); } - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream &s, Operation ser_action) { - READWRITE(header); - READWRITE(nonce); - size_t shorttxids_size = shorttxids.size(); - READWRITE(VARINT(shorttxids_size)); - shorttxids.resize(shorttxids_size); - for (size_t i = 0; i < shorttxids.size(); i++) { - uint32_t lsb = shorttxids[i] & 0xffffffff; - uint16_t msb = (shorttxids[i] >> 32) & 0xffff; - READWRITE(lsb); - READWRITE(msb); - shorttxids[i] = (uint64_t(msb) << 32) | uint64_t(lsb); - } - READWRITE(prefilledtxn); + SERIALIZE_METHODS(TestHeaderAndShortIDs, obj) { + READWRITE( + obj.header, obj.nonce, + Using>>(obj.shorttxids), + obj.prefilledtxn); } }; diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp --- a/src/test/dbwrapper_tests.cpp +++ b/src/test/dbwrapper_tests.cpp @@ -351,24 +351,21 @@ return *this += s.str; } - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream &s, Operation ser_action) { - if (ser_action.ForRead()) { - str.clear(); - char c = 0; - while (true) { - try { - READWRITE(c); - str.push_back(c); - } catch (const std::ios_base::failure &) { - break; - } - } - } else { - for (size_t i = 0; i < str.size(); i++) { - READWRITE(str[i]); + template void Serialize(Stream &s) const { + for (size_t i = 0; i < str.size(); i++) { + s << str[i]; + } + } + + template void Unserialize(Stream &s) { + str.clear(); + char c = 0; + while (true) { + try { + s >> c; + str.push_back(c); + } catch (const std::ios_base::failure &) { + break; } } } diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp --- a/src/test/serialize_tests.cpp +++ b/src/test/serialize_tests.cpp @@ -36,15 +36,12 @@ memcpy(charstrval, charstrvalin, sizeof(charstrval)); } - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream &s, Operation ser_action) { - READWRITE(intval); - READWRITE(boolval); - READWRITE(stringval); - READWRITE(charstrval); - READWRITE(txval); + SERIALIZE_METHODS(CSerializeMethodsTestSingle, obj) { + READWRITE(obj.intval); + READWRITE(obj.boolval); + READWRITE(obj.stringval); + READWRITE(obj.charstrval); + READWRITE(obj.txval); } bool operator==(const CSerializeMethodsTestSingle &rhs) { @@ -57,11 +54,10 @@ class CSerializeMethodsTestMany : public CSerializeMethodsTestSingle { public: using CSerializeMethodsTestSingle::CSerializeMethodsTestSingle; - ADD_SERIALIZE_METHODS; - template - inline void SerializationOp(Stream &s, Operation ser_action) { - READWRITE(intval, boolval, stringval, charstrval, txval); + SERIALIZE_METHODS(CSerializeMethodsTestMany, obj) { + READWRITE(obj.intval, obj.boolval, obj.stringval, obj.charstrval, + obj.txval); } }; diff --git a/src/txdb.cpp b/src/txdb.cpp --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -39,19 +39,11 @@ explicit CoinEntry(const COutPoint *ptr) : outpoint(const_cast(ptr)), key(DB_COIN) {} - template void Serialize(Stream &s) const { - s << key; - s << outpoint->GetTxId(); - s << VARINT(outpoint->GetN()); - } - - template void Unserialize(Stream &s) { - s >> key; - TxId id; - s >> id; - uint32_t n = 0; - s >> VARINT(n); - *outpoint = COutPoint(id, n); + SERIALIZE_METHODS(CoinEntry, obj) { + TxId id = obj.outpoint->GetTxId(); + uint32_t n = obj.outpoint->GetN(); + READWRITE(obj.key, id, n); + SER_READ(obj, *obj.outpoint = COutPoint(id, n)); } }; } // namespace