From 7f220ce48ce0a46dd7246bbba92458e7339475cc Mon Sep 17 00:00:00 2001 From: Lynix Date: Mon, 23 Nov 2015 13:45:35 +0100 Subject: [PATCH] Core/Serialization: Add bit serialization Former-commit-id: dbaf3a2d40a85955b4d48efba72a5df9d92d0eb1 --- include/Nazara/Core/Algorithm.inl | 46 +++++++++++++++++++++------ include/Nazara/Core/Serialization.hpp | 4 +++ include/Nazara/Core/Serializer.hpp | 2 +- include/Nazara/Core/Serializer.inl | 14 ++++++++ include/Nazara/Core/Stream.inl | 2 +- include/Nazara/Core/Unserializer.inl | 1 + 6 files changed, 58 insertions(+), 11 deletions(-) diff --git a/include/Nazara/Core/Algorithm.inl b/include/Nazara/Core/Algorithm.inl index 6e3d8853a..2e9661dd9 100644 --- a/include/Nazara/Core/Algorithm.inl +++ b/include/Nazara/Core/Algorithm.inl @@ -80,14 +80,33 @@ namespace Nz inline bool Serialize(SerializationContext& context, bool value) { - ///TODO: Handle bits writing (Serializing 8 bits should only use one byte) - UInt8 buffer = (value) ? 1 : 0; - return context.stream->Write(&buffer, 1) == 1; + if (context.currentBitPos == 8) + { + context.currentBitPos = 0; + context.currentByte = 0; + } + + if (value) + context.currentByte |= 1 << context.currentBitPos; + + if (++context.currentBitPos >= 8) + return Serialize(context, context.currentByte); + else + return true; } template std::enable_if_t::value, bool> Serialize(SerializationContext& context, T value) { + // Flush bits if a writing is in progress + if (context.currentBitPos != 8) + { + context.currentBitPos = 8; + + if (!Serialize(context, context.currentByte)) + NazaraWarning("Failed to flush bits"); + } + if (context.endianness != Endianness_Unknown && context.endianness != GetPlatformEndianness()) SwapBytes(&value, sizeof(T)); @@ -98,14 +117,20 @@ namespace Nz { NazaraAssert(value, "Invalid data pointer"); - UInt8 buffer; - if (context.stream->Read(&buffer, 1) == 1) + if (context.currentBitPos == 8) { - *value = (buffer == 1); - return true; + if (!Unserialize(context, &context.currentByte)) + return false; + + context.currentBitPos = 0; } - else - return false; + + if (value) + *value = (context.currentByte & (1 << context.currentBitPos)) != 0; + + context.currentBitPos++; + + return true; } template @@ -113,6 +138,9 @@ namespace Nz { NazaraAssert(value, "Invalid data pointer"); + // Reset bit position + context.currentBitPos = 8; + if (context.stream->Read(value, sizeof(T)) == sizeof(T)) { if (context.endianness != Endianness_Unknown && context.endianness != GetPlatformEndianness()) diff --git a/include/Nazara/Core/Serialization.hpp b/include/Nazara/Core/Serialization.hpp index 36e77caea..409aa6ace 100644 --- a/include/Nazara/Core/Serialization.hpp +++ b/include/Nazara/Core/Serialization.hpp @@ -21,12 +21,16 @@ namespace Nz { Stream* stream; Endianness endianness; + UInt8 currentBitPos; + UInt8 currentByte; }; struct UnserializationContext { Stream* stream; Endianness endianness; + UInt8 currentBitPos; + UInt8 currentByte; }; } diff --git a/include/Nazara/Core/Serializer.hpp b/include/Nazara/Core/Serializer.hpp index 95ca33190..994e85a19 100644 --- a/include/Nazara/Core/Serializer.hpp +++ b/include/Nazara/Core/Serializer.hpp @@ -20,7 +20,7 @@ namespace Nz inline Serializer(Stream& stream); Serializer(const Serializer&) = default; Serializer(Serializer&&) = default; - ~Serializer() = default; + ~Serializer(); inline Endianness GetDataEndianness() const; inline Stream& GetStream() const; diff --git a/include/Nazara/Core/Serializer.inl b/include/Nazara/Core/Serializer.inl index a61315090..168d7f812 100644 --- a/include/Nazara/Core/Serializer.inl +++ b/include/Nazara/Core/Serializer.inl @@ -2,16 +2,29 @@ // This file is part of the "Nazara Engine - Core module" // For conditions of distribution and use, see copyright notice in Config.hpp +#include #include namespace Nz { inline Serializer::Serializer(Stream& stream) { + m_serializationContext.currentBitPos = 8; m_serializationContext.endianness = Endianness_BigEndian; m_serializationContext.stream = &stream; } + inline Serializer::~Serializer() + { + if (m_serializationContext.currentBitPos != 8) + { + m_serializationContext.currentBitPos = 8; //< To prevent Serialize to flush bits itself + + if (!Serialize(m_serializationContext, m_serializationContext.currentByte)) + NazaraWarning("Failed to flush bits at serializer destruction"); + } + } + inline Endianness Serializer::GetDataEndianness() const { return m_serializationContext.endianness; @@ -43,3 +56,4 @@ namespace Nz } #include +#include "Serializer.hpp" diff --git a/include/Nazara/Core/Stream.inl b/include/Nazara/Core/Stream.inl index a7e17a099..6c5098060 100644 --- a/include/Nazara/Core/Stream.inl +++ b/include/Nazara/Core/Stream.inl @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include "Stream.hpp" namespace Nz { @@ -70,5 +71,4 @@ namespace Nz return WriteBlock(buffer, size); } - } diff --git a/include/Nazara/Core/Unserializer.inl b/include/Nazara/Core/Unserializer.inl index 97f91214f..3a832504a 100644 --- a/include/Nazara/Core/Unserializer.inl +++ b/include/Nazara/Core/Unserializer.inl @@ -8,6 +8,7 @@ namespace Nz { inline Unserializer::Unserializer(Stream& stream) { + m_unserializationContext.currentBitPos = 8; m_unserializationContext.endianness = Endianness_BigEndian; m_unserializationContext.stream = &stream; }