mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-11-11 14:38:29 +01:00
Merge #18317: Serialization improvements step 6 (all except wallet/gui)
f9ee0f37c2Add comments to CustomUintFormatter (Pieter Wuille)4eb5643e35Convert everything except wallet/qt to new serialization (Pieter Wuille)2b1f85e8c5Convert blockencodings_tests to new serialization (Pieter Wuille)73747afbbeConvert merkleblock to new serialization (Pieter Wuille)d06fedd1bcAdd SER_READ and SER_WRITE for read/write-dependent statements (Russell Yanofsky)6f9a1e5ad0Extend CustomUintFormatter to support enums (Russell Yanofsky)769ee5fa00Merge BigEndian functionality into CustomUintFormatter (Pieter Wuille) Pull request description: The next step of changes from #10785. This: * Adds support for enum serialization to `CustomUintFormatter`, used in `CAddress` for service flags. * Merges `BigEndian` into `CustomUintFormatter`, used in `CNetAddr` for port numbers. * Converts everything (except wallet and gui) to use the new serialization framework. ACKs for top commit: MarcoFalke: re-ACKf9ee0f37c2, only change is new documentation commit for CustomUintFormatter 📂 ryanofsky: Code review ACKf9ee0f37c2. Just new commit adding comment since last review jonatack: Code review re-ACKf9ee0f37c2only change since last review is an additional commit adding Doxygen documentation for `CustomUintFormatter`. Tree-SHA512: e7a0a36afae592d5a4ff8c81ae04d858ac409388e361f2bc197d9a78abca45134218497ab2dfd6d031e0cce0ca586cf857077b7c6ce17fccf67e2d367c1b6cd4
This commit is contained in:
@@ -190,6 +190,8 @@ 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)))
|
||||
#define SER_READ(obj, code) ::SerRead(s, ser_action, obj, [&](Stream& s, typename std::remove_const<Type>::type& obj) { code; })
|
||||
#define SER_WRITE(obj, code) ::SerWrite(s, ser_action, obj, [&](Stream& s, const Type& obj) { code; })
|
||||
|
||||
/**
|
||||
* Implement three methods for serializable objects. These are actually wrappers over
|
||||
@@ -518,7 +520,16 @@ struct VarIntFormatter
|
||||
}
|
||||
};
|
||||
|
||||
template<int Bytes>
|
||||
/** Serialization wrapper class for custom integers and enums.
|
||||
*
|
||||
* It permits specifying the serialized size (1 to 8 bytes) and endianness.
|
||||
*
|
||||
* Use the big endian mode for values that are stored in memory in native
|
||||
* byte order, but serialized in big endian notation. This is only intended
|
||||
* to implement serializers that are compatible with existing formats, and
|
||||
* its use is not recommended for new data structures.
|
||||
*/
|
||||
template<int Bytes, bool BigEndian = false>
|
||||
struct CustomUintFormatter
|
||||
{
|
||||
static_assert(Bytes > 0 && Bytes <= 8, "CustomUintFormatter Bytes out of range");
|
||||
@@ -527,52 +538,31 @@ struct CustomUintFormatter
|
||||
template <typename Stream, typename I> void Ser(Stream& s, I v)
|
||||
{
|
||||
if (v < 0 || v > MAX) throw std::ios_base::failure("CustomUintFormatter value out of range");
|
||||
uint64_t raw = htole64(v);
|
||||
s.write((const char*)&raw, Bytes);
|
||||
if (BigEndian) {
|
||||
uint64_t raw = htobe64(v);
|
||||
s.write(((const char*)&raw) + 8 - Bytes, Bytes);
|
||||
} else {
|
||||
uint64_t raw = htole64(v);
|
||||
s.write((const char*)&raw, Bytes);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Stream, typename I> void Unser(Stream& s, I& v)
|
||||
{
|
||||
static_assert(std::numeric_limits<I>::max() >= MAX && std::numeric_limits<I>::min() <= 0, "CustomUintFormatter type too small");
|
||||
using U = typename std::conditional<std::is_enum<I>::value, std::underlying_type<I>, std::common_type<I>>::type::type;
|
||||
static_assert(std::numeric_limits<U>::max() >= MAX && std::numeric_limits<U>::min() <= 0, "Assigned type too small");
|
||||
uint64_t raw = 0;
|
||||
s.read((char*)&raw, Bytes);
|
||||
v = le64toh(raw);
|
||||
if (BigEndian) {
|
||||
s.read(((char*)&raw) + 8 - Bytes, Bytes);
|
||||
v = static_cast<I>(be64toh(raw));
|
||||
} else {
|
||||
s.read((char*)&raw, Bytes);
|
||||
v = static_cast<I>(le64toh(raw));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** Serialization wrapper class for big-endian integers.
|
||||
*
|
||||
* Use this wrapper around integer types that are stored in memory in native
|
||||
* byte order, but serialized in big endian notation. This is only intended
|
||||
* to implement serializers that are compatible with existing formats, and
|
||||
* its use is not recommended for new data structures.
|
||||
*
|
||||
* Only 16-bit types are supported for now.
|
||||
*/
|
||||
template<typename I>
|
||||
class BigEndian
|
||||
{
|
||||
protected:
|
||||
I& m_val;
|
||||
public:
|
||||
explicit BigEndian(I& val) : m_val(val)
|
||||
{
|
||||
static_assert(std::is_unsigned<I>::value, "BigEndian type must be unsigned integer");
|
||||
static_assert(sizeof(I) == 2 && std::numeric_limits<I>::min() == 0 && std::numeric_limits<I>::max() == std::numeric_limits<uint16_t>::max(), "Unsupported BigEndian size");
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Serialize(Stream& s) const
|
||||
{
|
||||
ser_writedata16be(s, m_val);
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Unserialize(Stream& s)
|
||||
{
|
||||
m_val = ser_readdata16be(s);
|
||||
}
|
||||
};
|
||||
template<int Bytes> using BigEndianFormatter = CustomUintFormatter<Bytes, true>;
|
||||
|
||||
/** Formatter for integers in CompactSize format. */
|
||||
struct CompactSizeFormatter
|
||||
@@ -626,9 +616,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template<typename I>
|
||||
BigEndian<I> WrapBigEndian(I& n) { return BigEndian<I>(n); }
|
||||
|
||||
/** Formatter to serialize/deserialize vector elements using another formatter
|
||||
*
|
||||
* Example:
|
||||
@@ -1124,6 +1111,28 @@ inline void SerReadWriteMany(Stream& s, CSerActionUnserialize ser_action, Args&&
|
||||
::UnserializeMany(s, args...);
|
||||
}
|
||||
|
||||
template<typename Stream, typename Type, typename Fn>
|
||||
inline void SerRead(Stream& s, CSerActionSerialize ser_action, Type&&, Fn&&)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Stream, typename Type, typename Fn>
|
||||
inline void SerRead(Stream& s, CSerActionUnserialize ser_action, Type&& obj, Fn&& fn)
|
||||
{
|
||||
fn(s, std::forward<Type>(obj));
|
||||
}
|
||||
|
||||
template<typename Stream, typename Type, typename Fn>
|
||||
inline void SerWrite(Stream& s, CSerActionSerialize ser_action, Type&& obj, Fn&& fn)
|
||||
{
|
||||
fn(s, std::forward<Type>(obj));
|
||||
}
|
||||
|
||||
template<typename Stream, typename Type, typename Fn>
|
||||
inline void SerWrite(Stream& s, CSerActionUnserialize ser_action, Type&&, Fn&&)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
inline void WriteVarInt(CSizeComputer &s, I n)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user