From aaaa3fa9477eef9ea72e4a501d130c57b47b470a Mon Sep 17 00:00:00 2001 From: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz> Date: Sat, 11 Jul 2020 09:55:38 +0200 Subject: [PATCH] Replace READWRITEAS macro with AsBase wrapping function Co-authored-by: Pieter Wuille --- src/addrman_impl.h | 3 +-- src/index/disktxpos.h | 3 +-- src/netaddress.h | 3 +-- src/primitives/block.h | 3 +-- src/protocol.h | 2 +- src/script/script.h | 2 +- src/serialize.h | 36 ++++++++++++++++++++++++++++++++---- 7 files changed, 38 insertions(+), 14 deletions(-) diff --git a/src/addrman_impl.h b/src/addrman_impl.h index 9aff408e342..1cfaca04a3d 100644 --- a/src/addrman_impl.h +++ b/src/addrman_impl.h @@ -65,8 +65,7 @@ public: SERIALIZE_METHODS(AddrInfo, obj) { - READWRITEAS(CAddress, obj); - READWRITE(obj.source, Using>(obj.m_last_success), obj.nAttempts); + READWRITE(AsBase(obj), obj.source, Using>(obj.m_last_success), obj.nAttempts); } AddrInfo(const CAddress &addrIn, const CNetAddr &addrSource) : CAddress(addrIn), source(addrSource) diff --git a/src/index/disktxpos.h b/src/index/disktxpos.h index 7718755b789..1004f7ae87d 100644 --- a/src/index/disktxpos.h +++ b/src/index/disktxpos.h @@ -14,8 +14,7 @@ struct CDiskTxPos : public FlatFilePos SERIALIZE_METHODS(CDiskTxPos, obj) { - READWRITEAS(FlatFilePos, obj); - READWRITE(VARINT(obj.nTxOffset)); + READWRITE(AsBase(obj), VARINT(obj.nTxOffset)); } CDiskTxPos(const FlatFilePos &blockIn, unsigned int nTxOffsetIn) : FlatFilePos(blockIn.nFile, blockIn.nPos), nTxOffset(nTxOffsetIn) { diff --git a/src/netaddress.h b/src/netaddress.h index 7cba6c00d09..143cdd4fa3f 100644 --- a/src/netaddress.h +++ b/src/netaddress.h @@ -540,8 +540,7 @@ public: SERIALIZE_METHODS(CService, obj) { - READWRITEAS(CNetAddr, obj); - READWRITE(Using>(obj.port)); + READWRITE(AsBase(obj), Using>(obj.port)); } friend class CServiceHash; diff --git a/src/primitives/block.h b/src/primitives/block.h index bd11279a6e0..861d362414b 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -87,8 +87,7 @@ public: SERIALIZE_METHODS(CBlock, obj) { - READWRITEAS(CBlockHeader, obj); - READWRITE(obj.vtx); + READWRITE(AsBase(obj), obj.vtx); } void SetNull() diff --git a/src/protocol.h b/src/protocol.h index ac4545c3111..316b7a11f2d 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -433,7 +433,7 @@ public: } // Invoke V1/V2 serializer for CService parent object. OverrideStream os(&s, s.GetType(), use_v2 ? ADDRV2_FORMAT : 0); - SerReadWriteMany(os, ser_action, ReadWriteAsHelper(obj)); + SerReadWriteMany(os, ser_action, AsBase(obj)); } //! Always included in serialization. The behavior is unspecified if the value is not representable as uint32_t. diff --git a/src/script/script.h b/src/script/script.h index 902f756afcf..c329a2afd6e 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -434,7 +434,7 @@ public: CScript(std::vector::const_iterator pbegin, std::vector::const_iterator pend) : CScriptBase(pbegin, pend) { } CScript(const unsigned char* pbegin, const unsigned char* pend) : CScriptBase(pbegin, pend) { } - SERIALIZE_METHODS(CScript, obj) { READWRITEAS(CScriptBase, obj); } + SERIALIZE_METHODS(CScript, obj) { READWRITE(AsBase(obj)); } explicit CScript(int64_t b) { operator<<(b); } explicit CScript(opcodetype b) { operator<<(b); } diff --git a/src/serialize.h b/src/serialize.h index 39f2c0f3ae7..08c10fbce43 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -133,12 +133,40 @@ enum SER_GETHASH = (1 << 2), }; -//! 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; } +/** + * Convert any argument to a reference to X, maintaining constness. + * + * This can be used in serialization code to invoke a base class's + * serialization routines. + * + * Example use: + * class Base { ... }; + * class Child : public Base { + * int m_data; + * public: + * SERIALIZE_METHODS(Child, obj) { + * READWRITE(AsBase(obj), obj.m_data); + * } + * }; + * + * static_cast cannot easily be used here, as the type of Obj will be const Child& + * during serialization and Child& during deserialization. AsBase will convert to + * const Base& and Base& appropriately. + */ +template +Out& AsBase(In& x) +{ + static_assert(std::is_base_of_v); + return x; +} +template +const Out& AsBase(const In& x) +{ + static_assert(std::is_base_of_v); + return x; +} #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; })