226 lines
6.2 KiB
C++
226 lines
6.2 KiB
C++
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose: A fast stack memory allocator that uses virtual memory if available
|
|
//
|
|
//=============================================================================//
|
|
|
|
#ifndef MEMSTACK_H
|
|
#define MEMSTACK_H
|
|
|
|
#if defined(_WIN32)
|
|
#pragma once
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
typedef unsigned MemoryStackMark_t;
|
|
|
|
class CMemoryStack {
|
|
public:
|
|
CMemoryStack();
|
|
~CMemoryStack();
|
|
|
|
bool Init(unsigned maxSize = 0, unsigned commitSize = 0,
|
|
unsigned initialCommit = 0, unsigned alignment = 16);
|
|
#ifdef _X360
|
|
bool InitPhysical(unsigned size = 0, unsigned alignment = 16);
|
|
#endif
|
|
void Term();
|
|
|
|
int GetSize();
|
|
int GetMaxSize();
|
|
int GetUsed();
|
|
|
|
void *Alloc(unsigned bytes, bool bClear = false) RESTRICT;
|
|
|
|
MemoryStackMark_t GetCurrentAllocPoint();
|
|
void FreeToAllocPoint(MemoryStackMark_t mark, bool bDecommit = true);
|
|
void FreeAll(bool bDecommit = true);
|
|
|
|
void Access(void **ppRegion, unsigned *pBytes);
|
|
|
|
void PrintContents();
|
|
|
|
void *GetBase();
|
|
const void *GetBase() const {
|
|
return const_cast<CMemoryStack *>(this)->GetBase();
|
|
}
|
|
|
|
private:
|
|
bool CommitTo(byte *) RESTRICT;
|
|
|
|
byte *m_pNextAlloc;
|
|
byte *m_pCommitLimit;
|
|
byte *m_pAllocLimit;
|
|
|
|
byte *m_pBase;
|
|
|
|
unsigned m_maxSize;
|
|
unsigned m_alignment;
|
|
#ifdef _WIN32
|
|
unsigned m_commitSize;
|
|
unsigned m_minCommit;
|
|
#endif
|
|
#ifdef _X360
|
|
bool m_bPhysical;
|
|
#endif
|
|
};
|
|
|
|
//-------------------------------------
|
|
|
|
FORCEINLINE void *CMemoryStack::Alloc(unsigned bytes, bool bClear) RESTRICT {
|
|
Assert(m_pBase);
|
|
|
|
int alignment = m_alignment;
|
|
if (bytes) {
|
|
bytes = AlignValue(bytes, alignment);
|
|
} else {
|
|
bytes = alignment;
|
|
}
|
|
|
|
void *pResult = m_pNextAlloc;
|
|
byte *pNextAlloc = m_pNextAlloc + bytes;
|
|
|
|
if (pNextAlloc > m_pCommitLimit) {
|
|
if (!CommitTo(pNextAlloc)) {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if (bClear) {
|
|
memset(pResult, 0, bytes);
|
|
}
|
|
|
|
m_pNextAlloc = pNextAlloc;
|
|
|
|
return pResult;
|
|
}
|
|
|
|
//-------------------------------------
|
|
|
|
inline int CMemoryStack::GetMaxSize() { return m_maxSize; }
|
|
|
|
//-------------------------------------
|
|
|
|
inline int CMemoryStack::GetUsed() { return (m_pNextAlloc - m_pBase); }
|
|
|
|
//-------------------------------------
|
|
|
|
inline void *CMemoryStack::GetBase() { return m_pBase; }
|
|
|
|
//-------------------------------------
|
|
|
|
inline MemoryStackMark_t CMemoryStack::GetCurrentAllocPoint() {
|
|
return (m_pNextAlloc - m_pBase);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// The CUtlMemoryStack class:
|
|
// A fixed memory class
|
|
//-----------------------------------------------------------------------------
|
|
template <typename T, typename I, size_t MAX_SIZE, size_t COMMIT_SIZE = 0,
|
|
size_t INITIAL_COMMIT = 0>
|
|
class CUtlMemoryStack {
|
|
public:
|
|
// constructor, destructor
|
|
CUtlMemoryStack(int nGrowSize = 0, int nInitSize = 0) {
|
|
m_MemoryStack.Init(MAX_SIZE * sizeof(T), COMMIT_SIZE * sizeof(T),
|
|
INITIAL_COMMIT * sizeof(T), 4);
|
|
COMPILE_TIME_ASSERT(sizeof(T) % 4 == 0);
|
|
}
|
|
CUtlMemoryStack(T *pMemory, int numElements) { Assert(0); }
|
|
|
|
// Can we use this index?
|
|
bool IsIdxValid(I i) const { return (i >= 0) && (i < m_nAllocated); }
|
|
|
|
// Specify the invalid ('null') index that we'll only return on failure
|
|
static const I INVALID_INDEX = (I)-1; // For use with COMPILE_TIME_ASSERT
|
|
static I InvalidIndex() { return INVALID_INDEX; }
|
|
|
|
class Iterator_t {
|
|
Iterator_t(I i) : index(i) {}
|
|
I index;
|
|
friend class CUtlMemoryStack<T, I, MAX_SIZE, COMMIT_SIZE,
|
|
INITIAL_COMMIT>;
|
|
|
|
public:
|
|
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(m_nAllocated ? 0 : InvalidIndex());
|
|
}
|
|
Iterator_t Next(const Iterator_t &it) const {
|
|
return Iterator_t(it.index < m_nAllocated ? 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 it.index >= 0 && it.index < m_nAllocated;
|
|
}
|
|
Iterator_t InvalidIterator() const { return Iterator_t(InvalidIndex()); }
|
|
|
|
// Gets the base address
|
|
T *Base() { return (T *)m_MemoryStack.GetBase(); }
|
|
const T *Base() const { return (const T *)m_MemoryStack.GetBase(); }
|
|
|
|
// element access
|
|
T &operator[](I i) {
|
|
Assert(IsIdxValid(i));
|
|
return Base()[i];
|
|
}
|
|
const T &operator[](I i) const {
|
|
Assert(IsIdxValid(i));
|
|
return Base()[i];
|
|
}
|
|
T &Element(I i) {
|
|
Assert(IsIdxValid(i));
|
|
return Base()[i];
|
|
}
|
|
const T &Element(I i) const {
|
|
Assert(IsIdxValid(i));
|
|
return Base()[i];
|
|
}
|
|
|
|
// Attaches the buffer to external memory....
|
|
void SetExternalBuffer(T *pMemory, int numElements) { Assert(0); }
|
|
|
|
// Size
|
|
int NumAllocated() const { return m_nAllocated; }
|
|
int Count() const { return m_nAllocated; }
|
|
|
|
// Grows the memory, so that at least allocated + num elements are allocated
|
|
void Grow(int num = 1) {
|
|
Assert(num > 0);
|
|
m_nAllocated += num;
|
|
m_MemoryStack.Alloc(num * sizeof(T));
|
|
}
|
|
|
|
// Makes sure we've got at least this much memory
|
|
void EnsureCapacity(int num) {
|
|
Assert(num <= MAX_SIZE);
|
|
if (m_nAllocated < num) Grow(num - m_nAllocated);
|
|
}
|
|
|
|
// Memory deallocation
|
|
void Purge() {
|
|
m_MemoryStack.FreeAll();
|
|
m_nAllocated = 0;
|
|
}
|
|
|
|
// is the memory externally allocated?
|
|
bool IsExternallyAllocated() const { return false; }
|
|
|
|
// Set the size by which the memory grows
|
|
void SetGrowSize(int size) {}
|
|
|
|
private:
|
|
CMemoryStack m_MemoryStack;
|
|
int m_nAllocated;
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#endif // MEMSTACK_H
|