You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
458 lines
12 KiB
C++
458 lines
12 KiB
C++
/*
|
|
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
* its licensors.
|
|
*
|
|
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
* distribution (the "License"). All use of this software is governed by the License,
|
|
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
*
|
|
*/
|
|
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
|
|
#ifndef CRYINCLUDE_CRYCOMMON_TARRAY_H
|
|
#define CRYINCLUDE_CRYCOMMON_TARRAY_H
|
|
#pragma once
|
|
|
|
|
|
#include <ILog.h>
|
|
#include <Cry_Math.h>
|
|
#include <AzCore/IO/FileIO.h>
|
|
#include <STLGlobalAllocator.h>
|
|
|
|
#ifndef CLAMP
|
|
#define CLAMP(X, mn, mx) ((X) < (mn) ? (mn) : ((X) < (mx) ? (X) : (mx)))
|
|
#endif
|
|
|
|
#ifndef SATURATE
|
|
#define SATURATE(X) clamp_tpl(X, 0.f, 1.f)
|
|
#endif
|
|
|
|
#ifndef SATURATEB
|
|
#define SATURATEB(X) CLAMP(X, 0, 255)
|
|
#endif
|
|
|
|
#ifndef LERP
|
|
#define LERP(A, B, Alpha) ((A) + (Alpha) * ((B)-(A)))
|
|
#endif
|
|
|
|
// Safe memory freeing
|
|
#ifndef SAFE_DELETE
|
|
#define SAFE_DELETE(p) { if (p) { delete (p); (p) = NULL; } \
|
|
}
|
|
#endif
|
|
|
|
#ifndef SAFE_DELETE_ARRAY
|
|
#define SAFE_DELETE_ARRAY(p) { if (p) { delete[] (p); (p) = NULL; } \
|
|
}
|
|
#endif
|
|
|
|
#ifndef SAFE_RELEASE
|
|
#define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p) = NULL; } \
|
|
}
|
|
#endif
|
|
|
|
#ifndef SAFE_RELEASE_FORCE
|
|
#define SAFE_RELEASE_FORCE(p) { if (p) { (p)->ReleaseForce(); (p) = NULL; } \
|
|
}
|
|
#endif
|
|
|
|
|
|
// General array class.
|
|
// Can refer to a general (unowned) region of memory (m_nAllocatedCount = 0).
|
|
// Can allocate, grow, and shrink an array.
|
|
// Does not deep copy.
|
|
|
|
template<class T>
|
|
class TArray
|
|
{
|
|
protected:
|
|
T* m_pElements;
|
|
unsigned int m_nCount;
|
|
unsigned int m_nAllocatedCount;
|
|
|
|
public:
|
|
typedef T value_type;
|
|
|
|
// Empty array.
|
|
TArray()
|
|
{
|
|
ClearArr();
|
|
}
|
|
|
|
// Create a new array, delete it on destruction.
|
|
TArray(int Count)
|
|
{
|
|
m_nCount = Count;
|
|
m_nAllocatedCount = Count;
|
|
m_pElements = NULL;
|
|
Realloc(0);
|
|
}
|
|
TArray(int Use, int Max)
|
|
{
|
|
m_nCount = Use;
|
|
m_nAllocatedCount = Max;
|
|
m_pElements = NULL;
|
|
Realloc(0);
|
|
}
|
|
|
|
// Reference pre-existing memory. Does not delete it.
|
|
TArray(T* Elems, int Count)
|
|
{
|
|
m_pElements = Elems;
|
|
m_nCount = Count;
|
|
m_nAllocatedCount = 0;
|
|
}
|
|
~TArray()
|
|
{
|
|
Free();
|
|
}
|
|
|
|
void Free()
|
|
{
|
|
m_nCount = 0;
|
|
if (m_nAllocatedCount && AZ::AllocatorInstance<CryLegacySTLAllocator>::IsReady())
|
|
{
|
|
AZ::AllocatorInstance<CryLegacySTLAllocator>::Get().DeAllocate(m_pElements);
|
|
}
|
|
m_nAllocatedCount = 0;
|
|
m_pElements = NULL;
|
|
}
|
|
|
|
void Create (int Count)
|
|
{
|
|
m_pElements = NULL;
|
|
m_nCount = Count;
|
|
m_nAllocatedCount = Count;
|
|
Realloc(0);
|
|
Clear();
|
|
}
|
|
void Copy (const TArray<T>& src)
|
|
{
|
|
m_pElements = NULL;
|
|
m_nCount = m_nAllocatedCount = src.Num();
|
|
Realloc(0);
|
|
PREFAST_ASSUME(m_pElements); // realloc asserts if it fails - so this is safe
|
|
memcpy(m_pElements, src.m_pElements, src.Num() * sizeof(T));
|
|
}
|
|
void Copy (const T* src, unsigned int numElems)
|
|
{
|
|
int nOffs = m_nCount;
|
|
Grow(numElems);
|
|
memcpy(&m_pElements[nOffs], src, numElems * sizeof(T));
|
|
}
|
|
void Align4Copy (const T* src, unsigned int& numElems)
|
|
{
|
|
int nOffs = m_nCount;
|
|
Grow((numElems + 3) & ~3);
|
|
memcpy(&m_pElements[nOffs], src, numElems * sizeof(T));
|
|
if (numElems & 3)
|
|
{
|
|
int nSet = 4 - (numElems & 3);
|
|
memset(&m_pElements[nOffs + numElems], 0, nSet);
|
|
numElems += nSet;
|
|
}
|
|
}
|
|
|
|
void Realloc([[maybe_unused]] int nOldAllocatedCount)
|
|
{
|
|
if (!m_nAllocatedCount)
|
|
{
|
|
m_pElements = NULL;
|
|
}
|
|
else
|
|
{
|
|
m_pElements = static_cast<decltype(m_pElements)>(AZ::AllocatorInstance<CryLegacySTLAllocator>::Get().ReAllocate(m_pElements, m_nAllocatedCount * sizeof(T), alignof(T)));
|
|
assert (m_pElements);
|
|
}
|
|
}
|
|
|
|
void Remove(unsigned int Index, unsigned int Count = 1)
|
|
{
|
|
if (Count)
|
|
{
|
|
memmove(m_pElements + Index, m_pElements + (Index + Count), sizeof(T) * (m_nCount - Index - Count));
|
|
m_nCount -= Count;
|
|
}
|
|
}
|
|
|
|
void Shrink()
|
|
{
|
|
if (m_nCount == 0 || m_nAllocatedCount == 0)
|
|
{
|
|
return;
|
|
}
|
|
assert(m_nAllocatedCount >= m_nCount);
|
|
if (m_nAllocatedCount != m_nCount)
|
|
{
|
|
int nOldAllocatedCount = m_nAllocatedCount;
|
|
m_nAllocatedCount = m_nCount;
|
|
Realloc(nOldAllocatedCount);
|
|
}
|
|
}
|
|
|
|
void _Remove(unsigned int Index, unsigned int Count)
|
|
{
|
|
assert (Index >= 0);
|
|
assert (Index <= m_nCount);
|
|
assert ((Index + Count) <= m_nCount);
|
|
|
|
Remove(Index, Count);
|
|
}
|
|
|
|
unsigned int Num(void) const { return m_nCount; }
|
|
unsigned int Capacity(void) const { return m_nAllocatedCount; }
|
|
unsigned int MemSize(void) const { return m_nCount * sizeof(T); }
|
|
void SetNum(unsigned int n) { m_nCount = m_nAllocatedCount = n; }
|
|
void SetUse(unsigned int n) { m_nCount = n; }
|
|
void Alloc(unsigned int n) { int nOldAllocatedCount = m_nAllocatedCount; m_nAllocatedCount = n; Realloc(nOldAllocatedCount); }
|
|
void Reserve(unsigned int n) { int nOldAllocatedCount = m_nAllocatedCount; SetNum(n); Realloc(nOldAllocatedCount); Clear(); }
|
|
void ReserveNoClear(unsigned int n) { int nOldAllocatedCount = m_nAllocatedCount; SetNum(n); Realloc(nOldAllocatedCount); }
|
|
void Expand(unsigned int n)
|
|
{
|
|
if (n > m_nAllocatedCount)
|
|
{
|
|
ReserveNew(n);
|
|
}
|
|
}
|
|
void ReserveNew(unsigned int n)
|
|
{
|
|
int num = m_nCount;
|
|
if (n > m_nAllocatedCount)
|
|
{
|
|
int nOldAllocatedCount = m_nAllocatedCount;
|
|
m_nAllocatedCount = n * 2;
|
|
Realloc(nOldAllocatedCount);
|
|
}
|
|
m_nCount = n;
|
|
memset(&m_pElements[num], 0, sizeof(T) * (m_nCount - num));
|
|
}
|
|
T* Grow(unsigned int n)
|
|
{
|
|
int nStart = m_nCount;
|
|
m_nCount += n;
|
|
if (m_nCount > m_nAllocatedCount)
|
|
{
|
|
int nOldAllocatedCount = m_nAllocatedCount;
|
|
m_nAllocatedCount = m_nCount * 2;
|
|
Realloc(nOldAllocatedCount);
|
|
}
|
|
return &m_pElements[nStart];
|
|
}
|
|
T* GrowReset(unsigned int n)
|
|
{
|
|
int num = m_nAllocatedCount;
|
|
T* Obj = AddIndex(n);
|
|
if (num != m_nAllocatedCount)
|
|
{
|
|
memset(&m_pElements[num], 0, sizeof(T) * (m_nAllocatedCount - num));
|
|
}
|
|
return Obj;
|
|
}
|
|
|
|
unsigned int* GetNumAddr(void) { return &m_nCount; }
|
|
T** GetDataAddr(void) { return &m_pElements; }
|
|
|
|
T* Data(void) const { return m_pElements; }
|
|
T& Get(unsigned int id) const { return m_pElements[id]; }
|
|
|
|
|
|
void Assign(TArray& fa)
|
|
{
|
|
m_pElements = fa.m_pElements;
|
|
m_nCount = fa.m_nCount;
|
|
m_nAllocatedCount = fa.m_nAllocatedCount;
|
|
}
|
|
|
|
|
|
/*const TArray operator=(TArray fa) const
|
|
{
|
|
TArray<T> t = TArray(fa.m_nCount,fa.m_nAllocatedCount);
|
|
for ( int i=0; i<fa.Num(); i++ )
|
|
{
|
|
t.AddElem(fa[i]);
|
|
}
|
|
return t;
|
|
}*/
|
|
|
|
const T& operator[](unsigned int i) const { assert(i < m_nCount); return m_pElements[i]; }
|
|
T& operator[](unsigned int i) { assert(i < m_nCount); return m_pElements[i]; }
|
|
T& operator * () { assert(m_nCount > 0); return *m_pElements; }
|
|
|
|
TArray<T> operator()(unsigned int Start)
|
|
{
|
|
assert(Start < m_nCount);
|
|
return TArray<T>(m_pElements + Start, m_nCount - Start);
|
|
}
|
|
TArray<T> operator()(unsigned int Start, unsigned int Count)
|
|
{
|
|
assert(Start < m_nCount);
|
|
assert(Start + Count <= m_nCount);
|
|
return TArray<T>(m_pElements + Start, Count);
|
|
}
|
|
|
|
// For simple types only
|
|
TArray(const TArray<T>& cTA)
|
|
{
|
|
m_pElements = NULL;
|
|
m_nCount = m_nAllocatedCount = cTA.Num();
|
|
Realloc(0);
|
|
if (m_pElements)
|
|
{
|
|
memcpy(m_pElements, &cTA[0], m_nCount * sizeof(T));
|
|
}
|
|
/*for (unsigned int i=0; i<cTA.Num(); i++ )
|
|
{
|
|
AddElem(cTA[i]);
|
|
}*/
|
|
}
|
|
inline TArray& operator = (const TArray& cTA)
|
|
{
|
|
Free();
|
|
new(this)TArray(cTA);
|
|
return *this;
|
|
}
|
|
void ClearArr(void)
|
|
{
|
|
m_nCount = 0;
|
|
m_nAllocatedCount = 0;
|
|
m_pElements = NULL;
|
|
}
|
|
|
|
void Clear(void)
|
|
{
|
|
memset(m_pElements, 0, m_nCount * sizeof(T));
|
|
}
|
|
|
|
void AddString(const char* szStr)
|
|
{
|
|
assert(szStr);
|
|
int nLen = strlen(szStr) + 1;
|
|
T* pDst = Grow(nLen);
|
|
memcpy(pDst, szStr, nLen);
|
|
}
|
|
|
|
void Set(unsigned int m)
|
|
{
|
|
memset(m_pElements, m, m_nCount * sizeof(T));
|
|
}
|
|
|
|
ILINE T* AddIndex(unsigned int inc)
|
|
{
|
|
unsigned int nIndex = m_nCount;
|
|
unsigned int nNewCount = m_nCount + inc;
|
|
|
|
if (nNewCount > m_nAllocatedCount)
|
|
{
|
|
int nOldAllocatedCount = m_nAllocatedCount;
|
|
m_nAllocatedCount = nNewCount + (nNewCount >> 1) + 10;
|
|
Realloc(nOldAllocatedCount);
|
|
}
|
|
|
|
m_nCount = nNewCount;
|
|
return &m_pElements[nIndex];
|
|
}
|
|
|
|
T& Insert(unsigned int nIndex, unsigned int inc = 1)
|
|
{
|
|
m_nCount += inc;
|
|
if (m_nCount > m_nAllocatedCount)
|
|
{
|
|
int nOldAllocatedCount = m_nAllocatedCount;
|
|
m_nAllocatedCount = m_nCount + (m_nCount >> 1) + 32;
|
|
Realloc(nOldAllocatedCount);
|
|
}
|
|
memmove(&m_pElements[nIndex + inc], &m_pElements[nIndex], (m_nCount - inc - nIndex) * sizeof(T));
|
|
|
|
return m_pElements[nIndex];
|
|
}
|
|
|
|
void AddIndexNoCache(unsigned int inc)
|
|
{
|
|
m_nCount += inc;
|
|
if (m_nCount > m_nAllocatedCount)
|
|
{
|
|
int nOldAllocatedCount = m_nAllocatedCount;
|
|
m_nAllocatedCount = m_nCount;
|
|
Realloc(nOldAllocatedCount);
|
|
}
|
|
}
|
|
|
|
void Add(const T& elem){AddElem(elem); }
|
|
void AddElem(const T& elem)
|
|
{
|
|
unsigned int m = m_nCount;
|
|
AddIndex(1);
|
|
m_pElements[m] = elem;
|
|
}
|
|
void AddElemNoCache(const T& elem)
|
|
{
|
|
unsigned int m = m_nCount;
|
|
AddIndexNoCache(1);
|
|
m_pElements[m] = elem;
|
|
}
|
|
|
|
int Find(const T& p)
|
|
{
|
|
for (unsigned int i = 0; i < m_nCount; i++)
|
|
{
|
|
if (p == (*this)[i])
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void Delete(unsigned int n){DelElem(n); }
|
|
void DelElem(unsigned int n)
|
|
{
|
|
// memset(&m_pElements[n],0,sizeof(T));
|
|
_Remove(n, 1);
|
|
}
|
|
|
|
// Standard compliance interface
|
|
//
|
|
// This is for those who don't want to learn the non standard and
|
|
// thus not very convenient interface of TArray, but are unlucky
|
|
// enough not to be able to avoid using it.
|
|
void clear(){Free(); }
|
|
void resize(unsigned int nSize) { reserve(nSize); m_nCount = nSize; }
|
|
void reserve(unsigned int nSize)
|
|
{
|
|
if (nSize > m_nAllocatedCount)
|
|
{
|
|
Alloc(nSize);
|
|
}
|
|
}
|
|
unsigned size() const {return m_nCount; }
|
|
unsigned capacity() const {return m_nAllocatedCount; }
|
|
bool empty() const {return size() == 0; }
|
|
void push_back (const T& rSample) {Add(rSample); }
|
|
void pop_back () {m_nCount--; }
|
|
void erase (T* pElem)
|
|
{
|
|
int n = int(pElem - m_pElements);
|
|
assert(n >= 0 && n < m_nCount);
|
|
_Remove(n, 1);
|
|
}
|
|
T* begin() {return m_pElements; }
|
|
T* end() {return m_pElements + m_nCount; }
|
|
T last() {return m_pElements[m_nCount - 1]; }
|
|
const T* begin() const {return m_pElements; }
|
|
const T* end() const {return m_pElements + m_nCount; }
|
|
|
|
int GetMemoryUsage() const { return (int)(m_nAllocatedCount * sizeof(T)); }
|
|
};
|
|
|
|
template <class T>
|
|
inline void Exchange(T& X, T& Y)
|
|
{
|
|
const T Tmp = X;
|
|
X = Y;
|
|
Y = Tmp;
|
|
}
|
|
|
|
#endif // CRYINCLUDE_CRYCOMMON_TARRAY_H
|