diff options
Diffstat (limited to 'src/serialize.h')
-rw-r--r-- | src/serialize.h | 102 |
1 files changed, 55 insertions, 47 deletions
diff --git a/src/serialize.h b/src/serialize.h index dcc8d8691e..247e915298 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -59,6 +59,12 @@ inline T* NCONST_PTR(const T* val) return const_cast<T*>(val); } +//! Safely convert odd char pointer types to standard ones. +inline char* CharCast(char* c) { return c; } +inline char* CharCast(unsigned char* c) { return (char*)c; } +inline const char* CharCast(const char* c) { return c; } +inline const char* CharCast(const unsigned char* c) { return (const char*)c; } + /* * Lowest-level serialization and conversion. * @note Sizes of these types are verified in the tests @@ -148,8 +154,7 @@ enum SER_GETHASH = (1 << 2), }; -#define READWRITE(obj) (::SerReadWrite(s, (obj), ser_action)) -#define READWRITEMANY(...) (::SerReadWriteMany(s, ser_action, __VA_ARGS__)) +#define READWRITE(...) (::SerReadWriteMany(s, ser_action, __VA_ARGS__)) /** * Implement three methods for serializable objects. These are actually wrappers over @@ -178,6 +183,8 @@ template<typename Stream> inline void Serialize(Stream& s, int64_t a ) { ser_wri template<typename Stream> inline void Serialize(Stream& s, uint64_t a) { ser_writedata64(s, a); } template<typename Stream> inline void Serialize(Stream& s, float a ) { ser_writedata32(s, ser_float_to_uint32(a)); } template<typename Stream> inline void Serialize(Stream& s, double a ) { ser_writedata64(s, ser_double_to_uint64(a)); } +template<typename Stream, int N> inline void Serialize(Stream& s, const char (&a)[N]) { s.write(a, N); } +template<typename Stream, int N> inline void Serialize(Stream& s, const unsigned char (&a)[N]) { s.write(CharCast(a), N); } template<typename Stream> inline void Unserialize(Stream& s, char& a ) { a = ser_readdata8(s); } // TODO Get rid of bare char template<typename Stream> inline void Unserialize(Stream& s, int8_t& a ) { a = ser_readdata8(s); } @@ -190,6 +197,8 @@ template<typename Stream> inline void Unserialize(Stream& s, int64_t& a ) { a = template<typename Stream> inline void Unserialize(Stream& s, uint64_t& a) { a = ser_readdata64(s); } template<typename Stream> inline void Unserialize(Stream& s, float& a ) { a = ser_uint32_to_float(ser_readdata32(s)); } template<typename Stream> inline void Unserialize(Stream& s, double& a ) { a = ser_uint64_to_double(ser_readdata64(s)); } +template<typename Stream, int N> inline void Unserialize(Stream& s, char (&a)[N]) { s.read(a, N); } +template<typename Stream, int N> inline void Unserialize(Stream& s, unsigned char (&a)[N]) { s.read(CharCast(a), N); } template<typename Stream> inline void Serialize(Stream& s, bool a) { char f=a; ser_writedata8(s, f); } template<typename Stream> inline void Unserialize(Stream& s, bool& a) { char f=ser_readdata8(s); a=f; } @@ -297,9 +306,31 @@ uint64_t ReadCompactSize(Stream& is) * 2^32: [0x8E 0xFE 0xFE 0xFF 0x00] */ -template<typename I> +/** + * Mode for encoding VarInts. + * + * Currently there is no support for signed encodings. The default mode will not + * compile with signed values, and the legacy "nonnegative signed" mode will + * accept signed values, but improperly encode and decode them if they are + * negative. In the future, the DEFAULT mode could be extended to support + * negative numbers in a backwards compatible way, and additional modes could be + * added to support different varint formats (e.g. zigzag encoding). + */ +enum class VarIntMode { DEFAULT, NONNEGATIVE_SIGNED }; + +template <VarIntMode Mode, typename I> +struct CheckVarIntMode { + constexpr CheckVarIntMode() + { + static_assert(Mode != VarIntMode::DEFAULT || std::is_unsigned<I>::value, "Unsigned type required with mode DEFAULT."); + static_assert(Mode != VarIntMode::NONNEGATIVE_SIGNED || std::is_signed<I>::value, "Signed type required with mode NONNEGATIVE_SIGNED."); + } +}; + +template<VarIntMode Mode, typename I> inline unsigned int GetSizeOfVarInt(I n) { + CheckVarIntMode<Mode, I>(); int nRet = 0; while(true) { nRet++; @@ -313,9 +344,10 @@ inline unsigned int GetSizeOfVarInt(I n) template<typename I> inline void WriteVarInt(CSizeComputer& os, I n); -template<typename Stream, typename I> +template<typename Stream, VarIntMode Mode, typename I> void WriteVarInt(Stream& os, I n) { + CheckVarIntMode<Mode, I>(); unsigned char tmp[(sizeof(n)*8+6)/7]; int len=0; while(true) { @@ -330,9 +362,10 @@ void WriteVarInt(Stream& os, I n) } while(len--); } -template<typename Stream, typename I> +template<typename Stream, VarIntMode Mode, typename I> I ReadVarInt(Stream& is) { + CheckVarIntMode<Mode, I>(); I n = 0; while(true) { unsigned char chData = ser_readdata8(is); @@ -351,10 +384,10 @@ I ReadVarInt(Stream& is) } } -#define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj))) -#define VARINT(obj) REF(WrapVarInt(REF(obj))) -#define COMPACTSIZE(obj) REF(CCompactSize(REF(obj))) -#define LIMITED_STRING(obj,n) REF(LimitedString< n >(REF(obj))) +#define FLATDATA(obj) CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj)) +#define VARINT(obj, ...) WrapVarInt<__VA_ARGS__>(REF(obj)) +#define COMPACTSIZE(obj) CCompactSize(REF(obj)) +#define LIMITED_STRING(obj,n) LimitedString< n >(REF(obj)) /** * Wrapper for serializing arrays and POD. @@ -396,7 +429,7 @@ public: } }; -template<typename I> +template<VarIntMode Mode, typename I> class CVarInt { protected: @@ -406,12 +439,12 @@ public: template<typename Stream> void Serialize(Stream &s) const { - WriteVarInt<Stream,I>(s, n); + WriteVarInt<Stream,Mode,I>(s, n); } template<typename Stream> void Unserialize(Stream& s) { - n = ReadVarInt<Stream,I>(s); + n = ReadVarInt<Stream,Mode,I>(s); } }; @@ -462,8 +495,8 @@ public: } }; -template<typename I> -CVarInt<I> WrapVarInt(I& n) { return CVarInt<I>(n); } +template<VarIntMode Mode=VarIntMode::DEFAULT, typename I> +CVarInt<Mode, I> WrapVarInt(I& n) { return CVarInt<Mode, I>{n}; } /** * Forward declarations @@ -539,7 +572,7 @@ inline void Serialize(Stream& os, const T& a) } template<typename Stream, typename T> -inline void Unserialize(Stream& is, T& a) +inline void Unserialize(Stream& is, T&& a) { a.Unserialize(is); } @@ -825,19 +858,6 @@ struct CSerActionUnserialize constexpr bool ForRead() const { return true; } }; -template<typename Stream, typename T> -inline void SerReadWrite(Stream& s, const T& obj, CSerActionSerialize ser_action) -{ - ::Serialize(s, obj); -} - -template<typename Stream, typename T> -inline void SerReadWrite(Stream& s, T& obj, CSerActionUnserialize ser_action) -{ - ::Unserialize(s, obj); -} - - @@ -897,17 +917,11 @@ void SerializeMany(Stream& s) { } -template<typename Stream, typename Arg> -void SerializeMany(Stream& s, Arg&& arg) -{ - ::Serialize(s, std::forward<Arg>(arg)); -} - template<typename Stream, typename Arg, typename... Args> -void SerializeMany(Stream& s, Arg&& arg, Args&&... args) +void SerializeMany(Stream& s, const Arg& arg, const Args&... args) { - ::Serialize(s, std::forward<Arg>(arg)); - ::SerializeMany(s, std::forward<Args>(args)...); + ::Serialize(s, arg); + ::SerializeMany(s, args...); } template<typename Stream> @@ -915,27 +929,21 @@ inline void UnserializeMany(Stream& s) { } -template<typename Stream, typename Arg> -inline void UnserializeMany(Stream& s, Arg& arg) -{ - ::Unserialize(s, arg); -} - template<typename Stream, typename Arg, typename... Args> -inline void UnserializeMany(Stream& s, Arg& arg, Args&... args) +inline void UnserializeMany(Stream& s, Arg&& arg, Args&&... args) { ::Unserialize(s, arg); ::UnserializeMany(s, args...); } template<typename Stream, typename... Args> -inline void SerReadWriteMany(Stream& s, CSerActionSerialize ser_action, Args&&... args) +inline void SerReadWriteMany(Stream& s, CSerActionSerialize ser_action, const Args&... args) { - ::SerializeMany(s, std::forward<Args>(args)...); + ::SerializeMany(s, args...); } template<typename Stream, typename... Args> -inline void SerReadWriteMany(Stream& s, CSerActionUnserialize ser_action, Args&... args) +inline void SerReadWriteMany(Stream& s, CSerActionUnserialize ser_action, Args&&... args) { ::UnserializeMany(s, args...); } |