//====== Copyright © 1996-2007, Valve Corporation, All rights reserved. ======= // // Purpose: // //============================================================================= #include "mdllib_utils.h" ////////////////////////////////////////////////////////////////////////// // // CInsertionTracker implementation // ////////////////////////////////////////////////////////////////////////// void CInsertionTracker::InsertBytes( void *pos, int length ) { if ( length <= 0 ) return; Assert( m_map.InvalidIndex() == m_map.Find( ( byte * ) pos ) ); m_map.InsertOrReplace( ( byte * ) pos, length ); } int CInsertionTracker::GetNumBytesInserted() const { int iInserted = 0; for ( Map::IndexType_t idx = m_map.FirstInorder(); idx != m_map.InvalidIndex(); idx = m_map.NextInorder( idx ) ) { int numBytes = m_map.Element( idx ); iInserted += numBytes; } return iInserted; } void CInsertionTracker::Finalize() { // Iterate the map and find all the adjacent removal data blocks // TODO: } void CInsertionTracker::MemMove( void *ptrBase, int &length ) const { int numBytesInsertReq = GetNumBytesInserted(); byte *pbBlockEnd = BYTE_OFF_PTR( ptrBase, length ); length += numBytesInsertReq; for ( Map::IndexType_t idx = m_map.LastInorder(); idx != m_map.InvalidIndex(); idx = m_map.PrevInorder( idx ) ) { byte *ptr = m_map.Key( idx ); int numBytes = m_map.Element( idx ); // Move [ptr, pbBlockEnd) ->> + numBytesInsertReq memmove( BYTE_OFF_PTR( ptr, numBytesInsertReq ), ptr, BYTE_DIFF_PTR( ptr, pbBlockEnd ) ); // Inserted data memset( BYTE_OFF_PTR( ptr, numBytesInsertReq - numBytes ), 0, numBytes ); numBytesInsertReq -= numBytes; pbBlockEnd = ptr; } } int CInsertionTracker::ComputeOffset( void *ptrBase, int off ) const { void *ptrNewBase = ComputePointer( ptrBase ); void *ptrNewData = ComputePointer( BYTE_OFF_PTR( ptrBase, off ) ); return BYTE_DIFF_PTR( ptrNewBase, ptrNewData ); } void * CInsertionTracker::ComputePointer( void *ptrNothingInserted ) const { int iInserted = 0; // Iterate the map and find all the data that would be inserted before the given pointer for ( Map::IndexType_t idx = m_map.FirstInorder(); idx != m_map.InvalidIndex(); idx = m_map.NextInorder( idx ) ) { if ( m_map.Key( idx ) < ptrNothingInserted ) iInserted += m_map.Element( idx ); else break; } return BYTE_OFF_PTR( ptrNothingInserted, iInserted ); } ////////////////////////////////////////////////////////////////////////// // // CMemoryMovingTracker implementation // ////////////////////////////////////////////////////////////////////////// void CMemoryMovingTracker::RegisterBytes( void *pos, int length ) { if ( length <= 0 && m_ePolicy != MEMORY_MODIFY ) return; // -- hint if ( m_map.Count() && m_ePolicy == MEMORY_REMOVE ) { if ( m_hint.ptr < pos ) { if ( BYTE_OFF_PTR( m_hint.ptr, m_hint.len ) == pos ) { m_hint.len += length; m_map.Element( m_hint.idx ) = m_hint.len; return; } } else if ( m_hint.ptr > pos ) { if ( BYTE_OFF_PTR( pos, length ) == m_hint.ptr ) { m_hint.len += length; m_hint.ptr = BYTE_OFF_PTR( m_hint.ptr, - length ); m_map.Key( m_hint.idx ) = m_hint.ptr; m_map.Element( m_hint.idx ) = m_hint.len; return; } } } // -- end hint // Insert new Assert( m_map.InvalidIndex() == m_map.Find( ( byte * ) pos ) ); Map::IndexType_t idx = m_map.InsertOrReplace( ( byte * ) pos, length ); // New hint m_hint.idx = idx; m_hint.ptr = ( byte * ) pos; m_hint.len = length; } int CMemoryMovingTracker::GetNumBytesRegistered() const { int iRegistered = 0; for ( Map::IndexType_t idx = m_map.FirstInorder(); idx != m_map.InvalidIndex(); idx = m_map.NextInorder( idx ) ) { int numBytes = m_map.Element( idx ); if ( m_ePolicy == MEMORY_MODIFY && numBytes <= 0 ) continue; iRegistered += numBytes; } return iRegistered; } void CMemoryMovingTracker::RegisterBaseDelta( void *pOldBase, void *pNewBase ) { for ( Map::IndexType_t idx = m_map.FirstInorder(); idx != m_map.InvalidIndex(); idx = m_map.NextInorder( idx ) ) { m_map.Key( idx ) = BYTE_OFF_PTR( m_map.Key( idx ), BYTE_DIFF_PTR( pOldBase, pNewBase ) ); } m_hint.ptr = BYTE_OFF_PTR( m_hint.ptr, BYTE_DIFF_PTR( pOldBase, pNewBase ) ); } void CMemoryMovingTracker::Finalize() { // Iterate the map and find all the adjacent removal data blocks // TODO: } void CMemoryMovingTracker::MemMove( void *ptrBase, int &length ) const { if ( m_ePolicy == MEMORY_REMOVE ) { int iRemoved = 0; for ( Map::IndexType_t idx = m_map.FirstInorder(); idx != m_map.InvalidIndex(); idx = m_map.NextInorder( idx ) ) { byte *ptr = m_map.Key( idx ); int numBytes = m_map.Element( idx ); byte *ptrDest = BYTE_OFF_PTR( ptr, - iRemoved ); memmove( ptrDest, BYTE_OFF_PTR( ptrDest, numBytes ), BYTE_DIFF_PTR( BYTE_OFF_PTR( ptr, numBytes ), BYTE_OFF_PTR( ptrBase, length ) ) ); iRemoved += numBytes; } length -= iRemoved; } if ( m_ePolicy == MEMORY_INSERT ) { for ( Map::IndexType_t idx = m_map.LastInorder(); idx != m_map.InvalidIndex(); idx = m_map.PrevInorder( idx ) ) { byte *ptr = m_map.Key( idx ); int numBytes = m_map.Element( idx ); byte *ptrDest = BYTE_OFF_PTR( ptr, numBytes ); memmove( ptrDest, ptr, BYTE_DIFF_PTR( ptr, BYTE_OFF_PTR( ptrBase, length ) ) ); length += numBytes; } } if ( m_ePolicy == MEMORY_MODIFY ) { // Perform insertions first: for ( Map::IndexType_t idx = m_map.LastInorder(); idx != m_map.InvalidIndex(); idx = m_map.PrevInorder( idx ) ) { byte *ptr = m_map.Key( idx ); int numBytes = m_map.Element( idx ); if ( numBytes <= 0 ) continue; // this is removal byte *ptrDest = BYTE_OFF_PTR( ptr, numBytes ); memmove( ptrDest, ptr, BYTE_DIFF_PTR( ptr, BYTE_OFF_PTR( ptrBase, length ) ) ); length += numBytes; } // Now perform removals accounting for all insertions // that has happened up to the moment int numInsertedToPoint = 0; int iRemoved = 0; for ( Map::IndexType_t idx = m_map.FirstInorder(); idx != m_map.InvalidIndex(); idx = m_map.NextInorder( idx ) ) { byte *ptr = m_map.Key( idx ); int numBytes = m_map.Element( idx ); if ( numBytes >= 0 ) { numInsertedToPoint += numBytes; continue; // this is insertion that already happened } numBytes = -numBytes; ptr = BYTE_OFF_PTR( ptr, numInsertedToPoint ); byte *ptrDest = BYTE_OFF_PTR( ptr, - iRemoved ); memmove( ptrDest, BYTE_OFF_PTR( ptrDest, numBytes ), BYTE_DIFF_PTR( BYTE_OFF_PTR( ptr, numBytes ), BYTE_OFF_PTR( ptrBase, length ) ) ); iRemoved += numBytes; } length -= iRemoved; } } int CMemoryMovingTracker::ComputeOffset( void *ptrBase, int off ) const { void *ptrNewBase = ComputePointer( ptrBase ); void *ptrNewData = ComputePointer( BYTE_OFF_PTR( ptrBase, off ) ); return BYTE_DIFF_PTR( ptrNewBase, ptrNewData ); } void * CMemoryMovingTracker::ComputePointer( void *ptrNothingRemoved ) const { int iAffected = 0; // Iterate the map and find all the data that would be removed/inserted before the given pointer for ( Map::IndexType_t idx = m_map.FirstInorder(); idx != m_map.InvalidIndex(); idx = m_map.NextInorder( idx ) ) { if ( m_map.Key( idx ) < ptrNothingRemoved ) iAffected += m_map.Element( idx ); else break; } if ( m_ePolicy == MEMORY_REMOVE ) return BYTE_OFF_PTR( ptrNothingRemoved, - iAffected ); if ( m_ePolicy == MEMORY_INSERT || m_ePolicy == MEMORY_MODIFY ) return BYTE_OFF_PTR( ptrNothingRemoved, iAffected ); return ptrNothingRemoved; }