//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1995 - 1998 // // File: RowHeap.cxx // // Contents: Heap of rowsets. // // Classes: CRowHeap // // History: 05-Jun-95 KyleP Created // 14-JAN-97 KrishnaN Undefined CI_INETSRV and related changes // //---------------------------------------------------------------------------- #include #pragma hdrstop #include "rowheap.hxx" //+--------------------------------------------------------------------------- // // Member: CRowHeap::CRowHeap, public // // Synopsis: Constructor. // // Arguments: [cCursor] -- Max number of elements in heap. // // History: 05-Jun-95 KyleP Created. // //---------------------------------------------------------------------------- CRowHeap::CRowHeap( unsigned cCursor ) : _ahrowTop( cCursor ), _cCursor( cCursor ) { END_CONSTRUCTION( CRowHeap ); } //+--------------------------------------------------------------------------- // // Member: CRowHeap::Init, public // // Synopsis: Create heap. // // Arguments: [pComparator] -- Used to compare elements. // [apCursor] -- Heap created from these. // // History: 05-Jun-95 KyleP Created. // //---------------------------------------------------------------------------- void CRowHeap::Init( CRowComparator * pComparator, PMiniRowCache ** apCursor ) { _pComparator = pComparator; _apCursor = apCursor; // // Move invalid cursors to end. // int cValid = _cCursor; for ( int i = 0; i < cValid; i++ ) { if ( _apCursor[i]->IsAtEnd() ) { cValid--; PMiniRowCache * pTemp = _apCursor[i]; _apCursor[i] = _apCursor[cValid]; _apCursor[cValid] = pTemp; i--; } } // // And create a heap out of the rest. // MakeHeap( cValid ); } //+--------------------------------------------------------------------------- // // Member: CRowHeap::ReInit, public // // Synopsis: Recreate heap. // // Arguments: [cValid] -- Number of valid cursors. Others to end. // // History: 05-Jun-95 KyleP Created. // //---------------------------------------------------------------------------- void CRowHeap::ReInit( int cValid ) { MakeHeap( cValid ); } //+--------------------------------------------------------------------------- // // Member: CRowHeap::Validate, public // // Synopsis: See notes. // // Returns: State of heap. // // History: 05-Jun-95 KyleP Created. // // Notes: There are times when iteration stopped because some cursor // couldn't continue (usually for block-limited rows, or // some error condition). When this situation occurs, Validate // must be called to reset the heap. // //---------------------------------------------------------------------------- PMiniRowCache::ENext CRowHeap::Validate() { if ( !IsHeapEmpty() && Top()->IsAtEnd() ) return Next(); else return PMiniRowCache::Ok; } //+--------------------------------------------------------------------------- // // Member: CRowHeap::AdjustCacheSize, public // // Synopsis: Adjust size of row cache(s). // // Arguments: [cRows] -- Total number of rows to cache. // // History: 05-Jun-95 KyleP Created. // //---------------------------------------------------------------------------- void CRowHeap::AdjustCacheSize( ULONG cRows ) { if ( Count() > 0 ) { ULONG cRowsPerCursor = 1 + cRows / Count(); if ( cRowsPerCursor != Top()->CacheSize() ) { for ( int i = 0; i < _cCursor; i++ ) _apCursor[i]->SetCacheSize( cRowsPerCursor ); } } } //+--------------------------------------------------------------------------- // // Member: CRowHeap::Next, public // // Synopsis: Move to next element. // // Returns: State of heap. Move occurred only if PMiniRowCache::Ok. // // History: 05-Jun-95 KyleP Created. // //---------------------------------------------------------------------------- PMiniRowCache::ENext CRowHeap::Next( int iDir /* = 1 */ ) { PMiniRowCache::ENext next = Top()->Next( iDir ); if ( PMiniRowCache::NotNow == next ) return next; if ( PMiniRowCache::EndOfRows == next ) { RemoveTop(); if ( IsHeapEmpty() ) return next; next = PMiniRowCache::Ok; } _ahrowTop[Top()->Index()] = Top()->GetHROW(); Reheap(); return next; } //+--------------------------------------------------------------------------- // // Member: CRowHeap::NthToTop, public // // Effects: Moves Nth element of heap to top. // // Arguments: [n] -- Nth element of heap. // // History: 23-Jun-95 KyleP Created. // // Notes: This is different from CRowHeap::Next, because the caches // themselves are not touched. It is used for approximate // positioning. // // This is a destructive function! Elements are removed from // the heap. // //---------------------------------------------------------------------------- void CRowHeap::NthToTop( unsigned n ) { for ( ; n > 0; n-- ) { RemoveTop(); Reheap(); } } //+--------------------------------------------------------------------------- // // Member: CRowHeap::Add, public // // Synopsis: Add element to heap. // // Arguments: [pCursor] -- Cursor to add. // // History: 05-Jun-95 KyleP Created. // //---------------------------------------------------------------------------- void CRowHeap::Add( PMiniRowCache * pCursor ) { // // Special case: empty cursor. // if ( pCursor->IsAtEnd() ) { _ahrowTop[pCursor->Index()] = (HROW)-1; return; } _iEnd++; _ahrowTop[pCursor->Index()] = pCursor->GetHROW(); // // Special case: empty heap. // if ( 0 == _iEnd ) { _apCursor[0] = pCursor; return; } int child, parent; for ( child = _iEnd, parent = (_iEnd-1)/2; child > 0; child=parent, parent = (parent-1)/2) { if ( !_pComparator->IsLT( pCursor->GetData(), pCursor->DataLength(), pCursor->Index(), _apCursor[parent]->GetData(), _apCursor[parent]->DataLength(), _apCursor[parent]->Index() ) ) break; _apCursor[child] = _apCursor[parent]; } _apCursor[child] = pCursor; } //+--------------------------------------------------------------------------- // // Member: CRowHeap::Reheap, private // // Synopsis: 'Heapify'. Called when top element (only!) has changed. // // History: 05-Jun-95 KyleP Created. // //---------------------------------------------------------------------------- void CRowHeap::Reheap() { PMiniRowCache * root_item = _apCursor[0]; int parent, child; for ( parent = 0, child = 1; child <= _iEnd; parent = child, child = 2 * child + 1 ) { if ( child < _iEnd && _pComparator->IsLT( _apCursor[child+1]->GetData(), _apCursor[child+1]->DataLength(), _apCursor[child+1]->Index(), _apCursor[child]->GetData(), _apCursor[child]->DataLength(), _apCursor[child]->Index() ) ) { child++; } if ( !_pComparator->IsLT( _apCursor[child]->GetData(), _apCursor[child]->DataLength(), _apCursor[child]->Index(), root_item->GetData(), root_item->DataLength(), root_item->Index() ) ) { break; } _apCursor[parent] = _apCursor[child]; } _apCursor[parent] = root_item; # if CIDBG == 1 AssertCursorArrayIsValid(); # endif } //+--------------------------------------------------------------------------- // // Member: CRowHeap::MakeHeap, private // // Synopsis: 'Heapify'. Called when all elements have changed. // // Arguments: [cValid] -- Number of valid cursors, all positioned toward // beginning of array. // // History: 05-Jun-95 KyleP Created. // //---------------------------------------------------------------------------- void CRowHeap::MakeHeap( int cValid ) { _iEnd = -1; for ( int i = 0; i < cValid; i++ ) Add( _apCursor[i] ); for ( i = cValid; i < _cCursor; i++ ) _ahrowTop[_apCursor[i]->Index()] = (HROW)-1; # if CIDBG == 1 AssertCursorArrayIsValid(); # endif } #if CIDBG == 1 void CRowHeap::AssertCursorArrayIsValid() { for ( int i = 0; i < _cCursor; i++ ) for ( int j = i+1; j < _cCursor; j++ ) { if ( _apCursor[i] == _apCursor[j] ) { vqDebugOut(( DEB_ERROR, "Invalid rowheap: _apCursor[%d] (0x%x) == _apCursor[%d] (0x%x)\n", i, _apCursor[i], j, _apCursor[j] )); Win4Assert( _apCursor[i] != _apCursor[j] ); } } } #endif // CIDBG == 1