forked from facebookarchive/RakNet
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathVariableListDeltaTracker.h
146 lines (128 loc) · 4.92 KB
/
VariableListDeltaTracker.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/*
* 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.h"
#include "DS_List.h"
#include "RakMemoryOverride.h"
#include "BitStream.h"
#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