//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 2000. // // File: sglookup.cxx // // Contents: A class for doing a quick lookup of a segment based on the // key. It will do a binary search and locate the segment. // This is useful for doing row insertions into a large table // when keys are not coming in any specific order. // // Classes: CSegmentArrray // // History: 10-20-95 srikants Created // //---------------------------------------------------------------------------- #include "pch.cxx" #pragma hdrstop #include #include #include "tabledbg.hxx" //+--------------------------------------------------------------------------- // // Member: CSegmentArray consructor // // Synopsis: Initializes the segment array // // History: 10-20-95 srikants Created // //---------------------------------------------------------------------------- CSegmentArray::CSegmentArray() : CDynArrayInPlace(eMinSegments), _pComparator(0), _iHint(0) { } //+--------------------------------------------------------------------------- // // Member: CSegmentArray::_FindSegment // // Synopsis: Given a segment pointer, it searches for the segment in the // array and returns the index in the array. // // Arguments: [pSeg] - Segment to look for. // // Returns: Index in the array if the segment is located. // -1 otherwise. // // History: 10-25-95 srikants Created // //---------------------------------------------------------------------------- int CSegmentArray::_FindSegment( const CTableSegment * pSeg ) { Win4Assert( 0 != pSeg ); // // Optimization - use the last returned segment index as a hint // if ( _iHint < Count() && Get(_iHint) == pSeg ) return (int) _iHint; for ( unsigned i = 0; i < Count(); i++ ) { if ( Get(i) == pSeg ) { _iHint = i; return (int) i; } } // // The segment could not be located. // _iHint = 0; return -1; } //+--------------------------------------------------------------------------- // // Member: CSegmentArray::LookUp // // Synopsis: Looks up the segment which is likely to contain the given // key or is a candidate to insert the given key. // // Arguments: [key] - Key to look up. // // Returns: The segment pointer where to look for/insert the given key. // 0 if there are no segments // // History: 10-20-95 srikants Created // // Notes: Please note that each segment has only the "smallest" key in // that segment. We don't know anything about the highest key in // that segment. if we two adjacent segments with lowest keys // k1 and k3 and a new key if k1 < k2 < k3, // k2 will end up in segment 1 // //---------------------------------------------------------------------------- CTableSegment * CSegmentArray::LookUp( CTableRowKey & key ) { Win4Assert( 0 != _pComparator ); int cSegs = (int) Count(); if ( 0 == cSegs ) return 0; int iLow = 0; int iHigh = cSegs - 1; int iMid = iHigh/2; int iComp = 0; while ( iLow <= iHigh ) { iMid = (iLow + iHigh)/2; CTableSegment * pCurrSeg = Get( (unsigned) iMid ); iComp = _pComparator->Compare( key, pCurrSeg->GetLowestKey() ); if ( 0 == iComp ) return pCurrSeg; if ( iComp > 0 ) // key is bigger than the smallest key in the seg iLow = iMid+1; else // key is < the smallest key in the seg iHigh = iMid-1; } Win4Assert( iLow > iHigh ); int iGet = 0; if ( iMid > iHigh ) { Win4Assert( iLow == iMid ); Win4Assert( iComp < 0 ); iGet = iHigh >= 0 ? iHigh : 0; } else { Win4Assert( iMid == iHigh ); Win4Assert( iMid < iLow && iMid < cSegs ); iGet = iMid; } return Get( (unsigned) iGet ); } //+--------------------------------------------------------------------------- // // Member: CSegmentArray::Append // // Synopsis: Adds the given segment to the end of the array. // // Arguments: [pSeg] - Segment to be appended. // // History: 10-20-95 srikants Created // //---------------------------------------------------------------------------- void CSegmentArray::Append( CTableSegment * pSeg ) { Win4Assert( 0 != pSeg ); Win4Assert( !IsFound(pSeg) ); Add( pSeg, Count() ); } //+--------------------------------------------------------------------------- // // Member: CSegmentArray::InsertAfter // // Synopsis: Inserts the given segment after the marker segment // // Arguments: [pMarker] - Segment already present in the array. // [pSeg] - New segment to be inserted. // // History: 10-20-95 srikants Created // //---------------------------------------------------------------------------- void CSegmentArray::InsertAfter( const CTableSegment * pMarker, CTableSegment * pSeg ) { Win4Assert( 0 != pSeg ); Win4Assert( !IsFound(pSeg) ); Win4Assert( 0 != pMarker ); int iMarker = _FindSegment( pMarker ); Win4Assert( iMarker >= 0 ); Insert( pSeg, (unsigned)iMarker+1 ); } //+--------------------------------------------------------------------------- // // Member: CSegmentArray::InsertBefore // // Synopsis: Inserts the given segment "before" the marker segment // // Arguments: [pMarker] - The segment before which the new segment must // be inserted. If NULL, the given segment will be added as // the first segment in the array. // // [pSeg] - The new segment // // History: 10-20-95 srikants Created // //---------------------------------------------------------------------------- void CSegmentArray::InsertBefore( const CTableSegment * pMarker, CTableSegment * pSeg ) { Win4Assert( 0 != pSeg ); Win4Assert( !IsFound(pSeg) ); if ( 0 != pMarker ) { int iPos = _FindSegment( pMarker ); Win4Assert( iPos >= 0 ); Insert( pSeg, (unsigned) iPos ); } else { Insert( pSeg, 0 ); // make this the first in the array } } //+--------------------------------------------------------------------------- // // Member: CSegmentArray::Replace // // Synopsis: Replaces the old segment with the new segment // // Arguments: [pOld] - // [pNew] - // // History: 10-20-95 srikants Created // //---------------------------------------------------------------------------- void CSegmentArray::Replace( const CTableSegment * pOld, CTableSegment * pNew ) { Win4Assert( 0 != pOld && 0 != pNew ); int iPos = _FindSegment( pOld ); Win4Assert( iPos >= 0 ); Win4Assert( !IsFound( pNew ) ); Add( pNew, (unsigned) iPos ); } //+--------------------------------------------------------------------------- // // Member: CSegmentArray::_MoveEntries // // Synopsis: Moves entries from the specified offset by the given number // of entries.. // // Arguments: [iStart] - Starting offset to move // [cEntries] - Number of entries to move by. // // History: 10-20-95 srikants Created // //---------------------------------------------------------------------------- void CSegmentArray::_MoveEntries( unsigned iStart, unsigned cEntries ) { Win4Assert( iStart < _count ); if ( 0 == cEntries ) return; Win4Assert( cEntries + _count <= Size() ); unsigned iNewPos = iStart + cEntries; memmove( _aItem + iNewPos, _aItem + iStart, (_count - iStart) * sizeof(CTableSegment *) ); _count += cEntries; #if CIDBG==1 // // The caller can asser that the moved entries are all NULL. // for ( unsigned i = iStart; i < iNewPos; i++ ) { _aItem[i] = 0; } #endif // CIDBG==1 } //+--------------------------------------------------------------------------- // // Member: CSegmentArray::Replace // // Synopsis: Removes "pOld" from the list and inserts the new list of // segments in its place. // // Arguments: [pOld] - // [segList] - // // History: 10-20-95 srikants Created // //---------------------------------------------------------------------------- void CSegmentArray::Replace( const CTableSegment * pOld, CTableSegList & segList ) { unsigned cSegsToInsert = segList.GetSegmentsCount(); if ( cSegsToInsert == 0 ) { RemoveEntry( pOld ); return; } int iSeg = _FindSegment( pOld ); Win4Assert( iSeg >= 0 ); unsigned iInsert = (unsigned) iSeg; // // Replace the current segment with the first one in the list // CFwdTableSegIter iter( segList ); Win4Assert ( !segList.AtEnd(iter) ); _aItem[iInsert++] = iter.GetSegment(); segList.Advance(iter); cSegsToInsert--; if ( !segList.AtEnd(iter) ) { Win4Assert( cSegsToInsert > 0 ); // // There is more than one segment to replace with. We should // iterate and move them. // unsigned cTotalSegs = _count + cSegsToInsert; // // Grow the array if necessary. // if ( (cTotalSegs-1) >= _size ) _GrowToSize( cTotalSegs-1 ); if ( iInsert != _count ) { Win4Assert( iInsert < _count ); _MoveEntries( iInsert, cSegsToInsert ); } else { // // We are just appending at the end. No need to move anything // #if CIDBG==1 for ( unsigned i = _count; i < cTotalSegs; i++ ) { _aItem[i] = 0; } #endif // CIDBG==1 _count +=cSegsToInsert; Win4Assert( _count == cTotalSegs ); } for ( ; !segList.AtEnd(iter); segList.Advance(iter) ) { #if CIDBG==1 // // We are either appending to the end or the entries got moved // and nullified. // Win4Assert( 0 == _aItem[iInsert] ); #endif // CIDBG==1 Win4Assert( !IsFound(iter.GetSegment()) ); _aItem[iInsert++] = iter.GetSegment(); } } } //+--------------------------------------------------------------------------- // // Member: CSegmentArray::RemoveEntry // // Synopsis: Removes the specified segment from the array. // // Arguments: [pSeg] - // // History: 10-20-95 srikants Created // //---------------------------------------------------------------------------- void CSegmentArray::RemoveEntry( const CTableSegment * pSeg ) { int iSeg = _FindSegment( pSeg ); Win4Assert( iSeg >= 0 ); Remove( (unsigned) iSeg ); } #if CIDBG==1 //+--------------------------------------------------------------------------- // // Member: CSegmentArray::TestInSync // // Synopsis: Tests that the list and the array are fully in sync. // // Arguments: [list] - The global list of segments // // History: 10-25-95 srikants Created // //---------------------------------------------------------------------------- void CSegmentArray::TestInSync( CTableSegList & list ) { if ( Count() != list.GetSegmentsCount() ) { tbDebugOut(( DEB_ERROR, "Array Count = 0x%X ListCount = 0x%X \n", Count(), list.GetSegmentsCount() )); Win4Assert( !"Array Count and List Count Not In Sync" ); return; } unsigned i = 0; for ( CFwdTableSegIter iter(list); !list.AtEnd(iter); list.Advance(iter) ) { if ( iter.GetSegment() != Get(i) ) { tbDebugOut(( DEB_ERROR, "iter.GetSegment() = 0x%X : i = 0x%X : Array[i] = 0x%X\n", iter.GetSegment(), i, Get(i) )); Win4Assert( !"List and Array are not in sync" ); } i++; } } #endif // CIDBG==1