Skip to content

Commit

Permalink
Add optimized CSizeComputer serializers
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
sipa committed Nov 7, 2016
1 parent a2929a2 commit 25a211a
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/pubkey.h
Expand Up @@ -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
{
Expand Down
35 changes: 35 additions & 0 deletions src/serialize.h
Expand Up @@ -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
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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:
Expand All @@ -815,6 +833,12 @@ class CSizeComputer
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)
{
Expand Down Expand Up @@ -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)
{
Expand Down

0 comments on commit 25a211a

Please sign in to comment.