//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1991 - 2001. // // File: ORCURSOR.CXX // // Contents: Merge Cursor. Computes union of multiple cursors. // // Classes: COrCursor // // History: 26-Sep-91 BartoszM Created // //---------------------------------------------------------------------------- #include #pragma hdrstop #include #include //+--------------------------------------------------------------------------- // // Member: COrCursor::COrCursor, public // // Synopsis: Create a sursor that merges a number of cursors. // // Arguments: [cCursor] -- count of cursors // [curStack] -- cursors to be merged // // History: 26-Sep-91 BartoszM Created // 14-Jul-92 KyleP Use max function for Rank // 22-Feb-93 KyleP Avoid divide-by-zero // // Notes: The cursors and the array will be deleted by destructor. // The cursors have to come from one index // //---------------------------------------------------------------------------- COrCursor::COrCursor( int cCursor, CCurStack& curStack ) : _lMaxWeight( 0 ), _iCur( 0 ), _wid( widInvalid ) { // Two step construction of the heap. // We have to make sure that all cursors have a valid key int count = 0; CCursor** aCursor = curStack.AcqStack(); // remove empty cursors for ( int i = 0; i < cCursor; i++ ) { Win4Assert ( aCursor[i] != 0 ); if ( aCursor[i]->WorkId() == widInvalid ) { delete aCursor[i]; } else { _lMaxWeight = max( _lMaxWeight, aCursor[i]->GetWeight() ); if ( count != i ) aCursor[count++] = aCursor[i]; else count++; } } // // Avoid divide-by-zero // if ( _lMaxWeight == 0 ) _lMaxWeight = 1; _widHeap.MakeHeap ( count, aCursor ); if ( !_widHeap.IsEmpty() ) { CCursor & cursor = * _widHeap.Top(); _wid = cursor.WorkId(); _iid = cursor.IndexId(); _pid = cursor.Pid(); } } //+--------------------------------------------------------------------------- // // Member: COrCursor::WorkId, public // // Synopsis: Get current work id. // // History: 26-Sep-91 BartoszM Created // //---------------------------------------------------------------------------- WORKID COrCursor::WorkId() { return _wid; } //+--------------------------------------------------------------------------- // // Member: COrCursor::NextWorkId, public // // Synopsis: Move to next work id // // Returns: Target work id or widInvalid if no more wid's for current key // // History: 26-Sep-91 BartoszM Created // //---------------------------------------------------------------------------- WORKID COrCursor::NextWorkId() { if ( widInvalid == _wid ) return widInvalid; WORKID widNew; do { _widHeap.Top()->NextWorkId(); _widHeap.ReheapKey(); widNew = _widHeap.Top()->WorkId(); } while ( widNew == _wid ); _wid = widNew; return _wid; } //+--------------------------------------------------------------------------- // // Member: COrCursor::WorkIdCount, public // // Synopsis: return wid count // // History: 26-Sep-91 BartoszM Created // // Notes: 1. Sum up wid count of all cursors in widHeap // //---------------------------------------------------------------------------- ULONG COrCursor::WorkIdCount() { Win4Assert (( FALSE && "OrCursor::WorkIdCount called" )); return(0); } //+--------------------------------------------------------------------------- // // Member: COrCursor::HitCount, public // // Synopsis: return occurrence count // // History: 28-Feb-92 AmyA Created // // Notes: returns the occurrence count for the wid on top of _widHeap. // //---------------------------------------------------------------------------- ULONG COrCursor::HitCount() { if ( widInvalid == _wid ) return 0; ULONG hitCnt = 0; CCursor **vector = _widHeap.GetVector(); int count = _widHeap.Count(); for (int i=0; i < count; i++) { if ( vector[i]->WorkId() == _wid ) hitCnt += vector[i]->HitCount(); } return hitCnt; } //+--------------------------------------------------------------------------- // // Member: COrCursor::RatioFinished, public // // Synopsis: return approximate ratio of documents processed to total // documents. // // Notes: The ratio, while approximate, should not return 1/1 until // all cursors are exhausted. // //---------------------------------------------------------------------------- void COrCursor::RatioFinished (ULONG& denom, ULONG& num) { if ( widInvalid == _wid ) { denom = num = 1; return; } CCursor **vector = _widHeap.GetVector(); int count = _widHeap.Count(); unsigned cValid = 1; denom = 0; num = 0; for (int i=0; i < count; i++) { ULONG d, n; vector[i]->RatioFinished(d, n); Win4Assert( n <= d && d > 0 ); num += n; denom += d; Win4Assert( d <= denom ); // overflow? if (n == d) { WORKID widCurrent = vector[i]->WorkId(); if (widCurrent != widInvalid && widCurrent != _wid) cValid++; } } if (num == denom && cValid > 1) denom++; } //+--------------------------------------------------------------------------- // // Member: COrCursor::Rank, public // // Synopsis: returns a rank (turns the OrCursor into a Quorum Cursor) // // History: 13-Apr-92 AmyA Created // 23-Jun-92 MikeHew Added Weighting // 14-Jul-92 KyleP Use max function for Rank // // Notes: See "Automatic Text Processing", G. Salton, 10.4.2 for // a discussion of the weight formula. // //---------------------------------------------------------------------------- LONG COrCursor::Rank() { if ( widInvalid == _wid ) return 0; LONG lRank = 0; CCursor **vector = _widHeap.GetVector(); int cCur = _widHeap.Count(); for ( int i = 0; i < cCur; i++ ) { if ( vector[i]->WorkId() == _wid ) { LONG lNew = vector[i]->Rank() * vector[i]->GetWeight(); lRank = max( lRank, lNew ); } } // // Normalize weight. // lRank = lRank / _lMaxWeight; return ( lRank ); } //+--------------------------------------------------------------------------- // // Member: COrCursor::Hit, public // // Synopsis: Hits current child (indexed by _iCur) // Moves onto next child if empty. // // History: 07-Sep-92 MikeHew Created // // Notes: Hit() should not be called more than once, except by // NextHit() // //---------------------------------------------------------------------------- LONG COrCursor::Hit() { int cCur = _widHeap.Count(); CCursor ** aCur = _widHeap.GetVector(); Win4Assert( _iCur < cCur ); LONG rank = aCur[_iCur]->Hit(); // if this cursor is empty, find one that's not while ( rank == rankInvalid && ++_iCur < cCur ) { rank = aCur[_iCur]->Hit(); } return rank; } //+--------------------------------------------------------------------------- // // Member: COrCursor::NextHit, public // // Synopsis: NextHits current child (indexed by _iCur) // If current child becomes empty, increments _iCur // // History: 07-Sep-92 MikeHew Created // // Notes: NextHit() should not be called after returning rankInvalid // //---------------------------------------------------------------------------- LONG COrCursor::NextHit() { int cCur = _widHeap.Count(); CCursor ** aCur = _widHeap.GetVector(); Win4Assert( _iCur < cCur ); LONG rank = aCur[_iCur]->NextHit(); if ( rank == rankInvalid ) { if ( ++_iCur < cCur ) { return Hit(); } } return rank; }