891 lines
20 KiB
C++
891 lines
20 KiB
C++
/********************************************************************************
|
|
Copyright (C) 2001-2012 Hugh Bailey <obs.jim@gmail.com>
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
|
********************************************************************************/
|
|
|
|
|
|
#pragma once
|
|
|
|
template<typename T> class List
|
|
{
|
|
protected:
|
|
T *array;
|
|
unsigned int num;
|
|
|
|
public:
|
|
|
|
inline List() : array(NULL), num(0) {}
|
|
inline ~List()
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
inline T* Array() const {return array;}
|
|
inline unsigned int Num() const {return num;}
|
|
|
|
inline unsigned int Add(const T& val)
|
|
{
|
|
array = (T*)ReAllocate(array, sizeof(T)*++num);
|
|
mcpy(&array[(num-1)], (void*)&val, sizeof(T));
|
|
return num-1;
|
|
}
|
|
|
|
unsigned int SafeAdd(const T& val)
|
|
{
|
|
UINT i;
|
|
for(i=0; i<num; i++)
|
|
{
|
|
if(array[i] == val)
|
|
break;
|
|
}
|
|
|
|
return (i != num) ? i : Add(val);
|
|
}
|
|
|
|
inline void Insert(unsigned int index, const T& val)
|
|
{
|
|
assert(index <= num);
|
|
if(index > num) return;
|
|
|
|
if(!num && !index)
|
|
{
|
|
Add(val);
|
|
return;
|
|
}
|
|
|
|
//this makes it safe to insert an item already in the list
|
|
T *temp = (T*)Allocate(sizeof(T));
|
|
mcpy(temp, &val, sizeof(T));
|
|
|
|
UINT moveCount = num-index;
|
|
array = (T*)ReAllocate(array, sizeof(T)*++num);
|
|
if(moveCount)
|
|
mcpyrev(array+(index+1), array+index, moveCount*sizeof(T));
|
|
mcpy(&array[index], temp, sizeof(T));
|
|
|
|
Free(temp);
|
|
}
|
|
|
|
inline void Remove(unsigned int index)
|
|
{
|
|
assert(index < num);
|
|
if(index >= num) return;
|
|
|
|
if(!--num) {Free(array); array=NULL; return;}
|
|
|
|
mcpy(&array[index], &array[index+1], sizeof(T)*(num-index));
|
|
|
|
array = (T*)ReAllocate(array, sizeof(T)*num);
|
|
}
|
|
|
|
inline void RemoveItem(const T& obj)
|
|
{
|
|
for(UINT i=0; i<num; i++)
|
|
{
|
|
if(array[i] == obj)
|
|
{
|
|
Remove(i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void RemoveRange(UINT start, UINT end)
|
|
{
|
|
if(start > num || end > num || end <= start)
|
|
{
|
|
AppWarning(TEXT("List::RemoveRange: Invalid range specified."));
|
|
return;
|
|
}
|
|
|
|
UINT count = end-start;
|
|
if(count == 1)
|
|
{
|
|
Remove(start);
|
|
return;
|
|
}
|
|
else if(count == num)
|
|
{
|
|
Clear();
|
|
return;
|
|
}
|
|
|
|
num -= count;
|
|
|
|
UINT cutoffCount = num-start;
|
|
if(cutoffCount)
|
|
mcpy(array+start, array+end, cutoffCount*sizeof(T));
|
|
array = (T*)ReAllocate(array, num*sizeof(T));
|
|
}
|
|
|
|
inline void CopyArray(const T *new_array, unsigned int n)
|
|
{
|
|
if(!new_array && n)
|
|
{
|
|
AppWarning(TEXT("List::CopyArray: NULL array with count above zero"));
|
|
return;
|
|
}
|
|
|
|
SetSize(n);
|
|
|
|
if(!num) {array=NULL; return;}
|
|
|
|
mcpy(array, (void*)new_array, sizeof(T)*num);
|
|
}
|
|
|
|
inline void InsertArray(unsigned int index, const T *new_array, unsigned int n)
|
|
{
|
|
assert(index <= num);
|
|
|
|
if(index > num)
|
|
return;
|
|
|
|
if(!new_array && n)
|
|
{
|
|
AppWarning(TEXT("List::InsertArray: NULL array with count above zero"));
|
|
return;
|
|
}
|
|
|
|
if(!n)
|
|
return;
|
|
|
|
int oldnum = num;
|
|
|
|
SetSize(n+num);
|
|
|
|
assert(num);
|
|
|
|
if(!num) {array=NULL; return;}
|
|
|
|
mcpyrev(array+index+n, array+index, sizeof(T)*(oldnum-index));
|
|
mcpy(array+index, new_array, sizeof(T)*n);
|
|
}
|
|
|
|
inline void AppendArray(const T *new_array, unsigned int n)
|
|
{
|
|
if(!new_array && n)
|
|
{
|
|
AppWarning(TEXT("List::AppendArray: NULL array with count above zero"));
|
|
return;
|
|
}
|
|
|
|
if(!n)
|
|
return;
|
|
|
|
int oldnum = num;
|
|
|
|
SetSize(n+num);
|
|
|
|
assert(num);
|
|
|
|
if(!num) {array=NULL; return;}
|
|
|
|
mcpy(&array[oldnum], (void*)new_array, sizeof(T)*n);
|
|
}
|
|
|
|
inline BOOL SetSize(unsigned int n)
|
|
{
|
|
if(num == n)
|
|
return FALSE;
|
|
else if(!n)
|
|
{
|
|
Clear();
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL bClear=(n>num);
|
|
UINT oldNum=num;
|
|
|
|
num = n;
|
|
array = (T*)ReAllocate(array, sizeof(T)*num);
|
|
|
|
if(bClear)
|
|
zero(&array[oldNum], sizeof(T)*(num-oldNum));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
inline void MoveItem(int id, int newID)
|
|
{
|
|
register int last = num-1;
|
|
|
|
assert(id <= last);
|
|
if(newID == id || id > last || newID > last)
|
|
return;
|
|
|
|
T val;
|
|
mcpy(&val, array+id, sizeof(T));
|
|
if(newID < id)
|
|
mcpyrev(array+newID+1, array+newID, (id-newID)*sizeof(T));
|
|
else if(id < newID)
|
|
mcpy(array+id, array+id+1, (newID-id)*sizeof(T));
|
|
mcpy(array+newID, &val, sizeof(T));
|
|
zero(&val, sizeof(T));
|
|
}
|
|
|
|
inline void MoveToFront(int id)
|
|
{
|
|
register int last = num-1;
|
|
|
|
assert(id <= last);
|
|
if(id > last || id == 0)
|
|
return;
|
|
|
|
T val;
|
|
mcpy(&val, array+id, sizeof(T));
|
|
mcpyrev(array+1, array, id*sizeof(T));
|
|
mcpy(array, &val, sizeof(T));
|
|
zero(&val, sizeof(T));
|
|
}
|
|
|
|
inline void MoveToEnd(int id)
|
|
{
|
|
register int last = num-1;
|
|
|
|
assert(id <= last);
|
|
if(id >= last)
|
|
return;
|
|
|
|
T val;
|
|
mcpy(&val, array+id, sizeof(T));
|
|
mcpy(array+id, array+(id+1), (last-id)*sizeof(T)); //last-id = num-(id+1)
|
|
mcpy(array+last, &val, sizeof(T));
|
|
zero(&val, sizeof(T));
|
|
}
|
|
|
|
inline void RemoveDupes()
|
|
{
|
|
for(UINT i=0; i<num; i++)
|
|
{
|
|
T val1 = array[i];
|
|
for(UINT j=i+1; j<num; j++)
|
|
{
|
|
T val2 = array[j];
|
|
if(val1 == val2)
|
|
{
|
|
Remove(j);
|
|
--j;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void CopyList(const List<T>& list)
|
|
{
|
|
CopyArray(list.Array(), list.Num());
|
|
}
|
|
|
|
inline void InsertList(unsigned int index, const List<T>& list)
|
|
{
|
|
InsertArray(index, list.Array(), list.Num());
|
|
}
|
|
|
|
inline void AppendList(const List<T>& list)
|
|
{
|
|
AppendArray(list.Array(), list.Num());
|
|
}
|
|
|
|
inline void TransferFrom(List<T>& list)
|
|
{
|
|
if(array) Clear();
|
|
array = list.Array();
|
|
num = list.Num();
|
|
zero(&list, sizeof(List<T>));
|
|
}
|
|
|
|
inline void TransferFrom(T *arrayIn, UINT numIn)
|
|
{
|
|
if(array) Clear();
|
|
array = arrayIn;
|
|
num = numIn;
|
|
}
|
|
|
|
inline void TransferTo(List<T>& list)
|
|
{
|
|
list.TransferFrom(*this);
|
|
}
|
|
|
|
inline void TransferTo(T *&arrayIn, UINT &numIn)
|
|
{
|
|
arrayIn = array;
|
|
numIn = num;
|
|
zero(this, sizeof(List<T>));
|
|
}
|
|
|
|
inline void Clear()
|
|
{
|
|
if(array)
|
|
{
|
|
/*if(IsBadWritePtr(array, sizeof(T)*num))
|
|
CrashError(TEXT("what the.."));*/
|
|
Free(array);
|
|
array = NULL;
|
|
num = 0;
|
|
}
|
|
}
|
|
|
|
inline T* CreateNew()
|
|
{
|
|
SetSize(num+1);
|
|
|
|
T *value = &array[num-1];
|
|
|
|
return value;
|
|
}
|
|
|
|
inline T* InsertNew(int index)
|
|
{
|
|
T ins;
|
|
|
|
zero(&ins, sizeof(T));
|
|
|
|
Insert(index, ins);
|
|
|
|
return &array[index];
|
|
}
|
|
|
|
inline List<T>& operator<<(const T& val)
|
|
{
|
|
Add(val);
|
|
return *this;
|
|
}
|
|
|
|
inline T& GetElement(unsigned int index)
|
|
{
|
|
assert(index < num);
|
|
if(index >= num) {CrashError(TEXT("Out of range! List<%S>::operator[](%d)"), typeid(T).name(), index); return array[0];}
|
|
return array[index];
|
|
}
|
|
|
|
inline T& operator[](unsigned int index)
|
|
{
|
|
assert(index < num);
|
|
if(index >= num) {CrashError(TEXT("Out of range! List<%S>::operator[](%d)"), typeid(T).name(), index); return array[0];}
|
|
return array[index];
|
|
}
|
|
|
|
inline T& operator[](unsigned int index) const
|
|
{
|
|
assert(index < num);
|
|
if(index >= num) {CrashError(TEXT("Out of range! List<%S>::operator[](%d)"), typeid(T).name(), index); return array[0];}
|
|
return array[index];
|
|
}
|
|
|
|
inline T* operator+(unsigned int index)
|
|
{
|
|
assert(index < num);
|
|
if(index >= num) {CrashError(TEXT("Out of range! List<%S>::operator[](%d)"), typeid(T).name(), index); return NULL;}
|
|
return array+index;
|
|
}
|
|
|
|
inline T* operator+(unsigned int index) const
|
|
{
|
|
assert(index < num);
|
|
if(index >= num) {CrashError(TEXT("Out of range! List<%S>::operator[](%d)"), typeid(T).name(), index); return NULL;}
|
|
return array+index;
|
|
}
|
|
|
|
inline T* operator-(unsigned int index)
|
|
{
|
|
assert(index < num);
|
|
if(index >= num) {CrashError(TEXT("Out of range! List<%S>::operator[](%d)"), typeid(T).name(), index); return NULL;}
|
|
return array-index;
|
|
}
|
|
|
|
inline BOOL HasValue(const T& val) const
|
|
{
|
|
for(UINT i=0; i<num; i++)
|
|
if(array[i] == val) return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
inline UINT FindValueIndex(const T& val) const
|
|
{
|
|
for(UINT i=0; i<num; i++)
|
|
if(array[i] == val) return i;
|
|
|
|
return INVALID;
|
|
}
|
|
|
|
inline UINT FindNextValueIndex(const T& val, UINT lastIndex=INVALID) const
|
|
{
|
|
for(UINT i=lastIndex+1; i<num; i++)
|
|
if(array[i] == val) return i;
|
|
|
|
return INVALID;
|
|
}
|
|
|
|
inline void SwapValues(UINT valA, UINT valB)
|
|
{
|
|
assert(valA < num && valB < num);
|
|
if(valA == valB || valA >= num || valB >= num)
|
|
return;
|
|
mswap(array+valA, array+valB, sizeof(T));
|
|
}
|
|
|
|
inline T& Last() const
|
|
{
|
|
assert(num);
|
|
|
|
return array[num-1];
|
|
}
|
|
|
|
inline friend Serializer& operator<<(Serializer &s, List<T> &list)
|
|
{
|
|
if(s.IsLoading())
|
|
{
|
|
UINT num;
|
|
s << num;
|
|
list.SetSize(num);
|
|
if(num)
|
|
s.Serialize(list.array, sizeof(T)*list.num);
|
|
}
|
|
else
|
|
{
|
|
s << list.num;
|
|
if(list.num)
|
|
s.Serialize(list.array, sizeof(T)*list.num);
|
|
}
|
|
|
|
return s;
|
|
}
|
|
};
|
|
|
|
|
|
class BitList
|
|
{
|
|
List<UINT> Data;
|
|
UINT bitSize;
|
|
|
|
public:
|
|
inline BitList() : bitSize(0) {}
|
|
|
|
inline void Clear()
|
|
{
|
|
Data.Clear();
|
|
bitSize = 0;
|
|
}
|
|
|
|
inline void SetSize(int size)
|
|
{
|
|
if(size == bitSize)
|
|
return;
|
|
else if(size == 0)
|
|
{
|
|
Clear();
|
|
return;
|
|
}
|
|
|
|
int adjSize = ((size+31)/32);
|
|
Data.SetSize(adjSize);
|
|
|
|
bitSize = size;
|
|
}
|
|
|
|
inline void SetVal(unsigned int index, BOOL bVal)
|
|
{
|
|
if(bVal)
|
|
Set(index);
|
|
else
|
|
Clear(index);
|
|
}
|
|
|
|
unsigned int Add(BOOL bVal)
|
|
{
|
|
int index = bitSize;
|
|
SetSize(bitSize+1);
|
|
|
|
if(bVal) Set(index);
|
|
return index;
|
|
}
|
|
|
|
inline void TransferFrom(BitList &from)
|
|
{
|
|
Data.TransferFrom(from.Data);
|
|
bitSize = from.bitSize;
|
|
from.bitSize = 0;
|
|
}
|
|
|
|
inline void ClearAll()
|
|
{
|
|
int UINTOffset = ((bitSize+31)/32);
|
|
|
|
while(UINTOffset--)
|
|
Data[UINTOffset] = 0;
|
|
}
|
|
|
|
inline void SetAll()
|
|
{
|
|
int UINTOffset = (bitSize/32);
|
|
int bitOffset = (bitSize%32);
|
|
|
|
while(bitOffset--)
|
|
Data[UINTOffset] |= (1<<bitOffset);
|
|
while(UINTOffset--)
|
|
Data[UINTOffset] = 0xFFFFFFFF;
|
|
}
|
|
|
|
inline BitList& operator<<(const BOOL val)
|
|
{
|
|
Add(val);
|
|
return *this;
|
|
}
|
|
|
|
inline UINT Num() {return bitSize;}
|
|
|
|
inline BOOL operator[](unsigned int index) const
|
|
{
|
|
if(index >= bitSize) CrashError(TEXT("Out of range! BitList::operator[](%d)"), index);
|
|
|
|
int UINTOffset = (index/32);
|
|
int bitOffset = (index%32);
|
|
|
|
return Data[UINTOffset]&(1<<bitOffset);
|
|
}
|
|
|
|
inline void Set(unsigned int index)
|
|
{
|
|
if(index >= bitSize)
|
|
{
|
|
CrashError(TEXT("Out of range! BitList::Set(%d)"), index);
|
|
return;
|
|
}
|
|
|
|
int UINTOffset = (index/32);
|
|
int bitOffset = (index%32);
|
|
|
|
Data[UINTOffset] |= (1<<bitOffset);
|
|
}
|
|
|
|
inline void Clear(unsigned int index)
|
|
{
|
|
if(index >= bitSize)
|
|
{
|
|
CrashError(TEXT("Out of range! BitList::Clear(%d)"), index);
|
|
return;
|
|
}
|
|
|
|
int UINTOffset = (index/32);
|
|
int bitOffset = (index%32);
|
|
|
|
Data[UINTOffset] &= ~(1<<bitOffset);
|
|
}
|
|
|
|
inline BOOL Get(unsigned int index)
|
|
{
|
|
if(index >= bitSize) CrashError(TEXT("Out of range! BitList::Get(%d)"), index);
|
|
|
|
int UINTOffset = (index/32);
|
|
int bitOffset = (index%32);
|
|
|
|
return Data[UINTOffset]&(1<<bitOffset);
|
|
}
|
|
|
|
inline void CopyList(const BitList& list)
|
|
{
|
|
Clear();
|
|
|
|
bitSize = list.bitSize;
|
|
Data.CopyList(list.Data);
|
|
}
|
|
|
|
inline friend Serializer& operator<<(Serializer &s, BitList &list)
|
|
{
|
|
return s << list.Data << list.bitSize;
|
|
}
|
|
};
|
|
|
|
|
|
//===================================================================
|
|
// SafeList
|
|
// list that is index safe
|
|
//===================================================================
|
|
|
|
template<typename T> class SafeList : public List<T>
|
|
{
|
|
List<UINT> AvailableItems;
|
|
|
|
inline BOOL CheckAndCleanAvail()
|
|
{
|
|
UINT i;
|
|
for(i=0; i<AvailableItems.Num(); i++)
|
|
|
|
{
|
|
if(AvailableItems[i] == (num-1))
|
|
{
|
|
AvailableItems.Remove(i);
|
|
--num;
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
public:
|
|
inline unsigned int Add(const T& val)
|
|
{
|
|
if(AvailableItems.Num())
|
|
{
|
|
UINT avail = *AvailableItems.Array();
|
|
AvailableItems.Remove(0);
|
|
array[avail] = val;
|
|
return avail;
|
|
}
|
|
else
|
|
return List<T>::Add(val);
|
|
}
|
|
|
|
inline BOOL ItemExists(unsigned int id)
|
|
{
|
|
if(id >= num)
|
|
return FALSE;
|
|
for(int i=0; i<AvailableItems.Num(); i++)
|
|
{
|
|
if(AvailableItems[i] == id)
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
inline void Insert(unsigned int index, const T& val) {CrashError(TEXT("Illegal Insert into SafeList"));}
|
|
|
|
inline void Remove(unsigned int index)
|
|
{
|
|
assert(index < num);
|
|
if(index >= num) return;
|
|
|
|
if((index+1) == num)
|
|
{
|
|
--num;
|
|
while(CheckAndCleanAvail());
|
|
|
|
if(!num)
|
|
{Free(array); array = NULL;}
|
|
else
|
|
array = (T*)ReAllocate(array, sizeof(T)*num);
|
|
}
|
|
else
|
|
{
|
|
AvailableItems << index;
|
|
zero(&array[index], sizeof(T));
|
|
}
|
|
}
|
|
|
|
inline void CopyList(const SafeList<T>& safelist)
|
|
{
|
|
CopyArray(list.Array(), list.Num());
|
|
AvailableItems.CopyList(list.AvailableItems);
|
|
}
|
|
|
|
inline void AppendList(const SafeList<T>& safelist)
|
|
{
|
|
AppendArray(list.Array(), list.Num());
|
|
AvailableItems.AppendList(list.AvailableItems);
|
|
}
|
|
|
|
inline void operator=(const SafeList<T>& list)
|
|
{
|
|
array = list.Array();
|
|
num = list.Num();
|
|
AvailableItems = list.AvailableItems;
|
|
}
|
|
|
|
inline T* CreateNew(UINT *pID=NULL)
|
|
{
|
|
T *value;
|
|
if(AvailableItems.Num())
|
|
{
|
|
UINT avail = *AvailableItems.Array();
|
|
if(pID) *pID = avail;
|
|
|
|
AvailableItems.Remove(0);
|
|
value = array+avail;
|
|
}
|
|
else
|
|
{
|
|
if(pID) *pID = num;
|
|
|
|
SetSize(num+1);
|
|
|
|
value = &array[num-1];
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
inline void Clear()
|
|
{
|
|
AvailableItems.Clear();
|
|
List<T>::Clear();
|
|
}
|
|
|
|
inline int operator<<(const T& val)
|
|
{
|
|
return Add(val);
|
|
}
|
|
|
|
inline friend Serializer& operator<<(Serializer &s, SafeList<T> &list)
|
|
{
|
|
s << (List<T>&)list;
|
|
s << list.AvailableItems;
|
|
return s;
|
|
}
|
|
};
|
|
|
|
|
|
class BASE_EXPORT BufferInputSerializer : public Serializer
|
|
{
|
|
public:
|
|
BufferInputSerializer(const List<BYTE> &InBuffer) : buffer(InBuffer.Array()), bufferSize(InBuffer.Num()), position(0) {}
|
|
BufferInputSerializer(const void *pBuffer, DWORD dwSize) : buffer((const LPBYTE)pBuffer), bufferSize(dwSize), position(0) {}
|
|
|
|
BOOL IsLoading() {return TRUE;}
|
|
|
|
void Serialize(LPVOID lpData, DWORD length)
|
|
{
|
|
assert(lpData);
|
|
assert(length <= bufferSize-position);
|
|
|
|
if(!lpData)
|
|
return;
|
|
|
|
if(length > (bufferSize-position))
|
|
return;
|
|
|
|
mcpy(lpData, buffer+position, length);
|
|
position += length;
|
|
}
|
|
|
|
BOOL DataPending()
|
|
{
|
|
return position < bufferSize;
|
|
}
|
|
|
|
UINT64 Seek(INT64 offset, DWORD seekType=SERIALIZE_SEEK_START)
|
|
{
|
|
long newPos = 0;
|
|
|
|
if(seekType == SERIALIZE_SEEK_START)
|
|
newPos = (long)offset;
|
|
else
|
|
newPos = ((seekType == SERIALIZE_SEEK_CURRENT) ? (long)position : (long)bufferSize) + (long)offset;
|
|
|
|
if(newPos > (long)bufferSize)
|
|
{
|
|
offset -= newPos-bufferSize;
|
|
newPos = (long)bufferSize;
|
|
}
|
|
else if(newPos < 0)
|
|
{
|
|
offset -= newPos;
|
|
newPos = 0;
|
|
}
|
|
|
|
position = (DWORD)newPos;
|
|
|
|
return abs((long)offset);
|
|
}
|
|
|
|
UINT64 GetPos() const
|
|
{
|
|
return UINT64(position);
|
|
}
|
|
|
|
private:
|
|
const LPBYTE buffer;
|
|
DWORD bufferSize;
|
|
|
|
DWORD position;
|
|
};
|
|
|
|
class BASE_EXPORT BufferOutputSerializer : public Serializer
|
|
{
|
|
public:
|
|
BufferOutputSerializer(List<BYTE> &InBuffer, BOOL bAppend=TRUE)
|
|
: Buffer(InBuffer)
|
|
{
|
|
if(!bAppend)
|
|
{
|
|
Buffer.Clear();
|
|
position = 0;
|
|
}
|
|
else
|
|
position = Buffer.Num();
|
|
}
|
|
|
|
BOOL IsLoading() {return FALSE;}
|
|
|
|
void Serialize(LPVOID lpData, DWORD length)
|
|
{
|
|
assert(lpData);
|
|
assert(length);
|
|
|
|
if(!lpData || !length)
|
|
return;
|
|
|
|
register DWORD potentialSize = (position+length);
|
|
|
|
if(potentialSize > Buffer.Num())
|
|
Buffer.SetSize(potentialSize);
|
|
mcpy(Buffer+position, lpData, length);
|
|
position += length;
|
|
}
|
|
|
|
UINT64 Seek(INT64 offset, DWORD seekType=SERIALIZE_SEEK_START)
|
|
{
|
|
long newPos = 0;
|
|
if(seekType == SERIALIZE_SEEK_START)
|
|
newPos = (long)offset;
|
|
else
|
|
newPos = ((seekType == SERIALIZE_SEEK_CURRENT) ? (long)position : (long)Buffer.Num()) + (long)offset;
|
|
|
|
if(newPos < 0)
|
|
{
|
|
offset -= newPos;
|
|
newPos = 0;
|
|
}
|
|
|
|
position = (DWORD)newPos;
|
|
|
|
return abs((long)offset);
|
|
}
|
|
|
|
UINT64 GetPos() const
|
|
{
|
|
return UINT64(position);
|
|
}
|
|
|
|
private:
|
|
List<BYTE> &Buffer;
|
|
DWORD position;
|
|
};
|
|
|
|
|
|
template<typename T> T Lerp(const T &p1, const T &p2, float t)
|
|
{
|
|
return p1 + (p2-p1) * t;
|
|
}
|
|
|
|
|
|
template<typename T> void Swap(const T &p1, const T &p2)
|
|
{
|
|
T temp = p1;
|
|
p1 = p2;
|
|
p2 = temp;
|
|
}
|