libnative-utilities/include/raknet/VariableListDeltaTracker.hpp
2024-08-15 18:40:30 +08:00

147 lines
4.8 KiB
C++

/*
* Copyright (c) 2014, Oculus VR, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#include "NativeTypes.hpp"
#include "DS_List.hpp"
#include "RakMemoryOverride.hpp"
#include "BitStream.hpp"
#ifndef __VARIABLE_LIST_DELTA_TRACKER
#define __VARIABLE_LIST_DELTA_TRACKER
namespace RakNet
{
/// Class to write a series of variables, copy the contents to memory, and return if the newly written value is different than what was last written
/// Can also encode the reads, writes, and results directly to/from a bitstream
class VariableListDeltaTracker
{
public:
VariableListDeltaTracker();
~VariableListDeltaTracker();
// Call before using a series of WriteVar
void StartWrite(void);
bool IsPastEndOfList(void) const {return nextWriteIndex>=variableList.Size();}
/// Records the passed value of the variable to memory, and returns true if the value is different from the write before that (or if it is the first write)
/// \pre Call StartWrite() before doing the first of a series of calls to WriteVar or other functions that call WriteVar
/// \note Variables must be of the same type, written in the same order, each time
template <class VarType>
bool WriteVar(const VarType &varData)
{
RakNet::BitStream temp;
temp.Write(varData);
if (nextWriteIndex>=variableList.Size())
{
variableList.Push(VariableLastValueNode(temp.GetData(),temp.GetNumberOfBytesUsed()),_FILE_AND_LINE_);
nextWriteIndex++;
return true; // Different because it's new
}
if (temp.GetNumberOfBytesUsed()!=variableList[nextWriteIndex].byteLength)
{
variableList[nextWriteIndex].lastData=(char*) rakRealloc_Ex(variableList[nextWriteIndex].lastData, temp.GetNumberOfBytesUsed(),_FILE_AND_LINE_);
variableList[nextWriteIndex].byteLength=temp.GetNumberOfBytesUsed();
memcpy(variableList[nextWriteIndex].lastData,temp.GetData(),temp.GetNumberOfBytesUsed());
nextWriteIndex++;
variableList[nextWriteIndex].isDirty=false;
return true; // Different because the serialized size is different
}
if (variableList[nextWriteIndex].isDirty==false && memcmp(temp.GetData(),variableList[nextWriteIndex].lastData, variableList[nextWriteIndex].byteLength)==0)
{
nextWriteIndex++;
return false; // Same because not dirty and memcmp is the same
}
variableList[nextWriteIndex].isDirty=false;
memcpy(variableList[nextWriteIndex].lastData,temp.GetData(),temp.GetNumberOfBytesUsed());
nextWriteIndex++;
return true; // Different because dirty or memcmp was different
}
/// Calls WriteVar. If the variable has changed, writes true, and writes the variable. Otherwise writes false.
template <class VarType>
bool WriteVarToBitstream(const VarType &varData, RakNet::BitStream *bitStream)
{
bool wasDifferent = WriteVar(varData);
bitStream->Write(wasDifferent);
if (wasDifferent)
{
bitStream->Write(varData);
return true;
}
return false;
}
/// Calls WriteVarToBitstream(). Additionally, adds the boolean result of WriteVar() to boolean bit array
template <class VarType>
bool WriteVarToBitstream(const VarType &varData, RakNet::BitStream *bitStream, unsigned char *bArray, unsigned short writeOffset)
{
if (WriteVarToBitstream(varData,bitStream)==true)
{
BitSize_t numberOfBitsMod8 = writeOffset & 7;
if ( numberOfBitsMod8 == 0 )
bArray[ writeOffset >> 3 ] = 0x80;
else
bArray[ writeOffset >> 3 ] |= 0x80 >> ( numberOfBitsMod8 ); // Set the bit to 1
return true;
}
else
{
if ( ( writeOffset & 7 ) == 0 )
bArray[ writeOffset >> 3 ] = 0;
return false;
}
}
/// Paired with a call to WriteVarToBitstream(), will read a variable if it had changed. Otherwise the values remains the same.
template <class VarType>
static bool ReadVarFromBitstream(VarType &varData, RakNet::BitStream *bitStream)
{
bool wasWritten;
if (bitStream->Read(wasWritten)==false)
return false;
if (wasWritten)
{
if (bitStream->Read(varData)==false)
return false;
}
return wasWritten;
}
/// Variables flagged dirty will cause WriteVar() to return true, even if the variable had not otherwise changed
/// This updates all the variables in the list, where in each index \a varsWritten is true, so will the variable at the corresponding index be flagged dirty
void FlagDirtyFromBitArray(unsigned char *bArray);
/// \internal
struct VariableLastValueNode
{
VariableLastValueNode();
VariableLastValueNode(const unsigned char *data, int _byteLength);
~VariableLastValueNode();
char *lastData;
unsigned int byteLength;
bool isDirty;
};
protected:
/// \internal
DataStructures::List<VariableLastValueNode> variableList;
/// \internal
unsigned int nextWriteIndex;
};
}
#endif