//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1991 - 1992. // // File: SORT.CXX // // Contents: Key sorting // // History: 12-Jun-91 BartoszM Created // 19-Jun-91 reviewed // //---------------------------------------------------------------------------- #include #pragma hdrstop #include #include "sort.hxx" #include "compress.hxx" void CDirectory::AddEntry ( CBlock* pBlock, CKeyBuf& key ) { /* ciDebugOut (( DEB_ITRACE, "directory: add %d - %.*ws\n", _counter, key.StrLen(), key.GetStr() )); */ _tree.Add ( _counter, key ); _blocks [_counter] = pBlock; _counter++; } //+--------------------------------------------------------------------------- // // Member: CSortChunk::CSortChunk, public // // Synopsis: Copy logically sorted buffer into sort chunk // using a compressor // // Arguments: [maxOccTable] -- table of max occurrences for wids // // History: 28-May-92 KyleP Separate Single/Multiple wid compressor // 07-Jun-91 BartoszM Created // //---------------------------------------------------------------------------- CSortChunk::CSortChunk( CMaxOccTable& maxOccTable ) : _blocks( 0 ), _cBlocks( 0 ), _maxOccTable( maxOccTable ) { } //+--------------------------------------------------------------------------- // // Member: CSortChunk::Init, public // // Synopsis: 2nd-phase of construction for a CShortChunk // // Arguments: [buf] -- sorted entry buffer // [cb] -- count of bytes in buffer // [widMax] -- maximum WORKID for the word list. // // History: 28-May-92 KyleP Separate Single/Multiple wid compressor // 07-Jun-91 BartoszM Created // //---------------------------------------------------------------------------- void CSortChunk::Init( const BYTE * pBuf, ULONG cb, WORKID widMax ) { //ciDebugOut (( DEB_ITRACE, "copying into sort chunk\n" )); if ( cb < sizeof(int) + sizeof(WORKID) ) { // buffer is too small to hold correct information THROW(CException(CI_CORRUPT_FILTER_BUFFER)); } // extract necessary information from the end of the buffer const BYTE* pbEndVector = pBuf + cb - sizeof(int) - sizeof(WORKID); INT_PTR * pEndVector = (INT_PTR *)pbEndVector; int offsetVector = *(int *)(pbEndVector + sizeof(WORKID)); _widSingle = *(WORKID *)(pbEndVector); INT_PTR * pVector = (INT_PTR *)(pBuf + offsetVector); int cbEntries = (int)((BYTE *)pVector - pBuf); // get count by taking size of the array of offsets, then subtracting space // for the two sentinel entries. int count = (int)(pEndVector - pVector) - 2; if ( (offsetVector < 0) || ( count < 0 ) ) { // pVector is not valid THROW(CException(CI_CORRUPT_FILTER_BUFFER)); } _cBlocks = 0; OCCURRENCE oldOcc = OCC_INVALID; if ( pVector[0] >= cbEntries || pVector[0] < 0 ) { THROW(CException(CI_CORRUPT_FILTER_BUFFER)); } CEntry * pLastEntry = (CEntry *)(pBuf + pVector[0]); // sentinel if ((pLastEntry->Pid()!=0)|| (pLastEntry->Wid()!=widInvalid)|| (pLastEntry->Occ()!=0)|| (pLastEntry->Count()!=0)) { // this is not a sentinel THROW(CException(CI_CORRUPT_FILTER_BUFFER)); } if ( _widSingle == widInvalid ) { CCompress compr; _blocks = compr.GetFirstBlock(); for ( int i = 1; i <= count; i++ ) { if ( pVector[i] >= cbEntries || pVector[i] < 0 ) { THROW(CException(CI_CORRUPT_FILTER_BUFFER)); } CEntry * pEntry = (CEntry *)(pBuf + pVector[i]); OCCURRENCE newOcc = pEntry->Occ(); Win4Assert(pEntry->Pid()!=pidInvalid); // invalid PROPID Win4Assert(pEntry->Pid()!=pidAll); Win4Assert(pEntry->Wid()<=widMax); // invalid WORKID Win4Assert(pEntry->Wid() != 0); // invalid WORKID Win4Assert(pEntry->Wid()<=CI_MAX_DOCS_IN_WORDLIST); // invalid WORKID Win4Assert(newOcc!=OCC_INVALID); // invalid OCCURRENCE Win4Assert(pEntry->Count()<=MAXKEYSIZE); // invalid key size Win4Assert( pLastEntry->Compare( pEntry ) <= 0 ); // unsorted buffer if ((pEntry->Pid() == pidInvalid)|| // invalid PROPID (pEntry->Pid() == pidAll)|| (pEntry->Wid() > widMax)|| // invalid WORKID (pEntry->Wid() > CI_MAX_DOCS_IN_WORDLIST)|| // invalid WORKID (pEntry->Wid() == 0 ) || // invalid WORKID (newOcc == OCC_INVALID)|| // invalid OCCURRENCE (pEntry->Count() > MAXKEYSIZE)|| // invalid key size (pLastEntry->Compare( pEntry ) > 0)) // unsorted buffer { THROW(CException(CI_CORRUPT_FILTER_BUFFER)); } _maxOccTable.PutOcc( pEntry->Wid(), pEntry->Pid(), pEntry->Occ() ); if ( !compr.SameKey ( pEntry->Count(), pEntry->GetKeyBuf() ) || !compr.SamePid ( pEntry->Pid() ) ) { compr.PutKey( pEntry->Count(), pEntry->GetKeyBuf(), pEntry->Pid() ); compr.PutWid( pEntry->Wid() ); } else { if ( !compr.SameWid ( pEntry->Wid() ) ) { compr.PutWid ( pEntry->Wid() ); } else if ( newOcc == oldOcc ) { // adding exact same key twice THROW(CException(CI_CORRUPT_FILTER_BUFFER)); } } compr.PutOcc( newOcc ); oldOcc = newOcc; pLastEntry = pEntry; } _cBlocks = compr.KeyBlockCount(); } else { if ( _widSingle > widMax ) { // invalid WORKID ciDebugOut (( DEB_WARN, "_widSingle %d, widMax %d\n", _widSingle, widMax )); THROW(CException(CI_CORRUPT_FILTER_BUFFER)); } COneWidCompress compr; _blocks = compr.GetFirstBlock(); for ( int i = 1; i <= count; i++ ) { if ( pVector[i] >= cbEntries || pVector[i] < 0 ) { THROW(CException(CI_CORRUPT_FILTER_BUFFER)); } CEntry * pEntry = (CEntry *)(pBuf + pVector[i]); OCCURRENCE newOcc = pEntry->Occ(); if ((pEntry->Pid()==pidInvalid)|| // invalid PROPID (pEntry->Pid()==pidAll)|| (newOcc==OCC_INVALID)|| // invalid OCCURRENCE (pEntry->Count()>MAXKEYSIZE)|| // invalid key size (pLastEntry->Compare(pEntry)>0)) // unsorted buffer { THROW(CException(CI_CORRUPT_FILTER_BUFFER)); } _maxOccTable.PutOcc( _widSingle, pEntry->Pid(), pEntry->Occ() ); if ( !compr.SameKey ( pEntry->Count(), pEntry->GetKeyBuf() ) || !compr.SamePid ( pEntry->Pid() ) ) { compr.PutKey( pEntry->Count(), pEntry->GetKeyBuf(), pEntry->Pid() ); } else if ( newOcc == oldOcc ) { // adding exact same key twice THROW(CException(CI_CORRUPT_FILTER_BUFFER)); } compr.PutOcc( newOcc ); oldOcc = newOcc; pLastEntry = pEntry; } _cBlocks = compr.KeyBlockCount(); } _dir.Init ( _cBlocks ); // scan blocks and add all the keys CKeyBuf keyBuf; for ( CBlock* pBlock = _blocks; pBlock != 0; pBlock = pBlock->_pNext ) { if ( pBlock->_offFirstKey != offInvalid ) { pBlock->GetFirstKey( keyBuf ); _dir.AddEntry( pBlock, keyBuf ); } } // save some memory _blocks->CompressList(); _dir.Done(); } //Init //+--------------------------------------------------------------------------- // // Member: CSortChunk::~CSortChunk, public // // History: 12-Aug-91 BartoszM Created // //---------------------------------------------------------------------------- CSortChunk::~CSortChunk () { while ( _blocks != 0 ) { CBlock * tmp = _blocks; _blocks = _blocks->_pNext; delete tmp; } } //+--------------------------------------------------------------------------- // // Member: CSortChunk::QueryCursor // // Synopsis: Creates a cursor for a given key // // Arguments: [iid] -- index id // [widTable] -- wid translation table // // History: 28-May-92 KyleP Separate Single/Multiple wid compressor // 27-Sep-91 BartoszM Created // //---------------------------------------------------------------------------- CChunkCursor* CSortChunk::QueryCursor ( INDEXID iid, const CWidTable& widTable, WORKID widMax ) { XPtr xCur; if ( _widSingle == widInvalid ) xCur.Set( new CManyWidChunkCursor ( iid, widTable, this, widMax, _maxOccTable ) ); else xCur.Set( new COneWidChunkCursor( iid, widTable, _widSingle, this, widMax, _maxOccTable ) ); xCur->Init(); return xCur.Acquire(); } //+--------------------------------------------------------------------------- // // Member: CSortChunk::QueryCursor // // Synopsis: Creates a cursor for a given key // // Arguments: [iid] -- index id // [widTable] -- wid translation table // [pkey] -- key to seek // // Returns: Cursor or NULL if key not found // // History: 28-May-92 KyleP Separate Single/Multiple wid compressor // 27-Sep-91 BartoszM Created // //---------------------------------------------------------------------------- CChunkCursor* CSortChunk::QueryCursor ( INDEXID iid, const CWidTable& widTable, const CKey * pKeySearch, WORKID widMax ) { XPtr xCur; if ( _widSingle == widInvalid ) xCur.Set( new CManyWidChunkCursor ( iid, widTable, this, widMax, _maxOccTable ) ); else xCur.Set( new COneWidChunkCursor( iid, widTable, _widSingle, this, widMax, _maxOccTable ) ); const CKeyBuf* pKeyFound = xCur->SeekKey ( pKeySearch ); if ( !pKeyFound || !pKeySearch->MatchPid (*pKeyFound) || pKeySearch->CompareStr(*pKeyFound) != 0 ) { xCur.Free(); } return xCur.Acquire(); } //+--------------------------------------------------------------------------- // // Member: CSortChunk::CreateRange(), public // // Synopsis: Adds all cursors with keys between pkey and pkeyEnd to curStk. // // Arguments: [curStk] -- CKeyCurStack to add cursors to. // [pkey] -- Beginning of key range. // [pkeyEnd] -- End of key range. // [iid] -- Index id for QueryCursor. // [widTable] -- Wid Table for QueryCursor. // // History: 07-Feb-92 AmyA Created. // 14-Feb-92 AmyA Moved from CWordList. // 28-May-92 KyleP Separate Single/Multiple wid compressor // //---------------------------------------------------------------------------- void CSortChunk::CreateRange(COccCurStack & curStk, const CKey * pKeyStart, const CKey * pKeyEnd, INDEXID iid, const CWidTable& widTable, WORKID widMax ) { XPtr xCursor; if ( _widSingle == widInvalid ) xCursor.Set( new CManyWidChunkCursor ( iid, widTable, this, widMax, _maxOccTable ) ); else xCursor.Set( new COneWidChunkCursor( iid, widTable, _widSingle, this, widMax, _maxOccTable ) ); const CKeyBuf* pKeyCurrent = xCursor->SeekKey ( pKeyStart ); if ( 0 == pKeyCurrent ) { xCursor.Free(); return; } CChunkCursor * pCursor = xCursor.Acquire(); curStk.Push( pCursor ); PROPID pid = pKeyStart->Pid(); ciDebugOut((DEB_ITRACE, "Found key %.*ws, pid %d\n", pKeyCurrent->StrLen(), pKeyCurrent->GetStr(), pKeyCurrent->Pid())); do { if (pid != pidAll) // exact pid match { // skip wrong pids while (pid != pKeyCurrent->Pid()) { #if CIDBG == 1 //------------------------------------------ if (pKeyCurrent) { ciDebugOut(( DEB_ITRACE, " skip: %.*ws, pid %d, wid %d\n", pKeyCurrent->StrLen(), pKeyCurrent->GetStr(), pKeyCurrent->Pid(), pCursor->WorkId() )); } else ciDebugOut(( DEB_ITRACE, " key\n" )); #endif //-------------------------------------------------- pKeyCurrent = pCursor->GetNextKey(); if (pKeyCurrent == 0 || pKeyEnd->CompareStr(*pKeyCurrent) < 0 ) break; } // either pid matches or we have overshot // i.e. different pids and current string > end } if (pKeyCurrent == 0 || !pKeyEnd->MatchPid (*pKeyCurrent) || pKeyEnd->CompareStr (*pKeyCurrent) < 0 ) { break; // <--- LOOP EXIT } if ( _widSingle == widInvalid ) pCursor = new CManyWidChunkCursor( *(CManyWidChunkCursor *)pCursor ); else pCursor = new COneWidChunkCursor( *(COneWidChunkCursor *)pCursor ); curStk.Push(pCursor); pKeyCurrent = pCursor->GetNextKey(); #if CIDBG == 1 if (pKeyCurrent) { ciDebugOut((DEB_ITRACE, "Key is %.*ws\n", pKeyCurrent->StrLen(), pKeyCurrent->GetStr())); } else ciDebugOut(( DEB_ITRACE, " key\n" )); #endif // CIDBG == 1 } while ( pKeyCurrent ); // Since we have one more cursor in curStk than we wanted... curStk.DeleteTop(); } //+--------------------------------------------------------------------------- // // Member: CManyWidChunkCursor::CManyWidChunkCursor, private // // Synopsis: initialize a chunk cursor // // Arguments: [iid] -- index id // [widTable] -- wid translation table // [pChunk] -- sort chunk // [widMax] -- maximum wid // [maxOccTable] -- table of max occurrences of wids // // Notes: No seek is made! Can be used for merges, // otherwise Seek has to be called next. // // History: 22-May-91 Brianb Created // 05-Jun-91 BartoszM Rewrote it // //---------------------------------------------------------------------------- CManyWidChunkCursor::CManyWidChunkCursor( INDEXID iid, const CWidTable& widTable, CSortChunk *pChunk, WORKID widMax, CMaxOccTable& maxOccTable ) : CChunkCursor(iid, widMax, pChunk), _widTable( widTable ), _maxOccTable( maxOccTable ) { Win4Assert ( pChunk != 0 ); } void CManyWidChunkCursor::Init() { Init( _pChunk->GetBlock() ); } void CManyWidChunkCursor::Init( CBlock* pBlock ) { Win4Assert ( pBlock != 0 ); _decomp.Init ( pBlock ); const CKeyBuf *pKey = _decomp.GetKey(); if ( pKey ) _pid = pKey->Pid(); // should try to position on a valid work id _curFakeWid = _decomp.WorkId(); WORKID wid = _widTable.FakeWidToWid( _curFakeWid ); Win4Assert ( _curFakeWid != widInvalid ); if ( wid == widInvalid ) wid = NextWorkId(); if ( wid == widInvalid ) GetNextKey(); } //+--------------------------------------------------------------------------- // // Member: CManyWidChunkCursor::SeekKey,private // // Synopsis: seek to the specified key // // Effects: positions cursor at specified key or later // // History: 22-May-91 Brianb Created // 05-Jun-91 BartoszM Rewrote it // //---------------------------------------------------------------------------- const CKeyBuf * CManyWidChunkCursor::SeekKey( const CKey * pkey ) { Win4Assert ( pkey != 0 ); CDirectory& dir = _pChunk->GetDir(); CBlock* pBlock = dir.Seek ( *pkey ); Init ( pBlock ); const CKeyBuf * tmpKey = _decomp.GetKey(); //---------------------------------------------------- // Notice: Make sure that pidAll is smaller // than any other legal PID. If the search key // has pidAll we want to be positioned at the beginning // of the range. //---------------------------------------------------- Win4Assert ( pidAll == 0 ); while ( tmpKey != 0 && pkey->Compare(*tmpKey) > 0 ) tmpKey = GetNextKey(); if ( tmpKey ) { _pid = tmpKey->Pid(); UpdateWeight(); } return tmpKey; } //+--------------------------------------------------------------------------- // // Member: CManyWidChunkCursor::GetKey, public // // Synopsis: return the current key, NULL if it doesn't exist // // Returns: current key // // History: 22-May-91 Brianb Created // 05-Jun-91 BartoszM Rewrote it // //---------------------------------------------------------------------------- const CKeyBuf *CManyWidChunkCursor::GetKey() { return _decomp.GetKey(); } //+--------------------------------------------------------------------------- // // Member: CManyWidChunkCursor::GetNextKey, public // // Synopsis: advance to next key and return it if it exists // // Effects: changes cursor position // // Returns: next key if it exists or NULL // // History: 22-May-91 Brianb Created // 05-Jun-91 BartoszM Rewrote it // //---------------------------------------------------------------------------- const CKeyBuf * CManyWidChunkCursor::GetNextKey() { const CKeyBuf* key; WORKID wid; do { key = _decomp.GetNextKey(); if ( key != 0) { _curFakeWid = _decomp.WorkId(); wid = _widTable.FakeWidToWid( _curFakeWid ); Win4Assert( _curFakeWid != widInvalid ); if ( wid == widInvalid ) wid = NextWorkId(); } } while ( key != 0 && wid == widInvalid ); if ( key ) { _pid = key->Pid(); UpdateWeight(); } return key; } //+--------------------------------------------------------------------------- // // Member: CManyWidChunkCursor::WorkId, public // // Synopsis: return current work id under cursor // // Returns: a workid or widInvalid // // History: 22-May-91 Brianb Created // 05-Jun-91 BartoszM Rewrote it // 28-May-92 KyleP Added WorkId mapping // //---------------------------------------------------------------------------- WORKID CManyWidChunkCursor::WorkId() { _curFakeWid = _decomp.WorkId(); return ( _widTable.FakeWidToWid( _curFakeWid ) ); } //+--------------------------------------------------------------------------- // // Member: CManyWidChunkCursor::NextWorkId // // Synopsis: Advance to next workid within key and return it if it exists // // Returns: next workid or widInvalid if it doesn't exist // // History: 22-May-91 Brianb Created // 05-Jun-91 BartoszM Rewrote it // 28-May-92 KyleP Added WorkId mapping // 22-Sep-93 AmyA Added additional check for widInvalid // //---------------------------------------------------------------------------- WORKID CManyWidChunkCursor::NextWorkId() { WORKID wid; do { _curFakeWid = _decomp.NextWorkId(); wid = _widTable.FakeWidToWid( _curFakeWid ); } while ( wid == widInvalid && _curFakeWid != widInvalid ); return wid; } void CManyWidChunkCursor::RatioFinished (ULONG& denom, ULONG& num) { _decomp.RatioFinished (denom, num); } //+--------------------------------------------------------------------------- // // Member: CManyWidChunkCursor::Occurrence, public // // Synopsis: return current occurrence under cursor // // Returns: occurrence or OCC_INVALID // // History: 22-May-91 Brianb Created // 05-Jun-91 BartoszM Rewrote it // //---------------------------------------------------------------------------- OCCURRENCE CManyWidChunkCursor::Occurrence() { return _decomp.Occurrence(); } //+--------------------------------------------------------------------------- // // Member: CManyWidChunkCursor::NextOccurrence, public // // Synopsis: advance to next occurrence within current workid // // Returns: next occurrence if it exists, otherwise OCC_INVALID // // History: 22-May-91 Brianb Created // 05-Jun-91 BartoszM Rewrote it // //---------------------------------------------------------------------------- OCCURRENCE CManyWidChunkCursor::NextOccurrence() { return _decomp.NextOccurrence(); } //+--------------------------------------------------------------------------- // // Member: CManyWidChunkCursor::MaxOccurrence, public // // Synopsis: Returns max occurrence count of current workid and pid // // History: 20-Jun-96 SitaramR Created // //---------------------------------------------------------------------------- OCCURRENCE CManyWidChunkCursor::MaxOccurrence() { return _maxOccTable.GetMaxOcc( _curFakeWid, _pid ); } //+--------------------------------------------------------------------------- // // Member: CManyWidChunkCursor::WorkIdCount, public // // Synopsis: return wid count // // Expects: cursor positioned after key, wid heap empty // // History: 21-Jun-91 BartoszM Created // //---------------------------------------------------------------------------- ULONG CManyWidChunkCursor::WorkIdCount() { return _decomp.WorkIdCount(); } //+--------------------------------------------------------------------------- // // Member: CManyWidChunkCursor::OccurrenceCount, public // // Synopsis: return occurrence count // // Expects: cursor positioned after work id // // History: 21-Jun-91 BartoszM Created // //---------------------------------------------------------------------------- ULONG CManyWidChunkCursor::OccurrenceCount() { return _decomp.OccurrenceCount(); } //+--------------------------------------------------------------------------- // // Member: CManyWidChunkCursor::HitCount, public // // Synopsis: return occurrence count for current work id // // Expects: cursor positioned after work id // // History: 27-Feb-92 AmyA Created // //---------------------------------------------------------------------------- ULONG CManyWidChunkCursor::HitCount() { return OccurrenceCount(); } //+--------------------------------------------------------------------------- // // Member: COneWidChunkCursor::COneWidChunkCursor, private // // Synopsis: initialize a chunk cursor // // Arguments: [iid] -- index id // [widTable] -- wid mapping // [wid] -- The single wid in the chunk. // [pChunk] -- sort chunk // [widMax] -- maximum wid // [maxOccTable] -- table of max occurrences of wids // // Notes: No seek is made! Can be used for merges, // otherwise Seek has to be called next. // // History: 28-May-92 KyleP Created // //---------------------------------------------------------------------------- COneWidChunkCursor::COneWidChunkCursor( INDEXID iid, CWidTable const & widTable, WORKID wid, CSortChunk *pChunk, WORKID widMax, CMaxOccTable& maxOccTable ) : CChunkCursor( iid, widMax, pChunk ), _wid( widTable.FakeWidToWid( wid ) ), _maxOccTable( maxOccTable ), _fakeWid( wid ) { _widReal = _wid; } void COneWidChunkCursor::Init() { _decomp.Init ( _pChunk->GetBlock() ); const CKeyBuf *pKey = _decomp.GetKey(); if ( pKey ) _pid = pKey->Pid(); } //+--------------------------------------------------------------------------- // // Member: COneWidChunkCursor::SeekKey,private // // Synopsis: Seek to the specified key // // Effects: positions cursor at specified key or later // // Arguments: [pkey] -- Key to seek to. // // History: 28-May-92 KyleP Created // //---------------------------------------------------------------------------- const CKeyBuf * COneWidChunkCursor::SeekKey( const CKey * pkey ) { if ( _widReal == widInvalid ) return 0; Win4Assert ( pkey != 0 ); // // Find the chunk. // CDirectory& dir = _pChunk->GetDir(); CBlock* pBlock = dir.Seek ( *pkey ); Win4Assert ( pBlock != 0 ); // // Set up. // _decomp.Init ( pBlock ); // // Go forward to the correct key. // CKeyBuf const * tmpKey; //---------------------------------------------------- // Notice: Make sure that pidAll is smaller // than any other legal PID. If the search key // has pidAll we want to be positioned at the beginning // of the range. //---------------------------------------------------- Win4Assert ( pidAll == 0 ); for ( tmpKey = _decomp.GetKey(); tmpKey != 0 && pkey->Compare(*tmpKey) > 0; tmpKey = _decomp.GetNextKey() ) continue; // Null body if ( tmpKey ) { _pid = tmpKey->Pid(); UpdateWeight(); } return tmpKey; } //+--------------------------------------------------------------------------- // // Member: COneWidChunkCursor::GetKey, public // // Synopsis: return the current key, NULL if it doesn't exist // // Returns: current key // // History: 28-May-92 KyleP Created // //---------------------------------------------------------------------------- const CKeyBuf *COneWidChunkCursor::GetKey() { if ( _widReal == widInvalid ) return 0; return _decomp.GetKey(); } //+--------------------------------------------------------------------------- // // Member: COneWidChunkCursor::GetNextKey, public // // Synopsis: advance to next key and return it if it exists // // Effects: changes cursor position // // Returns: next key if it exists or NULL // // History: 28-May-92 KyleP Created // 02-Jun-92 KyleP Restore real wid // //---------------------------------------------------------------------------- const CKeyBuf * COneWidChunkCursor::GetNextKey() { if ( _widReal == widInvalid ) return 0; const CKeyBuf* key = _decomp.GetNextKey(); if ( key ) { _wid = _widReal; _pid = key->Pid(); UpdateWeight(); } return key; } //+--------------------------------------------------------------------------- // // Member: COneWidChunkCursor::WorkId, public // // Synopsis: return current work id under cursor // // Returns: a workid or widInvalid // // History: 28-May-92 KyleP Created // //---------------------------------------------------------------------------- WORKID COneWidChunkCursor::WorkId() { return( _wid ); } //+--------------------------------------------------------------------------- // // Member: COneWidChunkCursor::NextWorkId // // Synopsis: Advance to next workid within key and return it if it exists // // Returns: next workid or widInvalid if it doesn't exist // // History: 28-May-92 KyleP Created // //---------------------------------------------------------------------------- WORKID COneWidChunkCursor::NextWorkId() { _wid = widInvalid; return( widInvalid ); } void COneWidChunkCursor::RatioFinished (ULONG& denom, ULONG& num) { denom = 1; if (_wid == widInvalid) num = 1; else num = 0; } //+--------------------------------------------------------------------------- // // Member: COneWidChunkCursor::WorkIdCount, public // // Returns: 1 // // Expects: cursor positioned after key, wid heap empty // // History: 28-May-92 KyleP Created // //---------------------------------------------------------------------------- ULONG COneWidChunkCursor::WorkIdCount() { return( 1 ); } //+--------------------------------------------------------------------------- // // Member: COneWidChunkCursor::Occurrence, public // // Synopsis: return current occurrence under cursor // // Returns: occurrence or OCC_INVALID // // History: 28-May-92 KyleP Created // //---------------------------------------------------------------------------- OCCURRENCE COneWidChunkCursor::Occurrence() { Win4Assert( _wid != widInvalid ); return _decomp.Occurrence(); } //+--------------------------------------------------------------------------- // // Member: COneWidChunkCursor::NextOccurrence, public // // Synopsis: advance to next occurrence within current workid // // Returns: next occurrence if it exists, otherwise OCC_INVALID // // History: 28-May-92 KyleP Created // //---------------------------------------------------------------------------- OCCURRENCE COneWidChunkCursor::NextOccurrence() { Win4Assert( _wid != widInvalid ); return _decomp.NextOccurrence(); } //+--------------------------------------------------------------------------- // // Member: COneWidChunkCursor::MaxOccurrence, public // // Synopsis: Returns max occurrence count of current workid and pid // // History: 20-Jun-96 SitaramR Created // //---------------------------------------------------------------------------- OCCURRENCE COneWidChunkCursor::MaxOccurrence() { return _maxOccTable.GetMaxOcc( _fakeWid, _pid ); } //+--------------------------------------------------------------------------- // // Member: COneWidChunkCursor::OccurrenceCount, public // // Synopsis: return occurrence count // // Expects: cursor positioned after work id // // History: 28-May-92 KyleP Created // //---------------------------------------------------------------------------- ULONG COneWidChunkCursor::OccurrenceCount() { Win4Assert( _wid != widInvalid ); return _decomp.OccurrenceCount(); } //+--------------------------------------------------------------------------- // // Member: COneWidChunkCursor::HitCount, public // // Synopsis: return occurrence count for current work id // // Expects: cursor positioned after work id // // History: 28-May-92 KyleP Created // //---------------------------------------------------------------------------- ULONG COneWidChunkCursor::HitCount() { return OccurrenceCount(); } //+------------------------------------------------------------------------- // // Member: CWidTable::CWidTable, public // // Synopsis: Create a WorkId mapping table. // // History: 20-May-92 KyleP Created // //-------------------------------------------------------------------------- CWidTable::CWidTable() : _count( 0 ) { #if CIDBG == 1 // // Initially the table will be all 0 \(illegal wid\) // memset( _table, 0, sizeof(_table) ); #endif } //+------------------------------------------------------------------------- // // Member: CWidTable::WidToFakeWid, public // // Synopsis: Maps a WorkId to a table index. // // Arguments: [wid] -- WorkId to map. May already be mapped. // // Returns: The index of [wid] // // History: 20-May-92 KyleP Created // // Notes: This is clearly a non-optimal insertion algorithm but // it's called so infrequently that a more complex solution // would involve more code than it's worth. // //-------------------------------------------------------------------------- WORKID CWidTable::WidToFakeWid( WORKID wid ) { Win4Assert( _count <= CI_MAX_DOCS_IN_WORDLIST ); for ( int iDoc = _count - 1; iDoc >= 0; iDoc-- ) { if ( wid == _table[iDoc].Wid() ) return( iDocToFakeWid ( iDoc ) ); } WORKID fakeWid = iDocToFakeWid ( _count ); _table[ _count ].SetWid( wid ); _count++; return( fakeWid ); }