Files
UnrealEngine/Engine/Source/Runtime/Online/BuildPatchServices/Private/BuildPatchHash.h
2025-05-18 13:04:45 +08:00

156 lines
4.8 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Core/RingBuffer.h"
/*=============================================================================
BuildPatchHash.h: Declares and implements template classes for use with the
Build and Patching hash functionality.
=============================================================================*/
/**
* A macro for barrel rolling a 64 bit value n times to the left.
* @param Value The value to shift
* @param Shifts The number of times to shift
*/
#define ROTLEFT_64B( Value, Shifts ) Value = ( ( ( Value ) << ( ( Shifts ) % 64 ) ) | ( ( Value ) >> ( ( 64 - ( ( Shifts ) % 64 ) ) % 64 ) ) )
/**
* A static struct containing 64bit polynomial constant and hash table lookup for use with FRollingHash.
*/
struct FRollingHashConst
{
// The lookup hash table
static uint64 HashTable[ 256 ];
/**
* Builds the hash table for use when hashing. Must be called before using FRollingHash.
*/
static void Init();
};
/**
* A class that performs a rolling hash
*/
class FRollingHash
{
// A typedef for our data ring buffer
typedef TRingBuffer< uint8 > HashRingBuffer;
public:
/**
* Constructor
*/
FRollingHash(uint32 WindowSize);
/**
* Pass this function the initial data set to start the Rolling Hash with.
* @param NewByte The byte to add to the hash state
*/
void ConsumeByte( const uint8& NewByte );
/**
* Helper to consume from a byte array
* @param NewBytes The byte array
* @param NumBytes The number of bytes to consume
*/
void ConsumeBytes( const uint8* NewBytes, const uint32& NumBytes );
/**
* Rolls the window by one byte forwards.
* @param NewByte The byte that will be added to the front of the window
*/
void RollForward( const uint8& NewByte );
/**
* Clears all data ready for a new entire data set
*/
void Clear();
/**
* Get the HashState for the current window
* @return The hash state
*/
const uint64 GetWindowHash() const;
/**
* Get the Ring Buffer for the current window
* @return The ring buffer
*/
const HashRingBuffer& GetWindowData() const;
/**
* Get how many DataValueType values we still need to consume until our window is full
* @return The number of DataValueType we still need
*/
const uint32 GetNumDataNeeded() const;
/**
* @return the size of our window
*/
const uint32 GetWindowSize() const;
/**
* Static function to simply return the hash for a given data range.
* @param DataSet The buffer to the data.
* @param WindowSize The buffer of length.
* @return The hash state for the provided data
*/
static uint64 GetHashForDataSet( const uint8* DataSet, uint32 WindowSize );
private:
FRollingHash();
// The data size that we roll over.
const uint32 WindowSize = 0;
// The current hash value
uint64 HashState = 0;
// The number of bytes we have consumed so far, used in hash function and to check validity of calls
uint32 NumBytesConsumed = 0;
// Store the data to make access and rolling easier
HashRingBuffer WindowData = 0;
};
/**
* A static function to perform sanity checks on the rolling hash class.
*/
static bool CheckRollingHashAlgorithm()
{
bool bCheckOk = true;
// Sanity Check the RollingHash code!!
FString IndivWords[6];
IndivWords[0] = "123456"; IndivWords[1] = "7890-="; IndivWords[2] = "qwerty"; IndivWords[3] = "uiop[]"; IndivWords[4] = "asdfgh"; IndivWords[5] = "jkl;'#";
FString DataToRollOver = FString::Printf( TEXT( "%s%s%s%s%s%s" ), *IndivWords[0], *IndivWords[1], *IndivWords[2], *IndivWords[3], *IndivWords[4], *IndivWords[5] );
uint64 IndivHashes[6];
for (uint32 idx = 0; idx < 6; ++idx )
{
uint8 Converted[6];
for (uint32 iChar = 0; iChar < 6; ++iChar )
Converted[iChar] = IndivWords[idx][iChar];
IndivHashes[idx] = FRollingHash::GetHashForDataSet( Converted, 6 );
}
FRollingHash RollingHash(6);
uint32 StrIdx = 0;
for (uint32 k=0; k<6; ++k)
RollingHash.ConsumeByte( DataToRollOver[ StrIdx++ ] );
bCheckOk = bCheckOk && IndivHashes[0] == RollingHash.GetWindowHash();
for (uint32 k=0; k<6; ++k)
RollingHash.RollForward( DataToRollOver[ StrIdx++ ] );
bCheckOk = bCheckOk && IndivHashes[1] == RollingHash.GetWindowHash();
for (uint32 k=0; k<6; ++k)
RollingHash.RollForward( DataToRollOver[ StrIdx++ ] );
bCheckOk = bCheckOk && IndivHashes[2] == RollingHash.GetWindowHash();
for (uint32 k=0; k<6; ++k)
RollingHash.RollForward( DataToRollOver[ StrIdx++ ] );
bCheckOk = bCheckOk && IndivHashes[3] == RollingHash.GetWindowHash();
for (uint32 k=0; k<6; ++k)
RollingHash.RollForward( DataToRollOver[ StrIdx++ ] );
bCheckOk = bCheckOk && IndivHashes[4] == RollingHash.GetWindowHash();
for (uint32 k=0; k<6; ++k)
RollingHash.RollForward( DataToRollOver[ StrIdx++ ] );
bCheckOk = bCheckOk && IndivHashes[5] == RollingHash.GetWindowHash();
return bCheckOk;
}