Merge #12731: Support serialization as another type without casting

818dc74 Support serialization as another type without casting (Pieter Wuille)

Pull request description:

  This adds a `READWRITEAS(type, obj)` macro which serializes `obj` as if it were converted to `const type&` when `const`, and to `type&` when non-`const`. No actual cast is involved, so this only works when this conversion can be done automatically.

  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 is a redo of #12712, using a slightly different interface.

Tree-SHA512: 262f0257284ff99b5ffaec9b997c194e221522ba35c3ac8eaa9bb344449d7ea0a314de254dc77449fa7aaa600f8cd9a24da65aade8c1ec6aa80c6e9a7bba5ca7
This commit is contained in:
Wladimir J. van der Laan 2018-04-10 19:56:22 +02:00 committed by Pasta
parent 101f73bb6d
commit 96e2c5a25f
No known key found for this signature in database
GPG Key ID: 52527BEDABE87984
7 changed files with 14 additions and 9 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -162,8 +162,13 @@ enum
SER_GETHASH = (1 << 2),
};
//! 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(obj) (::SerReadWrite(s, (obj), ser_action))
#define READWRITEMANY(...) (::SerReadWriteMany(s, ser_action, __VA_ARGS__))
#define READWRITEMANY(...) (::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
@ -376,7 +381,7 @@ I ReadVarInt(Stream& is)
#define COMPACTSIZE(obj) REF(CCompactSize(REF(obj)))
#define LIMITED_STRING(obj,n) REF(LimitedString< n >(REF(obj)))
/**
/**
* Wrapper for serializing arrays and POD.
*/
class CFlatData

View File

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

View File

@ -419,7 +419,7 @@ public:
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
s << vUnused << mapValueCopy << vOrderForm << fTimeReceivedIsTxTime << nTimeReceived << fFromMe << fSpent;
}
@ -430,7 +430,7 @@ public:
Init(nullptr);
char fSpent;
s >> *static_cast<CMerkleTx*>(this);
s >> static_cast<CMerkleTx&>(*this);
std::vector<CMerkleTx> vUnused; //!< Used to be vtxPrev
s >> vUnused >> mapValue >> vOrderForm >> fTimeReceivedIsTxTime >> nTimeReceived >> fFromMe >> fSpent;