// Copyright Epic Games, Inc. All Rights Reserved. #include "NetworkAutomationTest.h" #include "NetworkAutomationTestMacros.h" #include "Iris/Serialization/BitPacking.h" #include "Iris/Serialization/NetBitStreamReader.h" #include "Iris/Serialization/NetBitStreamWriter.h" #include namespace UE::Net::Private { template class TTestBitPacking : public FNetworkAutomationTestSuiteFixture { protected: void TestSerialize(); void InitWriter(); void InitReaderFromWriter(); void SerializeDelta(const SourceType Value, const SourceType PrevValue); void DeserializeDelta(SourceType& OutValue, const SourceType PrevValue); enum : uint32 { BufferSize = 64, }; FNetBitStreamReader Reader; FNetBitStreamWriter Writer; alignas(16) uint8 StateBuffer[BufferSize]; static const uint8 SmallBitCountTable[]; static const uint32 SmallBitCountTableEntryCount; static const SourceType Values[]; static const SIZE_T ValueCount; }; template const uint8 TTestBitPacking::SmallBitCountTable[] = { 0, BitCount/2, BitCount - 2, }; template const uint32 TTestBitPacking::SmallBitCountTableEntryCount = sizeof(SmallBitCountTable)/sizeof(SmallBitCountTable[0]); template const SourceType TTestBitPacking::Values[] = { TIsSigned::Value ? (SourceType(-(typename TSignedIntType::Type)(std::numeric_limits::max() >> (sizeof(SourceType)*8U - BitCount)) - SourceType(1))) : SourceType(0), // MinValue SourceType(Values[0] + SourceType(1)), std::numeric_limits::max() >> (sizeof(SourceType)*8U - BitCount), // Max value for desired bitcount SourceType(SourceType(Values[0] + Values[2])/SourceType(2)), }; template const SIZE_T TTestBitPacking::ValueCount = sizeof(Values)/sizeof(Values[0]); #define UE_NET_IMPLEMENT_DELTA_SERIALIZATION_TEST(TestClassName, SourceType, BitCount) \ class TestClassName : public TTestBitPacking \ { \ protected: \ }; \ \ UE_NET_TEST_FIXTURE(TestClassName, TestSerialize) \ { \ TestSerialize(); \ } \ // Signed integer UE_NET_IMPLEMENT_DELTA_SERIALIZATION_TEST(FTestInt8BitPacking, int8, 8); UE_NET_IMPLEMENT_DELTA_SERIALIZATION_TEST(FTest7BitIntBitPacking, int8, 7); UE_NET_IMPLEMENT_DELTA_SERIALIZATION_TEST(FTestInt16BitPacking, int16, 16); UE_NET_IMPLEMENT_DELTA_SERIALIZATION_TEST(FTest14BitInt16BitPacking, int16, 14); UE_NET_IMPLEMENT_DELTA_SERIALIZATION_TEST(FTestInt32BitPacking, int32, 32); UE_NET_IMPLEMENT_DELTA_SERIALIZATION_TEST(FTest29BitInt32BitPacking, int32, 29); UE_NET_IMPLEMENT_DELTA_SERIALIZATION_TEST(FTestInt64BitPacking, int64, 64); UE_NET_IMPLEMENT_DELTA_SERIALIZATION_TEST(FTest33BitInt64BitPacking, int64, 33); // Unsigned integer UE_NET_IMPLEMENT_DELTA_SERIALIZATION_TEST(FTestUint8BitPacking, uint8, 8); UE_NET_IMPLEMENT_DELTA_SERIALIZATION_TEST(FTest7BitUintBitPacking, uint8, 7); UE_NET_IMPLEMENT_DELTA_SERIALIZATION_TEST(FTestUint16BitPacking, uint16, 16); UE_NET_IMPLEMENT_DELTA_SERIALIZATION_TEST(FTest14BitUint16BitPacking, uint16, 14); UE_NET_IMPLEMENT_DELTA_SERIALIZATION_TEST(FTestUint32BitPacking, uint32, 32); UE_NET_IMPLEMENT_DELTA_SERIALIZATION_TEST(FTest29BitUint32BitPacking, uint32, 29); UE_NET_IMPLEMENT_DELTA_SERIALIZATION_TEST(FTestUint64BitPacking, uint64, 64); UE_NET_IMPLEMENT_DELTA_SERIALIZATION_TEST(FTest33BitUint64BitPacking, uint64, 33); #undef UE_NET_IMPLEMENT_DELTA_SERIALIZATION_TEST // template void TTestBitPacking::InitWriter() { Writer.InitBytes(StateBuffer, sizeof(StateBuffer)); } template void TTestBitPacking::InitReaderFromWriter() { Reader.InitBits(StateBuffer, Writer.GetPosBits()); } template void TTestBitPacking::SerializeDelta(const SourceType Value, const SourceType PrevValue) { typedef typename TUnsignedIntType::Type UnsignedType; typedef typename TSignedIntType::Type SignedType; if (TIsSigned::Value) { SerializeIntDelta(Writer, SignedType(Value), SignedType(PrevValue), SmallBitCountTable, SmallBitCountTableEntryCount, BitCount); } else { SerializeUintDelta(Writer, UnsignedType(Value), UnsignedType(PrevValue), SmallBitCountTable, SmallBitCountTableEntryCount, BitCount); } Writer.CommitWrites(); } template void TTestBitPacking::DeserializeDelta(SourceType& OutValue, const SourceType PrevValue) { typedef typename TUnsignedIntType::Type UnsignedType; typedef typename TSignedIntType::Type SignedType; if (TIsSigned::Value) { DeserializeIntDelta(Reader, reinterpret_cast(OutValue), SignedType(PrevValue), SmallBitCountTable, SmallBitCountTableEntryCount, BitCount); } else { DeserializeUintDelta(Reader, reinterpret_cast(OutValue), UnsignedType(PrevValue), SmallBitCountTable, SmallBitCountTableEntryCount, BitCount); } } template void TTestBitPacking::TestSerialize() { // Try each value against all values for (SIZE_T ValueIt = 0, ValueEndIt = ValueCount; ValueIt != ValueEndIt; ++ValueIt) { const SourceType Value = Values[ValueIt]; for (SIZE_T PrevValueIt = 0, PrevValueEndIt = ValueCount; PrevValueIt != ValueEndIt; ++PrevValueIt) { const SourceType PrevValue = Values[PrevValueIt]; InitWriter(); SerializeDelta(Value, PrevValue); UE_NET_ASSERT_FALSE_MSG(Writer.IsOverflown(), "Serialize delta between " << Value << " and " << PrevValue << " caused bit stream overflow"); InitReaderFromWriter(); SourceType DeserializedValue; DeserializeDelta(DeserializedValue, PrevValue); UE_NET_ASSERT_FALSE_MSG(Reader.IsOverflown(), "Deserialize delta between " << Value << " and " << PrevValue << " caused bit stream overflow"); UE_NET_ASSERT_EQ_MSG(DeserializedValue, Value, "Failed serializing value " << Value << " with previous value " << PrevValue << " using " << (TIsSigned::Value ? "signed " : "unsigned ") << BitCount << "-bit integer"); } } } }