aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPieter Wuille <pieter.wuille@gmail.com>2016-10-28 17:50:04 -0700
committerPieter Wuille <pieter.wuille@gmail.com>2016-11-07 13:56:27 -0800
commit25a211aa9edfeccc1e65bf699e0b32619cef2157 (patch)
tree07345f3d4cc10cd2d2c3419a6074a41c99bb20f2
parenta2929a26f5cf3501804fd12071dd6cf6b464a545 (diff)
Add optimized CSizeComputer serializers
To get the advantages of faster GetSerializeSize() implementations back that were removed in "Make GetSerializeSize a wrapper on top of CSizeComputer", reintroduce them in the few places in the form of a specialized Serialize() implementation. This actually gets us in a better state than before, as these even get used when they're invoked indirectly in the serialization of another object.
-rw-r--r--src/pubkey.h5
-rw-r--r--src/serialize.h35
2 files changed, 40 insertions, 0 deletions
diff --git a/src/pubkey.h b/src/pubkey.h
index 15207f89e1..9499862210 100644
--- a/src/pubkey.h
+++ b/src/pubkey.h
@@ -210,6 +210,11 @@ struct CExtPubKey {
void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]);
bool Derive(CExtPubKey& out, unsigned int nChild) const;
+ void Serialize(CSizeComputer& s) const
+ {
+ // Optimized implementation for ::GetSerializeSize that avoids copying.
+ s.seek(BIP32_EXTKEY_SIZE + 1); // add one byte for the size (compact int)
+ }
template <typename Stream>
void Serialize(Stream& s) const
{
diff --git a/src/serialize.h b/src/serialize.h
index 8e37f56723..91864e1b64 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -151,6 +151,8 @@ inline float ser_uint32_to_float(uint32_t y)
// i.e. anything that supports .read(char*, size_t) and .write(char*, size_t)
//
+class CSizeComputer;
+
enum
{
// primary actions
@@ -225,6 +227,8 @@ inline unsigned int GetSizeOfCompactSize(uint64_t nSize)
else return sizeof(unsigned char) + sizeof(uint64_t);
}
+inline void WriteCompactSize(CSizeComputer& os, uint64_t nSize);
+
template<typename Stream>
void WriteCompactSize(Stream& os, uint64_t nSize)
{
@@ -319,6 +323,9 @@ inline unsigned int GetSizeOfVarInt(I n)
return nRet;
}
+template<typename I>
+inline void WriteVarInt(CSizeComputer& os, I n);
+
template<typename Stream, typename I>
void WriteVarInt(Stream& os, I n)
{
@@ -800,6 +807,17 @@ inline void SerReadWrite(Stream& s, T& obj, CSerActionUnserialize ser_action)
+/* ::GetSerializeSize implementations
+ *
+ * Computing the serialized size of objects is done through a special stream
+ * object of type CSizeComputer, which only records the number of bytes written
+ * to it.
+ *
+ * If your Serialize or SerializationOp method has non-trivial overhead for
+ * serialization, it may be worthwhile to implement a specialized version for
+ * CSizeComputer, which uses the s.seek() method to record bytes that would
+ * be written instead.
+ */
class CSizeComputer
{
protected:
@@ -815,6 +833,12 @@ public:
this->nSize += _nSize;
}
+ /** Pretend _nSize bytes are written, without specifying them. */
+ void seek(size_t _nSize)
+ {
+ this->nSize += _nSize;
+ }
+
template<typename T>
CSizeComputer& operator<<(const T& obj)
{
@@ -878,6 +902,17 @@ inline void SerReadWriteMany(Stream& s, CSerActionUnserialize ser_action, Args&.
::UnserializeMany(s, args...);
}
+template<typename I>
+inline void WriteVarInt(CSizeComputer &s, I n)
+{
+ s.seek(GetSizeOfVarInt<I>(n));
+}
+
+inline void WriteCompactSize(CSizeComputer &s, uint64_t nSize)
+{
+ s.seek(GetSizeOfCompactSize(nSize));
+}
+
template <typename T>
size_t GetSerializeSize(const T& t, int nType, int nVersion = 0)
{