//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1991 - 2000. // // File: PComp.hxx // // Contents: Persistent index compressor, and decompressor // // Classes: CCoder, CKeyComp, CPersComp // // History: 03-Jul-91 KyleP Created // 05-Nov-91 BartoszM Restructured to use CCoder // 05-Dec-93 w-PatG Restructured to use CKeyComp // // Notes: The CKeyComp class is under development, testing phase. // Several revisions must be made to increase the amount of // inheritence, and improve the coding algorithm used by CKeyComp. // //---------------------------------------------------------------------------- #pragma once #include #include #include #include "bitstm.hxx" #define LINK_MAX_BITS (CI_PAGE_SHIFT + 8) // The max. value of "link" of the persistent index #define LINK_MAX_VALUE ( 1 << LINK_MAX_BITS ) // const unsigned OccDeltaBits = 7; // Bits to initially store an // occurrence delta. class CPageBuffer; //+--------------------------------------------------------------------------- // // Class: CCoder // // Purpose: Common class for encoding/decoding of compressed data // // Interface: // // History: 05-Nov-91 BartoszM Created // //---------------------------------------------------------------------------- class CCoder { public: CCoder(WORKID widMax); CCoder(WORKID widMax, const CKeyBuf& keyInit); CCoder(CCoder& orig); virtual ~CCoder(); #if DEVL == 1 void Dump(); #endif #ifdef CIEXTMODE void CiExtDump(void *ciExtSelf); #endif protected: UINT AverageWidBits ( UINT cWid ); void SetAverageBits ( UINT cWid ) { _cbitAverageWid = AverageWidBits ( cWid ); } const WORKID _widMaximum; // Maximum workid in current index CKeyBuf _key; WORKID _wid; OCCURRENCE _occ; UINT _cbitAverageWid; // Log of the average WorkId delta. }; __forceinline UINT CCoder::AverageWidBits ( UINT cWid ) { ciAssert ( cWid != 0 ); ciAssert ( _widMaximum / cWid != 0 ); UINT x = Log2(_widMaximum / cWid); ciAssert ( x <= ULONG_BITS ); ciAssert ( x > 0 ); return x; } //+--------------------------------------------------------------------------- // // Class: CKeyComp (kcomp) // // Purpose: Key compressor // // Interface: (Under development) // // History: 12-Nov-93 w-PatG Created. // // Notes: Derived class that lies between base class CCoder and further // derived class CPersCoder. //---------------------------------------------------------------------------- const LONGLONG eSigKeyComp = 0x20504d4f4359454bi64; // "KEYCOMP" class CKeyComp: public CCoder { public: CKeyComp(CPhysIndex& phIndex, WORKID widMax, BOOL fUseLinks = TRUE); CKeyComp(CPhysIndex& phIndex, WORKID widMax, const BitOffset & bitOffRestart, const BitOffset & bitOffSplitKey, const CKeyBuf & splitKey, BOOL fUseLinks = TRUE); ~CKeyComp(); void PutKey(const CKeyBuf * pkey, BitOffset & bitOffCurKey); __forceinline void GetOffset( BitOffset & bitOff ) { _bitStream.GetOffset( bitOff ); } __forceinline BOOL IsAtSentinel() { return _key.IsMaxKey(); } #if DEVL == 1 void Dump(); #endif void ZeroToEndOfPage() { _bitStream.ZeroToEndOfPage(); } void InitSignature() { _bitStream.InitSignature(); } void WriteFirstKeyFull() { _fWriteFirstKeyFull = TRUE; } #ifdef CIEXTMODE void CiExtDump(void *ciExtSelf); #endif void FreeStream() { _bitStream.FreeStream(); _bitStreamLink.FreeStream(); } protected: void BitCompress(ULONG ul, unsigned cbitAverage); void IBitCompress(ULONG ul, unsigned cbitAverage, unsigned bitSize); void PutPSSize ( unsigned cPrefix, unsigned cSuffix ); void PutPid ( PROPID pid ); const LONGLONG _sigKeyComp; // CPhysIndex & _phIndex; // The Physical Index for the bitstream CWBitStream _bitStream; // must be created first BOOL _fUseLinks; CPBitStream _bitStreamLink; BitOffset _bitOffCurKey; // These two bitOffsets are used to rewind BitOffset _bitOffLastKey; // the compressor to the previous key. BOOL _fWriteFirstKeyFull; // Write first key on each page fully }; //+--------------------------------------------------------------------------- // // Class: CKeyDeComp (kdcomp) // // Purpose: Persistent key de-compressor // // Interface: // // History: 09-Jul-91 KyleP Created. // 22-Nov-93 w-PatG Converted from CPersDeComp // // Notes: One of the key requirements for using de-compressors is // that if an operation fails because the end of page was // reached, that *same* operation must be the first one // performed on the following compressor. // //---------------------------------------------------------------------------- const LONGLONG eSigKeyDeComp = 0x504d4f434459454bi64; // "KEYDCOMP" class CKeyDeComp: public CCoder, public CKeyCursor { public: CKeyDeComp( PDirectory& pDir, INDEXID iid, CPhysIndex& phIndex, WORKID widMax, BOOL fUseLinks = TRUE, BOOL fUseDir = TRUE ); CKeyDeComp( PDirectory& pDir, INDEXID iid, CPhysIndex& phIndex, BitOffset& posKey, const CKeyBuf& keyInit, const CKey* pKey, WORKID widMax, BOOL fUseLinks = TRUE, BOOL fUseDir = TRUE ); CKeyDeComp( CKeyDeComp & decomp ); ~CKeyDeComp(); const CKeyBuf * GetKey(); const CKeyBuf * GetNextKey(); virtual const CKeyBuf * GetNextKey( BitOffset * pBitOff ); virtual const CKeyBuf * GetKey( BitOffset * pBitOff ); PROPID Pid(); void GetOffset( BitOffset & bitOff ); void FreeStream() { _bitStream.FreeStream(); } void RefillStream() { _bitStream.RefillStream(); } // // Unused. Required for inheritance. // OCCURRENCE Occurrence(); OCCURRENCE NextOccurrence(); ULONG OccurrenceCount(); OCCURRENCE MaxOccurrence(); WORKID WorkId(); WORKID NextWorkId(); ULONG HitCount(); #if DEVL == 1 void Dump(); #endif #ifdef CIEXTMODE void CiExtDump(void *ciExtSelf); #endif protected: const CKeyBuf* SeekKey(const CKey* pKey); ULONG BitUnCompress(unsigned cbitAverage); ULONG IBitUnCompress(unsigned cbitAverage, ULONG ulPartial); void LoadKey(); void LoadPSSize ( unsigned& cPrefix, unsigned& cSuffix ); void LoadPid (); BOOL IsAtSentinel() const { return _fAtSentinel; } const LONGLONG _sigKeyDeComp; CRBitStream _bitStream; BOOL _fUseLinks; BitOffset _bitOffNextKey; PDirectory& _pDir; BOOL _fUseDir; BOOL _fAtSentinel; // TRUE if at sentinel (end) key. CPhysIndex & _physIndex; #if (CIDBG == 1) BOOL _fLastKeyFromDir; // TRUE if last key looked up in directory #else BOOL _fDummy; // to keep chk/free size the same #endif }; //+--------------------------------------------------------------------------- // // Class: CPersComp (pcomp) // // Purpose: Persistent index compressor // // Interface: // // History: 03-Jul-91 KyleP Created. // 02-Dec-93 w-PatG Altered to use CKeyComp. // //---------------------------------------------------------------------------- const LONGLONG eSigPersComp = 0x504d4f4353524550i64; // "PERSCOMP" class CPersComp: public CKeyComp { public: CPersComp(CPhysIndex& phIndex, WORKID widMax); CPersComp(CPhysIndex& phIndex, WORKID widMax, const BitOffset & bitOffRestart, const BitOffset & bitoffSplitKey, const CKeyBuf & splitKey ); ~CPersComp(); void PutKey(const CKeyBuf * pkey, ULONG cWorkId, BitOffset & bitOffCurKey); void PutWorkId(WORKID wid, OCCURRENCE maxOcc, ULONG cOccurrence); inline void PutOccurrence(OCCURRENCE occ); #if DEVL == 1 void Dump(); #endif #ifdef CIEXTMODE void CiExtDump(void *ciExtSelf); #endif void FreeStream() { _bitStreamPatch.FreeStream(); CKeyComp::FreeStream(); } protected: inline void BackSpace(); void SetCWIDAccuracy(); void PatchWidCount (); void PutWidCount ( ULONG cWorkId ); void SkipWidCount (); void PutMaxOccurrence( OCCURRENCE maxOcc ); const LONGLONG _sigPersComp; unsigned _cWidActual; // Used to decide if the originally unsigned _cWidProposed; // Original WorkId count. Used to // allocate space for the count. CPBitStream _bitStreamPatch; // Used to back patch wid count // created after main _bitStream #if DEVL == 1 unsigned _cOccLeft; // ciVerify the specified number of #endif }; //+--------------------------------------------------------------------------- //---------------------------------------------------------------------------- inline void CPersComp::BackSpace() { _bitStream.Seek(_bitOffCurKey); if ( _fUseLinks ) _bitStreamLink.Seek(_bitOffLastKey); ZeroToEndOfPage(); _phIndex.SetUsedPagesCount( _bitOffCurKey.Page() + 1 ); _cWidProposed = _cWidActual; _key.SetCount( 0 ); } //+--------------------------------------------------------------------------- // // Class: CPersDeComp (pdcomp) // // Purpose: Persistent index de-compressor // // Interface: // // History: 09-Jul-91 KyleP Created. // 02-Dec-93 w-PatG Altered to use CKeyComp. // // Notes: One of the key requirements for using de-compressors is // that if an operation fails because the end of page was // reached, that *same* operation must be the first one // performed on the following compressor. // // //---------------------------------------------------------------------------- const LONGLONG eSigPersDeComp = 0x504d434453524550i64; // "PERSDCMP" class CPersDeComp: public CKeyDeComp { public: CPersDeComp( PDirectory& pDir, INDEXID iid, CPhysIndex& phIndex, WORKID widMax, BOOL fUseLinks = TRUE, BOOL fUseDir = TRUE ); CPersDeComp( PDirectory& pDir, INDEXID iid, CPhysIndex& phIndex, BitOffset& posKey, const CKeyBuf& keyInit, const CKey* pKey, WORKID widMax, BOOL fUseLinks = TRUE, BOOL fUseDir = TRUE); CPersDeComp(CPersDeComp& orig); ~CPersDeComp(); const CKeyBuf * GetNextKey(); const CKeyBuf * GetNextKey( BitOffset * pbitOff ); WORKID WorkId(); WORKID NextWorkId(); ULONG WorkIdCount(); OCCURRENCE Occurrence(); OCCURRENCE NextOccurrence(); OCCURRENCE MaxOccurrence() { return _maxOcc; } ULONG OccurrenceCount(); ULONG HitCount() { return OccurrenceCount(); } void RatioFinished ( ULONG& denom, ULONG& num ); #if DEVL == 1 void Dump(); #endif #ifdef CIEXTMODE void CiExtDump(void *ciExtSelf); #endif private: void LoadKey(); void FinishKeyLoad(); void LoadWorkId(); void LoadOccurrence(); void LoadFirstOccurrence(); void LoadWidCount (); void LoadMaxOccurrence(); const LONGLONG _sigPersDeComp; // // 'Current' state of the decompressor. These values are always // valid and are returned by the various Get functions. // ULONG _cWid; ULONG _cOcc; OCCURRENCE _maxOcc; // // 'Transient' state. Helps the decompressor figure out what/where // its decompressing. // BOOL _fcwidAccurate; ULONG _cWidLeft; ULONG _cOccLeft; }; //+--------------------------------------------------------------------------- // // Member: CPersComp::PutOccurrence, public // // Synopsis: Store an occurrence for the current WorkId. // // Arguments: [occ] -- The occurrence to store. // // Modifies: [occ] is added to the persistent index. // // History: 08-Jul-91 KyleP Created. // //---------------------------------------------------------------------------- __forceinline void CPersComp::PutOccurrence(OCCURRENCE occ) { ciAssert(occ != OCC_INVALID); ciAssert(occ > _occ); ciAssert(_cOccLeft > 0); ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME,"%d ", occ )); BitCompress(occ - _occ, OccDeltaBits); _occ = occ; #if CIDBG == 1 _cOccLeft--; #endif } //+--------------------------------------------------------------------------- // // Member: CKeyComp::BitCompress, 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. // //---------------------------------------------------------------------------- __forceinline void CKeyComp::BitCompress(ULONG ul, unsigned cbitAverage) { ciAssert(cbitAverage > 0); ciAssert(cbitAverage <= ULONG_BITS ); unsigned bitSize = Log2(ul); // // If bitSize < cbitAverage then rightshift // to make it cbitAverage and store cbitAverage bits // plus the signal bit (0 = done, 1 = more) // if (bitSize <= cbitAverage) { // // Store cbitAverage bits of ul // plus a trailing 0 bit for end-of-sequence // cbitAverage == ULONG_BITS (maximum!) is a special case, // no trailing bit is used. if (cbitAverage < ULONG_BITS) _bitStream.PutBits(ul << 1, cbitAverage + 1); else { ciAssert(cbitAverage == ULONG_BITS); _bitStream.PutBits(ul, ULONG_BITS); } } else IBitCompress(ul, cbitAverage, bitSize); } __forceinline PROPID CKeyDeComp::Pid() { return GetKey()? _key.Pid(): pidInvalid; }