This repository has been archived on 2024-06-13. You can view files and clone it, but cannot push or open issues or pull requests.
2020-08-04 13:13:01 -04:00

295 lines
8.1 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
// A stack based on a growable array
//=============================================================================//
#ifndef UTLSTACK_H
#define UTLSTACK_H
#include <assert.h>
#include <string.h>
#include "utlmemory.h"
//-----------------------------------------------------------------------------
// The CUtlStack class:
// A growable stack class which doubles in size by default.
// It will always keep all elements consecutive in memory, and may move the
// elements around in memory (via a realloc) when elements are pushed or
// popped. Clients should therefore refer to the elements of the stack
// by index (they should *never* maintain pointers to elements in the stack).
//-----------------------------------------------------------------------------
template <class T, class M = CUtlMemory<T> >
class CUtlStack {
public:
// constructor, destructor
CUtlStack(int growSize = 0, int initSize = 0);
~CUtlStack();
void CopyFrom(const CUtlStack<T, M>& from);
// element access
T& operator[](int i);
T const& operator[](int i) const;
T& Element(int i);
T const& Element(int i) const;
// Gets the base address (can change when adding elements!)
T* Base();
T const* Base() const;
// Looks at the stack top
T& Top();
T const& Top() const;
// Size
int Count() const;
// Is element index valid?
bool IsIdxValid(int i) const;
// Adds an element, uses default constructor
int Push();
// Adds an element, uses copy constructor
int Push(T const& src);
// Pops the stack
void Pop();
void Pop(T& oldTop);
void PopMultiple(int num);
// Makes sure we have enough memory allocated to store a requested # of
// elements
void EnsureCapacity(int num);
// Clears the stack, no deallocation
void Clear();
// Memory deallocation
void Purge();
private:
// Grows the stack allocation
void GrowStack();
// For easier access to the elements through the debugger
void ResetDbgInfo();
M m_Memory;
int m_Size;
// For easier access to the elements through the debugger
T* m_pElements;
};
//-----------------------------------------------------------------------------
// For easier access to the elements through the debugger
//-----------------------------------------------------------------------------
template <class T, class M>
inline void CUtlStack<T, M>::ResetDbgInfo() {
m_pElements = m_Memory.Base();
}
//-----------------------------------------------------------------------------
// constructor, destructor
//-----------------------------------------------------------------------------
template <class T, class M>
CUtlStack<T, M>::CUtlStack(int growSize, int initSize)
: m_Memory(growSize, initSize), m_Size(0) {
ResetDbgInfo();
}
template <class T, class M>
CUtlStack<T, M>::~CUtlStack() {
Purge();
}
//-----------------------------------------------------------------------------
// copy into
//-----------------------------------------------------------------------------
template <class T, class M>
void CUtlStack<T, M>::CopyFrom(const CUtlStack<T, M>& from) {
Purge();
EnsureCapacity(from.Count());
for (int i = 0; i < from.Count(); i++) {
Push(from[i]);
}
}
//-----------------------------------------------------------------------------
// element access
//-----------------------------------------------------------------------------
template <class T, class M>
inline T& CUtlStack<T, M>::operator[](int i) {
assert(IsIdxValid(i));
return m_Memory[i];
}
template <class T, class M>
inline T const& CUtlStack<T, M>::operator[](int i) const {
assert(IsIdxValid(i));
return m_Memory[i];
}
template <class T, class M>
inline T& CUtlStack<T, M>::Element(int i) {
assert(IsIdxValid(i));
return m_Memory[i];
}
template <class T, class M>
inline T const& CUtlStack<T, M>::Element(int i) const {
assert(IsIdxValid(i));
return m_Memory[i];
}
//-----------------------------------------------------------------------------
// Gets the base address (can change when adding elements!)
//-----------------------------------------------------------------------------
template <class T, class M>
inline T* CUtlStack<T, M>::Base() {
return m_Memory.Base();
}
template <class T, class M>
inline T const* CUtlStack<T, M>::Base() const {
return m_Memory.Base();
}
//-----------------------------------------------------------------------------
// Returns the top of the stack
//-----------------------------------------------------------------------------
template <class T, class M>
inline T& CUtlStack<T, M>::Top() {
assert(m_Size > 0);
return Element(m_Size - 1);
}
template <class T, class M>
inline T const& CUtlStack<T, M>::Top() const {
assert(m_Size > 0);
return Element(m_Size - 1);
}
//-----------------------------------------------------------------------------
// Size
//-----------------------------------------------------------------------------
template <class T, class M>
inline int CUtlStack<T, M>::Count() const {
return m_Size;
}
//-----------------------------------------------------------------------------
// Is element index valid?
//-----------------------------------------------------------------------------
template <class T, class M>
inline bool CUtlStack<T, M>::IsIdxValid(int i) const {
return (i >= 0) && (i < m_Size);
}
//-----------------------------------------------------------------------------
// Grows the stack
//-----------------------------------------------------------------------------
template <class T, class M>
void CUtlStack<T, M>::GrowStack() {
if (m_Size >= m_Memory.NumAllocated()) m_Memory.Grow();
++m_Size;
ResetDbgInfo();
}
//-----------------------------------------------------------------------------
// Makes sure we have enough memory allocated to store a requested # of elements
//-----------------------------------------------------------------------------
template <class T, class M>
void CUtlStack<T, M>::EnsureCapacity(int num) {
m_Memory.EnsureCapacity(num);
ResetDbgInfo();
}
//-----------------------------------------------------------------------------
// Adds an element, uses default constructor
//-----------------------------------------------------------------------------
template <class T, class M>
int CUtlStack<T, M>::Push() {
GrowStack();
Construct(&Element(m_Size - 1));
return m_Size - 1;
}
//-----------------------------------------------------------------------------
// Adds an element, uses copy constructor
//-----------------------------------------------------------------------------
template <class T, class M>
int CUtlStack<T, M>::Push(T const& src) {
GrowStack();
CopyConstruct(&Element(m_Size - 1), src);
return m_Size - 1;
}
//-----------------------------------------------------------------------------
// Pops the stack
//-----------------------------------------------------------------------------
template <class T, class M>
void CUtlStack<T, M>::Pop() {
assert(m_Size > 0);
Destruct(&Element(m_Size - 1));
--m_Size;
}
template <class T, class M>
void CUtlStack<T, M>::Pop(T& oldTop) {
assert(m_Size > 0);
oldTop = Top();
Pop();
}
template <class T, class M>
void CUtlStack<T, M>::PopMultiple(int num) {
assert(m_Size >= num);
for (int i = 0; i < num; ++i) Destruct(&Element(m_Size - i - 1));
m_Size -= num;
}
//-----------------------------------------------------------------------------
// Element removal
//-----------------------------------------------------------------------------
template <class T, class M>
void CUtlStack<T, M>::Clear() {
for (int i = m_Size; --i >= 0;) Destruct(&Element(i));
m_Size = 0;
}
//-----------------------------------------------------------------------------
// Memory deallocation
//-----------------------------------------------------------------------------
template <class T, class M>
void CUtlStack<T, M>::Purge() {
Clear();
m_Memory.Purge();
ResetDbgInfo();
}
#endif // UTLSTACK_H