Seaside/SpyCustom/sdk/utlblockmemory.h
2021-06-16 18:48:15 +03:00

294 lines
6.7 KiB
C++

#ifndef UTLBLOCKMEMORY_H
#define UTLBLOCKMEMORY_H
#ifdef _WIN32
#pragma once
#endif
#include "dbg.h"
#include "platform.h"
#include "mathlib.h"
#include "memalloc.h"
#include "memdbgon.h"
#pragma warning (disable:4100)
#pragma warning (disable:4514)
#ifdef UTBLOCKLMEMORY_TRACK
#define UTLBLOCKMEMORY_TRACK_ALLOC() MemAlloc_RegisterAllocation( "Sum of all UtlBlockMemory", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 )
#define UTLBLOCKMEMORY_TRACK_FREE() if ( !m_pMemory ) ; else MemAlloc_RegisterDeallocation( "Sum of all UtlBlockMemory", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 )
#else
#define UTLBLOCKMEMORY_TRACK_ALLOC() ((void)0)
#define UTLBLOCKMEMORY_TRACK_FREE() ((void)0)
#endif
template< class T, class I >
class CUtlBlockMemory
{
public:
CUtlBlockMemory(int nGrowSize = 0, int nInitSize = 0);
~CUtlBlockMemory();
void Init(int nGrowSize = 0, int nInitSize = 0);
T* Base() { return NULL; }
const T* Base() const { return NULL; }
class Iterator_t
{
public:
Iterator_t(I i) : index(i) {}
I index;
bool operator==(const Iterator_t it) const { return index == it.index; }
bool operator!=(const Iterator_t it) const { return index != it.index; }
};
Iterator_t First() const { return Iterator_t(IsIdxValid(0) ? 0 : InvalidIndex()); }
Iterator_t Next(const Iterator_t& it) const { return Iterator_t(IsIdxValid(it.index + 1) ? it.index + 1 : InvalidIndex()); }
I GetIndex(const Iterator_t& it) const { return it.index; }
bool IsIdxAfter(I i, const Iterator_t& it) const { return i > it.index; }
bool IsValidIterator(const Iterator_t& it) const { return IsIdxValid(it.index); }
Iterator_t InvalidIterator() const { return Iterator_t(InvalidIndex()); }
T& operator[](I i);
const T& operator[](I i) const;
T& Element(I i);
const T& Element(I i) const;
bool IsIdxValid(I i) const;
static I InvalidIndex() { return (I)-1; }
void Swap(CUtlBlockMemory< T, I >& mem);
int NumAllocated() const;
int Count() const { return NumAllocated(); }
void Grow(int num = 1);
void EnsureCapacity(int num);
void Purge();
void Purge(int numElements);
protected:
int Index(int major, int minor) const { return (major << m_nIndexShift) | minor; }
int MajorIndex(int i) const { return i >> m_nIndexShift; }
int MinorIndex(int i) const { return i & m_nIndexMask; }
void ChangeSize(int nBlocks);
int NumElementsInBlock() const { return m_nIndexMask + 1; }
T** m_pMemory;
int m_nBlocks;
int m_nIndexMask : 27;
int m_nIndexShift : 5;
};
template< class T, class I >
CUtlBlockMemory<T, I>::CUtlBlockMemory(int nGrowSize, int nInitAllocationCount)
: m_pMemory(0), m_nBlocks(0), m_nIndexMask(0), m_nIndexShift(0)
{
Init(nGrowSize, nInitAllocationCount);
}
template< class T, class I >
CUtlBlockMemory<T, I>::~CUtlBlockMemory()
{
Purge();
}
template< class T, class I >
void CUtlBlockMemory<T, I>::Swap(CUtlBlockMemory< T, I >& mem)
{
swap(m_pMemory, mem.m_pMemory);
swap(m_nBlocks, mem.m_nBlocks);
swap(m_nIndexMask, mem.m_nIndexMask);
swap(m_nIndexShift, mem.m_nIndexShift);
}
template< class T, class I >
void CUtlBlockMemory<T, I>::Init(int nGrowSize , int nInitSize )
{
Purge();
if (nGrowSize == 0)
{
nGrowSize = (127 + sizeof(T)) / sizeof(T);
}
nGrowSize = SmallestPowerOfTwoGreaterOrEqual(nGrowSize);
m_nIndexMask = nGrowSize - 1;
m_nIndexShift = 0;
while (nGrowSize > 1)
{
nGrowSize >>= 1;
++m_nIndexShift;
}
Assert(m_nIndexMask + 1 == (1 << m_nIndexShift));
Grow(nInitSize);
}
template< class T, class I >
inline T& CUtlBlockMemory<T, I>::operator[](I i)
{
Assert(IsIdxValid(i));
T* pBlock = m_pMemory[MajorIndex(i)];
return pBlock[MinorIndex(i)];
}
template< class T, class I >
inline const T& CUtlBlockMemory<T, I>::operator[](I i) const
{
Assert(IsIdxValid(i));
const T* pBlock = m_pMemory[MajorIndex(i)];
return pBlock[MinorIndex(i)];
}
template< class T, class I >
inline T& CUtlBlockMemory<T, I>::Element(I i)
{
Assert(IsIdxValid(i));
T* pBlock = m_pMemory[MajorIndex(i)];
return pBlock[MinorIndex(i)];
}
template< class T, class I >
inline const T& CUtlBlockMemory<T, I>::Element(I i) const
{
Assert(IsIdxValid(i));
const T* pBlock = m_pMemory[MajorIndex(i)];
return pBlock[MinorIndex(i)];
}
template< class T, class I >
inline int CUtlBlockMemory<T, I>::NumAllocated() const
{
return m_nBlocks * NumElementsInBlock();
}
template< class T, class I >
inline bool CUtlBlockMemory<T, I>::IsIdxValid(I i) const
{
return (i >= 0) && (MajorIndex(i) < m_nBlocks);
}
template< class T, class I >
void CUtlBlockMemory<T, I>::Grow(int num)
{
if (num <= 0)
return;
int nBlockSize = NumElementsInBlock();
int nBlocks = (num + nBlockSize - 1) / nBlockSize;
ChangeSize(m_nBlocks + nBlocks);
}
template< class T, class I >
void CUtlBlockMemory<T, I>::ChangeSize(int nBlocks)
{
UTLBLOCKMEMORY_TRACK_FREE();
int nBlocksOld = m_nBlocks;
m_nBlocks = nBlocks;
UTLBLOCKMEMORY_TRACK_ALLOC();
if (m_pMemory)
{
for (int i = m_nBlocks; i < nBlocksOld; ++i)
{
UTLBLOCKMEMORY_TRACK_FREE();
free((void*)m_pMemory[i]);
}
MEM_ALLOC_CREDIT_CLASS();
m_pMemory = (T**)realloc(m_pMemory, m_nBlocks * sizeof(T*));
Assert(m_pMemory);
}
else
{
MEM_ALLOC_CREDIT_CLASS();
m_pMemory = (T**)malloc(m_nBlocks * sizeof(T*));
Assert(m_pMemory);
}
if (!m_pMemory)
{
Error("CUtlBlockMemory overflow!\n");
}
int nBlockSize = NumElementsInBlock();
for (int i = nBlocksOld; i < m_nBlocks; ++i)
{
MEM_ALLOC_CREDIT_CLASS();
m_pMemory[i] = (T*)malloc(nBlockSize * sizeof(T));
Assert(m_pMemory[i]);
}
}
template< class T, class I >
inline void CUtlBlockMemory<T, I>::EnsureCapacity(int num)
{
Grow(num - NumAllocated());
}
template< class T, class I >
void CUtlBlockMemory<T, I>::Purge()
{
if (!m_pMemory)
return;
for (int i = 0; i < m_nBlocks; ++i)
{
UTLBLOCKMEMORY_TRACK_FREE();
free((void*)m_pMemory[i]);
}
m_nBlocks = 0;
UTLBLOCKMEMORY_TRACK_FREE();
free((void*)m_pMemory);
m_pMemory = 0;
}
template< class T, class I >
void CUtlBlockMemory<T, I>::Purge(int numElements)
{
Assert(numElements >= 0);
int nAllocated = NumAllocated();
if (numElements > nAllocated)
{
Assert(numElements <= nAllocated);
return;
}
if (numElements <= 0)
{
Purge();
return;
}
int nBlockSize = NumElementsInBlock();
int nBlocksOld = m_nBlocks;
int nBlocks = (numElements + nBlockSize - 1) / nBlockSize;
if (nBlocks == m_nBlocks)
return;
ChangeSize(nBlocks);
}
#include "memdbgoff.h"
#endif