From b98c14c4e362a8e59d7a3b021651a19ea61b29dd Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Mon, 12 Sep 2016 14:38:01 -0400 Subject: [PATCH] serialization: teach serializers variadics Also add a variadic CDataStream ctor for ease-of-use. --- src/serialize.h | 49 +++++++++++++++++++++++++ src/streams.h | 7 ++++ src/test/serialize_tests.cpp | 71 +++++++++++++++++++++++++++++++++++- 3 files changed, 126 insertions(+), 1 deletion(-) diff --git a/src/serialize.h b/src/serialize.h index 1f51da82fffa2..82870c45b3b0b 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -160,6 +160,7 @@ enum }; #define READWRITE(obj) (::SerReadWrite(s, (obj), nType, nVersion, ser_action)) +#define READWRITEMANY(...) (::SerReadWriteMany(s, nType, nVersion, ser_action, __VA_ARGS__)) /** * Implement three methods for serializable objects. These are actually wrappers over @@ -960,4 +961,52 @@ class CSizeComputer } }; +template +void SerializeMany(Stream& s, int nType, int nVersion) +{ +} + +template +void SerializeMany(Stream& s, int nType, int nVersion, Arg&& arg) +{ + ::Serialize(s, std::forward(arg), nType, nVersion); +} + +template +void SerializeMany(Stream& s, int nType, int nVersion, Arg&& arg, Args&&... args) +{ + ::Serialize(s, std::forward(arg), nType, nVersion); + ::SerializeMany(s, nType, nVersion, std::forward(args)...); +} + +template +inline void UnserializeMany(Stream& s, int nType, int nVersion) +{ +} + +template +inline void UnserializeMany(Stream& s, int nType, int nVersion, Arg& arg) +{ + ::Unserialize(s, arg, nType, nVersion); +} + +template +inline void UnserializeMany(Stream& s, int nType, int nVersion, Arg& arg, Args&... args) +{ + ::Unserialize(s, arg, nType, nVersion); + ::UnserializeMany(s, nType, nVersion, args...); +} + +template +inline void SerReadWriteMany(Stream& s, int nType, int nVersion, CSerActionSerialize ser_action, Args&&... args) +{ + ::SerializeMany(s, nType, nVersion, std::forward(args)...); +} + +template +inline void SerReadWriteMany(Stream& s, int nType, int nVersion, CSerActionUnserialize ser_action, Args&... args) +{ + ::UnserializeMany(s, nType, nVersion, args...); +} + #endif // BITCOIN_SERIALIZE_H diff --git a/src/streams.h b/src/streams.h index 7132364eb1951..fa001c112accc 100644 --- a/src/streams.h +++ b/src/streams.h @@ -112,6 +112,13 @@ class CDataStream Init(nTypeIn, nVersionIn); } + template + CDataStream(int nTypeIn, int nVersionIn, Args&&... args) + { + Init(nTypeIn, nVersionIn); + ::SerializeMany(*this, nType, nVersion, std::forward(args)...); + } + void Init(int nTypeIn, int nVersionIn) { nReadPos = 0; diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp index bec2c7459d8c9..4c0fdc77f70be 100644 --- a/src/test/serialize_tests.cpp +++ b/src/test/serialize_tests.cpp @@ -10,11 +10,54 @@ #include #include - using namespace std; BOOST_FIXTURE_TEST_SUITE(serialize_tests, BasicTestingSetup) +class CSerializeMethodsTestSingle +{ +protected: + int intval; + bool boolval; + std::string stringval; + const char* charstrval; + CTransaction txval; +public: + CSerializeMethodsTestSingle() = default; + CSerializeMethodsTestSingle(int intvalin, bool boolvalin, std::string stringvalin, const char* charstrvalin, CTransaction txvalin) : intval(intvalin), boolval(boolvalin), stringval(std::move(stringvalin)), charstrval(charstrvalin), txval(txvalin){} + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(intval); + READWRITE(boolval); + READWRITE(stringval); + READWRITE(FLATDATA(charstrval)); + READWRITE(txval); + } + + bool operator==(const CSerializeMethodsTestSingle& rhs) + { + return intval == rhs.intval && \ + boolval == rhs.boolval && \ + stringval == rhs.stringval && \ + strcmp(charstrval, rhs.charstrval) == 0 && \ + txval == rhs.txval; + } +}; + +class CSerializeMethodsTestMany : public CSerializeMethodsTestSingle +{ +public: + using CSerializeMethodsTestSingle::CSerializeMethodsTestSingle; + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITEMANY(intval, boolval, stringval, FLATDATA(charstrval), txval); + } +}; + BOOST_AUTO_TEST_CASE(sizes) { BOOST_CHECK_EQUAL(sizeof(char), GetSerializeSize(char(0), 0)); @@ -297,4 +340,30 @@ BOOST_AUTO_TEST_CASE(insert_delete) BOOST_CHECK_EQUAL(ss.size(), 0); } +BOOST_AUTO_TEST_CASE(class_methods) +{ + int intval(100); + bool boolval(true); + std::string stringval("testing"); + const char* charstrval("testing charstr"); + CMutableTransaction txval; + CSerializeMethodsTestSingle methodtest1(intval, boolval, stringval, charstrval, txval); + CSerializeMethodsTestMany methodtest2(intval, boolval, stringval, charstrval, txval); + CSerializeMethodsTestSingle methodtest3; + CSerializeMethodsTestMany methodtest4; + CDataStream ss(SER_DISK, PROTOCOL_VERSION); + BOOST_CHECK(methodtest1 == methodtest2); + ss << methodtest1; + ss >> methodtest4; + ss << methodtest2; + ss >> methodtest3; + BOOST_CHECK(methodtest1 == methodtest2); + BOOST_CHECK(methodtest2 == methodtest3); + BOOST_CHECK(methodtest3 == methodtest4); + + CDataStream ss2(SER_DISK, PROTOCOL_VERSION, intval, boolval, stringval, FLATDATA(charstrval), txval); + ss2 >> methodtest3; + BOOST_CHECK(methodtest3 == methodtest4); +} + BOOST_AUTO_TEST_SUITE_END()