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:
commit
0a8054e7cd
7 changed files with 13 additions and 8 deletions
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -155,7 +155,12 @@ enum
|
||||||
SER_GETHASH = (1 << 2),
|
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(...) (::SerReadWriteMany(s, ser_action, __VA_ARGS__))
|
#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
|
||||||
|
|
|
@ -47,7 +47,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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -396,7 +396,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;
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue