//+------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1994 - 1995. // // File: rowcomp.cxx // // Contents: Implementation of CRowIndex // // Classes: CRowCompareVariant // // History: 23 Aug 1994 dlee Created // // Notes: All of these routines assume the caller (in this case the // table window) is locked, so they don't do their own locking // to protect data. // //-------------------------------------------------------------------------- #include "pch.cxx" #pragma hdrstop #include #include // for CFixedVarAllocator #include #include #include "tabledbg.hxx" #include "rowindex.hxx" #include "rowcomp.hxx" #include "tblwindo.hxx" #include "colcompr.hxx" //+------------------------------------------------------------------------- // // Member: CRowCompareVariant::CRowCompareVariant, public // // Synopsis: Constructor for comparator object. Basically just // invokes the PropSet comparator. // // Arguments: [TableWindow] -- table window object // // History: 29 Aug 1994 dlee Created // //-------------------------------------------------------------------------- CRowCompareVariant::CRowCompareVariant(CTableWindow &TableWindow) : _TableWindow(TableWindow), _cProps(TableWindow.SortOrder().Count()), _aComparator(_cProps), _aVar1(_cProps), _aVar2(_cProps), _apVar1(_cProps), _apVar2(_cProps), _apColumn(_cProps), _aVarFlags1(_cProps), _aVarFlags2(_cProps), _pPathStore(0), _sharedBuf(TableWindow._sharedBuf), _xBuffer(), _widCached(widInvalid) { // // Initialize an array of pointers to the variants, which is what // the comparison routine wants (and needs because some variants are // larger than a variant -- their out of line data is in the same // block after the variant-proper data). // // Also make an array of sort column data // for (unsigned i = 0; i < _cProps; i++) { _aVarFlags1[i] = eNone; _aVarFlags2[i] = eNone; _apVar1[i] = &(_aVar1[i]); _apVar2[i] = &(_aVar2[i]); BOOL fFound = FALSE; SSortKey Key = _TableWindow.SortOrder().Get( i ); _apColumn[i] = _TableWindow._Columns.Find( Key.pidColumn, fFound ); Win4Assert(fFound); } _InitComparators( _TableWindow.SortOrder() ); } //CRowCompareVariant //+------------------------------------------------------------------------- // // Member: CRowCompareVariant::~CRowCompareVariant, public // // Synopsis: Destructor for comparator object. Frees allocated variants // left around after an exception or those that are buffered // for variant set 1. // // History: 12 Sep 1994 dlee Created // //-------------------------------------------------------------------------- CRowCompareVariant::~CRowCompareVariant() { _Cleanup1(); _Cleanup2(); } //~CRowCompareVariant //+------------------------------------------------------------------------- // // Member: CRowCompareVariant::_FreeVariant, private // // Synopsis: Frees allocated variant depending on its source // // Arguments: [pColumn] -- column needed to get compressor // [pVar] -- variant to free // [eSource] -- source of the variant allocation // // History: 12 Sep 1994 dlee Created // //-------------------------------------------------------------------------- inline void CRowCompareVariant::_FreeVariant( CTableColumn * pColumn, CTableVariant * pVar, EVariantSource eSource) { switch (eSource) { case eCompressor : (pColumn->GetCompressor())->FreeVariant( pVar ); break; case eNewx : delete pVar; break; case eBuffer: _xBuffer.Release(); break; default : Win4Assert(! "CRowCompareVariant::_FreeVariant() bad"); break; } } //_FreeVariant //+------------------------------------------------------------------------- // // Member: CRowCompareVariant::_Cleanup1, private // // Synopsis: Frees allocated variants // // History: 12 Sep 1994 dlee Created // //-------------------------------------------------------------------------- inline void CRowCompareVariant::_Cleanup1() { for (unsigned i = 0; i < _cProps; i++) { if (eNone != _aVarFlags1[i]) { _FreeVariant( _apColumn[i], _apVar1[i], _aVarFlags1[i] ); _aVarFlags1[i] = eNone; _apVar1[i] = &(_aVar1[i]); } } } //_Cleanup1 //+------------------------------------------------------------------------- // // Member: CRowCompareVariant::_Cleanup2, private // // Synopsis: Frees allocated variants // // History: 12 Sep 1994 dlee Created // //-------------------------------------------------------------------------- inline void CRowCompareVariant::_Cleanup2() { for (unsigned i = 0; i < _cProps; i++) { if (eNone != _aVarFlags2[i]) { _FreeVariant( _apColumn[i], _apVar2[i], _aVarFlags2[i] ); _aVarFlags2[i] = eNone; // Don't have to restore this pointer -- never changes for 2 Win4Assert( _apVar2[i] == &(_aVar2[i]) ); //_apVar2[i] = &(_aVar2[i]); } } } //_Cleanup2 //+------------------------------------------------------------------------- // // Member: CRowCompareVariant::_MakeVariant, private // // Synopsis: Makes variants from raw row data. Variants are needed // by the comparator. // // Arguments: [pColumn] -- column description // [pbRow] -- pointer to raw row data for row (source) // [pVar] -- variant pointer (destination) // [rSource] -- source of the variant's allocation, // only touched if not eNone // // History: 1 Sep 1994 dlee Created // //-------------------------------------------------------------------------- void CRowCompareVariant::_MakeVariant( CTableColumn * pColumn, BYTE * pbRow, CTableVariant * pVar, EVariantSource & rSource) { pbRow += pColumn->GetValueOffset(); if (pColumn->IsCompressedCol()) { // // Get the compressed data into a variant. Ignore the return // code. Assume that if GetData() is unable to find data it sets // the variant to VT_EMPTY, which the comparator is expecting. // (pColumn->GetCompressor())->GetData( pVar, pColumn->GetStoredType(), pColumn->GetValueSize() ? * ((ULONG *) pbRow) : 0, pColumn->PropId ); rSource = eCompressor; } else { // Create variants from non-compressed data Win4Assert( pColumn->IsValueStored() ); pVar->Init( pColumn->GetStoredType(), pbRow, pColumn->GetValueSize() ); // Convert out of line data from offset to pointer pVar->OffsetsToPointers( _TableWindow._DataAllocator ); } } //_MakeVariant //+------------------------------------------------------------------------- // // Member: CRowCompareVariant::_MakeVariant, private // // Synopsis: Makes variants from raw row data. Variants are needed // by the comparator. Always puts variants in Var1, never // in Var2. // // Arguments: [pColumn] -- column description // [rObject] -- object accessor for variant construction // [iProp] -- index of variant to which data is written // // Notes: inline -- only called once // // History: 1 Sep 1994 dlee Created // //-------------------------------------------------------------------------- inline void CRowCompareVariant::_MakeVariant( CTableColumn * pColumn, CRetriever & rObject, unsigned iProp) { ULONG cbBuf = sizeof CTableVariant; GetValueResult eGvr = rObject.GetPropertyValue( pColumn->PropId, _apVar1[iProp], &cbBuf ); // // If the data won't fit in a normal variant, either use the built-in // buffer or allocate a large one which will be freed after the // comparison. // if (eGvr == GVRNotEnoughSpace) { CTableVariant *pvar; if (!_xBuffer.InUse() && maxcbBuffer >= cbBuf) { if (0 == _xBuffer.GetPointer()) _xBuffer.Init(maxcbBuffer); else _xBuffer.AddRef(); pvar = (CTableVariant *) _xBuffer.GetPointer(); _aVarFlags1[iProp] = eBuffer; } else { pvar = (CTableVariant*) new BYTE[cbBuf]; _aVarFlags1[iProp] = eNewx; } eGvr = rObject.GetPropertyValue( pColumn->PropId, pvar, &cbBuf ); _apVar1[iProp] = pvar; } if ( GVRNotAvailable == eGvr || GVRSharingViolation == eGvr ) { // No value for this property -- make an empty variant _apVar1[iProp]->vt = VT_EMPTY; } else if ( GVRSuccess != eGvr ) { THROW( CException( CRetriever::NtStatusFromGVR(eGvr)) ); } } //_MakeVariant //+--------------------------------------------------------------------------- // // Function: _InitComparators // // Synopsis: Initializes the comparators methods for each of the columns // which need to be compared. // // Arguments: [sortSet] - The columns that need to be sorted on. // // History: 5-11-95 srikants Created // // Notes: // //---------------------------------------------------------------------------- void CRowCompareVariant::_InitComparators( CSortSet const & sortSet ) { for ( unsigned i = 0; i < _cProps; i++ ) { _aComparator[i].Init( sortSet.Get(i).dwOrder ); if ( 0 == _pPathStore && 0 != _apColumn[i]->GetCompressor() ) { _pPathStore = _apColumn[i]->GetCompressor()->GetPathStore(); if ( 0 != _pPathStore ) { Win4Assert( _apColumn[i]->PropId == pidName || _apColumn[i]->PropId == pidPath || _apColumn[i]->PropId == pidWorkId ); } } } } //+--------------------------------------------------------------------------- // // Function: _GetPathId // // Synopsis: Returns the "pathId" stored in the row that the path compressor // can understand. // // Arguments: [col] - The column description. // [pbRow] - Row in the window. // // Returns: PATHID in the row. // // History: 5-11-95 srikants Created // // Notes: // //---------------------------------------------------------------------------- PATHID CRowCompareVariant::_GetPathId( const CTableColumn & col , BYTE * pbRow ) { return _TableWindow.RowWorkid( pbRow ); } //+--------------------------------------------------------------------------- // // Function: _MakeVariant // // Synopsis: Creates a variant and is optimized to use the sharedBuf // if possible. // // Arguments: [iCol] - Index of the column // [sharedBuf] - Global shared buffer // [obj] - The object retriever // // Returns: A pointer to the variant (if successful) // // History: 5-22-95 srikants Created // // Notes: This is optimized to avoid doing a memory allocation in // case the column is bigger than a simple variant. It // will use the global shared memory (sharedBuf) if it has // been acquired by the caller. // //---------------------------------------------------------------------------- // inline PROPVARIANT * CRowCompareVariant::_MakeVariant( unsigned iCol, XUseSharedBuffer &sharedBuf, CRetriever & obj ) { PROPVARIANT * pVarnt = 0; if ( sharedBuf.IsAcquired() ) { // // The shared buffer has been acquired by the caller and so we // can use it to get the variant. // pVarnt = (PROPVARIANT *) sharedBuf.LokGetBuffer(); ULONG cbBuf = sharedBuf.LokGetSize(); ULONG propId = _apColumn[iCol]->PropId; GetValueResult gvr = obj.GetPropertyValue( propId, pVarnt, &cbBuf ); if ( GVRNotEnoughSpace == gvr ) { pVarnt = 0; } else if ( GVRNotAvailable == gvr || GVRSharingViolation == gvr ) { // No value for this property -- make an empty variant _apVar1[iCol]->vt = VT_EMPTY; pVarnt = _apVar1[iCol]; } else if ( GVRSuccess != gvr ) { THROW( CException( CRetriever::NtStatusFromGVR(gvr) ) ); } } if ( 0 == pVarnt ) { // // Either the sharedBuf was not acquired by the caller or the // buffer is not enough to hold the data. // if ( eNone == _aVarFlags1[iCol] ) { _MakeVariant( _apColumn[iCol], obj, iCol ); } pVarnt = _apVar1[iCol]; } Win4Assert( 0 != pVarnt ); return pVarnt; } //+--------------------------------------------------------------------------- // // Function: _FastCompare // // Synopsis: A fast comparator for two rows in the window. It does a // quick compare on pidWorkId, pidPath and pidName. // // Arguments: [iCol] - Index of the column to be compared. // [pbRow1] - Pointer to the window row 1 // [pbRow2] - Pointer to the window row 2 // [iComp] - (OUTPUT) result of comparison. // // 0 - if equal // +1 - if row1 > row2 // -1 - if row1 < row2 // // Returns: TRUE if a fast compare was done. FALSE o/w // // History: 5-11-95 srikants Created // // Notes: // //---------------------------------------------------------------------------- // inline BOOL CRowCompareVariant::_FastCompare( unsigned iCol, BYTE *pbRow1, BYTE *pbRow2, int & iComp ) { ULONG propId = _apColumn[iCol]->PropId; switch ( propId ) { case pidWorkId: { WORKID widRow1 = _TableWindow.RowWorkid( pbRow1 ); WORKID widRow2 = _TableWindow.RowWorkid( pbRow2 ); iComp = widRow1 - widRow2; } break; case pidName: case pidPath: if ( 0 == _apColumn[iCol]->GetCompressor() ) return FALSE; Win4Assert( _apColumn[iCol]->GetValueSize() == sizeof(PATHID) ); { PATHID pathid1 = _GetPathId( *_apColumn[iCol], pbRow1 ); PATHID pathid2 = _GetPathId( *_apColumn[iCol], pbRow2 ); iComp = _pPathStore->Compare( pathid1, pathid2, propId ); } break; default: return FALSE; } return TRUE; } //+--------------------------------------------------------------------------- // // Function: _FastCompare // // Synopsis: Same as above except that it compares an object retriever to // a row in the window. // // Arguments: [iCol] - // [obj] - // [pbRow2] - // [iComp] - // // Returns: TRUE if a fast compare was done; FALSE o/w // // Modifies: // // History: 5-11-95 srikants Created // // Notes: // //---------------------------------------------------------------------------- // inline BOOL CRowCompareVariant::_FastCompare( unsigned iCol, CRetriever & obj, XUseSharedBuffer & sharedBuf, BYTE * pbRow2, int & iComp ) { ULONG propId = _apColumn[iCol]->PropId; switch ( propId ) { case pidWorkId: { WORKID widRow1 = obj.WorkId(); WORKID widRow2 = _TableWindow.RowWorkid( pbRow2 ); iComp = widRow1 - widRow2; } break; case pidName: case pidPath: if ( 0 == _apColumn[iCol]->GetCompressor() ) return FALSE; Win4Assert( _apColumn[iCol]->GetValueSize() == sizeof(PATHID) ); { PATHID pathid2 = _GetPathId( *_apColumn[iCol], pbRow2 ); PROPVARIANT * pVarnt = _MakeVariant( iCol, sharedBuf, obj ); iComp = _pPathStore->Compare( *pVarnt, pathid2, propId ); } break; default: return FALSE; } return TRUE; } //+--------------------------------------------------------------------------- // // Function: Compare // // Synopsis: Compares two rows in the window. // // Arguments: [oRow1] - Offset of row1 // [oRow2] - Offset of row2 // // Returns: 0 if the rows are the same, // positive column # of first column of row1 greater than row2 // negative column # of first column of row1 less than row2 // // History: 5-11-95 srikants Created // // Notes: // //---------------------------------------------------------------------------- int CRowCompareVariant::Compare( TBL_OFF oRow1, TBL_OFF oRow2 ) { BYTE *pbRow1 = (BYTE *) _TableWindow. _DataAllocator.FixedPointer( oRow1 ); BYTE *pbRow2 = (BYTE *) _TableWindow. _DataAllocator.FixedPointer( oRow2 ); WORKID widRow1 = _TableWindow.RowWorkid( pbRow1 ); WORKID widRow2 = _TableWindow.RowWorkid( pbRow2 ); if ( widRow1 != _widCached ) { _Cleanup1(); _widCached = widRow1; } int iComp = 0 ; for ( unsigned i = 0; ( 0 == iComp ) && (i < _cProps) ; i++ ) { if ( _FastCompare( i, pbRow1, pbRow2, iComp ) ) { iComp *= _aComparator[i].GetDirMult(); } else { if ( eNone == _aVarFlags1[i] ) { _MakeVariant( _apColumn[i], pbRow1, _apVar1[i], _aVarFlags1[i] ); } _MakeVariant( _apColumn[i], pbRow2, _apVar2[i], _aVarFlags2[i] ); iComp = _aComparator[i].Compare( _apVar1[i], _apVar2[i] ); } } _Cleanup2(); if ( 0 == iComp ) return 0; else if ( iComp > 0 ) return i; else return - (int) i; } //Compare //+--------------------------------------------------------------------------- // // Function: CompareObject // // Synopsis: Compares an object retriever to a row in the window. // // Arguments: [obj] - // [oRow2] - // // Returns: // // History: 5-11-95 srikants Created // // Notes: // //---------------------------------------------------------------------------- int CRowCompareVariant::CompareObject( CRetriever & obj , TBL_OFF oRow2 ) { BYTE *pbRow2 = (BYTE *) _TableWindow. _DataAllocator.FixedPointer( oRow2 ); WORKID widRow1 = obj.WorkId(); if ( widRow1 != _widCached ) { _Cleanup1(); _widCached = widRow1; } XUseSharedBuffer xSharedBuf(_sharedBuf, FALSE); if ( !_sharedBuf.IsInUse() ) { xSharedBuf.LokAcquire(); } int iComp = 0; for ( unsigned i = 0; ( 0 == iComp ) && (i < _cProps) ; i++ ) { if ( _FastCompare( i, obj, xSharedBuf, pbRow2, iComp ) ) { iComp *= _aComparator[i].GetDirMult(); } else { if ( eNone == _aVarFlags1[i] ) { _MakeVariant( _apColumn[i], obj, i ); } _MakeVariant( _apColumn[i], pbRow2, _apVar2[i], _aVarFlags2[i] ); iComp = _aComparator[i].Compare( _apVar1[i], _apVar2[i] ); } } _Cleanup2(); if ( 0 == iComp ) return 0; else if ( iComp > 0 ) return i; else return - (int) i; } //CompareObject