/** Resize block management by this constant.
As a result there are approx. 20 * MAXENTRY == 20000 entries available */ const sal_uInt16 nBlockGrowSize = 20;
#if OSL_DEBUG_LEVEL > 2 #define CHECKIDX( p, n, i, c ) CheckIdx( p, n, i, c ); void CheckIdx( BlockInfo** ppInf, sal_uInt16 nBlock, sal_Int32 nSize, sal_uInt16 nCur )
{
assert( !nSize || nCur < nBlock ); // BigPtrArray: CurIndex invalid
sal_Int32 nIdx = 0; for( sal_uInt16 nCnt = 0; nCnt < nBlock; ++nCnt, ++ppInf )
{
nIdx += (*ppInf)->nElem; // Array with holes is not allowed
assert( !nCnt || (*(ppInf-1))->nEnd + 1 == (*ppInf)->nStart );
}
assert(nIdx == nSize); // invalid count in nSize
} #else #define CHECKIDX( p, n, i, c ) #endif
// Also moving is done simply here. Optimization is useless because of the // division of this field into multiple parts. void BigPtrArray::Move( sal_Int32 from, sal_Int32 to )
{ if (from != to)
{
sal_uInt16 cur = Index2Block( from );
BlockInfo* p = m_ppInf[ cur ];
BigPtrEntry* pElem = p->mvData[ from - p->nStart ];
Insert( pElem, to ); // insert first, then delete!
ImplRemove( ( to < from ) ? ( from + 1 ) : from, 1, /*bClearElement*/false );
}
}
BigPtrEntry* BigPtrArray::operator[]( sal_Int32 idx ) const
{
assert(idx < m_nSize); // operator[]: Index out of bounds
m_nCur = Index2Block( idx );
BlockInfo* p = m_ppInf[ m_nCur ]; return p->mvData[ idx - p->nStart ];
}
/** Search a block at a given position */
sal_uInt16 BigPtrArray::Index2Block( sal_Int32 pos ) const
{ // last used block?
BlockInfo* p = m_ppInf[ m_nCur ]; if( p->nStart <= pos && p->nEnd >= pos ) return m_nCur; // Index = 0? if( !pos ) return0;
BlockInfo* p;
sal_uInt16 cur; if( !m_nSize )
{ // special case: insert first element
cur = 0;
p = InsBlock( cur );
} elseif( pos == m_nSize )
{ // special case: insert at end
cur = m_nBlock - 1;
p = m_ppInf[ cur ]; if( p->nElem == MAXENTRY ) // the last block is full, create a new one
p = InsBlock( ++cur );
} else
{ // standard case:
cur = Index2Block( pos );
p = m_ppInf[ cur ];
}
if( p->nElem == MAXENTRY )
{ // does the last entry fit into the next block?
BlockInfo* q; if( cur < ( m_nBlock - 1 ) && m_ppInf[ cur+1 ]->nElem < MAXENTRY )
{
q = m_ppInf[ cur+1 ]; if( q->nElem )
{ int nCount = q->nElem; auto pFrom = q->mvData.begin() + nCount; auto pTo = pFrom + 1; while( nCount-- )
{
*--pTo = *--pFrom;
++((*pTo)->m_nOffset);
}
}
q->nStart--;
q->nEnd--;
} else
{ // If it does not fit, then insert a new block. But if there is more // than 50% space in the array then compress first. if( /*nBlock == nMaxBlock &&*/
m_nBlock > ( m_nSize / ( MAXENTRY / 2 ) ) &&
cur >= Compress() )
{ // Something was moved before the current position and all // pointer might be invalid. Thus restart Insert.
Insert( pElem, pos ); return ;
}
q = InsBlock( cur+1 );
}
// entry does not fit anymore - clear space
BigPtrEntry* pLast = p->mvData[ MAXENTRY-1 ];
pLast->m_nOffset = 0;
pLast->m_pBlock = q;
q->mvData[ 0 ] = pLast;
q->nElem++;
q->nEnd++;
p->nEnd--;
p->nElem--;
} // now we have free space - insert
pos -= p->nStart;
assert(pos < MAXENTRY); if( pos != p->nElem )
{ int nCount = p->nElem - sal_uInt16(pos); auto pFrom = p->mvData.begin() + p->nElem; auto pTo = pFrom + 1; while( nCount-- )
{
*--pTo = *--pFrom;
++( *pTo )->m_nOffset;
}
} // insert element and update indices
pElem->m_nOffset = sal_uInt16(pos);
pElem->m_pBlock = p;
p->mvData[ pos ] = pElem;
p->nEnd++;
p->nElem++;
m_nSize++; if( cur != ( m_nBlock - 1 ) ) UpdIndex( cur );
m_nCur = cur;
void BigPtrArray::ImplReplace( sal_Int32 idx, BigPtrEntry* pElem, bool bClearElement)
{
assert(idx < m_nSize); // Index out of bounds
m_nCur = Index2Block( idx );
BlockInfo* p = m_ppInf[ m_nCur ];
pElem->m_nOffset = sal_uInt16(idx - p->nStart);
pElem->m_pBlock = p;
// clear the back-pointers from the old element back to element array. helps to flush out stale accesses. if (bClearElement)
{
p->mvData[idx - p->nStart]->m_pBlock = nullptr;
p->mvData[idx - p->nStart]->m_nOffset = 0;
}
// update with new element
p->mvData[ idx - p->nStart ] = pElem;
}
/** Speed up the complicated removal logic in SwNodes::RemoveNode. ReplacesthenodeAFTERpNotTheOne. ReturnstheentryBEFOREpNotTheOne.
*/
BigPtrEntry* BigPtrArray::ReplaceTheOneAfter( BigPtrEntry* pNotTheOne, BigPtrEntry* pNewEntry)
{
assert(pNotTheOne->m_pBlock->pBigArr == this);
BlockInfo* p = pNotTheOne->m_pBlock;
sal_uInt16 nOffset = pNotTheOne->m_nOffset;
// if the next node is inside the current block if (nOffset < p->nElem - 1)
{
++nOffset;
p->mvData[nOffset] = pNewEntry;
pNewEntry->m_nOffset = nOffset;
pNewEntry->m_pBlock = p;
--nOffset;
} else
{ // slow path
BigPtrArray::ImplReplace( pNotTheOne->GetPos()+1, pNewEntry, /*bClearElement*/false );
}
// if the previous node is inside the current block if (nOffset != 0)
{
--nOffset; return p->mvData[nOffset];
} else
{ // slow path
sal_Int32 nPrevPos = pNotTheOne->GetPos(); if (nPrevPos == 0) return nullptr; return BigPtrArray::operator[]( nPrevPos - 1 );
}
}
// Iterate over InfoBlock array from beginning to end. If there is a deleted // block in between so move all following ones accordingly. The pointer <pp> // represents the "old" and <qq> the "new" array.
BlockInfo** pp = m_ppInf.get(), **qq = pp;
BlockInfo* p;
BlockInfo* pLast(nullptr); // last empty block
sal_uInt16 nLast = 0; // missing elements
sal_uInt16 nBlkdel = 0; // number of deleted blocks
sal_uInt16 nFirstChgPos = USHRT_MAX; // at which position was the 1st change?
// convert fill percentage into number of remaining elements shortconst nMax = MAXENTRY - tools::Long(MAXENTRY) * COMPRESSLVL / 100;
for( sal_uInt16 cur = 0; cur < m_nBlock; ++cur )
{
p = *pp++;
sal_uInt16 n = p->nElem; // Check if a not completely full block will be ignored. This happens if // the current block would have to be split but the filling of the // inspected block is already over its threshold value. In this case we // do not fill more (it's expensive because of a double memmove() call) if( nLast && ( n > nLast ) && ( nLast < nMax ) )
nLast = 0; if( nLast )
{ if( USHRT_MAX == nFirstChgPos )
nFirstChgPos = cur;
// Not full yet? Then fill up. if( n > nLast )
n = nLast;
// move elements from current to last block auto pElem = pLast->mvData.begin() + pLast->nElem; auto pFrom = p->mvData.begin(); for( sal_uInt16 nCount = n, nOff = pLast->nElem;
nCount; --nCount, ++pElem )
{
*pElem = *pFrom++;
(*pElem)->m_pBlock = pLast;
(*pElem)->m_nOffset = nOff++;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.