From 3d796f89962842e91e7d88e57c1d2d579f01052e Mon Sep 17 00:00:00 2001 From: Kamil Domanski Date: Wed, 20 Aug 2014 08:42:31 +0200 Subject: overhaul serialization code The implementation of each class' serialization/deserialization is no longer passed within a macro. The implementation now lies within a template of form: template inline static size_t SerializationOp(T thisPtr, Stream& s, Operation ser_action, int nType, int nVersion) { size_t nSerSize = 0; /* CODE */ return nSerSize; } In cases when codepath should depend on whether or not we are just deserializing (old fGetSize, fWrite, fRead flags) an additional clause can be used: bool fRead = boost::is_same(); The IMPLEMENT_SERIALIZE macro will now be a freestanding clause added within class' body (similiar to Qt's Q_OBJECT) to implement GetSerializeSize, Serialize and Unserialize. These are now wrappers around the "SerializationOp" template. --- src/serialize.h | 68 ++++++++++++++++++++++++--------------------------------- 1 file changed, 28 insertions(+), 40 deletions(-) (limited to 'src/serialize.h') diff --git a/src/serialize.h b/src/serialize.h index 17cb724bee..7e0ecc2edf 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -22,6 +22,7 @@ #include #include +#include class CAutoFile; class CDataStream; @@ -37,6 +38,14 @@ inline T& REF(const T& val) return const_cast(val); } +// Used to acquire a const pointer "this" and generate a const +// serialization operation from a template +template +inline T MAKE_CONST(T val) +{ + return const_cast(val); +} + /** Get begin pointer of vector (non-const version). * @note These functions avoid the undefined case of indexing into an empty * vector, as well as that of indexing after the end of the vector. @@ -79,48 +88,27 @@ enum SER_GETHASH = (1 << 2), }; -#define IMPLEMENT_SERIALIZE(statements) \ - unsigned int GetSerializeSize(int nType, int nVersion) const \ - { \ - CSerActionGetSerializeSize ser_action; \ - const bool fGetSize = true; \ - const bool fWrite = false; \ - const bool fRead = false; \ - unsigned int nSerSize = 0; \ - ser_streamplaceholder s; \ - assert(fGetSize||fWrite||fRead); /* suppress warning */ \ - s.nType = nType; \ - s.nVersion = nVersion; \ - {statements} \ - return nSerSize; \ - } \ - template \ - void Serialize(Stream& s, int nType, int nVersion) const \ - { \ - CSerActionSerialize ser_action; \ - const bool fGetSize = false; \ - const bool fWrite = true; \ - const bool fRead = false; \ - unsigned int nSerSize = 0; \ - assert(fGetSize||fWrite||fRead); /* suppress warning */ \ - {statements} \ - } \ - template \ - void Unserialize(Stream& s, int nType, int nVersion) \ - { \ - CSerActionUnserialize ser_action; \ - const bool fGetSize = false; \ - const bool fWrite = false; \ - const bool fRead = true; \ - unsigned int nSerSize = 0; \ - assert(fGetSize||fWrite||fRead); /* suppress warning */ \ - {statements} \ - } - #define READWRITE(obj) (nSerSize += ::SerReadWrite(s, (obj), nType, nVersion, ser_action)) - - +/* Implement three methods for serializable objects. These are actually wrappers over + * "SerializationOp" template, which implements the body of each class' serialization + * code. Adding "IMPLEMENT_SERIALIZE" in the body of the class causes these wrappers to be + * added as members. */ +#define IMPLEMENT_SERIALIZE \ + size_t GetSerializeSize(int nType, int nVersion) const { \ + ser_streamplaceholder s; \ + s.nType = nType; \ + s.nVersion = nVersion; \ + return SerializationOp(MAKE_CONST(this), s, CSerActionGetSerializeSize(), nType, nVersion); \ + } \ + template \ + void Serialize(Stream& s, int nType, int nVersion) const { \ + SerializationOp(MAKE_CONST(this), s, CSerActionSerialize(), nType, nVersion); \ + } \ + template \ + void Unserialize(Stream& s, int nType, int nVersion) { \ + SerializationOp(this, s, CSerActionUnserialize(), nType, nVersion); \ + } -- cgit v1.2.3 From 5d96b4ae0188fcad36105642c5d69249d37fdbb5 Mon Sep 17 00:00:00 2001 From: Kamil Domanski Date: Wed, 20 Aug 2014 18:09:29 +0200 Subject: remove fields of ser_streamplaceholder The nType and nVersion fields of stream objects are never accessed from outside the class (or perhaps from the inside too, I haven't checked). Thus no need to have them in a placeholder, whose only purpose is to fill the "Stream" template parameter in serialization implementation. --- src/serialize.h | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'src/serialize.h') diff --git a/src/serialize.h b/src/serialize.h index 7e0ecc2edf..c0666d30a5 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -97,8 +97,6 @@ enum #define IMPLEMENT_SERIALIZE \ size_t GetSerializeSize(int nType, int nVersion) const { \ ser_streamplaceholder s; \ - s.nType = nType; \ - s.nVersion = nVersion; \ return SerializationOp(MAKE_CONST(this), s, CSerActionGetSerializeSize(), nType, nVersion); \ } \ template \ @@ -835,13 +833,7 @@ inline unsigned int SerReadWrite(Stream& s, T& obj, int nType, int nVersion, CSe return 0; } -struct ser_streamplaceholder -{ - int nType; - int nVersion; -}; - - +struct ser_streamplaceholder { }; -- cgit v1.2.3 From 84881f8c472cc67dc757686eb7dc3b495b13cab8 Mon Sep 17 00:00:00 2001 From: Kamil Domanski Date: Wed, 20 Aug 2014 22:44:38 +0200 Subject: rework overhauled serialization methods to non-static Thanks to Pieter Wuille for most of the work on this commit. I did not fixup the overhaul commit, because a rebase conflicted with "remove fields of ser_streamplaceholder". I prefer not to risk making a mistake while resolving it. --- src/serialize.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src/serialize.h') diff --git a/src/serialize.h b/src/serialize.h index c0666d30a5..6eefa18135 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -38,12 +38,12 @@ inline T& REF(const T& val) return const_cast(val); } -// Used to acquire a const pointer "this" and generate a const -// serialization operation from a template +// Used to acquire a non-const pointer "this" to generate bodies +// of const serialization operations from a template template -inline T MAKE_CONST(T val) +inline T* NCONST_PTR(const T* val) { - return const_cast(val); + return const_cast(val); } /** Get begin pointer of vector (non-const version). @@ -97,15 +97,15 @@ enum #define IMPLEMENT_SERIALIZE \ size_t GetSerializeSize(int nType, int nVersion) const { \ ser_streamplaceholder s; \ - return SerializationOp(MAKE_CONST(this), s, CSerActionGetSerializeSize(), nType, nVersion); \ + return NCONST_PTR(this)->SerializationOp(s, CSerActionGetSerializeSize(), nType, nVersion); \ } \ template \ void Serialize(Stream& s, int nType, int nVersion) const { \ - SerializationOp(MAKE_CONST(this), s, CSerActionSerialize(), nType, nVersion); \ + NCONST_PTR(this)->SerializationOp(s, CSerActionSerialize(), nType, nVersion); \ } \ template \ void Unserialize(Stream& s, int nType, int nVersion) { \ - SerializationOp(this, s, CSerActionUnserialize(), nType, nVersion); \ + SerializationOp(s, CSerActionUnserialize(), nType, nVersion); \ } -- cgit v1.2.3 From 31e9a8384a77947f6777d035992f4734618ed206 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 21 Aug 2014 00:49:32 +0200 Subject: Use CSizeComputer to avoid counting sizes in SerializationOp --- src/serialize.h | 51 +++++++++++++++++++++++---------------------------- 1 file changed, 23 insertions(+), 28 deletions(-) (limited to 'src/serialize.h') diff --git a/src/serialize.h b/src/serialize.h index 6eefa18135..4e6ca57a49 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -22,7 +22,6 @@ #include #include -#include class CAutoFile; class CDataStream; @@ -88,24 +87,25 @@ enum SER_GETHASH = (1 << 2), }; -#define READWRITE(obj) (nSerSize += ::SerReadWrite(s, (obj), nType, nVersion, ser_action)) +#define READWRITE(obj) (::SerReadWrite(s, (obj), nType, nVersion, ser_action)) /* Implement three methods for serializable objects. These are actually wrappers over * "SerializationOp" template, which implements the body of each class' serialization * code. Adding "IMPLEMENT_SERIALIZE" in the body of the class causes these wrappers to be * added as members. */ -#define IMPLEMENT_SERIALIZE \ - size_t GetSerializeSize(int nType, int nVersion) const { \ - ser_streamplaceholder s; \ - return NCONST_PTR(this)->SerializationOp(s, CSerActionGetSerializeSize(), nType, nVersion); \ - } \ - template \ - void Serialize(Stream& s, int nType, int nVersion) const { \ - NCONST_PTR(this)->SerializationOp(s, CSerActionSerialize(), nType, nVersion); \ - } \ - template \ - void Unserialize(Stream& s, int nType, int nVersion) { \ - SerializationOp(s, CSerActionUnserialize(), nType, nVersion); \ +#define IMPLEMENT_SERIALIZE \ + size_t GetSerializeSize(int nType, int nVersion) const { \ + CSizeComputer s(nType, nVersion); \ + NCONST_PTR(this)->SerializationOp(s, CSerActionSerialize(), nType, nVersion);\ + return s.size(); \ + } \ + template \ + void Serialize(Stream& s, int nType, int nVersion) const { \ + NCONST_PTR(this)->SerializationOp(s, CSerActionSerialize(), nType, nVersion);\ + } \ + template \ + void Unserialize(Stream& s, int nType, int nVersion) { \ + SerializationOp(s, CSerActionUnserialize(), nType, nVersion); \ } @@ -809,32 +809,27 @@ void Unserialize(Stream& is, std::set& m, int nType, int nVersion) // // Support for IMPLEMENT_SERIALIZE and READWRITE macro // -class CSerActionGetSerializeSize { }; -class CSerActionSerialize { }; -class CSerActionUnserialize { }; - -template -inline unsigned int SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionGetSerializeSize ser_action) +struct CSerActionSerialize { - return ::GetSerializeSize(obj, nType, nVersion); -} + bool ForRead() const { return false; } +}; +struct CSerActionUnserialize +{ + bool ForRead() const { return true; } +}; template -inline unsigned int SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionSerialize ser_action) +inline void SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionSerialize ser_action) { ::Serialize(s, obj, nType, nVersion); - return 0; } template -inline unsigned int SerReadWrite(Stream& s, T& obj, int nType, int nVersion, CSerActionUnserialize ser_action) +inline void SerReadWrite(Stream& s, T& obj, int nType, int nVersion, CSerActionUnserialize ser_action) { ::Unserialize(s, obj, nType, nVersion); - return 0; } -struct ser_streamplaceholder { }; - -- cgit v1.2.3