|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1991 - 2000.
//
// File: PComp.cxx
//
// Contents: Persistent index compressor, decompressor
//
// Classes: CCoder, CKeyComp, CPersComp
//
// History: 05-Jul-91 KyleP Created
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#pragma optimize( "t", on )
#include "pcomp.hxx"
#include "bitstm.hxx"
const unsigned short NoKey = 0xffff;
const unsigned OccCountBits = 3; // Bits to initially store for
// an occurrence count.
const unsigned cPidBits = 4;
//+---------------------------------------------------------------------------
//
// Member: CCoder::CCoder, public
//
// Synopsis: Creates a coder
//
// Arguments: [widMax] -- The maximum workid in this index
//
// History: 05-Nov-91 BartoszM Created.
//
//----------------------------------------------------------------------------
CCoder::CCoder ( WORKID widMax) :_widMaximum(widMax), _wid(0), _occ(0) { _key.SetCount(0); }
//+---------------------------------------------------------------------------
//
// Member: CCoder::CCoder, public
//
// Synopsis: Creates a coder
//
// Arguments: [widMax] -- The maximum workid in this index
// [keyInit] -- initial key
//
// History: 26-Aug-92 BartoszM Created.
//
//----------------------------------------------------------------------------
CCoder::CCoder ( WORKID widMax, const CKeyBuf& keyInit) :_widMaximum(widMax), _wid(0), _occ(0), _key(keyInit) { }
//+---------------------------------------------------------------------------
//
// Member: CCoder::CCoder, public
//
// Synopsis: Copy Constructor
//
// Arguments: [coder] -- The original CCoder that is being copied.
//
// History: 15-Jan-92 AmyA Created.
//
//----------------------------------------------------------------------------
CCoder::CCoder ( CCoder &coder) :_key(coder._key), _widMaximum(coder._widMaximum), _wid(coder._wid), _occ(coder._occ), _cbitAverageWid(coder._cbitAverageWid) { }
//+---------------------------------------------------------------------------
//
// Member: CCoder::~CCoder, public
//
// History: 05-Nov-91 BartoszM Created.
//
//----------------------------------------------------------------------------
CCoder::~CCoder ( ) { }
//+---------------------------------------------------------------------------
//
// Member: CKeyComp::CKeyComp, public
//
// Synopsis: Creates a new (empty) key compressor.
//
// Arguments: [phIndex] -- physical index
//
// [widMax] -- The maximum workid which may be stored via
// PutWorkId.
//
// History: 13-Nov-93 w-PatG Created.
//
//----------------------------------------------------------------------------
CKeyComp::CKeyComp( CPhysIndex& phIndex, WORKID widMax, BOOL fUseLinks )
: CCoder( widMax ), _sigKeyComp(eSigKeyComp), _phIndex(phIndex), _bitStream ( phIndex ), _fUseLinks( fUseLinks ), _bitStreamLink(phIndex), _fWriteFirstKeyFull(FALSE) { _bitOffCurKey.Init(0,0); _bitOffLastKey.Init(0,0); }
//+---------------------------------------------------------------------------
//
// Function: CKeyComp
//
// Synopsis: Constructor used for creating a key compressor during a
// restarted master merge. It has the ability to open an
// existing index stream, seek to the specified point after
// which new keys are to be added and zero-fill fromt the
// starting point to the end of the page. Subsequent pages
// are automatically zero-filled when they are loaded.
//
// Arguments: [phIndex] -- The physindex to which new keys are
// going to be added
// [widMax] -- Maximum wid in the index.
// [bitoffRestart] -- BitOffset indicating where the new
// keys will be added.
// [bitoffSplitKey] -- BitOffset of the last key written
// successfully to the disk completely. It is assumed that
// there will be no need to even fix up the forward links.
// [splitKey] -- The key which was written last.
// [fUseLinks] -- Flag indicating if forward links should
// be used or not.
//
// History: 4-10-94 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
CKeyComp::CKeyComp( CPhysIndex& phIndex, WORKID widMax, const BitOffset & bitoffRestart, const BitOffset & bitoffSplitKey, const CKeyBuf & splitKey, BOOL fUseLinks )
: CCoder( widMax ), _sigKeyComp(eSigKeyComp), _phIndex(phIndex), _bitStream ( phIndex, bitoffRestart, FALSE ), _fUseLinks( fUseLinks ), _bitStreamLink(phIndex), _fWriteFirstKeyFull(FALSE) { //
// Zero fill everything after the current position to the end of the
// page.
//
ZeroToEndOfPage();
// Write the signature
InitSignature(); _bitOffCurKey.Init(0,0); _bitOffLastKey.Init(0,0);
//
// Position to the place from where new keys must be written.
//
#if CIDBG == 1
BitOffset bitOffCurr; GetOffset(bitOffCurr); Win4Assert( bitoffRestart.Page() == bitOffCurr.Page() && bitoffRestart.Offset() == bitOffCurr.Offset() ); // _bitStream.Seek(bitoffRestart);
#endif // CIDBG
//
// If we are restarting and the split key is not the "MinKey"
// then we must remember the split key as the "previous key".
// If the split key is "MinKey", then we are starting from
// beginning.
//
_key = splitKey;
if ( _fUseLinks ) { //
// Initialize the forward link tracker.
//
_bitStreamLink.Seek(bitoffSplitKey); } }
//+---------------------------------------------------------------------------
//
// Member: CKeyComp::~CKeyComp, public
//
// Synopsis: Destroy a compressor/buffer pair.
//
// Effects: The main effect of destroying a compressor is that the
// associated buffer is also destroyed (presumably storing
// the data to a persistent medium).
//
// Signals: ???
//
// History: 05-Jul-91 KyleP Created.
// 13-Nov-93 w-PatG Converted from CPersComp to CKeyComp
//
// Notes: Previous compressor is deleted in PutKey
//
//----------------------------------------------------------------------------
CKeyComp::~CKeyComp() { ciDebugOut (( DEB_PCOMP,"CKeyComp::~CKeyComp() -- Last Key = %.*ws\n", _key.StrLen(), _key.GetStr() )); }
//+---------------------------------------------------------------------------
//
// Member: CKeyComp::PutKey, public
//
// Synopsis: Starts recording data for a new key.
//
// Arguments: [key] -- The new key.
//
// [bitOff] -- (out) actual bit offset of the key in the index
//
// History: 05-Jul-91 KyleP Created.
// 22-Nov-93 w-PatG Converted from CPersComp.
//
// Notes: The structure for each key is:
// Prefix/Suffix size
// Suffix
// Property ID (Actually the key id)
//
//----------------------------------------------------------------------------
void CKeyComp::PutKey(const CKeyBuf * pkey, BitOffset & bitOffCurKey) { //Debug message broken into two pieces due to use of static buffer
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME, "\"%.*ws\"", pkey->StrLen(), pkey->GetStr() ));
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME, " after \"%.*ws\"", _key.StrLen(), _key.GetStr() ));
Win4Assert(pkey->Count() != 0 ); Win4Assert((_key.Count() == 0) || Compare(&_key, pkey) < 0); Win4Assert(pkey->Pid() != pidAll); Win4Assert(pkey->Pid() != pidInvalid);
// record the offset now.
// for use by the directory
_bitStream.GetOffset ( _bitOffCurKey ); bitOffCurKey = _bitOffCurKey;
if ( _fUseLinks ) { // Get offset of previous key (the link stream is there)
_bitStreamLink.GetOffset (_bitOffLastKey);
// store the link data
ULONG DeltaValue = bitOffCurKey.Delta(_bitOffLastKey); ciDebugOut (( 0x02000000, "@@@@ Delta : %lu @@@@\n", DeltaValue )); // check whether the size of whole persistent index exceed the maximum limit
if ( DeltaValue >= LINK_MAX_VALUE ) { ciDebugOut (( 0x01000000 | DEB_PCOMP | DEB_NOCOMPNAME, "\n@@@@ Key : \"%.*ws\" Exceed the MAX SIZE : %lu\n", _key.StrLen(), _key.GetStr(), DeltaValue )); DeltaValue = 0; } _bitStreamLink.OverwriteBits( DeltaValue, LINK_MAX_BITS );
// reposition the link stream
_bitStreamLink.Seek ( bitOffCurKey );
// save space for the link
_bitStream.PutBits ( 0, LINK_MAX_BITS ); }
//
// If we need to write the FIRST key on each page in its entirety,
// and we have crossed a page boundary, then set the prefix to 0,
// which forces the key to be written in its entirety.
//
unsigned cPrefix = 0; if ( _fWriteFirstKeyFull && ( _bitOffCurKey.Page() != _bitOffLastKey.Page()) ) { //
// If we're not using links, then we haven't been tracking the
// bit offset of the last key. Do it here.
//
if ( !_fUseLinks ) { _bitOffLastKey = _bitOffCurKey; } } else { unsigned mincb = __min(_key.Count(), pkey->Count());
for (cPrefix = 0; cPrefix < mincb; cPrefix++) if ((_key.GetBuf())[cPrefix] != (pkey->GetBuf())[cPrefix]) break; }
unsigned cSuffix = pkey->Count() - cPrefix;
PutPSSize ( cPrefix, cSuffix );
//
// Store the suffix.
//
_bitStream.PutBytes( pkey->GetBuf() + cPrefix, cSuffix);
PutPid ( pkey->Pid() );
//
// Copy the piece of key that changed.
//
memcpy(_key.GetWritableBuf() + cPrefix, pkey->GetBuf() + cPrefix, cSuffix); _key.SetCount( pkey->Count() ); _key.SetPid ( pkey->Pid() );
}
//+---------------------------------------------------------------------------
//
// Member: CKeyComp::IBitCompress, private
//
// Synopsis: Compress and store a number.
//
// Arguments: [ul] -- Number to store.
//
// [cbitAverage] -- Minimum number of bits to store.
//
// Algorithm: First, store the bottom cbitAverage bits.
// while there are more bits to store
// store a 1 bit indicating more to follow
// store the next n bits, where n = 2, 3, 4, ...
// store a 0 bit indicating end of sequence
//
// History: 08-Jul-91 KyleP Created.
// 06-Dec-93 w-PatG Moved from CPersComp.
//
//----------------------------------------------------------------------------
void CKeyComp::IBitCompress(ULONG ul, unsigned cbitAverage, unsigned bitSize) { //
// Figure out the size of the 'hole' after the last bits are
// written out and add 0 bits at the high end so that the
// last putbits really stores exactly the remaining bits.
// (Right pad the number)
//
int cbitToStore; int cbitPadding = (int)(bitSize - cbitAverage);
for (cbitToStore = 2; cbitPadding > 0; cbitToStore++) cbitPadding -= cbitToStore;
Win4Assert(cbitPadding >= -cbitToStore);
cbitPadding = -cbitPadding; bitSize += cbitPadding;
//
// Store the bits a dword at a time for efficiency. They are kept
// in ultmp until they are stored. cbitTmp is the count of valid bits
// in ulTmp. ibitValid is the highest unstored bit.
//
int ibitValid; ULONG ulTmp; unsigned cbitTmp;
ibitValid = bitSize; Win4Assert( (ibitValid - cbitAverage) < ULONG_BITS ); ulTmp = ul >> (ibitValid - cbitAverage); cbitTmp = cbitAverage;
ibitValid -= cbitAverage;
bitSize -= cbitAverage;
//
// Now store the cbitAverage bits and the
// remaining bits, 2, 3, 4, ... at a time
//
for (cbitToStore = 2; ibitValid > 0; cbitToStore++) { //
// If there isn't enough space left in the DWord, then
// write it out and start a new one.
//
if (cbitTmp + cbitToStore + 1 > ULONG_BITS) { _bitStream.PutBits(ulTmp, cbitTmp); ulTmp = 0; cbitTmp = 0; }
//
// Store a continuation bit
//
ulTmp = (ulTmp << 1) | 1; cbitTmp++;
//
// Store the next top 2, 3, ... bits
//
Win4Assert( cbitToStore < ULONG_BITS ); Win4Assert( (ibitValid - cbitToStore) < ULONG_BITS );
ulTmp = (ulTmp << cbitToStore) | (ul >> (ibitValid - cbitToStore)) & ~(0xffffffffL << cbitToStore);
ibitValid -= cbitToStore; cbitTmp += cbitToStore;
Win4Assert(ibitValid >= 0); // Loop should terminate w/
// ibitValid == 0
}
//
// Write out the final termination bit (0).
//
if (cbitTmp == ULONG_BITS) { _bitStream.PutBits(ulTmp, cbitTmp); ulTmp = 0; cbitTmp = 0; }
ulTmp <<= 1;
_bitStream.PutBits(ulTmp, cbitTmp + 1); }
//+---------------------------------------------------------------------------
//
// Member: CKeyComp::PutPSSize, private
//
// Synopsis: Writes key prefix and suffix sizes
//
// Arguments: [cPrefix] -- size of prefix
// [cSuffix] -- size of suffix
//
// History: 06-Nov-91 BartoszM Created.
// 22-Nov-93 w-PatG Moved from CPersComp to CKeyComp
//
// Notes:
// Store the prefix/suffix size followed by the suffix. If both
// the prefix and suffix fit in 4 bits each then store each as
// 4 bits, else store a 0 byte followed by a 8 bits each for
// prefix and suffix.
//
//----------------------------------------------------------------------------
inline void CKeyComp::PutPSSize ( unsigned cPrefix, unsigned cSuffix ) { Win4Assert ( cPrefix + cSuffix != 0 );
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME, "\n(%d:%d) ", cPrefix, cSuffix ));
if ((cPrefix <= 0xF) && (cSuffix <= 0xF)) { _bitStream.PutBits((cPrefix << 4) | cSuffix, 8); } else { Win4Assert((cPrefix < 256) && (cSuffix < 256)); Win4Assert(cPrefix + cSuffix <= MAXKEYSIZE ); _bitStream.PutBits((cPrefix << 8) | cSuffix, 8 + 16); } }
//+---------------------------------------------------------------------------
//
// Member: CKeyComp::PutPid, private
//
// Synopsis: Writes Property ID
//
// Arguments: [pid] -- property id
//
// History: 06-Nov-91 BartoszM Created.
// 22-Nov-93 w-PatG Moved from CPersComp to CKeyComp
//
//----------------------------------------------------------------------------
inline void CKeyComp::PutPid ( PROPID pid ) { //
// Just store a 0 bit if contents, else
// a 1 followed by ULONG propid.
//
if ( pid == pidContents) { _bitStream.PutBits(0, 1); } else { ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME, " =PID %d= ", pid ));
_bitStream.PutBits(1, 1); BitCompress ( pid, cPidBits ); } }
//+---------------------------------------------------------------------------
//
// Member: CKeyDeComp::CKeyDeComp, public
//
// Synopsis: Creates a new persistent decompressor
// at the beginning of an index
//
// Arguments: [iid] -- index id
// [phIndex] -- physical index
// [widMax] -- Maximum workid which may be in the buffer.
// This must be the same number was was used
// during compression.
//
// History: 12-Jul-91 KyleP Created.
// 21-Apr-92 BartoszM Split into two constructors
// 30-Nov-93 w-PatG Converted from CPersDeComp
// 10-Apr-94 SrikantS Adapted to not use the directory
// because it may not exist during a
// restarted master merge.
//
// Notes: Some of the arguments passed in may later be deemed to be
// unnecessary. Some may be converted to different purposes at a
// later date.
//----------------------------------------------------------------------------
CKeyDeComp::CKeyDeComp( PDirectory& pDir, INDEXID iid, CPhysIndex& phIndex, WORKID widMax, BOOL fUseLinks, BOOL fUseDir ) : CCoder ( widMax ), CKeyCursor (iid, widMax), _sigKeyDeComp(eSigKeyDeComp), _bitStream ( phIndex ), _fUseLinks( fUseLinks ), _pDir( pDir ), _fUseDir( fUseDir ), _fAtSentinel( FALSE ), _physIndex ( phIndex ) #if (CIDBG == 1)
,_fLastKeyFromDir( FALSE ) #endif
{ LoadKey(); }
//+---------------------------------------------------------------------------
//
// Member: CKeyDeComp::CKeyDeComp, public
//
// Synopsis: Creates a new persistent decompressor.
// positioned at a specified key
//
// Arguments: [iid] -- index id
// [phIndex] -- physical index
// [keyPos] -- bit offset to key stored in directory
// [keyInit] -- initial key
// [pKey] -- actual key to search for
// [widMax] -- Maximum workid which may be in the buffer.
// This must be the same number was was used
// during compression.
//
// History: 12-Jul-91 KyleP Created.
// 21-Apr-92 BartoszM Split into two constructors
// 30-Nov-93 w-PatG Converted from CPersDeComp
//
//----------------------------------------------------------------------------
CKeyDeComp::CKeyDeComp( PDirectory& pDir, INDEXID iid, CPhysIndex& phIndex, BitOffset& keyPos, const CKeyBuf& keyInit, const CKey* pKey, WORKID widMax, BOOL fUseLinks, BOOL fUseDir ) : CCoder ( widMax, keyInit ), CKeyCursor (iid, widMax), _sigKeyDeComp(eSigKeyDeComp), _bitStream( phIndex, keyPos ), _fUseLinks( fUseLinks ), _pDir( pDir ), _fUseDir( fUseDir ), _fAtSentinel( FALSE ), _physIndex ( phIndex ) #if (CIDBG == 1)
,_fLastKeyFromDir( FALSE ) #endif
{ Win4Assert(pKey);
LoadKey();
SeekKey( pKey); }
//+---------------------------------------------------------------------------
//
// Member: CKeyDeComp::CKeyDeComp, public
//
// Synopsis: Copy Constructor
//
// Effects: Copies most of the values in decomp. Calls copy constructor
// for CCoder.
//
// Arguments: [decomp] -- Original CKeyDeComp to be copied.
//
// History: 08-Jan-92 AmyA Created.
// 07-Dec-93 w-PatG Stole from CPersDeComp.
//
//----------------------------------------------------------------------------
CKeyDeComp::CKeyDeComp(CKeyDeComp & decomp) : CCoder (decomp), CKeyCursor(decomp), _sigKeyDeComp(eSigKeyDeComp), _bitStream(decomp._bitStream), _fUseLinks( decomp._fUseLinks ), _bitOffNextKey(decomp._bitOffNextKey), _pDir( decomp._pDir ), _fUseDir( decomp._fUseDir ), _fAtSentinel( decomp._fAtSentinel ), _physIndex(decomp._physIndex) #if (CIDBG == 1)
,_fLastKeyFromDir( decomp._fLastKeyFromDir ) #endif
{ }
//+---------------------------------------------------------------------------
//
// Member: CKeyDeComp::~CKeyDeComp, public
//
// Synopsis: Destroy a decompressor/buffer pair.
//
// Effects: The main effect of destroying a decompressor is that the
// associated buffer is also destroyed (presumably storing
// the data to a persistent medium).
//
// Signals: ???
//
// History: 30-Nov-93 w-PatG Created.
//
//----------------------------------------------------------------------------
CKeyDeComp::~CKeyDeComp() {}
//+---------------------------------------------------------------------------
//
// Member: CKeyDeComp::GetKey, public
//
// Synopsis: Retrieves the current key.
//
// Returns: A pointer to the current key. If at the end of page or
// end of index, returns null.
//
// History: 15-Jul-91 KyleP Created.
// 30-Nov-93 w-PatG Moved from CPersDeComp.
//
//----------------------------------------------------------------------------
const CKeyBuf * CKeyDeComp::GetKey( BitOffset * pBitOff ) { if ( IsAtSentinel() ) return(0);
if ( pBitOff ) GetOffset( *pBitOff );
return(&_key); }
const CKeyBuf * CKeyDeComp::GetKey() { if ( IsAtSentinel() ) return(0);
return(&_key); }
//+---------------------------------------------------------------------------
//
// Member: CKeyDeComp::GetNextKey, public
//
// Synopsis: Retrieve the next key from the content index.
//
// Arguments: [pBitOff] -- optional, will have the offset of the beginning
// of the key.
//
// Returns: A pointer to the key, or 0 if end of page/index reached.
//
// History: 15-Jul-91 KyleP Created.
// 30-Nov-93 w-PatG Converted from CPersDeComp.
// 10-Apr-94 SrikantS Added pBitOff as an optional param.
//
//----------------------------------------------------------------------------
const CKeyBuf * CKeyDeComp::GetNextKey( BitOffset * pBitOff ) {
if ( _fUseLinks ) { if ( !_bitOffNextKey.Valid() ) { Win4Assert( _fUseDir ); _pDir.SeekNext( _key, 0, _bitOffNextKey ); Win4Assert( _bitOffNextKey.Valid() );
ciDebugOut (( 0x01000000 | DEB_PCOMP | DEB_NOCOMPNAME, "*** Result : Page %lu OffSet %lu\n", _bitOffNextKey.Page(), _bitOffNextKey.Offset() )); #if (CIDBG == 1)
_fLastKeyFromDir = TRUE; #endif // CIDBG == 1
} _bitStream.Seek ( _bitOffNextKey ); }
if ( pBitOff ) { _bitStream.GetOffset( *pBitOff ); }
LoadKey();
const CKeyBuf * pkey = GetKey();
return(pkey); }
const CKeyBuf * CKeyDeComp::GetNextKey() { return GetNextKey( 0 ); }
void CKeyDeComp::GetOffset( BitOffset & bitOff ) { _bitStream.GetOffset( bitOff ); }
//+---------------------------------------------------------------------------
//
// Member: CKeyDeComp::SeekKey, private
//
// Synopsis: Seek in the decompressor
//
// Arguments: [pkey] -- Key to search for.
//
// [op] -- Seek equality operation (EQ, GE, etc.)
//
// Returns: A pointer to the key to cursor is actually on. This may
// be = or > [pkey].
//
// History: 26-Apr-91 KyleP Created.
// 25-Aug-92 BartoszM Moved to CPersDecomp
// 30-Nov-93 w-PatG Moved to CKeyDeComp
//
//----------------------------------------------------------------------------
const CKeyBuf * CKeyDeComp::SeekKey(const CKey * pKeySearch) { //
// Find the key >= the specified key.
//
const CKeyBuf* pKeyFound = GetKey();
while (pKeyFound != 0) { //----------------------------------------------------
// 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 );
// skip keys less than the search key
if ( pKeySearch->Compare(*pKeyFound) > 0) { pKeyFound = GetNextKey(); } else break; } return(pKeyFound); }
void CPersDeComp::RatioFinished (ULONG& denom, ULONG& num) { denom = _cWid; Win4Assert ( _cWid >= _cWidLeft ); num = _cWid - _cWidLeft; }
//+---------------------------------------------------------------------------
//
// Member: CKeyDeComp::BitUnCompress, private
//
// Synopsis: Uncompress a number
//
// Arguments: [cbitAverage] -- Minimum number of bits to store.
//
// History: 15-Jul-91 KyleP Created.
//
//----------------------------------------------------------------------------
__forceinline ULONG CKeyDeComp::BitUnCompress( unsigned cbitAverage) { //
// Get the initial count plus a stop bit.
//
Win4Assert( cbitAverage < ULONG_BITS );
ULONG ul = _bitStream.GetBits(cbitAverage + 1);
//
// Simple case: The number fits in the original cbitAverage bits
// (e.g. the stop bit is 0).
// No additional processing necessary.
//
// Complex: Retrieve additional components.
//
if ((ul & 1) == 0) return(ul >> 1);
return IBitUnCompress ( cbitAverage, ul ); }
//+---------------------------------------------------------------------------
//
// Member: CKeyDeComp::IBitUnCompress, private
//
// Synopsis: Uncompress a number
//
// Arguments: [cbitAverage] -- Minimum number of bits to store.
//
// History: 15-Jul-91 KyleP Created.
// 06-Dec-93 w-PatG Moved from CPersDeComp.
//
//----------------------------------------------------------------------------
ULONG CKeyDeComp::IBitUnCompress( unsigned cbitAverage, ULONG ul) {
Win4Assert ( ul & 1 );
int BitsToGetPlus1 = 3;
do { //
// Kill the stop bit.
//
ul >>= 1;
//
// Get the next component and its stop bit.
//
ULONG ulPartial = _bitStream.GetBits(BitsToGetPlus1);
Win4Assert( BitsToGetPlus1 < ULONG_BITS );
ul = (ul << BitsToGetPlus1) | ulPartial;
BitsToGetPlus1++; } while (ul & 1);
ul >>= 1; return(ul); }
//+---------------------------------------------------------------------------
//
// Member: CKeyDeComp::LoadKey, private
//
// Synopsis: Loads data for the next key.
//
// Effects: Reads a key from the current position in _bitStream and
// sets per key state.
//
// Signals: ???
//
// History: 12-Jul-91 KyleP Created.
// 06-Dec-93 w-PatG Modified from CPersDeComp.
//
//----------------------------------------------------------------------------
void CKeyDeComp::LoadKey() {
ULONG TmpValue;
if ( _fUseLinks ) { _bitStream.GetOffset ( _bitOffNextKey ); TmpValue = _bitStream.GetBits ( LINK_MAX_BITS ); }
//
// Retrieve the prefix/suffix. Assume they are stored in 4 bits each
// first.
//
unsigned cPrefix, cSuffix;
LoadPSSize ( cPrefix, cSuffix );
//
// Load the key itself.
//
#if CIDBG == 1
if ( _fLastKeyFromDir ) { //
// We know what the key should be. Compute prefix and
// suffix. Make sure they match.
//
unsigned mincb = __min( _key.Count(), _pDir.GetLastKey().Count() );
for (unsigned cOldPrefix = 0; cOldPrefix < mincb; cOldPrefix++) { if ( (_key.GetBuf())[cOldPrefix] != (_pDir.GetLastKey().GetBuf())[cOldPrefix] ) break; }
unsigned cOldSuffix = _pDir.GetLastKey().Count() - cOldPrefix;
if ( (0 != cPrefix) && (cPrefix != cOldPrefix || cSuffix != cOldSuffix) ) { ciDebugOut(( DEB_ERROR, "Corrupt index or directory!\n" )); ciDebugOut(( DEB_ERROR, "From index: cPrefix = %d, cSuffix = %d\n", cPrefix, cSuffix )); ciDebugOut(( DEB_ERROR, "From directory: cPrefix = %d, cSuffix = %d\n", cOldPrefix, cOldSuffix )); Win4Assert( !"Corrupt index or directory" ); }
_fLastKeyFromDir = FALSE; } #endif // CIDBG == 1
if ( 0 == ( cPrefix + cSuffix ) ) { //
// Disabled asserts prior to widespread Query rollout in NT 5, so
// that the general NT user is not bothered by this asserts.
//
//Win4Assert ( "Data corruption" && cPrefix + cSuffix != 0 );
PStorage & storage = _physIndex.GetStorage(); storage.ReportCorruptComponent( L"KeyDecompressor1" ); THROW( CException( CI_CORRUPT_DATABASE) ); }
if ( cPrefix > _key.Count() ) { //
// Disabled asserts prior to widespread Query rollout in NT 5, so
// that the general NT user is not bothered by this asserts.
//
//Win4Assert ( "Data corruption" && cPrefix <= _key.Count() );
PStorage & storage = _physIndex.GetStorage(); storage.ReportCorruptComponent( L"KeyDecompressor2" ); THROW( CException( CI_CORRUPT_DATABASE) ); }
_bitStream.GetBytes(_key.GetWritableBuf() + cPrefix, cSuffix);
_key.SetCount( cPrefix + cSuffix );
if ( _key.IsMaxKey() ) { ciDebugOut (( DEB_ITRACE, "\n<<Sentinel key>>\n" )); _fAtSentinel = TRUE; return; }
#if CIDBG == 1
//
// This it to test the directory-index interaction when things go wrong. Don't delete
// this code before talking with Dwight/SrikantS/KyleP.
//
#if 0
{ iidDebug = 0x10002; // Looking for this index
WCHAR wcsDebugKey[] = L"TRUE"; // Looking for this key
unsigned lenDebug = min( wcslen( wcsDebugKey ), _key.StrLen() );
//
// If the key we are looking for is found in the desired index, break and
// step through the code to see what is going on.
//
if ( iidDebug == _iid && 0 == _wcsnicmp( _key.GetStr(), wcsDebugKey , lenDebug ) ) { Win4Assert( !"Only during baby-sitting mode" ); }
} #endif // 1
#endif // CIDBG==1
//
// Load the property ID.
//
//
// Store a 0 bit if contents, else
// a 1 followed by ULONG propid.
//
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME, "\"%.*ws\" ", _key.StrLen(),_key.GetStr()));
LoadPid();
// continue to set _bitOffNextKey
if ( _fUseLinks ) { if ( TmpValue == 0 ) { // the size of the current index must exceed the
// max. limit. Use CI Directory to search the next key
// position
ciDebugOut (( 0x01000000, "\n*** Key : \"%.*ws\"\n",_key.StrLen(), _key.GetStr() )); ciDebugOut (( 0x01000000 | DEB_PCOMP | DEB_NOCOMPNAME, "\n\t*** Start search next key's offset\n" )); _bitOffNextKey.SetInvalid();
} else { _bitOffNextKey += TmpValue; ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME, "\n\t$$$ Next key : Page %lu OffSet %lu\n", _bitOffNextKey.Page(), _bitOffNextKey.Offset() )); } }
}
//+---------------------------------------------------------------------------
//
// Member: CKeyDeComp::LoadPSSize, private
//
// Synopsis: Load key prefix and suffix sizes
//
// Arguments: [cPrefix] -- (return) prefix size
// [cSuffix] -- (return) suffix size
//
// History: 05-Nov-91 BartoszM Created.
// 30-Nov-93 w-PatG Moved from CPersDeComp.
//
//----------------------------------------------------------------------------
inline void CKeyDeComp::LoadPSSize ( unsigned& cPrefix, unsigned& cSuffix ) { ULONG ul = _bitStream.GetBits(8);
if (ul != 0) // 4 bits for prefix and suffix
{ cPrefix = (unsigned)ul >> 4; cSuffix = (unsigned)ul & 0xF; } else // 8 bits for prefix and suffix
{ ul = _bitStream.GetBits(16);
cPrefix = (unsigned)ul >> 8; cSuffix = (unsigned)ul & 0xFF; }
Win4Assert(cPrefix + cSuffix <= MAXKEYSIZE ); ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME, "\n(%d:%d) ", cPrefix, cSuffix)); }
//+---------------------------------------------------------------------------
//
// Member: CKeyDeComp::LoadPid, private
//
// Synopsis: Load property id
//
// History: 05-Nov-91 BartoszM Created.
// 06-Dec-93 w-PatG Moved from CPersDeComp.
//
// Notes: The Property id is used for different purposes in CKeyDeComp
// and CPersDeComp. In CKeyDeComp, a PROPID is actually a key id.
//
//----------------------------------------------------------------------------
__forceinline void CKeyDeComp::LoadPid () { ULONG ul = _bitStream.GetBits(1);
if (ul == 0) { _key.SetPid(pidContents); } else { ul = BitUnCompress ( cPidBits ); _key.SetPid (ul); } #if CIDBG == 1
if (ul != 0) ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME," =PID %d= ", ul )); #endif
}
//
// Unused, but required for inheritance.
//
OCCURRENCE CKeyDeComp::Occurrence() { Win4Assert( !"CKeyDeComp::Occurrence() -- invalid call" ); return( 0 ); }
OCCURRENCE CKeyDeComp::NextOccurrence() { Win4Assert( !"CKeyDeComp::NextOccurrence() -- invalid call" ); return( 0 ); }
ULONG CKeyDeComp::OccurrenceCount() { Win4Assert( !"CKeyDeComp::OccurrenceCount() -- invalid call" ); return( 0 ); }
OCCURRENCE CKeyDeComp::MaxOccurrence() { Win4Assert( !"CKeyDeComp::MaxOccurrence() -- invalid call" ); return( 1 ); }
WORKID CKeyDeComp::WorkId() { Win4Assert( !"CKeyDeComp::WorkId() -- invalid call" ); return( 0 ); }
WORKID CKeyDeComp::NextWorkId() { Win4Assert( !"CKeyDeComp::NextWorkId() -- invalid call" ); return( 0 ); }
ULONG CKeyDeComp::HitCount() { Win4Assert( !"CKeyDeComp::HitCount() -- invalid call" ); return(0); }
//+---------------------------------------------------------------------------
//
// Member: CPersComp::CPersComp, public
//
// Synopsis: Creates a new (empty) persistent compressor.
//
// Arguments: [phIndex] -- physical index
//
// [widMax] -- The maximum workid which may be stored via
// PutWorkId.
//
// History: 05-Jul-91 KyleP Created.
//
//----------------------------------------------------------------------------
CPersComp::CPersComp( CPhysIndex& phIndex, WORKID widMax)
: CKeyComp( phIndex, widMax ), _sigPersComp(eSigPersComp), _cWidProposed(0), _cWidActual(0), _bitStreamPatch ( phIndex ) { #if CIDBG == 1
_cOccLeft = 0; #endif // CIDBG == 1
}
//+---------------------------------------------------------------------------
//
// Function: CPersComp::CPersComp
//
// Synopsis: Constructor for the persistent compressor capable of dealing
// with a partially constructed index stream during a restarted
// master merge.
//
// Arguments: [phIndex] -- The physical index being constructed
// during a restarted master merge.
// [widMax] -- Maximum wid for the index.
// [bitOffRestart] -- Offset where to restart adding new
// keys.
// [bitOffSplitKey] -- Beginning offset of the last key added.
// If no keys added, set to 0,0.
// [splitKey] -- The key last successfully written to
// disk (split key). If there is no key, set it to "MinKey".
//
// History: 4-10-94 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
CPersComp::CPersComp( CPhysIndex& phIndex, WORKID widMax, const BitOffset & bitOffRestart, const BitOffset & bitOffSplitKey, const CKeyBuf & splitKey)
: CKeyComp( phIndex, widMax, bitOffRestart, bitOffSplitKey, splitKey), _sigPersComp(eSigPersComp), _cWidProposed(0), _cWidActual(0), _bitStreamPatch ( phIndex ) { #if CIDBG == 1
_cOccLeft = 0; #endif // CIDBG == 1
}
//+---------------------------------------------------------------------------
//
// Member: CPersComp::~CPersComp, public
//
// Synopsis: Destroy a compressor/buffer pair.
//
// Effects: The main effect of destroying a compressor is that the
// associated buffer is also destroyed (presumably storing
// the data to a persistent medium).
//
// Signals: ???
//
// History: 05-Jul-91 KyleP Created.
//
// Notes: Previous compressor is deleted in PutKey
//
//----------------------------------------------------------------------------
CPersComp::~CPersComp() { ciDebugOut (( DEB_PCOMP,"CPersComp::~CPersComp() -- Last Key = %.*ws\n", _key.StrLen(), _key.GetStr() )); }
//+---------------------------------------------------------------------------
//
// Member: CPersComp::PatchWidCount, private
//
// Synopsis: Overwrites wid count
//
// History: 06-Nov-91 BartoszM Created.
//
//----------------------------------------------------------------------------
inline void CPersComp::PatchWidCount () { if (_cWidProposed <= 15) { _bitStreamPatch.OverwriteBits(_cWidActual, 4); } else if (_cWidProposed <= 255) { _bitStreamPatch.OverwriteBits(_cWidActual, 12); // 4 0's + 8 bit number
} else { _bitStreamPatch.OverwriteBits(0, 12); // 12 0's
_bitStreamPatch.OverwriteBits(_cWidActual, ULONG_BITS); // ULONG_BITS bit number
} }
//+---------------------------------------------------------------------------
//
// Member: CPersComp::PutWidCount, private
//
// Synopsis: Writes work id count
//
// Arguments: [cWorkId] -- Count of wid's
//
// History: 06-Nov-91 BartoszM Created.
//
// Notes: Store the workid count. First, store the WID count used for
// compression. We will store a 4 bit count. If the count is
// greater than 15 then a 4-bit 0 will be stored followed by an 8 bit
// count. If the count is greater than 255 then a 12-bit 0 will be
// stored followed by a ULONG_BITS bit count.
//
//----------------------------------------------------------------------------
inline void CPersComp::PutWidCount ( ULONG cWorkId ) { Win4Assert(cWorkId > 0);
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME, "[%d]", cWorkId ));
BitOffset off;
// Position the patch stream at current offset
_bitStream.GetOffset(off); _bitStreamPatch.Seek(off);
if (cWorkId <= 15) { _bitStream.PutBits(cWorkId, 4); } else if (cWorkId <= 255) { _bitStream.PutBits(cWorkId, 12); // 4 0's + 8 bit number
} else { _bitStream.PutBits(0, 12); // 12 0's
_bitStream.PutBits(cWorkId, ULONG_BITS); // ULONG_BITS bit number
}
//
// Store a single bit indicating whether the count is accurrate.
// Regardless of whether it is accurrate, it is used for encoding.
//
_bitStream.PutBits(1, 1);
}
//+---------------------------------------------------------------------------
//
// Member: CPersComp::SkipWidCount, private
//
// Synopsis: Skips wid count
//
// History: 06-Nov-91 BartoszM Created.
//
//----------------------------------------------------------------------------
inline void CPersComp::SkipWidCount () { unsigned posDelta;
if (_cWidProposed <= 15) posDelta = 4; else if (_cWidProposed <= 255) posDelta = 12; else posDelta = 12 + ULONG_BITS;
_bitStreamPatch.SkipBits(posDelta); }
//+---------------------------------------------------------------------------
//
// Member: CPersComp::PutKey, public
//
// Synopsis: Starts recording data for a new key.
//
// Arguments: [key] -- The new key.
//
// [cWorkId] -- Count of work ids to follow.
//
// [bitOff] -- (out) actual bit offset of the key in the index
//
// History: 05-Jul-91 KyleP Created.
//
// Notes: The structure for each key is:
// Prefix/Suffix size
// Suffix
// Property ID
// Work ID count
//
//----------------------------------------------------------------------------
void CPersComp::PutKey(const CKeyBuf * pkey, ULONG cWorkId, BitOffset & bitOffCurKey) {
Win4Assert(_cOccLeft == 0); Win4Assert(cWorkId > 0);
#if 0
if ( ( _cWidActual == 0 ) && ( _cWidProposed != 0 ) ) { BackSpace(); } else { #endif // 0
//
// Set the WorkId count accuracy bit for the previous key (if any).
// Then reset the workid counter.
//
SetCWIDAccuracy(); #if 0
} #endif // 0
CKeyComp::PutKey(pkey, bitOffCurKey);
//
// Assume that a cursor just counted a few too many workids.
// If the final workid count is > _widMaximum that is very bad.
//
if ( cWorkId > _widMaximum ) cWorkId = _widMaximum;
PutWidCount ( cWorkId );
//
// Set up per/workid state
//
SetAverageBits ( cWorkId ); _wid = 0; _cWidProposed = cWorkId; _cWidActual = 0;
#if CIDBG == 1
_cOccLeft = 0; #endif
}
//+---------------------------------------------------------------------------
//
// Member: CPersComp::PutWorkId, public
//
// Synopsis: Store a new WorkId.
//
// Arguments: [wid] -- WorkId
// [maxOcc] -- Max occurrence of wid
// [cOccurrence] -- Count of occurrences to follow
//
// Requires: [wid] must be larger than the last WorkId stored in
// the current key.
//
// Modifies: The input is added to the new index.
//
// History: 08-Jul-91 KyleP Created.
//
//----------------------------------------------------------------------------
void CPersComp::PutWorkId(WORKID wid, OCCURRENCE maxOcc, ULONG cOccurrence) { Win4Assert(wid != widInvalid); Win4Assert(wid > 0); Win4Assert( wid > _wid ); Win4Assert( _cbitAverageWid > 0 ); Win4Assert(wid <= _widMaximum); Win4Assert(_cOccLeft == 0); Win4Assert( cOccurrence > 0 );
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME,"<%d>", wid ));
//
// Store the workid delta.
//
BitCompress(wid - _wid, _cbitAverageWid);
//
// Store the max occurrence
//
PutMaxOccurrence( maxOcc );
//
// And store the occurrence count.
//
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME,"(%d)", cOccurrence ));
BitCompress(cOccurrence, OccCountBits);
//
// Update state
//
_wid = wid; _occ = 0; _cWidActual++;
#if CIDBG == 1
_cOccLeft = cOccurrence; #endif
}
//+---------------------------------------------------------------------------
//
// Member: CPersComp::PutMaxOccurrence
//
// Synopsis: Writes the max occurrence using the same compression
// scheme as that for writing widCount
//
// Arguments: [maxOcc] -- Max occurrence to write
//
// History: 20-Jun-96 SitaramR Created
//
//----------------------------------------------------------------------------
void CPersComp::PutMaxOccurrence( OCCURRENCE maxOcc ) { Win4Assert( maxOcc > 0 );
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME, "[%d]", maxOcc ));
if ( maxOcc <= 15 ) { _bitStream.PutBits( maxOcc, 4 ); } else if ( maxOcc <= 255 ) { _bitStream.PutBits( maxOcc, 12 ); // 4 0's + 8 bit number
} else { _bitStream.PutBits( 0, 12 ); // 12 0's
_bitStream.PutBits( maxOcc, ULONG_BITS ); // ULONG_BITS bit number
} }
//+---------------------------------------------------------------------------
//
// Member: CPersComp::SetCWIDAccuracy, private
//
// Effects: Determines if the originally specified number of WorkIds
// was accurate, and sets the 'accuracy' bit in the key
// accordingly.
//
// Modifies: The most recent 'accuracy' bit may be changed. This may
// be in a previous compressor or the current compressor.
//
// History: 18-Jul-91 KyleP Created.
//
// Notes: The only time additional space is needed is when we have
// an inaccurate count which cannot be fixed up.
//
//----------------------------------------------------------------------------
void CPersComp::SetCWIDAccuracy() { Win4Assert(_cWidActual <= _widMaximum);
//
// If the count was accurrate, then do nothing except delete the
// previous compressor (if any). If the count is inaccurate, then
// set the 'accuracy' bit.
//
if (_cWidActual != _cWidProposed) {
//
// Decide if the count can be fixed up without having to shift
// any previously written data. This can generally be accomplished
// if the real count is either smaller than the proposed count or
// not too much larger *and* _cbitAverageWid remains the same.
//
Win4Assert ( _cWidActual <= _widMaximum );
if ( _cWidActual != 0 && _cbitAverageWid == AverageWidBits(_cWidActual) ) { // ciDebugOut (( DEB_PCOMP, "fixed.\n"));
Win4Assert(_cWidActual < _cWidProposed);
PatchWidCount ();
} else {
//
// If we can't fix the count, then just set the 'count invalid' bit.
// And append a workid delta of 0.
//
// ciDebugOut (( DEB_PCOMP, "not fixed.\n"));
//
// Read forward over the count.
//
SkipWidCount ();
//
// And set the count invalid bit
//
#if CIDBG == 1
if (_bitStreamPatch.PeekBit() != 1) { Dump(); Win4Assert ( _bitStreamPatch.PeekBit() == 1 ); } #endif // CIDBG == 1
_bitStreamPatch.OverwriteBits(0, 1);
//
// Store the sentinel workid delta.
//
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME," end "));
BitCompress(0, _cbitAverageWid);
}
_cWidActual = 0; _cWidProposed = 0; }
}
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::CPersDeComp, public
//
// Synopsis: Creates a new persistent decompressor
// at the beginning of an index
//
// Arguments: [iid] -- index id
// [phIndex] -- physical index
// [widMax] -- Maximum workid which may be in the buffer.
// This must be the same number was was used
// during compression.
// [fUseDir] -- Flag indicating if the directory should be
// used or not for decompressing. Normally set to FALSE but
// during an in-progress master merge, we may not have a
// directory constructed yet.
//
// History: 12-Jul-91 KyleP Created.
// 21-Apr-92 BartoszM Split into two constructors
// 10-Apr=94 SrikantS Added fUseDir for restarted master
// merge.
//
//----------------------------------------------------------------------------
CPersDeComp::CPersDeComp( PDirectory& pDir, INDEXID iid, CPhysIndex& phIndex, WORKID widMax, BOOL fUseLinks, BOOL fUseDir ) : CKeyDeComp( pDir, iid, phIndex, widMax, fUseLinks, fUseDir ), _sigPersDeComp(eSigPersDeComp) { FinishKeyLoad(); }
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::CPersDeComp, public
//
// Synopsis: Creates a new persistent decompressor.
// positioned at a specified key
//
// Arguments: [iid] -- index id
// [phIndex] -- physical index
// [keyPos] -- bit offset to key stored in directory
// [keyInit] -- initial key
// [pKey] -- actual key to search for
// [widMax] -- Maximum workid which may be in the buffer.
// This must be the same number was was used
// during compression.
// [fUseDir] -- Flag indicating if the directory should be
// used or not for decompressing. Normally set to FALSE but
// during an in-progress master merge, we may not have a
// directory constructed yet.
//
// History: 12-Jul-91 KyleP Created.
// 21-Apr-92 BartoszM Split into two constructors
// 10-Apr=94 SrikantS Added fUseDir for restarted master
// merge.
//
//----------------------------------------------------------------------------
CPersDeComp::CPersDeComp( PDirectory& pDir, INDEXID iid, CPhysIndex& phIndex, BitOffset& keyPos, const CKeyBuf& keyInit, const CKey* pKey, WORKID widMax, BOOL fUseLinks, BOOL fUseDir ) : CKeyDeComp( pDir, iid, phIndex, keyPos, keyInit, pKey, widMax, fUseLinks, fUseDir ), _sigPersDeComp(eSigPersDeComp), _maxOcc(OCC_INVALID) { FinishKeyLoad(); CKeyCursor::_pid = _key.Pid(); UpdateWeight(); }
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::CPersDeComp, public
//
// Synopsis: Copy Constructor
//
// Effects: Copies most of the values in decomp. Calls copy constructor
// for CCoder.
//
// Arguments: [decomp] -- Original CPersDeComp to be copied.
//
// History: 08-Jan-92 AmyA Created.
//
//----------------------------------------------------------------------------
CPersDeComp::CPersDeComp(CPersDeComp & decomp) : CKeyDeComp (decomp), _sigPersDeComp(eSigPersDeComp), _cWid(decomp._cWid), _cOcc(decomp._cOcc), _fcwidAccurate(decomp._fcwidAccurate), _cWidLeft(decomp._cWidLeft), _cOccLeft(decomp._cOccLeft), _maxOcc(OCC_INVALID) { UpdateWeight(); }
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::~CPersDeComp, public
//
// Synopsis: Destroy a decompressor/buffer pair.
//
// Effects: The main effect of destroying a decompressor is that the
// associated buffer is also destroyed (presumably storing
// the data to a persistent medium).
//
// Signals: ???
//
// History: 22-Jul-91 KyleP Created.
//
//----------------------------------------------------------------------------
CPersDeComp::~CPersDeComp() {}
const CKeyBuf * CPersDeComp::GetNextKey() { return GetNextKey(0); }
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::GetNextKey, public
//
// Synopsis: Retrieve the next key from the content index.
//
// Returns: A pointer to the key, or 0 if end of page/index reached.
//
// History: 15-Jul-91 KyleP Created.
// 10-Apr-94 SrikantS Added pBitOff and the ability to
// decompress without using the dir.
//
//----------------------------------------------------------------------------
const CKeyBuf * CPersDeComp::GetNextKey( BitOffset *pBitOff ) { //
// If we are not using links or
// we are not using the directory and the offset of next key
// is invalid, we must skip over the wid/occurrence data and
// find out the offset of the next key.
//
if ( !_fUseLinks || (!_fUseDir && !_bitOffNextKey.Valid()) ) { //
// Just iterate through any remaining data for this key.
//
while (_wid != widInvalid) { while ( 0 != _cOccLeft ) { BitUnCompress( OccDeltaBits ); _cOccLeft--; }
LoadWorkId(); }
if ( _fUseLinks ) { //
// We should fill the bitoffset for the next key as
// the current position in the bitstream.
//
Win4Assert( !_fUseDir ); _bitStream.GetOffset( _bitOffNextKey ); } }
const CKeyBuf * pkey = CKeyDeComp::GetNextKey( pBitOff );
if ( pkey ) { FinishKeyLoad(); CKeyCursor::_pid = pkey->Pid(); UpdateWeight(); }
return pkey; } //GetNextKey
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::WorkId, public
//
// Synopsis: Retrieves the current Work ID
//
// Returns: The current WorkId or, if there is none or if at the end
// of the compressor then returns widInvalid.
//
// History: 15-Jul-91 KyleP Created.
//
//----------------------------------------------------------------------------
WORKID CPersDeComp::WorkId() { return(_wid); }
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::NextWorkId, public
//
// Synopsis: Retrieve the next workid from the content index.
//
// Returns: A pointer to the workid, or widInvalid if end of
// page/index reached.
//
// History: 15-Jul-91 KyleP Created.
//
//----------------------------------------------------------------------------
WORKID CPersDeComp::NextWorkId() { //
// Just iterate through any remaining data for this WorkId.
//
while ( 0 != _cOccLeft ) { BitUnCompress( OccDeltaBits ); _cOccLeft--; }
// _occ may be invalid and really should be OCC_INVALID, but it doesn't matter
LoadWorkId();
return _wid; }
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::WorkIdCount, public
//
// Returns: The total count of workids for the current key.
//
// History: 15-Jul-91 KyleP Created.
//
// Notes: Unlike the Get* calls, it is illegal to get a workid count
// if there is no valid key.
//
//----------------------------------------------------------------------------
ULONG CPersDeComp::WorkIdCount() { Win4Assert( _key.Count() > 0 );
return(_cWid); }
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::Occurrence, public
//
// Synopsis: Retrieves the current occurrence
//
// Returns: The current occurrence or, if there is none or if at the end
// of the compressor then returns OCC_INVALID.
//
// History: 15-Jul-91 KyleP Created.
//
//----------------------------------------------------------------------------
OCCURRENCE CPersDeComp::Occurrence() { return(_occ); }
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::NextOccurrence, public
//
// Synopsis: Retrieve the next occurrence from the content index.
//
// Returns: A pointer to the occurrence, or OCC_INVALID if end of
// page/index reached.
//
// History: 15-Jul-91 KyleP Created.
//
//----------------------------------------------------------------------------
OCCURRENCE CPersDeComp::NextOccurrence() { LoadOccurrence();
return _occ; }
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::OccurrenceCount, public
//
// Returns: The total count of occurrences for the current workid.
//
// History: 15-Jul-91 KyleP Created.
//
// Notes: Unlike the Get* calls, it is illegal to get an occ count
// if there is no valid workid.
//
//----------------------------------------------------------------------------
ULONG CPersDeComp::OccurrenceCount() { Win4Assert(_wid != widInvalid);
return(_cOcc); }
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::LoadWidCount, private
//
// Synopsis: Loads wid count
//
// History: 05-Nov-91 BartoszM Created.
//
//----------------------------------------------------------------------------
inline void CPersDeComp::LoadWidCount () { //
// Get the WorkId count. Initially assume it is 4 bits, then 8,
// then ULONG_BITS.
//
ULONG ul = _bitStream.GetBits(4); ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME, "{0x%x}", ul ));
if (ul == 0) { ul = _bitStream.GetBits(8);
if (ul == 0) { ul = _bitStream.GetBits(ULONG_BITS); Win4Assert(ul != 0); } }
_cWid = _cWidLeft = ul;
//
// Get the bit signifying that the workid count is accurate.
//
ul = _bitStream.GetBits(1);
_fcwidAccurate = ul ? TRUE : FALSE;
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME, "[%s%d]", _fcwidAccurate?"":"!", _cWid )); }
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::LoadKey, private
//
// Synopsis: Loads data for the next key.
//
// Effects: Reads a key from the current position in _bitStream and
// sets per key state.
//
// Signals: ???
//
// History: 12-Jul-91 KyleP Created.
//
//----------------------------------------------------------------------------
void CPersDeComp::LoadKey() { CKeyDeComp::LoadKey(); FinishKeyLoad(); }
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::FinishKeyLoad, private
//
// Synopsis: Loads wid count and first wid. Finishes LoadKey call of
// CKeyDeComp
//
// History: 07-Dec-93 w-PatG Created.
//
//----------------------------------------------------------------------------
void CPersDeComp::FinishKeyLoad() { //Parent class has loaded in a key and id. Finish the job by loading in
//a wid count and first wid.
if ( IsAtSentinel() ) { _wid = widInvalid; _occ = OCC_INVALID; _maxOcc = OCC_INVALID; return; }
LoadWidCount (); _wid = 0;
#if CIDBG == 1
if ( _cWid > _widMaximum ) ciDebugOut (( DEB_ERROR, "_cWid = %ld, _widMaximum = %ld\n", _cWid, _widMaximum )); #endif
Win4Assert ( _cWid <= _widMaximum );
SetAverageBits( _cWid );
LoadWorkId(); }
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::LoadOccurrence, private
//
// Synopsis: Load an occurrence from the bit buffer.
//
// History: 15-Jul-91 KyleP Created.
//
//----------------------------------------------------------------------------
__forceinline void CPersDeComp::LoadOccurrence() { if (_cOccLeft == 0) { _occ = OCC_INVALID; return; }
ULONG occDelta = BitUnCompress(OccDeltaBits);
Win4Assert( occDelta > 0 );
_occ += occDelta; _cOccLeft--;
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME, "%d ", _occ )); }
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::LoadFirstOccurrence, private
//
// Synopsis: Load an occurrence from the bit buffer.
//
// History: 15-Jul-91 KyleP Created.
//
//----------------------------------------------------------------------------
__forceinline void CPersDeComp::LoadFirstOccurrence() { Win4Assert( 0 != _cOccLeft );
_occ = BitUnCompress(OccDeltaBits);
Win4Assert( _occ > 0 );
_cOccLeft--;
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME, "%d ", _occ )); }
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::LoadMaxOccurrence
//
// Synopsis: Load max occurrence from the bit buffer.
//
// History: 20-Jun-96 SitaramR Created
//
//----------------------------------------------------------------------------
__forceinline void CPersDeComp::LoadMaxOccurrence() { //
// Initially assume it is 4 bits, then 8, then ULONG_BITS
//
_maxOcc = _bitStream.GetBits(4);
if ( _maxOcc == 0 ) { _maxOcc = _bitStream.GetBits(8);
if ( _maxOcc == 0 ) { _maxOcc = _bitStream.GetBits(ULONG_BITS); Win4Assert( _maxOcc != 0 ); } }
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME, "{0x%x}", _maxOcc )); }
//+---------------------------------------------------------------------------
//
// Member: CPersDeComp::LoadWorkId, private
//
// Synopsis: Loads data for a WorkId.
//
// History: 15-Jul-91 KyleP Created.
//
//----------------------------------------------------------------------------
void CPersDeComp::LoadWorkId() { if (_cWidLeft == 0) { Win4Assert(_fcwidAccurate); _wid = widInvalid; return; }
ULONG widDelta = BitUnCompress( _cbitAverageWid);
if (widDelta == 0) { #if CIDBG == 1
if (_fcwidAccurate) Dump(); #endif
Win4Assert(!_fcwidAccurate); _wid = widInvalid; return; }
LoadMaxOccurrence();
ULONG occCount = BitUnCompress( OccCountBits);
_wid += widDelta;
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME, "<%d>", _wid ));
Win4Assert(_wid <= _widMaximum); _cOcc = _cOccLeft = occCount; _cWidLeft--;
ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME, "(%d)", _cOcc ));
LoadFirstOccurrence(); }
#if DEVL == 1
void CCoder::Dump() { #if CIDBG == 1
ciDebugOut((DEB_ITRACE, "CCoder:\n" "\t_widMaximum %d\n" "\tKey \"%.*ws\"\n" "\t_wid %d" "\t_occ %d\n" "\t_cbitAverageWid %d\n", _widMaximum, _key.StrLen(), _key.GetStr(), _wid, _occ, _cbitAverageWid )); #endif // CIDBG == 1
}
void CKeyComp::Dump() { }
void CKeyDeComp::Dump() { }
void CPersDeComp::Dump() { #if CIDBG == 1
CCoder::Dump(); ciDebugOut((DEB_ITRACE, "CPersDeComp:\n" "\t_cWid %d\n" "\t_cOcc %d\n" "\t_fcwidAccurate %d" "\t_cWidLeft %d\n" "\t_cOccLeft %d\n", _cWid, _cOcc, _fcwidAccurate, _cWidLeft, _cOccLeft )); _bitStream.Dump(); #endif // CIDBG == 1
}
void CPersComp::Dump() { #if CIDBG == 1
CCoder::Dump(); ciDebugOut((DEB_ITRACE, "CPersComp:\n" "\t_cWidActual %d\n" "\t_cWidProposed %d\n" "\t_cOccLeft %d\n", _cWidActual, _cWidProposed, _cOccLeft )); ciDebugOut((DEB_ITRACE, "BitStream\n" )); _bitStream.Dump(); ciDebugOut((DEB_ITRACE, "BitStreamPatch\n" )); _bitStreamPatch.Dump(); #endif // CIDBG == 1
} #endif // DEVL == 1
|