From 818dc74ba2745872fd68d2158380fc8bd331210e Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 7 Jul 2017 16:06:56 -0700 Subject: [PATCH] Support serialization as another type without casting This adds a READWRITEAS(type, obj) macro which serializes obj as if it were casted to (const type&) when const, and to (type&) when non-const. This makes it usable in serialization code that uses a single implementation for both serialization and deserializing, which doesn't know the constness of the object involved. --- src/addrman.h | 2 +- src/primitives/block.h | 2 +- src/protocol.h | 2 +- src/script/script.h | 2 +- src/serialize.h | 7 ++++++- src/txdb.h | 2 +- src/wallet/wallet.h | 4 ++-- 7 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/addrman.h b/src/addrman.h index 67423c6c5..3f163dab6 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -59,7 +59,7 @@ public: template inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(*static_cast(this)); + READWRITEAS(CAddress, *this); READWRITE(source); READWRITE(nLastSuccess); READWRITE(nAttempts); diff --git a/src/primitives/block.h b/src/primitives/block.h index 5d6d44ac7..1fca55d91 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -93,7 +93,7 @@ public: template inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(*static_cast(this)); + READWRITEAS(CBlockHeader, *this); READWRITE(vtx); } diff --git a/src/protocol.h b/src/protocol.h index e518d1194..b8deacb5f 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -349,7 +349,7 @@ public: uint64_t nServicesInt = nServices; READWRITE(nServicesInt); nServices = static_cast(nServicesInt); - READWRITE(*static_cast(this)); + READWRITEAS(CService, *this); } // TODO: make private (improves encapsulation) diff --git a/src/script/script.h b/src/script/script.h index 591777672..8e5a792c7 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -415,7 +415,7 @@ public: template inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(static_cast(*this)); + READWRITEAS(CScriptBase, *this); } CScript& operator+=(const CScript& b) diff --git a/src/serialize.h b/src/serialize.h index 91da6b0f8..341a138e8 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -148,7 +148,12 @@ enum SER_GETHASH = (1 << 2), }; -#define READWRITE(...) (::SerReadWriteMany(s, ser_action, __VA_ARGS__)) +//! Convert the reference base type to X, without changing constness or reference type. +template X& ReadWriteAsHelper(X& x) { return x; } +template const X& ReadWriteAsHelper(const X& x) { return x; } + +#define READWRITE(...) (::SerReadWriteMany(s, ser_action, __VA_ARGS__)) +#define READWRITEAS(type, obj) (::SerReadWriteMany(s, ser_action, ReadWriteAsHelper(obj))) /** * Implement three methods for serializable objects. These are actually wrappers over diff --git a/src/txdb.h b/src/txdb.h index 2fc69e563..830b65a32 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -46,7 +46,7 @@ struct CDiskTxPos : public CDiskBlockPos template inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(*static_cast(this)); + READWRITEAS(CDiskBlockPos, *this); READWRITE(VARINT(nTxOffset)); } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 5ac8457eb..ae94d5340 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -395,7 +395,7 @@ public: mapValueCopy["timesmart"] = strprintf("%u", nTimeSmart); } - s << *static_cast(this); + s << static_cast(*this); std::vector vUnused; //!< Used to be vtxPrev s << vUnused << mapValueCopy << vOrderForm << fTimeReceivedIsTxTime << nTimeReceived << fFromMe << fSpent; } @@ -406,7 +406,7 @@ public: Init(nullptr); char fSpent; - s >> *static_cast(this); + s >> static_cast(*this); std::vector vUnused; //!< Used to be vtxPrev s >> vUnused >> mapValue >> vOrderForm >> fTimeReceivedIsTxTime >> nTimeReceived >> fFromMe >> fSpent;