156 lines
4.8 KiB
C++
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;
|
|
}
|