csgo-2018-source/public/tier1/utlincrementalvector.h
2021-07-24 21:11:47 -07:00

273 lines
6.2 KiB
C++

//====== 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