aboutsummaryrefslogtreecommitdiff
path: root/src/serialize.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/serialize.h')
-rw-r--r--src/serialize.h102
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...);
}