diff options
| author | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:31:46 -0800 |
|---|---|---|
| committer | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:46:31 -0800 |
| commit | f56bb35301836e56582a575a75864392a0177875 (patch) | |
| tree | de61ddd39de3e7df52759711950b4c288592f0dc /mp/src/public/tier1/utlvector.h | |
| parent | Mark some more files as text. (diff) | |
| download | source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip | |
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/public/tier1/utlvector.h')
| -rw-r--r-- | mp/src/public/tier1/utlvector.h | 2420 |
1 files changed, 1210 insertions, 1210 deletions
diff --git a/mp/src/public/tier1/utlvector.h b/mp/src/public/tier1/utlvector.h index 3b8dd0ee..1f2fe6e1 100644 --- a/mp/src/public/tier1/utlvector.h +++ b/mp/src/public/tier1/utlvector.h @@ -1,1210 +1,1210 @@ -//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//
-// A growable array class that maintains a free list and keeps elements
-// in the same location
-//=============================================================================//
-
-#ifndef UTLVECTOR_H
-#define UTLVECTOR_H
-
-#ifdef _WIN32
-#pragma once
-#endif
-
-
-#include <string.h>
-#include "tier0/platform.h"
-#include "tier0/dbg.h"
-#include "tier0/threadtools.h"
-#include "tier1/utlmemory.h"
-#include "tier1/utlblockmemory.h"
-#include "tier1/strtools.h"
-
-#define FOR_EACH_VEC( vecName, iteratorName ) \
- for ( int iteratorName = 0; iteratorName < (vecName).Count(); iteratorName++ )
-#define FOR_EACH_VEC_BACK( vecName, iteratorName ) \
- for ( int iteratorName = (vecName).Count()-1; iteratorName >= 0; iteratorName-- )
-
-//-----------------------------------------------------------------------------
-// The CUtlVector class:
-// A growable array 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 PvRealloc) when elements are inserted or
-// removed. Clients should therefore refer to the elements of the vector
-// by index (they should *never* maintain pointers to elements in the vector).
-//-----------------------------------------------------------------------------
-template< class T, class A = CUtlMemory<T> >
-class CUtlVector
-{
- typedef A CAllocator;
-public:
- typedef T ElemType_t;
- typedef T* iterator;
- typedef const T* const_iterator;
-
- // constructor, destructor
- explicit CUtlVector( int growSize = 0, int initSize = 0 );
- explicit CUtlVector( T* pMemory, int allocationCount, int numElements = 0 );
- ~CUtlVector();
-
- // Copy the array.
- CUtlVector<T, A>& operator=( const CUtlVector<T, A> &other );
-
- // element access
- T& operator[]( int i );
- const T& operator[]( int i ) const;
- T& Element( int i );
- const T& Element( int i ) const;
- T& Head();
- const T& Head() const;
- T& Tail();
- const T& Tail() const;
-
- // STL compatible member functions. These allow easier use of std::sort
- // and they are forward compatible with the C++ 11 range-based for loops.
- iterator begin() { return Base(); }
- const_iterator begin() const { return Base(); }
- iterator end() { return Base() + Count(); }
- const_iterator end() const { return Base() + Count(); }
-
- // Gets the base address (can change when adding elements!)
- T* Base() { return m_Memory.Base(); }
- const T* Base() const { return m_Memory.Base(); }
-
- // Returns the number of elements in the vector
- // SIZE IS DEPRECATED!
- int Count() const;
- int Size() const; // don't use me!
-
- // Is element index valid?
- bool IsValidIndex( int i ) const;
- static int InvalidIndex();
-
- // Adds an element, uses default constructor
- int AddToHead();
- int AddToTail();
- int InsertBefore( int elem );
- int InsertAfter( int elem );
-
- // Adds an element, uses copy constructor
- int AddToHead( const T& src );
- int AddToTail( const T& src );
- int InsertBefore( int elem, const T& src );
- int InsertAfter( int elem, const T& src );
-
- // Adds multiple elements, uses default constructor
- int AddMultipleToHead( int num );
- int AddMultipleToTail( int num, const T *pToCopy=NULL );
- int InsertMultipleBefore( int elem, int num, const T *pToCopy=NULL ); // If pToCopy is set, then it's an array of length 'num' and
- int InsertMultipleAfter( int elem, int num );
-
- // Calls RemoveAll() then AddMultipleToTail.
- void SetSize( int size );
- void SetCount( int count );
- void SetCountNonDestructively( int count ); //sets count by adding or removing elements to tail TODO: This should probably be the default behavior for SetCount
-
- // Calls SetSize and copies each element.
- void CopyArray( const T *pArray, int size );
-
- // Fast swap
- void Swap( CUtlVector< T, A > &vec );
-
- // Add the specified array to the tail.
- int AddVectorToTail( CUtlVector<T, A> const &src );
-
- // Finds an element (element needs operator== defined)
- int Find( const T& src ) const;
-
- bool HasElement( const T& src ) const;
-
- // Makes sure we have enough memory allocated to store a requested # of elements
- void EnsureCapacity( int num );
-
- // Makes sure we have at least this many elements
- void EnsureCount( int num );
-
- // Element removal
- void FastRemove( int elem ); // doesn't preserve order
- void Remove( int elem ); // preserves order, shifts elements
- bool FindAndRemove( const T& src ); // removes first occurrence of src, preserves order, shifts elements
- bool FindAndFastRemove( const T& src ); // removes first occurrence of src, doesn't preserve order
- void RemoveMultiple( int elem, int num ); // preserves order, shifts elements
- void RemoveMultipleFromHead(int num); // removes num elements from tail
- void RemoveMultipleFromTail(int num); // removes num elements from tail
- void RemoveAll(); // doesn't deallocate memory
-
- // Memory deallocation
- void Purge();
-
- // Purges the list and calls delete on each element in it.
- void PurgeAndDeleteElements();
-
- // Compacts the vector to the number of elements actually in use
- void Compact();
-
- // Set the size by which it grows when it needs to allocate more memory.
- void SetGrowSize( int size ) { m_Memory.SetGrowSize( size ); }
-
- int NumAllocated() const; // Only use this if you really know what you're doing!
-
- void Sort( int (__cdecl *pfnCompare)(const T *, const T *) );
-
-#ifdef DBGFLAG_VALIDATE
- void Validate( CValidator &validator, char *pchName ); // Validate our internal structures
-#endif // DBGFLAG_VALIDATE
-
-protected:
- // Grows the vector
- void GrowVector( int num = 1 );
-
- // Shifts elements....
- void ShiftElementsRight( int elem, int num = 1 );
- void ShiftElementsLeft( int elem, int num = 1 );
-
- CAllocator m_Memory;
- int m_Size;
-
-#ifndef _X360
- // For easier access to the elements through the debugger
- // it's in release builds so this can be used in libraries correctly
- T *m_pElements;
-
- inline void ResetDbgInfo()
- {
- m_pElements = Base();
- }
-#else
- inline void ResetDbgInfo() {}
-#endif
-
-private:
- // Can't copy this unless we explicitly do it!
- // Use CCopyableUtlVector<T> to get this functionality
- CUtlVector( CUtlVector const& vec );
-};
-
-
-// this is kind of ugly, but until C++ gets templatized typedefs in C++0x, it's our only choice
-template < class T >
-class CUtlBlockVector : public CUtlVector< T, CUtlBlockMemory< T, int > >
-{
-public:
- explicit CUtlBlockVector( int growSize = 0, int initSize = 0 )
- : CUtlVector< T, CUtlBlockMemory< T, int > >( growSize, initSize ) {}
-
-private:
- // Private and unimplemented because iterator semantics are not currently supported
- // on CUtlBlockVector, due to its non-contiguous allocations.
- // typename is require to disambiguate iterator as a type versus other possibilities.
- typedef CUtlVector< T, CUtlBlockMemory< T, int > > Base;
- typename Base::iterator begin();
- typename Base::const_iterator begin() const;
- typename Base::iterator end();
- typename Base::const_iterator end() const;
-};
-
-//-----------------------------------------------------------------------------
-// The CUtlVectorFixed class:
-// A array class with a fixed allocation scheme
-//-----------------------------------------------------------------------------
-
-template< class BASE_UTLVECTOR, class MUTEX_TYPE = CThreadFastMutex >
-class CUtlVectorMT : public BASE_UTLVECTOR, public MUTEX_TYPE
-{
- typedef BASE_UTLVECTOR BaseClass;
-public:
- MUTEX_TYPE Mutex_t;
-
- // constructor, destructor
- explicit CUtlVectorMT( int growSize = 0, int initSize = 0 ) : BaseClass( growSize, initSize ) {}
- explicit CUtlVectorMT( typename BaseClass::ElemType_t* pMemory, int numElements ) : BaseClass( pMemory, numElements ) {}
-};
-
-
-//-----------------------------------------------------------------------------
-// The CUtlVectorFixed class:
-// A array class with a fixed allocation scheme
-//-----------------------------------------------------------------------------
-template< class T, size_t MAX_SIZE >
-class CUtlVectorFixed : public CUtlVector< T, CUtlMemoryFixed<T, MAX_SIZE > >
-{
- typedef CUtlVector< T, CUtlMemoryFixed<T, MAX_SIZE > > BaseClass;
-public:
-
- // constructor, destructor
- explicit CUtlVectorFixed( int growSize = 0, int initSize = 0 ) : BaseClass( growSize, initSize ) {}
- explicit CUtlVectorFixed( T* pMemory, int numElements ) : BaseClass( pMemory, numElements ) {}
-};
-
-
-//-----------------------------------------------------------------------------
-// The CUtlVectorFixedGrowable class:
-// A array class with a fixed allocation scheme backed by a dynamic one
-//-----------------------------------------------------------------------------
-template< class T, size_t MAX_SIZE >
-class CUtlVectorFixedGrowable : public CUtlVector< T, CUtlMemoryFixedGrowable<T, MAX_SIZE > >
-{
- typedef CUtlVector< T, CUtlMemoryFixedGrowable<T, MAX_SIZE > > BaseClass;
-
-public:
- // constructor, destructor
- explicit CUtlVectorFixedGrowable( int growSize = 0 ) : BaseClass( growSize, MAX_SIZE ) {}
-};
-
-
-//-----------------------------------------------------------------------------
-// The CUtlVectorConservative class:
-// A array class with a conservative allocation scheme
-//-----------------------------------------------------------------------------
-template< class T >
-class CUtlVectorConservative : public CUtlVector< T, CUtlMemoryConservative<T> >
-{
- typedef CUtlVector< T, CUtlMemoryConservative<T> > BaseClass;
-public:
-
- // constructor, destructor
- explicit CUtlVectorConservative( int growSize = 0, int initSize = 0 ) : BaseClass( growSize, initSize ) {}
- explicit CUtlVectorConservative( T* pMemory, int numElements ) : BaseClass( pMemory, numElements ) {}
-};
-
-
-//-----------------------------------------------------------------------------
-// The CUtlVectorUltra Conservative class:
-// A array class with a very conservative allocation scheme, with customizable allocator
-// Especialy useful if you have a lot of vectors that are sparse, or if you're
-// carefully packing holders of vectors
-//-----------------------------------------------------------------------------
-#pragma warning(push)
-#pragma warning(disable : 4200) // warning C4200: nonstandard extension used : zero-sized array in struct/union
-#pragma warning(disable : 4815 ) // warning C4815: 'staticData' : zero-sized array in stack object will have no elements
-
-class CUtlVectorUltraConservativeAllocator
-{
-public:
- static void *Alloc( size_t nSize )
- {
- return malloc( nSize );
- }
-
- static void *Realloc( void *pMem, size_t nSize )
- {
- return realloc( pMem, nSize );
- }
-
- static void Free( void *pMem )
- {
- free( pMem );
- }
-
- static size_t GetSize( void *pMem )
- {
- return mallocsize( pMem );
- }
-
-};
-
-template <typename T, typename A = CUtlVectorUltraConservativeAllocator >
-class CUtlVectorUltraConservative : private A
-{
-public:
- CUtlVectorUltraConservative()
- {
- m_pData = StaticData();
- }
-
- ~CUtlVectorUltraConservative()
- {
- RemoveAll();
- }
-
- int Count() const
- {
- return m_pData->m_Size;
- }
-
- static int InvalidIndex()
- {
- return -1;
- }
-
- inline bool IsValidIndex( int i ) const
- {
- return (i >= 0) && (i < Count());
- }
-
- T& operator[]( int i )
- {
- Assert( IsValidIndex( i ) );
- return m_pData->m_Elements[i];
- }
-
- const T& operator[]( int i ) const
- {
- Assert( IsValidIndex( i ) );
- return m_pData->m_Elements[i];
- }
-
- T& Element( int i )
- {
- Assert( IsValidIndex( i ) );
- return m_pData->m_Elements[i];
- }
-
- const T& Element( int i ) const
- {
- Assert( IsValidIndex( i ) );
- return m_pData->m_Elements[i];
- }
-
- void EnsureCapacity( int num )
- {
- int nCurCount = Count();
- if ( num <= nCurCount )
- {
- return;
- }
- if ( m_pData == StaticData() )
- {
- m_pData = (Data_t *)A::Alloc( sizeof(int) + ( num * sizeof(T) ) );
- m_pData->m_Size = 0;
- }
- else
- {
- int nNeeded = sizeof(int) + ( num * sizeof(T) );
- int nHave = A::GetSize( m_pData );
- if ( nNeeded > nHave )
- {
- m_pData = (Data_t *)A::Realloc( m_pData, nNeeded );
- }
- }
- }
-
- int AddToTail( const T& src )
- {
- int iNew = Count();
- EnsureCapacity( Count() + 1 );
- m_pData->m_Elements[iNew] = src;
- m_pData->m_Size++;
- return iNew;
- }
-
- void RemoveAll()
- {
- if ( Count() )
- {
- for (int i = m_pData->m_Size; --i >= 0; )
- {
- Destruct(&m_pData->m_Elements[i]);
- }
- }
- if ( m_pData != StaticData() )
- {
- A::Free( m_pData );
- m_pData = StaticData();
-
- }
- }
-
- void PurgeAndDeleteElements()
- {
- if ( m_pData != StaticData() )
- {
- for( int i=0; i < m_pData->m_Size; i++ )
- {
- delete Element(i);
- }
- RemoveAll();
- }
- }
-
- void FastRemove( int elem )
- {
- Assert( IsValidIndex(elem) );
-
- Destruct( &Element(elem) );
- if (Count() > 0)
- {
- if ( elem != m_pData->m_Size -1 )
- memcpy( &Element(elem), &Element(m_pData->m_Size-1), sizeof(T) );
- --m_pData->m_Size;
- }
- if ( !m_pData->m_Size )
- {
- A::Free( m_pData );
- m_pData = StaticData();
- }
- }
-
- void Remove( int elem )
- {
- Destruct( &Element(elem) );
- ShiftElementsLeft(elem);
- --m_pData->m_Size;
- if ( !m_pData->m_Size )
- {
- A::Free( m_pData );
- m_pData = StaticData();
- }
- }
-
- int Find( const T& src ) const
- {
- int nCount = Count();
- for ( int i = 0; i < nCount; ++i )
- {
- if (Element(i) == src)
- return i;
- }
- return -1;
- }
-
- bool FindAndRemove( const T& src )
- {
- int elem = Find( src );
- if ( elem != -1 )
- {
- Remove( elem );
- return true;
- }
- return false;
- }
-
-
- bool FindAndFastRemove( const T& src )
- {
- int elem = Find( src );
- if ( elem != -1 )
- {
- FastRemove( elem );
- return true;
- }
- return false;
- }
-
- struct Data_t
- {
- int m_Size;
- T m_Elements[0];
- };
-
- Data_t *m_pData;
-private:
- void ShiftElementsLeft( int elem, int num = 1 )
- {
- int Size = Count();
- Assert( IsValidIndex(elem) || ( Size == 0 ) || ( num == 0 ));
- int numToMove = Size - elem - num;
- if ((numToMove > 0) && (num > 0))
- {
- Q_memmove( &Element(elem), &Element(elem+num), numToMove * sizeof(T) );
-
-#ifdef _DEBUG
- Q_memset( &Element(Size-num), 0xDD, num * sizeof(T) );
-#endif
- }
- }
-
-
-
- static Data_t *StaticData()
- {
- static Data_t staticData;
- Assert( staticData.m_Size == 0 );
- return &staticData;
- }
-};
-
-#pragma warning(pop)
-
-
-//-----------------------------------------------------------------------------
-// The CCopyableUtlVector class:
-// A array class that allows copy construction (so you can nest a CUtlVector inside of another one of our containers)
-// WARNING - this class lets you copy construct which can be an expensive operation if you don't carefully control when it happens
-// Only use this when nesting a CUtlVector() inside of another one of our container classes (i.e a CUtlMap)
-//-----------------------------------------------------------------------------
-template< typename T, typename A = CUtlMemory<T> >
-class CCopyableUtlVector : public CUtlVector< T, A >
-{
- typedef CUtlVector< T, A > BaseClass;
-public:
- explicit CCopyableUtlVector( int growSize = 0, int initSize = 0 ) : BaseClass( growSize, initSize ) {}
- explicit CCopyableUtlVector( T* pMemory, int numElements ) : BaseClass( pMemory, numElements ) {}
- virtual ~CCopyableUtlVector() {}
- CCopyableUtlVector( CCopyableUtlVector const& vec ) { this->CopyArray( vec.Base(), vec.Count() ); }
-};
-
-// TODO (Ilya): It seems like all the functions in CUtlVector are simple enough that they should be inlined.
-
-//-----------------------------------------------------------------------------
-// constructor, destructor
-//-----------------------------------------------------------------------------
-template< typename T, class A >
-inline CUtlVector<T, A>::CUtlVector( int growSize, int initSize ) :
- m_Memory(growSize, initSize), m_Size(0)
-{
- ResetDbgInfo();
-}
-
-template< typename T, class A >
-inline CUtlVector<T, A>::CUtlVector( T* pMemory, int allocationCount, int numElements ) :
- m_Memory(pMemory, allocationCount), m_Size(numElements)
-{
- ResetDbgInfo();
-}
-
-template< typename T, class A >
-inline CUtlVector<T, A>::~CUtlVector()
-{
- Purge();
-}
-
-template< typename T, class A >
-inline CUtlVector<T, A>& CUtlVector<T, A>::operator=( const CUtlVector<T, A> &other )
-{
- int nCount = other.Count();
- SetSize( nCount );
- for ( int i = 0; i < nCount; i++ )
- {
- (*this)[ i ] = other[ i ];
- }
- return *this;
-}
-
-
-//-----------------------------------------------------------------------------
-// element access
-//-----------------------------------------------------------------------------
-template< typename T, class A >
-inline T& CUtlVector<T, A>::operator[]( int i )
-{
- // Do an inline unsigned check for maximum debug-build performance.
- Assert( (unsigned)i < (unsigned)m_Size );
- return m_Memory[ i ];
-}
-
-template< typename T, class A >
-inline const T& CUtlVector<T, A>::operator[]( int i ) const
-{
- // Do an inline unsigned check for maximum debug-build performance.
- Assert( (unsigned)i < (unsigned)m_Size );
- return m_Memory[ i ];
-}
-
-template< typename T, class A >
-inline T& CUtlVector<T, A>::Element( int i )
-{
- // Do an inline unsigned check for maximum debug-build performance.
- Assert( (unsigned)i < (unsigned)m_Size );
- return m_Memory[ i ];
-}
-
-template< typename T, class A >
-inline const T& CUtlVector<T, A>::Element( int i ) const
-{
- // Do an inline unsigned check for maximum debug-build performance.
- Assert( (unsigned)i < (unsigned)m_Size );
- return m_Memory[ i ];
-}
-
-template< typename T, class A >
-inline T& CUtlVector<T, A>::Head()
-{
- Assert( m_Size > 0 );
- return m_Memory[ 0 ];
-}
-
-template< typename T, class A >
-inline const T& CUtlVector<T, A>::Head() const
-{
- Assert( m_Size > 0 );
- return m_Memory[ 0 ];
-}
-
-template< typename T, class A >
-inline T& CUtlVector<T, A>::Tail()
-{
- Assert( m_Size > 0 );
- return m_Memory[ m_Size - 1 ];
-}
-
-template< typename T, class A >
-inline const T& CUtlVector<T, A>::Tail() const
-{
- Assert( m_Size > 0 );
- return m_Memory[ m_Size - 1 ];
-}
-
-
-//-----------------------------------------------------------------------------
-// Count
-//-----------------------------------------------------------------------------
-template< typename T, class A >
-inline int CUtlVector<T, A>::Size() const
-{
- return m_Size;
-}
-
-template< typename T, class A >
-inline int CUtlVector<T, A>::Count() const
-{
- return m_Size;
-}
-
-
-//-----------------------------------------------------------------------------
-// Is element index valid?
-//-----------------------------------------------------------------------------
-template< typename T, class A >
-inline bool CUtlVector<T, A>::IsValidIndex( int i ) const
-{
- return (i >= 0) && (i < m_Size);
-}
-
-
-//-----------------------------------------------------------------------------
-// Returns in invalid index
-//-----------------------------------------------------------------------------
-template< typename T, class A >
-inline int CUtlVector<T, A>::InvalidIndex()
-{
- return -1;
-}
-
-
-//-----------------------------------------------------------------------------
-// Grows the vector
-//-----------------------------------------------------------------------------
-template< typename T, class A >
-void CUtlVector<T, A>::GrowVector( int num )
-{
- if (m_Size + num > m_Memory.NumAllocated())
- {
- MEM_ALLOC_CREDIT_CLASS();
- m_Memory.Grow( m_Size + num - m_Memory.NumAllocated() );
- }
-
- m_Size += num;
- ResetDbgInfo();
-}
-
-
-//-----------------------------------------------------------------------------
-// Sorts the vector
-//-----------------------------------------------------------------------------
-template< typename T, class A >
-void CUtlVector<T, A>::Sort( int (__cdecl *pfnCompare)(const T *, const T *) )
-{
- typedef int (__cdecl *QSortCompareFunc_t)(const void *, const void *);
- if ( Count() <= 1 )
- return;
-
- if ( Base() )
- {
- qsort( Base(), Count(), sizeof(T), (QSortCompareFunc_t)(pfnCompare) );
- }
- else
- {
- Assert( 0 );
- // this path is untested
- // if you want to sort vectors that use a non-sequential memory allocator,
- // you'll probably want to patch in a quicksort algorithm here
- // I just threw in this bubble sort to have something just in case...
-
- for ( int i = m_Size - 1; i >= 0; --i )
- {
- for ( int j = 1; j <= i; ++j )
- {
- if ( pfnCompare( &Element( j - 1 ), &Element( j ) ) < 0 )
- {
- V_swap( Element( j - 1 ), Element( j ) );
- }
- }
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// Makes sure we have enough memory allocated to store a requested # of elements
-//-----------------------------------------------------------------------------
-template< typename T, class A >
-void CUtlVector<T, A>::EnsureCapacity( int num )
-{
- MEM_ALLOC_CREDIT_CLASS();
- m_Memory.EnsureCapacity(num);
- ResetDbgInfo();
-}
-
-
-//-----------------------------------------------------------------------------
-// Makes sure we have at least this many elements
-//-----------------------------------------------------------------------------
-template< typename T, class A >
-void CUtlVector<T, A>::EnsureCount( int num )
-{
- if (Count() < num)
- AddMultipleToTail( num - Count() );
-}
-
-
-//-----------------------------------------------------------------------------
-// Shifts elements
-//-----------------------------------------------------------------------------
-template< typename T, class A >
-void CUtlVector<T, A>::ShiftElementsRight( int elem, int num )
-{
- Assert( IsValidIndex(elem) || ( m_Size == 0 ) || ( num == 0 ));
- int numToMove = m_Size - elem - num;
- if ((numToMove > 0) && (num > 0))
- Q_memmove( &Element(elem+num), &Element(elem), numToMove * sizeof(T) );
-}
-
-template< typename T, class A >
-void CUtlVector<T, A>::ShiftElementsLeft( int elem, int num )
-{
- Assert( IsValidIndex(elem) || ( m_Size == 0 ) || ( num == 0 ));
- int numToMove = m_Size - elem - num;
- if ((numToMove > 0) && (num > 0))
- {
- Q_memmove( &Element(elem), &Element(elem+num), numToMove * sizeof(T) );
-
-#ifdef _DEBUG
- Q_memset( &Element(m_Size-num), 0xDD, num * sizeof(T) );
-#endif
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Adds an element, uses default constructor
-//-----------------------------------------------------------------------------
-template< typename T, class A >
-inline int CUtlVector<T, A>::AddToHead()
-{
- return InsertBefore(0);
-}
-
-template< typename T, class A >
-inline int CUtlVector<T, A>::AddToTail()
-{
- return InsertBefore( m_Size );
-}
-
-template< typename T, class A >
-inline int CUtlVector<T, A>::InsertAfter( int elem )
-{
- return InsertBefore( elem + 1 );
-}
-
-template< typename T, class A >
-int CUtlVector<T, A>::InsertBefore( int elem )
-{
- // Can insert at the end
- Assert( (elem == Count()) || IsValidIndex(elem) );
-
- GrowVector();
- ShiftElementsRight(elem);
- Construct( &Element(elem) );
- return elem;
-}
-
-
-//-----------------------------------------------------------------------------
-// Adds an element, uses copy constructor
-//-----------------------------------------------------------------------------
-template< typename T, class A >
-inline int CUtlVector<T, A>::AddToHead( const T& src )
-{
- // Can't insert something that's in the list... reallocation may hose us
- Assert( (Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()) ) );
- return InsertBefore( 0, src );
-}
-
-template< typename T, class A >
-inline int CUtlVector<T, A>::AddToTail( const T& src )
-{
- // Can't insert something that's in the list... reallocation may hose us
- Assert( (Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()) ) );
- return InsertBefore( m_Size, src );
-}
-
-template< typename T, class A >
-inline int CUtlVector<T, A>::InsertAfter( int elem, const T& src )
-{
- // Can't insert something that's in the list... reallocation may hose us
- Assert( (Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()) ) );
- return InsertBefore( elem + 1, src );
-}
-
-template< typename T, class A >
-int CUtlVector<T, A>::InsertBefore( int elem, const T& src )
-{
- // Can't insert something that's in the list... reallocation may hose us
- Assert( (Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()) ) );
-
- // Can insert at the end
- Assert( (elem == Count()) || IsValidIndex(elem) );
-
- GrowVector();
- ShiftElementsRight(elem);
- CopyConstruct( &Element(elem), src );
- return elem;
-}
-
-
-//-----------------------------------------------------------------------------
-// Adds multiple elements, uses default constructor
-//-----------------------------------------------------------------------------
-template< typename T, class A >
-inline int CUtlVector<T, A>::AddMultipleToHead( int num )
-{
- return InsertMultipleBefore( 0, num );
-}
-
-template< typename T, class A >
-inline int CUtlVector<T, A>::AddMultipleToTail( int num, const T *pToCopy )
-{
- // Can't insert something that's in the list... reallocation may hose us
- Assert( (Base() == NULL) || !pToCopy || (pToCopy + num < Base()) || (pToCopy >= (Base() + Count()) ) );
-
- return InsertMultipleBefore( m_Size, num, pToCopy );
-}
-
-template< typename T, class A >
-int CUtlVector<T, A>::InsertMultipleAfter( int elem, int num )
-{
- return InsertMultipleBefore( elem + 1, num );
-}
-
-
-template< typename T, class A >
-void CUtlVector<T, A>::SetCount( int count )
-{
- RemoveAll();
- AddMultipleToTail( count );
-}
-
-template< typename T, class A >
-inline void CUtlVector<T, A>::SetSize( int size )
-{
- SetCount( size );
-}
-
-template< typename T, class A >
-void CUtlVector<T, A>::SetCountNonDestructively( int count )
-{
- int delta = count - m_Size;
- if(delta > 0) AddMultipleToTail( delta );
- else if(delta < 0) RemoveMultipleFromTail( -delta );
-}
-
-template< typename T, class A >
-void CUtlVector<T, A>::CopyArray( const T *pArray, int size )
-{
- // Can't insert something that's in the list... reallocation may hose us
- Assert( (Base() == NULL) || !pArray || (Base() >= (pArray + size)) || (pArray >= (Base() + Count()) ) );
-
- SetSize( size );
- for( int i=0; i < size; i++ )
- {
- (*this)[i] = pArray[i];
- }
-}
-
-template< typename T, class A >
-void CUtlVector<T, A>::Swap( CUtlVector< T, A > &vec )
-{
- m_Memory.Swap( vec.m_Memory );
- V_swap( m_Size, vec.m_Size );
-
-#ifndef _X360
- V_swap( m_pElements, vec.m_pElements );
-#endif
-}
-
-template< typename T, class A >
-int CUtlVector<T, A>::AddVectorToTail( CUtlVector const &src )
-{
- Assert( &src != this );
-
- int base = Count();
-
- // Make space.
- AddMultipleToTail( src.Count() );
-
- // Copy the elements.
- for ( int i=0; i < src.Count(); i++ )
- {
- (*this)[base + i] = src[i];
- }
-
- return base;
-}
-
-template< typename T, class A >
-inline int CUtlVector<T, A>::InsertMultipleBefore( int elem, int num, const T *pToInsert )
-{
- if( num == 0 )
- return elem;
-
- // Can insert at the end
- Assert( (elem == Count()) || IsValidIndex(elem) );
-
- GrowVector(num);
- ShiftElementsRight( elem, num );
-
- // Invoke default constructors
- for (int i = 0; i < num; ++i )
- Construct( &Element( elem+i ) );
-
- // Copy stuff in?
- if ( pToInsert )
- {
- for ( int i=0; i < num; i++ )
- {
- Element( elem+i ) = pToInsert[i];
- }
- }
-
- return elem;
-}
-
-
-//-----------------------------------------------------------------------------
-// Finds an element (element needs operator== defined)
-//-----------------------------------------------------------------------------
-template< typename T, class A >
-int CUtlVector<T, A>::Find( const T& src ) const
-{
- for ( int i = 0; i < Count(); ++i )
- {
- if (Element(i) == src)
- return i;
- }
- return -1;
-}
-
-template< typename T, class A >
-bool CUtlVector<T, A>::HasElement( const T& src ) const
-{
- return ( Find(src) >= 0 );
-}
-
-
-//-----------------------------------------------------------------------------
-// Element removal
-//-----------------------------------------------------------------------------
-template< typename T, class A >
-void CUtlVector<T, A>::FastRemove( int elem )
-{
- Assert( IsValidIndex(elem) );
-
- Destruct( &Element(elem) );
- if (m_Size > 0)
- {
- if ( elem != m_Size -1 )
- memcpy( reinterpret_cast<void*>( &Element(elem) ), reinterpret_cast<void*>( &Element(m_Size-1) ), sizeof(T) );
- --m_Size;
- }
-}
-
-template< typename T, class A >
-void CUtlVector<T, A>::Remove( int elem )
-{
- Destruct( &Element(elem) );
- ShiftElementsLeft(elem);
- --m_Size;
-}
-
-template< typename T, class A >
-bool CUtlVector<T, A>::FindAndRemove( const T& src )
-{
- int elem = Find( src );
- if ( elem != -1 )
- {
- Remove( elem );
- return true;
- }
- return false;
-}
-
-template< typename T, class A >
-bool CUtlVector<T, A>::FindAndFastRemove( const T& src )
-{
- int elem = Find( src );
- if ( elem != -1 )
- {
- FastRemove( elem );
- return true;
- }
- return false;
-}
-
-template< typename T, class A >
-void CUtlVector<T, A>::RemoveMultiple( int elem, int num )
-{
- Assert( elem >= 0 );
- Assert( elem + num <= Count() );
-
- for (int i = elem + num; --i >= elem; )
- Destruct(&Element(i));
-
- ShiftElementsLeft(elem, num);
- m_Size -= num;
-}
-
-template< typename T, class A >
-void CUtlVector<T, A>::RemoveMultipleFromHead( int num )
-{
- Assert( num <= Count() );
-
- for (int i = num; --i >= 0; )
- Destruct(&Element(i));
-
- ShiftElementsLeft(0, num);
- m_Size -= num;
-}
-
-template< typename T, class A >
-void CUtlVector<T, A>::RemoveMultipleFromTail( int num )
-{
- Assert( num <= Count() );
-
- for (int i = m_Size-num; i < m_Size; i++)
- Destruct(&Element(i));
-
- m_Size -= num;
-}
-
-template< typename T, class A >
-void CUtlVector<T, A>::RemoveAll()
-{
- for (int i = m_Size; --i >= 0; )
- {
- Destruct(&Element(i));
- }
-
- m_Size = 0;
-}
-
-
-//-----------------------------------------------------------------------------
-// Memory deallocation
-//-----------------------------------------------------------------------------
-
-template< typename T, class A >
-inline void CUtlVector<T, A>::Purge()
-{
- RemoveAll();
- m_Memory.Purge();
- ResetDbgInfo();
-}
-
-
-template< typename T, class A >
-inline void CUtlVector<T, A>::PurgeAndDeleteElements()
-{
- for( int i=0; i < m_Size; i++ )
- {
- delete Element(i);
- }
- Purge();
-}
-
-template< typename T, class A >
-inline void CUtlVector<T, A>::Compact()
-{
- m_Memory.Purge(m_Size);
-}
-
-template< typename T, class A >
-inline int CUtlVector<T, A>::NumAllocated() const
-{
- return m_Memory.NumAllocated();
-}
-
-
-//-----------------------------------------------------------------------------
-// Data and memory validation
-//-----------------------------------------------------------------------------
-#ifdef DBGFLAG_VALIDATE
-template< typename T, class A >
-void CUtlVector<T, A>::Validate( CValidator &validator, char *pchName )
-{
- validator.Push( typeid(*this).name(), this, pchName );
-
- m_Memory.Validate( validator, "m_Memory" );
-
- validator.Pop();
-}
-#endif // DBGFLAG_VALIDATE
-
-// A vector class for storing pointers, so that the elements pointed to by the pointers are deleted
-// on exit.
-template<class T> class CUtlVectorAutoPurge : public CUtlVector< T, CUtlMemory< T, int> >
-{
-public:
- ~CUtlVectorAutoPurge( void )
- {
- this->PurgeAndDeleteElements();
- }
-
-};
-
-// easy string list class with dynamically allocated strings. For use with V_SplitString, etc.
-// Frees the dynamic strings in destructor.
-class CUtlStringList : public CUtlVectorAutoPurge< char *>
-{
-public:
- void CopyAndAddToTail( char const *pString ) // clone the string and add to the end
- {
- char *pNewStr = new char[1 + strlen( pString )];
- V_strcpy( pNewStr, pString );
- AddToTail( pNewStr );
- }
-
- static int __cdecl SortFunc( char * const * sz1, char * const * sz2 )
- {
- return strcmp( *sz1, *sz2 );
- }
-
- inline void PurgeAndDeleteElements()
- {
- for( int i=0; i < m_Size; i++ )
- {
- delete [] Element(i);
- }
- Purge();
- }
-
- ~CUtlStringList( void )
- {
- this->PurgeAndDeleteElements();
- }
-};
-
-
-
-// <Sergiy> placing it here a few days before Cert to minimize disruption to the rest of codebase
-class CSplitString: public CUtlVector<char*, CUtlMemory<char*, int> >
-{
-public:
- CSplitString(const char *pString, const char *pSeparator);
- CSplitString(const char *pString, const char **pSeparators, int nSeparators);
- ~CSplitString();
- //
- // NOTE: If you want to make Construct() public and implement Purge() here, you'll have to free m_szBuffer there
- //
-private:
- void Construct(const char *pString, const char **pSeparators, int nSeparators);
- void PurgeAndDeleteElements();
-private:
- char *m_szBuffer; // a copy of original string, with '\0' instead of separators
-};
-
-
-#endif // CCVECTOR_H
+//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +// A growable array class that maintains a free list and keeps elements +// in the same location +//=============================================================================// + +#ifndef UTLVECTOR_H +#define UTLVECTOR_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include <string.h> +#include "tier0/platform.h" +#include "tier0/dbg.h" +#include "tier0/threadtools.h" +#include "tier1/utlmemory.h" +#include "tier1/utlblockmemory.h" +#include "tier1/strtools.h" + +#define FOR_EACH_VEC( vecName, iteratorName ) \ + for ( int iteratorName = 0; iteratorName < (vecName).Count(); iteratorName++ ) +#define FOR_EACH_VEC_BACK( vecName, iteratorName ) \ + for ( int iteratorName = (vecName).Count()-1; iteratorName >= 0; iteratorName-- ) + +//----------------------------------------------------------------------------- +// The CUtlVector class: +// A growable array 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 PvRealloc) when elements are inserted or +// removed. Clients should therefore refer to the elements of the vector +// by index (they should *never* maintain pointers to elements in the vector). +//----------------------------------------------------------------------------- +template< class T, class A = CUtlMemory<T> > +class CUtlVector +{ + typedef A CAllocator; +public: + typedef T ElemType_t; + typedef T* iterator; + typedef const T* const_iterator; + + // constructor, destructor + explicit CUtlVector( int growSize = 0, int initSize = 0 ); + explicit CUtlVector( T* pMemory, int allocationCount, int numElements = 0 ); + ~CUtlVector(); + + // Copy the array. + CUtlVector<T, A>& operator=( const CUtlVector<T, A> &other ); + + // element access + T& operator[]( int i ); + const T& operator[]( int i ) const; + T& Element( int i ); + const T& Element( int i ) const; + T& Head(); + const T& Head() const; + T& Tail(); + const T& Tail() const; + + // STL compatible member functions. These allow easier use of std::sort + // and they are forward compatible with the C++ 11 range-based for loops. + iterator begin() { return Base(); } + const_iterator begin() const { return Base(); } + iterator end() { return Base() + Count(); } + const_iterator end() const { return Base() + Count(); } + + // Gets the base address (can change when adding elements!) + T* Base() { return m_Memory.Base(); } + const T* Base() const { return m_Memory.Base(); } + + // Returns the number of elements in the vector + // SIZE IS DEPRECATED! + int Count() const; + int Size() const; // don't use me! + + // Is element index valid? + bool IsValidIndex( int i ) const; + static int InvalidIndex(); + + // Adds an element, uses default constructor + int AddToHead(); + int AddToTail(); + int InsertBefore( int elem ); + int InsertAfter( int elem ); + + // Adds an element, uses copy constructor + int AddToHead( const T& src ); + int AddToTail( const T& src ); + int InsertBefore( int elem, const T& src ); + int InsertAfter( int elem, const T& src ); + + // Adds multiple elements, uses default constructor + int AddMultipleToHead( int num ); + int AddMultipleToTail( int num, const T *pToCopy=NULL ); + int InsertMultipleBefore( int elem, int num, const T *pToCopy=NULL ); // If pToCopy is set, then it's an array of length 'num' and + int InsertMultipleAfter( int elem, int num ); + + // Calls RemoveAll() then AddMultipleToTail. + void SetSize( int size ); + void SetCount( int count ); + void SetCountNonDestructively( int count ); //sets count by adding or removing elements to tail TODO: This should probably be the default behavior for SetCount + + // Calls SetSize and copies each element. + void CopyArray( const T *pArray, int size ); + + // Fast swap + void Swap( CUtlVector< T, A > &vec ); + + // Add the specified array to the tail. + int AddVectorToTail( CUtlVector<T, A> const &src ); + + // Finds an element (element needs operator== defined) + int Find( const T& src ) const; + + bool HasElement( const T& src ) const; + + // Makes sure we have enough memory allocated to store a requested # of elements + void EnsureCapacity( int num ); + + // Makes sure we have at least this many elements + void EnsureCount( int num ); + + // Element removal + void FastRemove( int elem ); // doesn't preserve order + void Remove( int elem ); // preserves order, shifts elements + bool FindAndRemove( const T& src ); // removes first occurrence of src, preserves order, shifts elements + bool FindAndFastRemove( const T& src ); // removes first occurrence of src, doesn't preserve order + void RemoveMultiple( int elem, int num ); // preserves order, shifts elements + void RemoveMultipleFromHead(int num); // removes num elements from tail + void RemoveMultipleFromTail(int num); // removes num elements from tail + void RemoveAll(); // doesn't deallocate memory + + // Memory deallocation + void Purge(); + + // Purges the list and calls delete on each element in it. + void PurgeAndDeleteElements(); + + // Compacts the vector to the number of elements actually in use + void Compact(); + + // Set the size by which it grows when it needs to allocate more memory. + void SetGrowSize( int size ) { m_Memory.SetGrowSize( size ); } + + int NumAllocated() const; // Only use this if you really know what you're doing! + + void Sort( int (__cdecl *pfnCompare)(const T *, const T *) ); + +#ifdef DBGFLAG_VALIDATE + void Validate( CValidator &validator, char *pchName ); // Validate our internal structures +#endif // DBGFLAG_VALIDATE + +protected: + // Grows the vector + void GrowVector( int num = 1 ); + + // Shifts elements.... + void ShiftElementsRight( int elem, int num = 1 ); + void ShiftElementsLeft( int elem, int num = 1 ); + + CAllocator m_Memory; + int m_Size; + +#ifndef _X360 + // For easier access to the elements through the debugger + // it's in release builds so this can be used in libraries correctly + T *m_pElements; + + inline void ResetDbgInfo() + { + m_pElements = Base(); + } +#else + inline void ResetDbgInfo() {} +#endif + +private: + // Can't copy this unless we explicitly do it! + // Use CCopyableUtlVector<T> to get this functionality + CUtlVector( CUtlVector const& vec ); +}; + + +// this is kind of ugly, but until C++ gets templatized typedefs in C++0x, it's our only choice +template < class T > +class CUtlBlockVector : public CUtlVector< T, CUtlBlockMemory< T, int > > +{ +public: + explicit CUtlBlockVector( int growSize = 0, int initSize = 0 ) + : CUtlVector< T, CUtlBlockMemory< T, int > >( growSize, initSize ) {} + +private: + // Private and unimplemented because iterator semantics are not currently supported + // on CUtlBlockVector, due to its non-contiguous allocations. + // typename is require to disambiguate iterator as a type versus other possibilities. + typedef CUtlVector< T, CUtlBlockMemory< T, int > > Base; + typename Base::iterator begin(); + typename Base::const_iterator begin() const; + typename Base::iterator end(); + typename Base::const_iterator end() const; +}; + +//----------------------------------------------------------------------------- +// The CUtlVectorFixed class: +// A array class with a fixed allocation scheme +//----------------------------------------------------------------------------- + +template< class BASE_UTLVECTOR, class MUTEX_TYPE = CThreadFastMutex > +class CUtlVectorMT : public BASE_UTLVECTOR, public MUTEX_TYPE +{ + typedef BASE_UTLVECTOR BaseClass; +public: + MUTEX_TYPE Mutex_t; + + // constructor, destructor + explicit CUtlVectorMT( int growSize = 0, int initSize = 0 ) : BaseClass( growSize, initSize ) {} + explicit CUtlVectorMT( typename BaseClass::ElemType_t* pMemory, int numElements ) : BaseClass( pMemory, numElements ) {} +}; + + +//----------------------------------------------------------------------------- +// The CUtlVectorFixed class: +// A array class with a fixed allocation scheme +//----------------------------------------------------------------------------- +template< class T, size_t MAX_SIZE > +class CUtlVectorFixed : public CUtlVector< T, CUtlMemoryFixed<T, MAX_SIZE > > +{ + typedef CUtlVector< T, CUtlMemoryFixed<T, MAX_SIZE > > BaseClass; +public: + + // constructor, destructor + explicit CUtlVectorFixed( int growSize = 0, int initSize = 0 ) : BaseClass( growSize, initSize ) {} + explicit CUtlVectorFixed( T* pMemory, int numElements ) : BaseClass( pMemory, numElements ) {} +}; + + +//----------------------------------------------------------------------------- +// The CUtlVectorFixedGrowable class: +// A array class with a fixed allocation scheme backed by a dynamic one +//----------------------------------------------------------------------------- +template< class T, size_t MAX_SIZE > +class CUtlVectorFixedGrowable : public CUtlVector< T, CUtlMemoryFixedGrowable<T, MAX_SIZE > > +{ + typedef CUtlVector< T, CUtlMemoryFixedGrowable<T, MAX_SIZE > > BaseClass; + +public: + // constructor, destructor + explicit CUtlVectorFixedGrowable( int growSize = 0 ) : BaseClass( growSize, MAX_SIZE ) {} +}; + + +//----------------------------------------------------------------------------- +// The CUtlVectorConservative class: +// A array class with a conservative allocation scheme +//----------------------------------------------------------------------------- +template< class T > +class CUtlVectorConservative : public CUtlVector< T, CUtlMemoryConservative<T> > +{ + typedef CUtlVector< T, CUtlMemoryConservative<T> > BaseClass; +public: + + // constructor, destructor + explicit CUtlVectorConservative( int growSize = 0, int initSize = 0 ) : BaseClass( growSize, initSize ) {} + explicit CUtlVectorConservative( T* pMemory, int numElements ) : BaseClass( pMemory, numElements ) {} +}; + + +//----------------------------------------------------------------------------- +// The CUtlVectorUltra Conservative class: +// A array class with a very conservative allocation scheme, with customizable allocator +// Especialy useful if you have a lot of vectors that are sparse, or if you're +// carefully packing holders of vectors +//----------------------------------------------------------------------------- +#pragma warning(push) +#pragma warning(disable : 4200) // warning C4200: nonstandard extension used : zero-sized array in struct/union +#pragma warning(disable : 4815 ) // warning C4815: 'staticData' : zero-sized array in stack object will have no elements + +class CUtlVectorUltraConservativeAllocator +{ +public: + static void *Alloc( size_t nSize ) + { + return malloc( nSize ); + } + + static void *Realloc( void *pMem, size_t nSize ) + { + return realloc( pMem, nSize ); + } + + static void Free( void *pMem ) + { + free( pMem ); + } + + static size_t GetSize( void *pMem ) + { + return mallocsize( pMem ); + } + +}; + +template <typename T, typename A = CUtlVectorUltraConservativeAllocator > +class CUtlVectorUltraConservative : private A +{ +public: + CUtlVectorUltraConservative() + { + m_pData = StaticData(); + } + + ~CUtlVectorUltraConservative() + { + RemoveAll(); + } + + int Count() const + { + return m_pData->m_Size; + } + + static int InvalidIndex() + { + return -1; + } + + inline bool IsValidIndex( int i ) const + { + return (i >= 0) && (i < Count()); + } + + T& operator[]( int i ) + { + Assert( IsValidIndex( i ) ); + return m_pData->m_Elements[i]; + } + + const T& operator[]( int i ) const + { + Assert( IsValidIndex( i ) ); + return m_pData->m_Elements[i]; + } + + T& Element( int i ) + { + Assert( IsValidIndex( i ) ); + return m_pData->m_Elements[i]; + } + + const T& Element( int i ) const + { + Assert( IsValidIndex( i ) ); + return m_pData->m_Elements[i]; + } + + void EnsureCapacity( int num ) + { + int nCurCount = Count(); + if ( num <= nCurCount ) + { + return; + } + if ( m_pData == StaticData() ) + { + m_pData = (Data_t *)A::Alloc( sizeof(int) + ( num * sizeof(T) ) ); + m_pData->m_Size = 0; + } + else + { + int nNeeded = sizeof(int) + ( num * sizeof(T) ); + int nHave = A::GetSize( m_pData ); + if ( nNeeded > nHave ) + { + m_pData = (Data_t *)A::Realloc( m_pData, nNeeded ); + } + } + } + + int AddToTail( const T& src ) + { + int iNew = Count(); + EnsureCapacity( Count() + 1 ); + m_pData->m_Elements[iNew] = src; + m_pData->m_Size++; + return iNew; + } + + void RemoveAll() + { + if ( Count() ) + { + for (int i = m_pData->m_Size; --i >= 0; ) + { + Destruct(&m_pData->m_Elements[i]); + } + } + if ( m_pData != StaticData() ) + { + A::Free( m_pData ); + m_pData = StaticData(); + + } + } + + void PurgeAndDeleteElements() + { + if ( m_pData != StaticData() ) + { + for( int i=0; i < m_pData->m_Size; i++ ) + { + delete Element(i); + } + RemoveAll(); + } + } + + void FastRemove( int elem ) + { + Assert( IsValidIndex(elem) ); + + Destruct( &Element(elem) ); + if (Count() > 0) + { + if ( elem != m_pData->m_Size -1 ) + memcpy( &Element(elem), &Element(m_pData->m_Size-1), sizeof(T) ); + --m_pData->m_Size; + } + if ( !m_pData->m_Size ) + { + A::Free( m_pData ); + m_pData = StaticData(); + } + } + + void Remove( int elem ) + { + Destruct( &Element(elem) ); + ShiftElementsLeft(elem); + --m_pData->m_Size; + if ( !m_pData->m_Size ) + { + A::Free( m_pData ); + m_pData = StaticData(); + } + } + + int Find( const T& src ) const + { + int nCount = Count(); + for ( int i = 0; i < nCount; ++i ) + { + if (Element(i) == src) + return i; + } + return -1; + } + + bool FindAndRemove( const T& src ) + { + int elem = Find( src ); + if ( elem != -1 ) + { + Remove( elem ); + return true; + } + return false; + } + + + bool FindAndFastRemove( const T& src ) + { + int elem = Find( src ); + if ( elem != -1 ) + { + FastRemove( elem ); + return true; + } + return false; + } + + struct Data_t + { + int m_Size; + T m_Elements[0]; + }; + + Data_t *m_pData; +private: + void ShiftElementsLeft( int elem, int num = 1 ) + { + int Size = Count(); + Assert( IsValidIndex(elem) || ( Size == 0 ) || ( num == 0 )); + int numToMove = Size - elem - num; + if ((numToMove > 0) && (num > 0)) + { + Q_memmove( &Element(elem), &Element(elem+num), numToMove * sizeof(T) ); + +#ifdef _DEBUG + Q_memset( &Element(Size-num), 0xDD, num * sizeof(T) ); +#endif + } + } + + + + static Data_t *StaticData() + { + static Data_t staticData; + Assert( staticData.m_Size == 0 ); + return &staticData; + } +}; + +#pragma warning(pop) + + +//----------------------------------------------------------------------------- +// The CCopyableUtlVector class: +// A array class that allows copy construction (so you can nest a CUtlVector inside of another one of our containers) +// WARNING - this class lets you copy construct which can be an expensive operation if you don't carefully control when it happens +// Only use this when nesting a CUtlVector() inside of another one of our container classes (i.e a CUtlMap) +//----------------------------------------------------------------------------- +template< typename T, typename A = CUtlMemory<T> > +class CCopyableUtlVector : public CUtlVector< T, A > +{ + typedef CUtlVector< T, A > BaseClass; +public: + explicit CCopyableUtlVector( int growSize = 0, int initSize = 0 ) : BaseClass( growSize, initSize ) {} + explicit CCopyableUtlVector( T* pMemory, int numElements ) : BaseClass( pMemory, numElements ) {} + virtual ~CCopyableUtlVector() {} + CCopyableUtlVector( CCopyableUtlVector const& vec ) { this->CopyArray( vec.Base(), vec.Count() ); } +}; + +// TODO (Ilya): It seems like all the functions in CUtlVector are simple enough that they should be inlined. + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- +template< typename T, class A > +inline CUtlVector<T, A>::CUtlVector( int growSize, int initSize ) : + m_Memory(growSize, initSize), m_Size(0) +{ + ResetDbgInfo(); +} + +template< typename T, class A > +inline CUtlVector<T, A>::CUtlVector( T* pMemory, int allocationCount, int numElements ) : + m_Memory(pMemory, allocationCount), m_Size(numElements) +{ + ResetDbgInfo(); +} + +template< typename T, class A > +inline CUtlVector<T, A>::~CUtlVector() +{ + Purge(); +} + +template< typename T, class A > +inline CUtlVector<T, A>& CUtlVector<T, A>::operator=( const CUtlVector<T, A> &other ) +{ + int nCount = other.Count(); + SetSize( nCount ); + for ( int i = 0; i < nCount; i++ ) + { + (*this)[ i ] = other[ i ]; + } + return *this; +} + + +//----------------------------------------------------------------------------- +// element access +//----------------------------------------------------------------------------- +template< typename T, class A > +inline T& CUtlVector<T, A>::operator[]( int i ) +{ + // Do an inline unsigned check for maximum debug-build performance. + Assert( (unsigned)i < (unsigned)m_Size ); + return m_Memory[ i ]; +} + +template< typename T, class A > +inline const T& CUtlVector<T, A>::operator[]( int i ) const +{ + // Do an inline unsigned check for maximum debug-build performance. + Assert( (unsigned)i < (unsigned)m_Size ); + return m_Memory[ i ]; +} + +template< typename T, class A > +inline T& CUtlVector<T, A>::Element( int i ) +{ + // Do an inline unsigned check for maximum debug-build performance. + Assert( (unsigned)i < (unsigned)m_Size ); + return m_Memory[ i ]; +} + +template< typename T, class A > +inline const T& CUtlVector<T, A>::Element( int i ) const +{ + // Do an inline unsigned check for maximum debug-build performance. + Assert( (unsigned)i < (unsigned)m_Size ); + return m_Memory[ i ]; +} + +template< typename T, class A > +inline T& CUtlVector<T, A>::Head() +{ + Assert( m_Size > 0 ); + return m_Memory[ 0 ]; +} + +template< typename T, class A > +inline const T& CUtlVector<T, A>::Head() const +{ + Assert( m_Size > 0 ); + return m_Memory[ 0 ]; +} + +template< typename T, class A > +inline T& CUtlVector<T, A>::Tail() +{ + Assert( m_Size > 0 ); + return m_Memory[ m_Size - 1 ]; +} + +template< typename T, class A > +inline const T& CUtlVector<T, A>::Tail() const +{ + Assert( m_Size > 0 ); + return m_Memory[ m_Size - 1 ]; +} + + +//----------------------------------------------------------------------------- +// Count +//----------------------------------------------------------------------------- +template< typename T, class A > +inline int CUtlVector<T, A>::Size() const +{ + return m_Size; +} + +template< typename T, class A > +inline int CUtlVector<T, A>::Count() const +{ + return m_Size; +} + + +//----------------------------------------------------------------------------- +// Is element index valid? +//----------------------------------------------------------------------------- +template< typename T, class A > +inline bool CUtlVector<T, A>::IsValidIndex( int i ) const +{ + return (i >= 0) && (i < m_Size); +} + + +//----------------------------------------------------------------------------- +// Returns in invalid index +//----------------------------------------------------------------------------- +template< typename T, class A > +inline int CUtlVector<T, A>::InvalidIndex() +{ + return -1; +} + + +//----------------------------------------------------------------------------- +// Grows the vector +//----------------------------------------------------------------------------- +template< typename T, class A > +void CUtlVector<T, A>::GrowVector( int num ) +{ + if (m_Size + num > m_Memory.NumAllocated()) + { + MEM_ALLOC_CREDIT_CLASS(); + m_Memory.Grow( m_Size + num - m_Memory.NumAllocated() ); + } + + m_Size += num; + ResetDbgInfo(); +} + + +//----------------------------------------------------------------------------- +// Sorts the vector +//----------------------------------------------------------------------------- +template< typename T, class A > +void CUtlVector<T, A>::Sort( int (__cdecl *pfnCompare)(const T *, const T *) ) +{ + typedef int (__cdecl *QSortCompareFunc_t)(const void *, const void *); + if ( Count() <= 1 ) + return; + + if ( Base() ) + { + qsort( Base(), Count(), sizeof(T), (QSortCompareFunc_t)(pfnCompare) ); + } + else + { + Assert( 0 ); + // this path is untested + // if you want to sort vectors that use a non-sequential memory allocator, + // you'll probably want to patch in a quicksort algorithm here + // I just threw in this bubble sort to have something just in case... + + for ( int i = m_Size - 1; i >= 0; --i ) + { + for ( int j = 1; j <= i; ++j ) + { + if ( pfnCompare( &Element( j - 1 ), &Element( j ) ) < 0 ) + { + V_swap( Element( j - 1 ), Element( j ) ); + } + } + } + } +} + +//----------------------------------------------------------------------------- +// Makes sure we have enough memory allocated to store a requested # of elements +//----------------------------------------------------------------------------- +template< typename T, class A > +void CUtlVector<T, A>::EnsureCapacity( int num ) +{ + MEM_ALLOC_CREDIT_CLASS(); + m_Memory.EnsureCapacity(num); + ResetDbgInfo(); +} + + +//----------------------------------------------------------------------------- +// Makes sure we have at least this many elements +//----------------------------------------------------------------------------- +template< typename T, class A > +void CUtlVector<T, A>::EnsureCount( int num ) +{ + if (Count() < num) + AddMultipleToTail( num - Count() ); +} + + +//----------------------------------------------------------------------------- +// Shifts elements +//----------------------------------------------------------------------------- +template< typename T, class A > +void CUtlVector<T, A>::ShiftElementsRight( int elem, int num ) +{ + Assert( IsValidIndex(elem) || ( m_Size == 0 ) || ( num == 0 )); + int numToMove = m_Size - elem - num; + if ((numToMove > 0) && (num > 0)) + Q_memmove( &Element(elem+num), &Element(elem), numToMove * sizeof(T) ); +} + +template< typename T, class A > +void CUtlVector<T, A>::ShiftElementsLeft( int elem, int num ) +{ + Assert( IsValidIndex(elem) || ( m_Size == 0 ) || ( num == 0 )); + int numToMove = m_Size - elem - num; + if ((numToMove > 0) && (num > 0)) + { + Q_memmove( &Element(elem), &Element(elem+num), numToMove * sizeof(T) ); + +#ifdef _DEBUG + Q_memset( &Element(m_Size-num), 0xDD, num * sizeof(T) ); +#endif + } +} + + +//----------------------------------------------------------------------------- +// Adds an element, uses default constructor +//----------------------------------------------------------------------------- +template< typename T, class A > +inline int CUtlVector<T, A>::AddToHead() +{ + return InsertBefore(0); +} + +template< typename T, class A > +inline int CUtlVector<T, A>::AddToTail() +{ + return InsertBefore( m_Size ); +} + +template< typename T, class A > +inline int CUtlVector<T, A>::InsertAfter( int elem ) +{ + return InsertBefore( elem + 1 ); +} + +template< typename T, class A > +int CUtlVector<T, A>::InsertBefore( int elem ) +{ + // Can insert at the end + Assert( (elem == Count()) || IsValidIndex(elem) ); + + GrowVector(); + ShiftElementsRight(elem); + Construct( &Element(elem) ); + return elem; +} + + +//----------------------------------------------------------------------------- +// Adds an element, uses copy constructor +//----------------------------------------------------------------------------- +template< typename T, class A > +inline int CUtlVector<T, A>::AddToHead( const T& src ) +{ + // Can't insert something that's in the list... reallocation may hose us + Assert( (Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()) ) ); + return InsertBefore( 0, src ); +} + +template< typename T, class A > +inline int CUtlVector<T, A>::AddToTail( const T& src ) +{ + // Can't insert something that's in the list... reallocation may hose us + Assert( (Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()) ) ); + return InsertBefore( m_Size, src ); +} + +template< typename T, class A > +inline int CUtlVector<T, A>::InsertAfter( int elem, const T& src ) +{ + // Can't insert something that's in the list... reallocation may hose us + Assert( (Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()) ) ); + return InsertBefore( elem + 1, src ); +} + +template< typename T, class A > +int CUtlVector<T, A>::InsertBefore( int elem, const T& src ) +{ + // Can't insert something that's in the list... reallocation may hose us + Assert( (Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()) ) ); + + // Can insert at the end + Assert( (elem == Count()) || IsValidIndex(elem) ); + + GrowVector(); + ShiftElementsRight(elem); + CopyConstruct( &Element(elem), src ); + return elem; +} + + +//----------------------------------------------------------------------------- +// Adds multiple elements, uses default constructor +//----------------------------------------------------------------------------- +template< typename T, class A > +inline int CUtlVector<T, A>::AddMultipleToHead( int num ) +{ + return InsertMultipleBefore( 0, num ); +} + +template< typename T, class A > +inline int CUtlVector<T, A>::AddMultipleToTail( int num, const T *pToCopy ) +{ + // Can't insert something that's in the list... reallocation may hose us + Assert( (Base() == NULL) || !pToCopy || (pToCopy + num < Base()) || (pToCopy >= (Base() + Count()) ) ); + + return InsertMultipleBefore( m_Size, num, pToCopy ); +} + +template< typename T, class A > +int CUtlVector<T, A>::InsertMultipleAfter( int elem, int num ) +{ + return InsertMultipleBefore( elem + 1, num ); +} + + +template< typename T, class A > +void CUtlVector<T, A>::SetCount( int count ) +{ + RemoveAll(); + AddMultipleToTail( count ); +} + +template< typename T, class A > +inline void CUtlVector<T, A>::SetSize( int size ) +{ + SetCount( size ); +} + +template< typename T, class A > +void CUtlVector<T, A>::SetCountNonDestructively( int count ) +{ + int delta = count - m_Size; + if(delta > 0) AddMultipleToTail( delta ); + else if(delta < 0) RemoveMultipleFromTail( -delta ); +} + +template< typename T, class A > +void CUtlVector<T, A>::CopyArray( const T *pArray, int size ) +{ + // Can't insert something that's in the list... reallocation may hose us + Assert( (Base() == NULL) || !pArray || (Base() >= (pArray + size)) || (pArray >= (Base() + Count()) ) ); + + SetSize( size ); + for( int i=0; i < size; i++ ) + { + (*this)[i] = pArray[i]; + } +} + +template< typename T, class A > +void CUtlVector<T, A>::Swap( CUtlVector< T, A > &vec ) +{ + m_Memory.Swap( vec.m_Memory ); + V_swap( m_Size, vec.m_Size ); + +#ifndef _X360 + V_swap( m_pElements, vec.m_pElements ); +#endif +} + +template< typename T, class A > +int CUtlVector<T, A>::AddVectorToTail( CUtlVector const &src ) +{ + Assert( &src != this ); + + int base = Count(); + + // Make space. + AddMultipleToTail( src.Count() ); + + // Copy the elements. + for ( int i=0; i < src.Count(); i++ ) + { + (*this)[base + i] = src[i]; + } + + return base; +} + +template< typename T, class A > +inline int CUtlVector<T, A>::InsertMultipleBefore( int elem, int num, const T *pToInsert ) +{ + if( num == 0 ) + return elem; + + // Can insert at the end + Assert( (elem == Count()) || IsValidIndex(elem) ); + + GrowVector(num); + ShiftElementsRight( elem, num ); + + // Invoke default constructors + for (int i = 0; i < num; ++i ) + Construct( &Element( elem+i ) ); + + // Copy stuff in? + if ( pToInsert ) + { + for ( int i=0; i < num; i++ ) + { + Element( elem+i ) = pToInsert[i]; + } + } + + return elem; +} + + +//----------------------------------------------------------------------------- +// Finds an element (element needs operator== defined) +//----------------------------------------------------------------------------- +template< typename T, class A > +int CUtlVector<T, A>::Find( const T& src ) const +{ + for ( int i = 0; i < Count(); ++i ) + { + if (Element(i) == src) + return i; + } + return -1; +} + +template< typename T, class A > +bool CUtlVector<T, A>::HasElement( const T& src ) const +{ + return ( Find(src) >= 0 ); +} + + +//----------------------------------------------------------------------------- +// Element removal +//----------------------------------------------------------------------------- +template< typename T, class A > +void CUtlVector<T, A>::FastRemove( int elem ) +{ + Assert( IsValidIndex(elem) ); + + Destruct( &Element(elem) ); + if (m_Size > 0) + { + if ( elem != m_Size -1 ) + memcpy( reinterpret_cast<void*>( &Element(elem) ), reinterpret_cast<void*>( &Element(m_Size-1) ), sizeof(T) ); + --m_Size; + } +} + +template< typename T, class A > +void CUtlVector<T, A>::Remove( int elem ) +{ + Destruct( &Element(elem) ); + ShiftElementsLeft(elem); + --m_Size; +} + +template< typename T, class A > +bool CUtlVector<T, A>::FindAndRemove( const T& src ) +{ + int elem = Find( src ); + if ( elem != -1 ) + { + Remove( elem ); + return true; + } + return false; +} + +template< typename T, class A > +bool CUtlVector<T, A>::FindAndFastRemove( const T& src ) +{ + int elem = Find( src ); + if ( elem != -1 ) + { + FastRemove( elem ); + return true; + } + return false; +} + +template< typename T, class A > +void CUtlVector<T, A>::RemoveMultiple( int elem, int num ) +{ + Assert( elem >= 0 ); + Assert( elem + num <= Count() ); + + for (int i = elem + num; --i >= elem; ) + Destruct(&Element(i)); + + ShiftElementsLeft(elem, num); + m_Size -= num; +} + +template< typename T, class A > +void CUtlVector<T, A>::RemoveMultipleFromHead( int num ) +{ + Assert( num <= Count() ); + + for (int i = num; --i >= 0; ) + Destruct(&Element(i)); + + ShiftElementsLeft(0, num); + m_Size -= num; +} + +template< typename T, class A > +void CUtlVector<T, A>::RemoveMultipleFromTail( int num ) +{ + Assert( num <= Count() ); + + for (int i = m_Size-num; i < m_Size; i++) + Destruct(&Element(i)); + + m_Size -= num; +} + +template< typename T, class A > +void CUtlVector<T, A>::RemoveAll() +{ + for (int i = m_Size; --i >= 0; ) + { + Destruct(&Element(i)); + } + + m_Size = 0; +} + + +//----------------------------------------------------------------------------- +// Memory deallocation +//----------------------------------------------------------------------------- + +template< typename T, class A > +inline void CUtlVector<T, A>::Purge() +{ + RemoveAll(); + m_Memory.Purge(); + ResetDbgInfo(); +} + + +template< typename T, class A > +inline void CUtlVector<T, A>::PurgeAndDeleteElements() +{ + for( int i=0; i < m_Size; i++ ) + { + delete Element(i); + } + Purge(); +} + +template< typename T, class A > +inline void CUtlVector<T, A>::Compact() +{ + m_Memory.Purge(m_Size); +} + +template< typename T, class A > +inline int CUtlVector<T, A>::NumAllocated() const +{ + return m_Memory.NumAllocated(); +} + + +//----------------------------------------------------------------------------- +// Data and memory validation +//----------------------------------------------------------------------------- +#ifdef DBGFLAG_VALIDATE +template< typename T, class A > +void CUtlVector<T, A>::Validate( CValidator &validator, char *pchName ) +{ + validator.Push( typeid(*this).name(), this, pchName ); + + m_Memory.Validate( validator, "m_Memory" ); + + validator.Pop(); +} +#endif // DBGFLAG_VALIDATE + +// A vector class for storing pointers, so that the elements pointed to by the pointers are deleted +// on exit. +template<class T> class CUtlVectorAutoPurge : public CUtlVector< T, CUtlMemory< T, int> > +{ +public: + ~CUtlVectorAutoPurge( void ) + { + this->PurgeAndDeleteElements(); + } + +}; + +// easy string list class with dynamically allocated strings. For use with V_SplitString, etc. +// Frees the dynamic strings in destructor. +class CUtlStringList : public CUtlVectorAutoPurge< char *> +{ +public: + void CopyAndAddToTail( char const *pString ) // clone the string and add to the end + { + char *pNewStr = new char[1 + strlen( pString )]; + V_strcpy( pNewStr, pString ); + AddToTail( pNewStr ); + } + + static int __cdecl SortFunc( char * const * sz1, char * const * sz2 ) + { + return strcmp( *sz1, *sz2 ); + } + + inline void PurgeAndDeleteElements() + { + for( int i=0; i < m_Size; i++ ) + { + delete [] Element(i); + } + Purge(); + } + + ~CUtlStringList( void ) + { + this->PurgeAndDeleteElements(); + } +}; + + + +// <Sergiy> placing it here a few days before Cert to minimize disruption to the rest of codebase +class CSplitString: public CUtlVector<char*, CUtlMemory<char*, int> > +{ +public: + CSplitString(const char *pString, const char *pSeparator); + CSplitString(const char *pString, const char **pSeparators, int nSeparators); + ~CSplitString(); + // + // NOTE: If you want to make Construct() public and implement Purge() here, you'll have to free m_szBuffer there + // +private: + void Construct(const char *pString, const char **pSeparators, int nSeparators); + void PurgeAndDeleteElements(); +private: + char *m_szBuffer; // a copy of original string, with '\0' instead of separators +}; + + +#endif // CCVECTOR_H |