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.
This commit is contained in:
Pieter Wuille 2017-07-07 16:06:56 -07:00
parent 8ee5c7b747
commit 818dc74ba2
7 changed files with 13 additions and 8 deletions

View File

@ -59,7 +59,7 @@ public:
template <typename Stream, typename Operation> template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) { inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(*static_cast<CAddress*>(this)); READWRITEAS(CAddress, *this);
READWRITE(source); READWRITE(source);
READWRITE(nLastSuccess); READWRITE(nLastSuccess);
READWRITE(nAttempts); READWRITE(nAttempts);

View File

@ -93,7 +93,7 @@ public:
template <typename Stream, typename Operation> template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) { inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(*static_cast<CBlockHeader*>(this)); READWRITEAS(CBlockHeader, *this);
READWRITE(vtx); READWRITE(vtx);
} }

View File

@ -349,7 +349,7 @@ public:
uint64_t nServicesInt = nServices; uint64_t nServicesInt = nServices;
READWRITE(nServicesInt); READWRITE(nServicesInt);
nServices = static_cast<ServiceFlags>(nServicesInt); nServices = static_cast<ServiceFlags>(nServicesInt);
READWRITE(*static_cast<CService*>(this)); READWRITEAS(CService, *this);
} }
// TODO: make private (improves encapsulation) // TODO: make private (improves encapsulation)

View File

@ -415,7 +415,7 @@ public:
template <typename Stream, typename Operation> template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) { inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(static_cast<CScriptBase&>(*this)); READWRITEAS(CScriptBase, *this);
} }
CScript& operator+=(const CScript& b) CScript& operator+=(const CScript& b)

View File

@ -148,7 +148,12 @@ enum
SER_GETHASH = (1 << 2), 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<typename X> X& ReadWriteAsHelper(X& x) { return x; }
template<typename X> 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<type>(obj)))
/** /**
* Implement three methods for serializable objects. These are actually wrappers over * Implement three methods for serializable objects. These are actually wrappers over

View File

@ -46,7 +46,7 @@ struct CDiskTxPos : public CDiskBlockPos
template <typename Stream, typename Operation> template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) { inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(*static_cast<CDiskBlockPos*>(this)); READWRITEAS(CDiskBlockPos, *this);
READWRITE(VARINT(nTxOffset)); READWRITE(VARINT(nTxOffset));
} }

View File

@ -395,7 +395,7 @@ public:
mapValueCopy["timesmart"] = strprintf("%u", nTimeSmart); mapValueCopy["timesmart"] = strprintf("%u", nTimeSmart);
} }
s << *static_cast<const CMerkleTx*>(this); s << static_cast<const CMerkleTx&>(*this);
std::vector<CMerkleTx> vUnused; //!< Used to be vtxPrev std::vector<CMerkleTx> vUnused; //!< Used to be vtxPrev
s << vUnused << mapValueCopy << vOrderForm << fTimeReceivedIsTxTime << nTimeReceived << fFromMe << fSpent; s << vUnused << mapValueCopy << vOrderForm << fTimeReceivedIsTxTime << nTimeReceived << fFromMe << fSpent;
} }
@ -406,7 +406,7 @@ public:
Init(nullptr); Init(nullptr);
char fSpent; char fSpent;
s >> *static_cast<CMerkleTx*>(this); s >> static_cast<CMerkleTx&>(*this);
std::vector<CMerkleTx> vUnused; //!< Used to be vtxPrev std::vector<CMerkleTx> vUnused; //!< Used to be vtxPrev
s >> vUnused >> mapValue >> vOrderForm >> fTimeReceivedIsTxTime >> nTimeReceived >> fFromMe >> fSpent; s >> vUnused >> mapValue >> vOrderForm >> fTimeReceivedIsTxTime >> nTimeReceived >> fFromMe >> fSpent;