|
|
//+-------------------------------------------------------------------------
//
// 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 <bigtable.hxx>
#include <tblalloc.hxx> // for CFixedVarAllocator
#include <objcur.hxx>
#include <compare.hxx>
#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
|