You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1131 lines
33 KiB
1131 lines
33 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// 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 <pch.cxx>
|
|
#pragma hdrstop
|
|
|
|
#include <entry.hxx>
|
|
|
|
#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<CChunkCursor> 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<CChunkCursor> 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<CChunkCursor> 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, " <NULL> 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, " <NULL> 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 );
|
|
}
|