444 lines
10 KiB
C++
444 lines
10 KiB
C++
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Copyright (C) Microsoft Corporation, 1991 - 2000.
|
||
|
//
|
||
|
// File: NodeXpr.cxx
|
||
|
//
|
||
|
// Contents: Internal expression classes
|
||
|
//
|
||
|
// Classes: CXpr
|
||
|
//
|
||
|
// History: 11-Sep-91 KyleP Created
|
||
|
// 23-Jan-95 t-colinb Added Support for RTVector in
|
||
|
// CNodeXpr::IsMatch
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#include <pch.cxx>
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include <xpr.hxx>
|
||
|
#include <parse.hxx>
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CNodeXpr::CNodeXpr, public
|
||
|
//
|
||
|
// Synopsis: Initialze an empty node.
|
||
|
//
|
||
|
// Arguments: [type] -- Type of node (AND, OR, etc.)
|
||
|
// [cInit] -- A hint about the number of expressions which
|
||
|
// will be added to this node.
|
||
|
//
|
||
|
// Signals: ???
|
||
|
//
|
||
|
// History: 05-Dec-91 KyleP Created.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
CNodeXpr::CNodeXpr ( CXpr::NodeType type, unsigned cInit )
|
||
|
: CXpr ( type ),
|
||
|
_cXpr( 0 ),
|
||
|
_size( cInit )
|
||
|
{
|
||
|
_aXpr = new CXpr* [cInit];
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CNodeXpr::CNodeXpr, public
|
||
|
//
|
||
|
// Synopsis: Copy constructor
|
||
|
//
|
||
|
// Arguments: [nxpr] -- Node to copy from.
|
||
|
//
|
||
|
// Signals: ???
|
||
|
//
|
||
|
// History: 11-Dec-91 KyleP Created.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
CNodeXpr::CNodeXpr( CNodeXpr & nxpr )
|
||
|
: CXpr ( nxpr.NType() )
|
||
|
{
|
||
|
_cXpr = nxpr._cXpr;
|
||
|
_size = nxpr._cXpr;
|
||
|
_weight = nxpr._weight;
|
||
|
|
||
|
_aXpr = new CXpr * [ _size ];
|
||
|
RtlZeroMemory( _aXpr, _size * sizeof( CXpr * ) );
|
||
|
|
||
|
TRY
|
||
|
{
|
||
|
for ( int i = _cXpr-1; i >= 0; i-- )
|
||
|
_aXpr[i] = nxpr._aXpr[i]->Clone();
|
||
|
}
|
||
|
CATCH( CException, e )
|
||
|
{
|
||
|
for ( unsigned i = 0; i < _cXpr; i++ )
|
||
|
delete _aXpr[i];
|
||
|
|
||
|
delete _aXpr;
|
||
|
RETHROW();
|
||
|
}
|
||
|
END_CATCH
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CNodeXpr::~CNodeXpr, public
|
||
|
//
|
||
|
// Synopsis: Destroy subexpressions and cursor (if any)
|
||
|
//
|
||
|
// Signals: ???
|
||
|
//
|
||
|
// History: 05-Dec-91 KyleP Created.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
CNodeXpr::~CNodeXpr ()
|
||
|
{
|
||
|
for ( unsigned i = 0; i < _cXpr; i++ )
|
||
|
delete _aXpr[i];
|
||
|
|
||
|
delete _aXpr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CNodeXpr::Clone, public
|
||
|
//
|
||
|
// Returns: A copy of this node.
|
||
|
//
|
||
|
// Signals: ???
|
||
|
//
|
||
|
// Derivation: From base class CXpr, Always override in subclasses.
|
||
|
//
|
||
|
// History: 11-Dec-91 KyleP Created.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
CXpr * CNodeXpr::Clone()
|
||
|
{
|
||
|
return( new CNodeXpr( *this ) );
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CNodeXpr::SelectIndexing, public
|
||
|
//
|
||
|
// Effects: Selects indexing for children.
|
||
|
//
|
||
|
// History: 03-Nov-94 KyleP Created.
|
||
|
//
|
||
|
// Notes: Index selection is only applicable for AND nodes.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void CNodeXpr::SelectIndexing( CIndexStrategy & strategy )
|
||
|
{
|
||
|
BOOL fModeChange;
|
||
|
|
||
|
if ( NType() == NTAnd )
|
||
|
fModeChange = strategy.SetAndMode();
|
||
|
else if ( NType() == NTOr )
|
||
|
fModeChange = strategy.SetOrMode();
|
||
|
else
|
||
|
{
|
||
|
strategy.SetUnknownBounds();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for ( unsigned i = 0; i < _cXpr; i++ )
|
||
|
_aXpr[i]->SelectIndexing( strategy );
|
||
|
|
||
|
if ( fModeChange )
|
||
|
strategy.DoneWithBoolean();
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CNodeXpr::IsLeaf, public
|
||
|
//
|
||
|
// Returns: FALSE. Nodes are never leaf expressions.
|
||
|
//
|
||
|
// Derivation: From base class CXpr, Frequently override in subclasses.
|
||
|
//
|
||
|
// History: 12-Dec-91 KyleP Created.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
BOOL CNodeXpr::IsLeaf() const
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CNodeXpr::AddChild, public
|
||
|
//
|
||
|
// Synopsis: Add an expression to the node.
|
||
|
//
|
||
|
// Arguments: [child] -- Expression to add.
|
||
|
//
|
||
|
// Signals: ???
|
||
|
//
|
||
|
// History: 12-Dec-91 KyleP Created.
|
||
|
//
|
||
|
// Notes: Once an expression has been added to a node it is owned
|
||
|
// by that node. (e.g., no one else should delete it)
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void CNodeXpr::AddChild ( CXpr* child )
|
||
|
{
|
||
|
Win4Assert( child );
|
||
|
|
||
|
if ( _cXpr < _size )
|
||
|
{
|
||
|
_aXpr[_cXpr++] = child;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CXpr ** newArray = new CXpr * [ 2 * _size ];
|
||
|
memcpy( newArray, _aXpr, _cXpr * sizeof( CXpr * ) );
|
||
|
|
||
|
Win4Assert( _cXpr == _size );
|
||
|
newArray[_cXpr++] = child;
|
||
|
|
||
|
delete _aXpr;
|
||
|
_size *= 2;
|
||
|
_aXpr = newArray;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CNodeXpr::HitCount, public
|
||
|
//
|
||
|
// Returns: Sum for OR, Min for AND
|
||
|
//
|
||
|
// History: 01-May-91 KyleP Created.
|
||
|
//
|
||
|
// Notes: HitCount only makes sense for content clauses. If there
|
||
|
// are any non-content clauses then HitCount will return 0.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
ULONG CNodeXpr::HitCount( CRetriever & obj )
|
||
|
{
|
||
|
ULONG result;
|
||
|
|
||
|
switch ( NType() )
|
||
|
{
|
||
|
case NTAnd:
|
||
|
{
|
||
|
result = 0;
|
||
|
|
||
|
for (int i = Count()-1; i >= 0; i--)
|
||
|
{
|
||
|
ULONG thisChild = GetChild( i )->HitCount( obj );
|
||
|
result = (thisChild) ? min( result, thisChild ) : result;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case NTOr:
|
||
|
{
|
||
|
result = 0;
|
||
|
|
||
|
for (int i = Count()-1; i >= 0; i--)
|
||
|
{
|
||
|
ULONG thisChild = GetChild( i )->HitCount( obj );
|
||
|
if ( 0 != thisChild )
|
||
|
{
|
||
|
result += GetChild( i )->HitCount( obj );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
result = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
result = 0;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return( result );
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CNodeXpr::Rank, public
|
||
|
//
|
||
|
// Returns: Sum for OR, Min for AND
|
||
|
//
|
||
|
// History: 01-May-91 KyleP Created.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
LONG CNodeXpr::Rank( CRetriever & obj )
|
||
|
{
|
||
|
LONG result;
|
||
|
|
||
|
switch ( NType() )
|
||
|
{
|
||
|
case NTAnd:
|
||
|
{
|
||
|
result = MAX_QUERY_RANK;
|
||
|
|
||
|
for (int i = Count()-1; i >= 0; i--)
|
||
|
{
|
||
|
result = min( result, GetChild( i )->Rank( obj ) );
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case NTOr:
|
||
|
{
|
||
|
result = 0;
|
||
|
|
||
|
for (int i = Count()-1; i >= 0; i--)
|
||
|
{
|
||
|
result += GetChild( i )->Rank( obj );
|
||
|
}
|
||
|
|
||
|
result /= Count();
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
result = 0;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return( result );
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CNodeXpr::IsMatch, public
|
||
|
//
|
||
|
// Arguments: [obj] -- The objects table. [obj] is already positioned
|
||
|
// to the record to test.
|
||
|
// [wid] -- Workid of object to which [obj] is positioned.
|
||
|
//
|
||
|
// Returns: TRUE if the current record satisfies the relation.
|
||
|
//
|
||
|
// Signals: ???
|
||
|
//
|
||
|
// History: 20-Nov-91 KyleP Created.
|
||
|
// 23-Jan-95 t-colinb Added Support for RTVector in
|
||
|
//
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
BOOL CNodeXpr::IsMatch( CRetriever & obj )
|
||
|
{
|
||
|
Win4Assert( NType() == NTAnd ||
|
||
|
NType() == NTOr ||
|
||
|
NType() == NTVector );
|
||
|
|
||
|
//
|
||
|
// If some portion of the node has been indexed, adjust the cursor to
|
||
|
// the wid we're looking for.
|
||
|
//
|
||
|
|
||
|
WORKID widCur = widInvalid;
|
||
|
BOOL result;
|
||
|
|
||
|
switch ( NType() )
|
||
|
{
|
||
|
case NTAnd:
|
||
|
result = TRUE;
|
||
|
{
|
||
|
for (int i = Count()-1; result && i >= 0; i--)
|
||
|
{
|
||
|
result = GetChild( i )->IsMatch( obj );
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case NTOr:
|
||
|
case NTVector:
|
||
|
result = FALSE;
|
||
|
{
|
||
|
for (int i = Count()-1; !result && i >= 0; i--)
|
||
|
{
|
||
|
result = GetChild( i )->IsMatch( obj );
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
result = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CNodeXpr::RemoveChild, public
|
||
|
//
|
||
|
// Synopsis: Removes a node.
|
||
|
//
|
||
|
// Arguments: [iPos] -- Position of node to remove.
|
||
|
//
|
||
|
// Requires: [iPos] is a valid node.
|
||
|
//
|
||
|
// Returns: The child node which was removed.
|
||
|
//
|
||
|
// History: 19-Nov-91 KyleP Created.
|
||
|
//
|
||
|
// Notes: CNodeXpr does not guarantee the position of nodes across
|
||
|
// calls to RemoveChild.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
CXpr* CNodeXpr::RemoveChild ( unsigned iPos )
|
||
|
{
|
||
|
Win4Assert ( iPos <= _cXpr );
|
||
|
|
||
|
CXpr * pxp = _aXpr[iPos];
|
||
|
_aXpr[iPos] = _aXpr[ _cXpr - 1 ];
|
||
|
_cXpr--;
|
||
|
|
||
|
#if (CIDBG == 1)
|
||
|
_aXpr[ _cXpr ] = 0;
|
||
|
#endif
|
||
|
|
||
|
return( pxp );
|
||
|
}
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CVectorXpr::CVectorXpr, public
|
||
|
//
|
||
|
// Synopsis: Constructs a vector expression.
|
||
|
//
|
||
|
// Arguments: [type] -- Type of node (AND, OR, etc.)
|
||
|
// [cInit] -- A hint about the number of expressions
|
||
|
// which will be added.
|
||
|
// [RankMethod] -- Method used to compute rank.
|
||
|
//
|
||
|
// History: 24-Jul-92 KyleP Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
CVectorXpr::CVectorXpr( unsigned cInit,
|
||
|
ULONG RankMethod )
|
||
|
: CNodeXpr( CXpr::NTVector, cInit ),
|
||
|
_ulRankMethod( RankMethod )
|
||
|
{
|
||
|
}
|
||
|
|