You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
273 lines
6.2 KiB
273 lines
6.2 KiB
//====== Copyright © 1996-2009, Valve Corporation, All rights reserved. =======//
|
|
#ifndef INCREMENTAL_VECTOR_H
|
|
#define INCREMENTAL_VECTOR_H
|
|
|
|
// this class facilitates an array of pointers that get added and removed frequently;
|
|
// it's intrusive: the class that is pointed to must contain and maintain an index
|
|
#include "tier1/utlvector.h"
|
|
|
|
template < class CLASS >
|
|
struct DefaultIncrementalVectorAccessor_t
|
|
{
|
|
static int GetIndex( const CLASS * p ) { return p->m_nIncrementalVectorIndex; }
|
|
static void SetIndex( CLASS * p, int nIndex ) { p->m_nIncrementalVectorIndex = nIndex; }
|
|
};
|
|
|
|
|
|
template <class T, class Accessor = DefaultIncrementalVectorAccessor_t< T > , class Allocator = CUtlMemory< T* > >
|
|
class CUtlIncrementalVector
|
|
{
|
|
public:
|
|
T** Base(){ return m_data.Base(); }
|
|
T*const* Base()const{ return m_data.Base(); }
|
|
typedef T* ElemType_t;
|
|
typedef T** iterator;
|
|
typedef T*const* const_iterator;
|
|
enum { IsUtlVector = true }; // Used to match this at compiletime
|
|
|
|
iterator begin() { return Base(); }
|
|
const_iterator begin() const { return Base(); }
|
|
iterator end() { return Base() + Count(); }
|
|
const_iterator end() const { return Base() + Count(); }
|
|
|
|
void SetCountAndCreateOrDelete( int nNewCount )
|
|
{
|
|
int nOldCount = Count();
|
|
for( int i = nNewCount; i < nOldCount; ++i )
|
|
{
|
|
delete m_data[i];
|
|
}
|
|
m_data.SetCount( nNewCount );
|
|
for( int i = nOldCount; i < nNewCount; ++i )
|
|
{
|
|
m_data[i] = new T;
|
|
Accessor::SetIndex( m_data[i], i );
|
|
}
|
|
Validate();
|
|
}
|
|
|
|
int Count() const
|
|
{
|
|
return m_data.Count();
|
|
}
|
|
|
|
T* operator[]( int i )
|
|
{
|
|
Assert( !m_data[i] || Accessor::GetIndex( m_data[i] ) == i );
|
|
return m_data[i];
|
|
}
|
|
|
|
const T* operator[]( int i )const
|
|
{
|
|
Assert( !m_data[i] || Accessor::GetIndex( m_data[i] ) == i );
|
|
return m_data[i];
|
|
}
|
|
|
|
void SetElementToNull( int i )
|
|
{
|
|
m_data[ i ] = NULL;
|
|
}
|
|
|
|
T* AddToTail( T* p )
|
|
{
|
|
Validate();
|
|
Accessor::SetIndex( p, m_data.Count() );
|
|
m_data.AddToTail( p );
|
|
Validate();
|
|
return p;
|
|
}
|
|
|
|
void MoveToHead( T *pMid )
|
|
{
|
|
Validate();
|
|
int nMidIndex = Accessor::GetIndex( pMid );
|
|
Accessor::SetIndex( pMid, 0 );
|
|
T *pHead = m_data[0];
|
|
Accessor::SetIndex( pHead, nMidIndex );
|
|
m_data[0] = pMid;
|
|
m_data[nMidIndex] = pHead;
|
|
Validate();
|
|
}
|
|
|
|
void SwapItems( int i1, int i2 )
|
|
{
|
|
Validate();
|
|
T *p1 = m_data[i1];
|
|
T *p2 = m_data[i2];
|
|
|
|
Accessor::SetIndex( p1, i2 );
|
|
Accessor::SetIndex( p2, i1 );
|
|
m_data[i1] = p2;
|
|
m_data[i2] = p1;
|
|
Validate();
|
|
}
|
|
|
|
void InsertNewMultipleBefore( int nIndex, int nCount )
|
|
{
|
|
if( nCount )
|
|
{
|
|
for( int i = nIndex; i < m_data.Count(); ++i )
|
|
{
|
|
T *pElement = m_data[i];
|
|
Accessor::SetIndex( pElement, Accessor::GetIndex( pElement ) + nCount );
|
|
}
|
|
m_data.InsertMultipleBefore( nIndex, nCount );
|
|
for( int i = 0; i < nCount; ++i )
|
|
{
|
|
T *p = new T;
|
|
Accessor::SetIndex( p, nIndex + i );
|
|
m_data[ nIndex + i ] = p;
|
|
}
|
|
}
|
|
}
|
|
void RemoveAndDeleteMultiple( int nIndex, int nCount )
|
|
{
|
|
if( nCount )
|
|
{
|
|
for( int i = nIndex, nEnd = MIN( nIndex + nCount, m_data.Count() ); i < nEnd; ++i )
|
|
{
|
|
delete m_data[i];
|
|
}
|
|
m_data.RemoveMultiple( nIndex, nCount );
|
|
for ( int i = nIndex; i < m_data.Count(); ++i )
|
|
{
|
|
Accessor::SetIndex( m_data[ i ], i );
|
|
}
|
|
}
|
|
}
|
|
|
|
void RemoveMultiple( int nIndex, int nCount )
|
|
{
|
|
if ( nCount )
|
|
{
|
|
m_data.RemoveMultiple( nIndex, nCount );
|
|
for ( int i = nIndex; i < Count(); ++i )
|
|
{
|
|
Accessor::SetIndex( m_data[ i ], i );
|
|
}
|
|
}
|
|
}
|
|
void RemoveMultipleFromHead( int num )
|
|
{
|
|
if ( num )
|
|
{
|
|
m_data.RemoveMultipleFromHead( num );
|
|
for ( int i = 0; i < Count(); ++i )
|
|
{
|
|
Accessor::SetIndex( m_data[ i ], i );
|
|
}
|
|
}
|
|
}
|
|
|
|
void RemoveAndDelete( int nIndex ) ///< preserves order, shifts elements
|
|
{
|
|
if( nIndex < Count() )
|
|
{
|
|
delete m_data[nIndex];
|
|
for( int i = nIndex + 1; i < Count(); ++i )
|
|
{
|
|
Accessor::SetIndex( m_data[ i ], i - 1 );
|
|
m_data[ i - 1 ] = m_data[ i ];
|
|
}
|
|
m_data.RemoveMultipleFromTail( 1 );
|
|
}
|
|
}
|
|
|
|
void FastRemove( int elem ) // doesn't preserve order
|
|
{
|
|
Validate();
|
|
//T* pDeletable = m_data[elem];
|
|
T* pLast = m_data.Tail(); // Optimization Warning: pLast and pDelete pointers are aliased
|
|
m_data[elem] = pLast;
|
|
m_data.RemoveMultipleFromTail( 1 );
|
|
Accessor::SetIndex( pLast, elem );
|
|
// Accessor::SetIndex( pDeletable, -1 ); // this is not really necessary, except for debugging; there's also a danger that client deleted the object before calling FastRemove
|
|
Validate();
|
|
}
|
|
T* FindAndFastRemove( T* p ) // removes first occurrence of src, doesn't preserve order
|
|
{
|
|
int nIndex = Accessor::GetIndex( p );
|
|
Assert( m_data[nIndex] == p );
|
|
FastRemove( nIndex );
|
|
return p;
|
|
}
|
|
|
|
int Find( const T* p )const
|
|
{
|
|
int nIndex = Accessor::GetIndex( p );
|
|
if ( uint( nIndex ) < uint( Count() ) && m_data[ nIndex ] == p )
|
|
return nIndex;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
bool Has( const T *p )const
|
|
{
|
|
int nIndex = Accessor::GetIndex( p );
|
|
return uint( nIndex ) < uint( Count() ) && m_data[ nIndex ] == p;
|
|
}
|
|
|
|
void FastRemoveAndDelete( T* p )
|
|
{
|
|
int nIndex = Accessor::GetIndex( p );
|
|
FastRemove( nIndex );
|
|
delete p;
|
|
}
|
|
|
|
void PurgeAndDeleteElements()
|
|
{
|
|
Validate();
|
|
m_data.PurgeAndDeleteElements();
|
|
}
|
|
|
|
inline void Validate()
|
|
{
|
|
#if defined( DBGFLAG_ASSERT ) && defined( _DEBUG )
|
|
for( int i =0 ;i < Count(); ++i )
|
|
{
|
|
Assert( !m_data[i] || Accessor::GetIndex( m_data[i] ) == i );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void Purge()
|
|
{
|
|
m_data.Purge();
|
|
}
|
|
|
|
bool IsEmpty()const
|
|
{
|
|
return m_data.IsEmpty();
|
|
}
|
|
|
|
T *Tail()
|
|
{
|
|
return m_data.Tail();
|
|
}
|
|
|
|
void EnsureCapacity( int nCap )
|
|
{
|
|
m_data.EnsureCapacity( nCap );
|
|
}
|
|
|
|
void Sort( int (__cdecl *pfnCompare)(const ElemType_t *, const ElemType_t *) )
|
|
{
|
|
m_data.Sort( pfnCompare );
|
|
for( int i = 0; i < m_data.Count(); ++i )
|
|
{
|
|
Accessor::SetIndex( m_data[i], i );
|
|
}
|
|
}
|
|
protected:
|
|
CUtlVector< T*, Allocator > m_data;
|
|
};
|
|
|
|
#define DECLARE_INCREMENTAL_VECTOR_TYPE(CLASS, MEMBER) \
|
|
struct CLASS##_##NAME##_IncrementalVectorAccessor_t \
|
|
{ \
|
|
static int GetIndex( const CLASS * p ) { return p->MEMBER; } \
|
|
static void SetIndex( const CLASS * p, int nIndex ) { p->MEMBER = nIndex; } \
|
|
}; \
|
|
typedef CUtlIncrementalVector < CLASS, CLASS##_##NAME##_IncrementalVectorAccessor_t >
|
|
|
|
#endif
|