aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCory Fields <cory-nospam-@coryfields.com>2016-09-12 14:38:01 -0400
committerPieter Wuille <pieter.wuille@gmail.com>2016-11-03 13:32:09 -0700
commitb98c14c4e362a8e59d7a3b021651a19ea61b29dd (patch)
tree372648cea84dd1cfca0d86caab27ac0b18ecc6e2
parent82077ef6e49a08b3772d5c82f6e0cfe390e11966 (diff)
serialization: teach serializers variadics
Also add a variadic CDataStream ctor for ease-of-use.
-rw-r--r--src/serialize.h49
-rw-r--r--src/streams.h7
-rw-r--r--src/test/serialize_tests.cpp71
3 files changed, 126 insertions, 1 deletions
diff --git a/src/serialize.h b/src/serialize.h
index 1f51da82ff..82870c45b3 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 @@ public:
}
};
+template<typename Stream>
+void SerializeMany(Stream& s, int nType, int nVersion)
+{
+}
+
+template<typename Stream, typename Arg>
+void SerializeMany(Stream& s, int nType, int nVersion, Arg&& arg)
+{
+ ::Serialize(s, std::forward<Arg>(arg), nType, nVersion);
+}
+
+template<typename Stream, typename Arg, typename... Args>
+void SerializeMany(Stream& s, int nType, int nVersion, Arg&& arg, Args&&... args)
+{
+ ::Serialize(s, std::forward<Arg>(arg), nType, nVersion);
+ ::SerializeMany(s, nType, nVersion, std::forward<Args>(args)...);
+}
+
+template<typename Stream>
+inline void UnserializeMany(Stream& s, int nType, int nVersion)
+{
+}
+
+template<typename Stream, typename Arg>
+inline void UnserializeMany(Stream& s, int nType, int nVersion, Arg& arg)
+{
+ ::Unserialize(s, arg, nType, nVersion);
+}
+
+template<typename Stream, typename Arg, typename... Args>
+inline void UnserializeMany(Stream& s, int nType, int nVersion, Arg& arg, Args&... args)
+{
+ ::Unserialize(s, arg, nType, nVersion);
+ ::UnserializeMany(s, nType, nVersion, args...);
+}
+
+template<typename Stream, typename... Args>
+inline void SerReadWriteMany(Stream& s, int nType, int nVersion, CSerActionSerialize ser_action, Args&&... args)
+{
+ ::SerializeMany(s, nType, nVersion, std::forward<Args>(args)...);
+}
+
+template<typename Stream, typename... Args>
+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 7132364eb1..fa001c112a 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -112,6 +112,13 @@ public:
Init(nTypeIn, nVersionIn);
}
+ template <typename... Args>
+ CDataStream(int nTypeIn, int nVersionIn, Args&&... args)
+ {
+ Init(nTypeIn, nVersionIn);
+ ::SerializeMany(*this, nType, nVersion, std::forward<Args>(args)...);
+ }
+
void Init(int nTypeIn, int nVersionIn)
{
nReadPos = 0;
diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp
index bec2c7459d..4c0fdc77f7 100644
--- a/src/test/serialize_tests.cpp
+++ b/src/test/serialize_tests.cpp
@@ -10,11 +10,54 @@
#include <stdint.h>
#include <boost/test/unit_test.hpp>
-
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 <typename Stream, typename Operation>
+ 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 <typename Stream, typename Operation>
+ 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()