|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1991 - 2000.
//
// File: ANDCUR.CXX
//
// Contents: And Cursor. Computes intersection of multiple cursors.
//
// Classes: CAndCursor
//
// History: 24-May-91 BartoszM Created.
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include "andcur.hxx"
#pragma optimize( "t", on )
//+---------------------------------------------------------------------------
//
// Member: CAndCursor::CAndCursor, public
//
// Synopsis: Create a cursor that merges a number of cursors.
//
// Arguments: [cCursor] -- count of cursors
// [curStack] -- cursors to merge
//
// Notes: All cursors must come from the same index
// and the same property
//
// History: 24-May-91 BartoszM Created
// 22-Feb-93 KyleP Avoid divide-by-zero
//
//----------------------------------------------------------------------------
CAndCursor::CAndCursor( unsigned cCursor, CCurStack& curStack ) : _aCur ( curStack.AcqStack() ), _cCur ( cCursor ), _iCur ( 0 ), _lMaxWeight( 0 ) { Win4Assert ( _aCur[0] != 0 );
_iid = _aCur[0]->IndexId(); _pid = _aCur[0]->Pid();
//
// Calculate maximum weight of any child.
//
for ( UINT i = 0; i < _cCur; i++ ) { _lMaxWeight = max( _lMaxWeight, _aCur[i]->GetWeight() ); }
//
// Avoid divide-by-zero
//
if ( _lMaxWeight == 0 ) _lMaxWeight = 1;
// NTRAID#DB-NTBUG9-84004-2000/07/31-dlee Indexing Service internal cursors aren't optimized to use shortest cursors first
_wid = _aCur[0]->WorkId();
FindConjunction(); }
//+---------------------------------------------------------------------------
//
// Member: CAndCursor::~CAndCursor, public
//
// Synopsis: Delete the cursor together with children
//
// History: 24-May-91 BartoszM Created
//
//----------------------------------------------------------------------------
CAndCursor::~CAndCursor( ) { for ( unsigned i = 0; i < _cCur; i++ ) delete _aCur[i]; delete (void*) _aCur; }
//+---------------------------------------------------------------------------
//
// Member: CAndCursor::WorkId, public
//
// Synopsis: Get current work id.
//
// History: 24-May-91 BartoszM Created
//
//----------------------------------------------------------------------------
WORKID CAndCursor::WorkId() { return _wid; }
//+---------------------------------------------------------------------------
//
// Member: CAndCursor::NexWorkID, public
//
// Synopsis: Move to next work id
//
// Returns: Target work id or widInvalid if no more wid's for current key
//
// History: 24-May-91 BartoszM Created
//
//----------------------------------------------------------------------------
WORKID CAndCursor::NextWorkId() { // NTRAID#DB-NTBUG9-84004-2000/07/31-dlee Indexing Service internal cursors aren't optimized to use shortest cursors first
_wid = _aCur[0]->NextWorkId(); FindConjunction(); return _wid; }
//+---------------------------------------------------------------------------
//
// Member: CAndCursor::HitCount, public
//
// Synopsis: Returns smallest HitCount of all keys in current wid.
//
// Requires: _wid set to any of the current wid's
//
// Returns: smallest occurrence count of all keys in wid.
//
// History: 28-Feb-92 AmyA Created
//
// Notes: If there is no conjunction in current wid, returns 0.
//
//----------------------------------------------------------------------------
ULONG CAndCursor::HitCount() { ULONG count = _aCur[0]->HitCount();
for ( unsigned i = 1; i < _cCur; i++ ) { ULONG newcount = _aCur[i]->HitCount();
if ( newcount < count ) count = newcount; }
return count; }
void CAndCursor::RatioFinished (ULONG& denom, ULONG& num) { denom = 1; num = 0;
for (unsigned i=0; i < _cCur; i++) { ULONG d, n; _aCur[i]->RatioFinished(d, n); if (d == n) { // done if any cursor is done.
denom = d; num = n; Win4Assert( denom > 0 ); break; } else if (d > denom) { // the one with largest denom
// is the most meaningful
denom = d; num = n; } else if (d == denom && n < num ) { num = n; // be pessimistic
} } }
//+---------------------------------------------------------------------------
//
// Member: CAndCursor::Rank, public
//
// Synopsis: Returns smallest rank of all keys in current wid.
//
// Requires: _wid set to any of the current wid's
//
// Returns: smallest rank of all keys in wid.
//
// History: 14-Apr-92 AmyA Created
// 27-Jul-92 KyleP Use min function for weight
//
// Notes: If there is no conjunction in current wid, returns 0.
//
// See "Automatic Text Processing", G. Salton, 10.4.2 for
// a discussion of the weight formula.
//
//----------------------------------------------------------------------------
LONG CAndCursor::Rank() { LONG lRank = (MAX_QUERY_RANK - _aCur[0]->Rank()) * _aCur[0]->GetWeight();
for ( UINT i = 1; i < _cCur; i++ ) { LONG lNew = (MAX_QUERY_RANK - _aCur[i]->Rank()) * _aCur[i]->GetWeight(); lRank = max( lRank, lNew ); }
//
// Normalize weight.
//
lRank = MAX_QUERY_RANK - (lRank / _lMaxWeight);
return( lRank ); }
//+---------------------------------------------------------------------------
//
// Member: CAndCursor::FindConjunction, private
//
// Synopsis: Find nearest conjunction of all the same work id's
//
// Requires: _wid set to any of the current wid's
//
// Returns: TRUE when found, FALSE otherwise
//
// Modifies: [_wid] to point to conjunction or to widInvalid
//
// History: 24-May-91 BartoszM Created
//
// Notes: If cursors are in conjunction, no change results
//
//----------------------------------------------------------------------------
BOOL CAndCursor::FindConjunction() { BOOL fChange; do { fChange = FALSE;
// NTRAID#DB-NTBUG9-84004-2000/07/31-dlee Indexing Service internal cursors aren't optimized to use shortest cursors first
// for all cursors in turn
for ( unsigned i = 0; i < _cCur; i++ ) {
// Seek _wid increment cursor to or past current _wid
// or exit when exhausted
WORKID widTmp = _aCur[i]->WorkId();
while ( widTmp < _wid ) { widTmp = _aCur[i]->NextWorkId();
if ( widInvalid == widTmp ) { _wid = widInvalid; return FALSE; } }
// if overshot, try again with new _wid
if ( widTmp > _wid ) { _wid = widTmp; fChange = TRUE; break; } } } while ( fChange );
return TRUE; }
//+---------------------------------------------------------------------------
//
// Member: CAndCursor::Hit, public
//
// Synopsis: Hits current child (indexed by _iCur)
//
// History: 07-Sep-92 MikeHew Created
//
// Notes: Hit() should not be called more than once, except by
// NextHit()
//
//----------------------------------------------------------------------------
LONG CAndCursor::Hit() { Win4Assert( _iCur < _cCur );
if ( WorkId() == widInvalid ) { return rankInvalid; } else { return _aCur[_iCur]->Hit(); } }
//+---------------------------------------------------------------------------
//
// Member: CAndCursor::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 CAndCursor::NextHit() { Win4Assert( _iCur < _cCur );
LONG rank = _aCur[_iCur]->NextHit(); if ( rank == rankInvalid ) { if ( ++_iCur < _cCur ) { return Hit(); } }
return rank; }
|