aboutsummaryrefslogtreecommitdiff
path: root/src/serialize.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/serialize.h')
-rw-r--r--src/serialize.h93
1 files changed, 51 insertions, 42 deletions
diff --git a/src/serialize.h b/src/serialize.h
index fe53eeed31..af75c50ff9 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -190,6 +190,8 @@ template<typename X> const X& ReadWriteAsHelper(const X& x) { return x; }
#define READWRITE(...) (::SerReadWriteMany(s, ser_action, __VA_ARGS__))
#define READWRITEAS(type, obj) (::SerReadWriteMany(s, ser_action, ReadWriteAsHelper<type>(obj)))
+#define SER_READ(obj, code) ::SerRead(s, ser_action, obj, [&](Stream& s, typename std::remove_const<Type>::type& obj) { code; })
+#define SER_WRITE(obj, code) ::SerWrite(s, ser_action, obj, [&](Stream& s, const Type& obj) { code; })
/**
* Implement three methods for serializable objects. These are actually wrappers over
@@ -518,7 +520,16 @@ struct VarIntFormatter
}
};
-template<int Bytes>
+/** Serialization wrapper class for custom integers and enums.
+ *
+ * It permits specifying the serialized size (1 to 8 bytes) and endianness.
+ *
+ * Use the big endian mode for values that are stored in memory in native
+ * byte order, but serialized in big endian notation. This is only intended
+ * to implement serializers that are compatible with existing formats, and
+ * its use is not recommended for new data structures.
+ */
+template<int Bytes, bool BigEndian = false>
struct CustomUintFormatter
{
static_assert(Bytes > 0 && Bytes <= 8, "CustomUintFormatter Bytes out of range");
@@ -527,52 +538,31 @@ struct CustomUintFormatter
template <typename Stream, typename I> void Ser(Stream& s, I v)
{
if (v < 0 || v > MAX) throw std::ios_base::failure("CustomUintFormatter value out of range");
- uint64_t raw = htole64(v);
- s.write((const char*)&raw, Bytes);
+ if (BigEndian) {
+ uint64_t raw = htobe64(v);
+ s.write(((const char*)&raw) + 8 - Bytes, Bytes);
+ } else {
+ uint64_t raw = htole64(v);
+ s.write((const char*)&raw, Bytes);
+ }
}
template <typename Stream, typename I> void Unser(Stream& s, I& v)
{
- static_assert(std::numeric_limits<I>::max() >= MAX && std::numeric_limits<I>::min() <= 0, "CustomUintFormatter type too small");
+ using U = typename std::conditional<std::is_enum<I>::value, std::underlying_type<I>, std::common_type<I>>::type::type;
+ static_assert(std::numeric_limits<U>::max() >= MAX && std::numeric_limits<U>::min() <= 0, "Assigned type too small");
uint64_t raw = 0;
- s.read((char*)&raw, Bytes);
- v = le64toh(raw);
+ if (BigEndian) {
+ s.read(((char*)&raw) + 8 - Bytes, Bytes);
+ v = static_cast<I>(be64toh(raw));
+ } else {
+ s.read((char*)&raw, Bytes);
+ v = static_cast<I>(le64toh(raw));
+ }
}
};
-/** Serialization wrapper class for big-endian integers.
- *
- * Use this wrapper around integer types that are stored in memory in native
- * byte order, but serialized in big endian notation. This is only intended
- * to implement serializers that are compatible with existing formats, and
- * its use is not recommended for new data structures.
- *
- * Only 16-bit types are supported for now.
- */
-template<typename I>
-class BigEndian
-{
-protected:
- I& m_val;
-public:
- explicit BigEndian(I& val) : m_val(val)
- {
- static_assert(std::is_unsigned<I>::value, "BigEndian type must be unsigned integer");
- static_assert(sizeof(I) == 2 && std::numeric_limits<I>::min() == 0 && std::numeric_limits<I>::max() == std::numeric_limits<uint16_t>::max(), "Unsupported BigEndian size");
- }
-
- template<typename Stream>
- void Serialize(Stream& s) const
- {
- ser_writedata16be(s, m_val);
- }
-
- template<typename Stream>
- void Unserialize(Stream& s)
- {
- m_val = ser_readdata16be(s);
- }
-};
+template<int Bytes> using BigEndianFormatter = CustomUintFormatter<Bytes, true>;
/** Formatter for integers in CompactSize format. */
struct CompactSizeFormatter
@@ -626,9 +616,6 @@ public:
}
};
-template<typename I>
-BigEndian<I> WrapBigEndian(I& n) { return BigEndian<I>(n); }
-
/** Formatter to serialize/deserialize vector elements using another formatter
*
* Example:
@@ -1124,6 +1111,28 @@ inline void SerReadWriteMany(Stream& s, CSerActionUnserialize ser_action, Args&&
::UnserializeMany(s, args...);
}
+template<typename Stream, typename Type, typename Fn>
+inline void SerRead(Stream& s, CSerActionSerialize ser_action, Type&&, Fn&&)
+{
+}
+
+template<typename Stream, typename Type, typename Fn>
+inline void SerRead(Stream& s, CSerActionUnserialize ser_action, Type&& obj, Fn&& fn)
+{
+ fn(s, std::forward<Type>(obj));
+}
+
+template<typename Stream, typename Type, typename Fn>
+inline void SerWrite(Stream& s, CSerActionSerialize ser_action, Type&& obj, Fn&& fn)
+{
+ fn(s, std::forward<Type>(obj));
+}
+
+template<typename Stream, typename Type, typename Fn>
+inline void SerWrite(Stream& s, CSerActionUnserialize ser_action, Type&&, Fn&&)
+{
+}
+
template<typename I>
inline void WriteVarInt(CSizeComputer &s, I n)
{