996 lines
27 KiB
Plaintext
996 lines
27 KiB
Plaintext
|
/*++
|
||
|
|
||
|
Copyright (C) 1996-1999 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
DUMBNODE.H
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
WBEM Evaluation Tree
|
||
|
|
||
|
History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
template<class TPropType>
|
||
|
CFullCompareNode<TPropType>::CFullCompareNode(
|
||
|
const CFullCompareNode<TPropType>& Other,
|
||
|
BOOL bChildren)
|
||
|
: CPropertyNode(Other, FALSE), // copy without children
|
||
|
m_pRightMost(NULL)
|
||
|
{
|
||
|
if(bChildren)
|
||
|
{
|
||
|
// Need to copy the children. Iterate over our test point array
|
||
|
// =============================================================
|
||
|
|
||
|
for(TConstTestPointIterator it = Other.m_aTestPoints.Begin();
|
||
|
it != Other.m_aTestPoints.End(); it++)
|
||
|
{
|
||
|
CTestPoint<TPropType> NewPoint;
|
||
|
NewPoint.m_Test = it->m_Test;
|
||
|
|
||
|
// Make copies of the child branches
|
||
|
// =================================
|
||
|
|
||
|
NewPoint.m_pLeftOf = CEvalNode::CloneNode(it->m_pLeftOf);
|
||
|
NewPoint.m_pAt = CEvalNode::CloneNode(it->m_pAt);
|
||
|
|
||
|
// Add the test point to the array
|
||
|
// ===============================
|
||
|
|
||
|
m_aTestPoints.Append(NewPoint);
|
||
|
}
|
||
|
|
||
|
// Copy right-most
|
||
|
// ===============
|
||
|
|
||
|
m_pRightMost = CEvalNode::CloneNode(Other.m_pRightMost);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
template<class TPropType>
|
||
|
HRESULT CFullCompareNode<TPropType>::SetTest(VARIANT& v)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
CTokenValue Value;
|
||
|
if(!Value.SetVariant(v))
|
||
|
return WBEM_E_OUT_OF_MEMORY;
|
||
|
m_aTestPoints.Begin()->m_Test = Value;
|
||
|
|
||
|
return WBEM_S_NO_ERROR;
|
||
|
}
|
||
|
catch(CX_MemoryException)
|
||
|
{
|
||
|
return WBEM_E_OUT_OF_MEMORY;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template<class TPropType>
|
||
|
CFullCompareNode<TPropType>::~CFullCompareNode()
|
||
|
{
|
||
|
delete m_pRightMost;
|
||
|
}
|
||
|
|
||
|
template<class TPropType>
|
||
|
HRESULT CFullCompareNode<TPropType>::InsertMatching(
|
||
|
TTestPointIterator it,
|
||
|
TTestPointIterator it2, TTestPointIterator& itLast,
|
||
|
int nOp, CContextMetaData* pNamespace,
|
||
|
CImplicationList& Implications, bool bDeleteArg2)
|
||
|
{
|
||
|
//=====================================================================
|
||
|
// 'it' points to the node in 'this' that has the same value as the one
|
||
|
// 'it2' points to in pArg2. 'itLast' points to the last unhandled node
|
||
|
// in 'this' (looking left from 'it').
|
||
|
//=====================================================================
|
||
|
|
||
|
CEvalNode* pNew;
|
||
|
HRESULT hres;
|
||
|
|
||
|
// Merge our at-values
|
||
|
// ===================
|
||
|
|
||
|
hres = CEvalTree::Combine(it->m_pAt, it2->m_pAt, nOp, pNamespace,
|
||
|
Implications, true, bDeleteArg2, &pNew);
|
||
|
if(FAILED(hres))
|
||
|
return hres;
|
||
|
|
||
|
if(bDeleteArg2)
|
||
|
it2->m_pAt = NULL;
|
||
|
|
||
|
it->m_pAt = pNew;
|
||
|
|
||
|
// Merge our left-ofs
|
||
|
// ==================
|
||
|
|
||
|
hres = CEvalTree::Combine(it->m_pLeftOf, it2->m_pLeftOf, nOp, pNamespace,
|
||
|
Implications, true, bDeleteArg2, &pNew);
|
||
|
if(FAILED(hres))
|
||
|
return hres;
|
||
|
|
||
|
if(bDeleteArg2)
|
||
|
it2->m_pLeftOf = NULL;
|
||
|
|
||
|
it->m_pLeftOf = pNew;
|
||
|
|
||
|
//
|
||
|
// At this point, we need to merge the LeftOf of it2 with all the branches
|
||
|
// in this that are between the current insertion point and the previous
|
||
|
// insertion point. However, we do not need to do this if it2's LeftOf node
|
||
|
// is a noop for this operation (e.g. TRUE for an AND)
|
||
|
//
|
||
|
|
||
|
if(it != itLast && !CEvalNode::IsNoop(it2->m_pLeftOf, nOp))
|
||
|
{
|
||
|
hres = CombineWithBranchesToLeft(it, itLast, it2->m_pLeftOf, nOp,
|
||
|
pNamespace, Implications);
|
||
|
if(FAILED(hres))
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
// Move first unhandled iterator to the node beyond itLast
|
||
|
// =======================================================
|
||
|
|
||
|
itLast = it;
|
||
|
itLast++;
|
||
|
|
||
|
return WBEM_S_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
template<class TPropType>
|
||
|
HRESULT CFullCompareNode<TPropType>::InsertLess(
|
||
|
TTestPointIterator it,
|
||
|
TTestPointIterator it2, TTestPointIterator& itLast,
|
||
|
int nOp, CContextMetaData* pNamespace,
|
||
|
CImplicationList& Implications, bool bDeleteArg2)
|
||
|
{
|
||
|
//
|
||
|
// 'it' points to the node in 'this' that has a slightly larger value than
|
||
|
// the one 'it2' points to in pArg2. 'itLast' points to the last unhandled
|
||
|
// node in 'this' (looking left from 'it').
|
||
|
//
|
||
|
|
||
|
HRESULT hres;
|
||
|
|
||
|
// Check if 'it' is point to the end of the list --- in that case it's
|
||
|
// "left-of" is actually right-most
|
||
|
// ===================================================================
|
||
|
|
||
|
CEvalNode* pItLeft = NULL;
|
||
|
if(it == m_aTestPoints.End())
|
||
|
pItLeft = m_pRightMost;
|
||
|
else
|
||
|
pItLeft = it->m_pLeftOf;
|
||
|
|
||
|
|
||
|
// First of all, we need to insert the node at it2 into 'this' list, just
|
||
|
// before 'it'.
|
||
|
// ======================================================================
|
||
|
|
||
|
CTestPoint<TPropType> NewNode = *it2;
|
||
|
|
||
|
// It's at branch is the combination of our left and arg2 at
|
||
|
// =========================================================
|
||
|
|
||
|
hres = CEvalTree::Combine(pItLeft, it2->m_pAt, nOp, pNamespace,
|
||
|
Implications, false, bDeleteArg2, &NewNode.m_pAt);
|
||
|
if(FAILED(hres))
|
||
|
return hres;
|
||
|
|
||
|
if(bDeleteArg2)
|
||
|
it2->m_pAt = NULL;
|
||
|
|
||
|
// It's left-of branch is the combination of our left and arg2 left
|
||
|
// ================================================================
|
||
|
|
||
|
// We can reuse it2->Left iff every node left of 'it' in 'this' has been
|
||
|
// handled
|
||
|
// =====================================================================
|
||
|
|
||
|
bool bDeleteIt2Left = (bDeleteArg2 && (it == itLast));
|
||
|
|
||
|
hres = CEvalTree::Combine(pItLeft, it2->m_pLeftOf, nOp, pNamespace,
|
||
|
Implications, false, bDeleteIt2Left, &NewNode.m_pLeftOf);
|
||
|
if(FAILED(hres))
|
||
|
return hres;
|
||
|
|
||
|
if(bDeleteIt2Left)
|
||
|
it2->m_pLeftOf = NULL;
|
||
|
|
||
|
// IMPORTANT: Once we insert the new node, all the iterators into 'this'
|
||
|
// will be invalidated --- that includes it and itLast. So, we need to do
|
||
|
// out left-walk before we actually insert.
|
||
|
// ===================================================
|
||
|
|
||
|
//
|
||
|
// At this point, we need to merge the LeftOf of it2 with all the branches
|
||
|
// in this that are between the current insertion point and the previous
|
||
|
// insertion point. However, we do not need to do this if it2's LeftOf node
|
||
|
// is a noop for this operation (e.g. TRUE for an AND)
|
||
|
//
|
||
|
|
||
|
if(it != itLast && !CEvalNode::IsNoop(it2->m_pLeftOf, nOp))
|
||
|
{
|
||
|
//
|
||
|
// Note to self: bDeleteIt2Left could not have been true, so
|
||
|
// it2->m_pLeftOf could not have been deleted. We are OK here
|
||
|
//
|
||
|
|
||
|
hres = CombineWithBranchesToLeft(it, itLast, it2->m_pLeftOf, nOp,
|
||
|
pNamespace, Implications);
|
||
|
if(FAILED(hres))
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
// Now we can actually insert
|
||
|
// ==========================
|
||
|
|
||
|
TTestPointIterator itNew = m_aTestPoints.Insert(it, NewNode);
|
||
|
|
||
|
// Move first unhandled iterator to the node just right of insertion
|
||
|
// =================================================================
|
||
|
|
||
|
itLast = itNew;
|
||
|
itLast++;
|
||
|
|
||
|
return WBEM_S_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
template<class TPropType>
|
||
|
HRESULT CFullCompareNode<TPropType>::CombineWithBranchesToLeft(
|
||
|
TTestPointIterator itWalk, TTestPointIterator itLast,
|
||
|
CEvalNode* pArg2,
|
||
|
int nOp, CContextMetaData* pNamespace,
|
||
|
CImplicationList& Implications)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
CEvalNode* pNew = NULL;
|
||
|
|
||
|
// Walk left until we reach the first unhandled node
|
||
|
// =================================================
|
||
|
|
||
|
do
|
||
|
{
|
||
|
if(itWalk == m_aTestPoints.Begin())
|
||
|
break;
|
||
|
|
||
|
itWalk--;
|
||
|
|
||
|
// Merge at-value
|
||
|
// ==============
|
||
|
|
||
|
hres = CEvalTree::Combine(itWalk->m_pAt, pArg2, nOp,
|
||
|
pNamespace, Implications, true, false, &pNew);
|
||
|
if(FAILED(hres))
|
||
|
return hres;
|
||
|
|
||
|
itWalk->m_pAt = pNew;
|
||
|
|
||
|
// Merge left-ofs
|
||
|
// ==============
|
||
|
|
||
|
hres = CEvalTree::Combine(itWalk->m_pLeftOf, pArg2, nOp,
|
||
|
pNamespace, Implications, true, false, &pNew);
|
||
|
if(FAILED(hres))
|
||
|
return hres;
|
||
|
|
||
|
itWalk->m_pLeftOf = pNew;
|
||
|
}
|
||
|
while(itWalk != itLast);
|
||
|
|
||
|
return WBEM_S_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
|
||
|
template<class TPropType>
|
||
|
HRESULT CFullCompareNode<TPropType>::CombineBranchesWith(
|
||
|
CBranchingNode* pRawArg2, int nOp, CContextMetaData* pNamespace,
|
||
|
CImplicationList& Implications,
|
||
|
bool bDeleteThis, bool bDeleteArg2, CEvalNode** ppRes)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
CFullCompareNode<TPropType>* pArg2 = (CFullCompareNode<TPropType>*)pRawArg2;
|
||
|
*ppRes = NULL;
|
||
|
|
||
|
// Check which one is larger
|
||
|
// =========================
|
||
|
|
||
|
if(m_aTestPoints.GetSize() < pArg2->m_aTestPoints.GetSize())
|
||
|
{
|
||
|
return pArg2->CombineBranchesWith(this, FlipEvalOp(nOp), pNamespace,
|
||
|
Implications, bDeleteArg2, bDeleteThis, ppRes);
|
||
|
}
|
||
|
|
||
|
if(!bDeleteThis)
|
||
|
{
|
||
|
// Damn. Clone.
|
||
|
// ============
|
||
|
|
||
|
return ((CFullCompareNode<TPropType>*)Clone())->CombineBranchesWith(
|
||
|
pRawArg2, nOp, pNamespace, Implications, true, // reuse clone!
|
||
|
bDeleteArg2, ppRes);
|
||
|
}
|
||
|
|
||
|
CEvalNode* pNew = NULL;
|
||
|
|
||
|
TTestPointIterator itLast = m_aTestPoints.Begin();
|
||
|
|
||
|
//
|
||
|
// itLast points to the left-most location in our list of test points that
|
||
|
// we have not considered yet --- it is guaranteed that any further
|
||
|
// insertions from the second list will occur after this point
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// it2, on the other hand, iterates simply over the second list of test
|
||
|
// points, inserting each one into the combined list one by one
|
||
|
//
|
||
|
|
||
|
for(TTestPointIterator it2 = pArg2->m_aTestPoints.Begin();
|
||
|
it2 != pArg2->m_aTestPoints.End(); it2++)
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// First, we search for the location in our list of test points of the
|
||
|
// insertion point for the value of it2. bMatch is set to true if the
|
||
|
// same test point exists, and false if it does not and the returned
|
||
|
// iterator points to the element to the right of the insertion point.
|
||
|
//
|
||
|
|
||
|
TTestPointIterator it;
|
||
|
bool bMatch = m_aTestPoints.Find(it2->m_Test, &it);
|
||
|
if(bMatch)
|
||
|
{
|
||
|
hres = InsertMatching(it, it2, itLast, nOp, pNamespace,
|
||
|
Implications, bDeleteArg2);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hres = InsertLess(it, it2, itLast, nOp, pNamespace,
|
||
|
Implications, bDeleteArg2);
|
||
|
// invalidates 'it'!
|
||
|
}
|
||
|
|
||
|
if(FAILED(hres))
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// At this point, we need to merge the RightMost of arg2 with all the
|
||
|
// branches in this that come after the last insertion point.
|
||
|
// However, we do not need to do this if arg2's RightMost node
|
||
|
// is a noop for this operation (e.g. TRUE for an AND)
|
||
|
//
|
||
|
|
||
|
if(itLast != m_aTestPoints.End() &&
|
||
|
!CEvalNode::IsNoop(pArg2->m_pRightMost, nOp))
|
||
|
{
|
||
|
hres = CombineWithBranchesToLeft(m_aTestPoints.End(), itLast,
|
||
|
pArg2->m_pRightMost, nOp, pNamespace, Implications);
|
||
|
if(FAILED(hres))
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
hres = CEvalTree::Combine(m_pRightMost, pArg2->m_pRightMost, nOp,
|
||
|
pNamespace, Implications, true, bDeleteArg2,
|
||
|
&pNew);
|
||
|
if(FAILED(hres))
|
||
|
return hres;
|
||
|
|
||
|
m_pRightMost = pNew;
|
||
|
|
||
|
if(bDeleteArg2)
|
||
|
pArg2->m_pRightMost = NULL;
|
||
|
|
||
|
// Merge the nulls
|
||
|
// ===============
|
||
|
|
||
|
CEvalTree::Combine(m_pNullBranch, pArg2->m_pNullBranch, nOp,
|
||
|
pNamespace, Implications, true, bDeleteArg2,
|
||
|
&pNew);
|
||
|
m_pNullBranch = pNew;
|
||
|
|
||
|
// Reset them in deleted versions
|
||
|
// ==============================
|
||
|
|
||
|
if(bDeleteArg2)
|
||
|
pArg2->m_pNullBranch = NULL;
|
||
|
|
||
|
// Delete what needs deleting
|
||
|
// ==========================
|
||
|
|
||
|
if(bDeleteArg2)
|
||
|
delete pArg2;
|
||
|
|
||
|
*ppRes = this;
|
||
|
return WBEM_S_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
template<class TPropType>
|
||
|
HRESULT CFullCompareNode<TPropType>::CombineInOrderWith(CEvalNode* pArg2,
|
||
|
int nOp, CContextMetaData* pNamespace,
|
||
|
CImplicationList& OrigImplications,
|
||
|
bool bDeleteThis, bool bDeleteArg2,
|
||
|
CEvalNode** ppRes)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
*ppRes = Clone();
|
||
|
if(*ppRes == NULL)
|
||
|
return WBEM_E_OUT_OF_MEMORY;
|
||
|
CFullCompareNode<TPropType>* pNew = (CFullCompareNode<TPropType>*)*ppRes;
|
||
|
|
||
|
try
|
||
|
{
|
||
|
CImplicationList Implications(OrigImplications);
|
||
|
hres = pNew->AdjustCompile(pNamespace, Implications);
|
||
|
if(FAILED(hres))
|
||
|
return hres;
|
||
|
|
||
|
CEvalNode* pNewBranch = NULL;
|
||
|
|
||
|
for(TTestPointIterator it = pNew->m_aTestPoints.Begin();
|
||
|
it != pNew->m_aTestPoints.End(); it++)
|
||
|
{
|
||
|
// Combine our At-branch with pArg2
|
||
|
// ================================
|
||
|
|
||
|
hres = CEvalTree::Combine(it->m_pAt, pArg2, nOp, pNamespace,
|
||
|
Implications, true, false, &pNewBranch);
|
||
|
if(FAILED(hres))
|
||
|
{
|
||
|
delete pNew;
|
||
|
return hres;
|
||
|
}
|
||
|
it->m_pAt = pNewBranch;
|
||
|
|
||
|
// Now do the same for our left-of branch
|
||
|
// ======================================
|
||
|
|
||
|
hres = CEvalTree::Combine(it->m_pLeftOf, pArg2, nOp, pNamespace,
|
||
|
Implications, true, false, &pNewBranch);
|
||
|
if(FAILED(hres))
|
||
|
{
|
||
|
delete pNew;
|
||
|
return hres;
|
||
|
}
|
||
|
it->m_pLeftOf = pNewBranch;
|
||
|
}
|
||
|
|
||
|
hres = CEvalTree::Combine(pNew->m_pRightMost, pArg2, nOp, pNamespace,
|
||
|
Implications, true, false, &pNewBranch);
|
||
|
if(FAILED(hres))
|
||
|
{
|
||
|
delete pNew;
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
pNew->m_pRightMost = pNewBranch;
|
||
|
|
||
|
hres = CEvalTree::Combine(pNew->m_pNullBranch, pArg2, nOp, pNamespace,
|
||
|
Implications, true, false, &pNewBranch);
|
||
|
if(FAILED(hres))
|
||
|
{
|
||
|
delete pNew;
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
pNew->m_pNullBranch = pNewBranch;
|
||
|
|
||
|
if(bDeleteThis)
|
||
|
delete this;
|
||
|
if(bDeleteArg2)
|
||
|
delete pArg2;
|
||
|
return WBEM_S_NO_ERROR;
|
||
|
}
|
||
|
catch(CX_MemoryException)
|
||
|
{
|
||
|
return WBEM_E_OUT_OF_MEMORY;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template<class TPropType>
|
||
|
int CFullCompareNode<TPropType>::SubCompare(CEvalNode* pRawOther)
|
||
|
{
|
||
|
CFullCompareNode<TPropType>* pOther =
|
||
|
(CFullCompareNode<TPropType>*)pRawOther;
|
||
|
|
||
|
// Compare handles
|
||
|
// ===============
|
||
|
|
||
|
int nCompare;
|
||
|
nCompare = m_lPropHandle - pOther->m_lPropHandle;
|
||
|
if(nCompare)
|
||
|
return nCompare;
|
||
|
|
||
|
// Compare array sizes
|
||
|
// ===================
|
||
|
|
||
|
nCompare = m_aTestPoints.GetSize() - pOther->m_aTestPoints.GetSize();
|
||
|
if(nCompare)
|
||
|
return nCompare;
|
||
|
|
||
|
// Compare all points
|
||
|
// ==================
|
||
|
|
||
|
TTestPointIterator it;
|
||
|
TTestPointIterator itOther;
|
||
|
for(it = m_aTestPoints.Begin(), itOther = pOther->m_aTestPoints.Begin();
|
||
|
it != m_aTestPoints.End(); it++, itOther++)
|
||
|
{
|
||
|
if(it->m_Test < itOther->m_Test)
|
||
|
return -1;
|
||
|
else if(it->m_Test > itOther->m_Test)
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
// Compare all branches
|
||
|
// ====================
|
||
|
|
||
|
for(it = m_aTestPoints.Begin(), itOther = pOther->m_aTestPoints.Begin();
|
||
|
it != m_aTestPoints.End(); it++, itOther++)
|
||
|
{
|
||
|
nCompare = CEvalTree::Compare(it->m_pLeftOf, itOther->m_pLeftOf);
|
||
|
if(nCompare)
|
||
|
return nCompare;
|
||
|
|
||
|
nCompare = CEvalTree::Compare(it->m_pAt, itOther->m_pAt);
|
||
|
if(nCompare)
|
||
|
return nCompare;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
template<class TPropType>
|
||
|
HRESULT CFullCompareNode<TPropType>::OptimizeSelf()
|
||
|
{
|
||
|
TTestPointIterator it = m_aTestPoints.Begin();
|
||
|
while(it != m_aTestPoints.End())
|
||
|
{
|
||
|
TTestPointIterator itPrev = it;
|
||
|
it++;
|
||
|
|
||
|
CEvalNode** ppLeft = &itPrev->m_pLeftOf;
|
||
|
CEvalNode** ppMiddle = &itPrev->m_pAt;
|
||
|
CEvalNode** ppRight = it != m_aTestPoints.End() ?
|
||
|
&it->m_pLeftOf : &m_pRightMost;
|
||
|
|
||
|
//
|
||
|
// compare all three test point nodes. If all the same then we
|
||
|
// can optimize the test point out. Also, two nodes are treated
|
||
|
// the same if at least one of them is the invalid node.
|
||
|
//
|
||
|
|
||
|
if ( !CEvalNode::IsInvalid( *ppLeft ) )
|
||
|
{
|
||
|
if ( !CEvalNode::IsInvalid( *ppMiddle ) )
|
||
|
{
|
||
|
if( CEvalTree::Compare( *ppLeft, *ppMiddle ) != 0 )
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ppMiddle = ppLeft;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( !CEvalNode::IsInvalid( *ppMiddle ) )
|
||
|
{
|
||
|
if ( !CEvalNode::IsInvalid( *ppRight ) )
|
||
|
{
|
||
|
if( CEvalTree::Compare( *ppMiddle, *ppRight ) != 0 )
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// we're going to optimize the test point out, but first
|
||
|
// make sure to set rightmost to point to the middle branch.
|
||
|
// Make sure to unhook appropriate pointers before removing
|
||
|
// the test node, since it owns the memory for them.
|
||
|
//
|
||
|
|
||
|
delete *ppRight;
|
||
|
*ppRight = *ppMiddle;
|
||
|
*ppMiddle = NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// optimize the test point out.
|
||
|
//
|
||
|
it = m_aTestPoints.Remove( itPrev );
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
template<class TPropType>
|
||
|
DWORD CFullCompareNode<TPropType>::ApplyPredicate(CLeafPredicate* pPred)
|
||
|
{
|
||
|
DWORD dwRes;
|
||
|
for(TTestPointIterator it = m_aTestPoints.Begin();
|
||
|
it != m_aTestPoints.End(); it++)
|
||
|
{
|
||
|
if (it->m_pLeftOf)
|
||
|
{
|
||
|
dwRes = it->m_pLeftOf->ApplyPredicate(pPred);
|
||
|
if(dwRes & WBEM_DISPOSITION_FLAG_DELETE)
|
||
|
{
|
||
|
delete it->m_pLeftOf;
|
||
|
it->m_pLeftOf = NULL;
|
||
|
}
|
||
|
else if ( dwRes & WBEM_DISPOSITION_FLAG_INVALIDATE )
|
||
|
{
|
||
|
delete it->m_pLeftOf;
|
||
|
it->m_pLeftOf = CValueNode::GetStandardInvalid();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (it->m_pAt)
|
||
|
{
|
||
|
dwRes = it->m_pAt->ApplyPredicate(pPred);
|
||
|
if(dwRes & WBEM_DISPOSITION_FLAG_DELETE)
|
||
|
{
|
||
|
delete it->m_pAt;
|
||
|
it->m_pAt = NULL;
|
||
|
}
|
||
|
else if ( dwRes & WBEM_DISPOSITION_FLAG_INVALIDATE )
|
||
|
{
|
||
|
delete it->m_pAt;
|
||
|
it->m_pAt = CValueNode::GetStandardInvalid();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (m_pRightMost)
|
||
|
{
|
||
|
dwRes = m_pRightMost->ApplyPredicate(pPred);
|
||
|
if(dwRes & WBEM_DISPOSITION_FLAG_DELETE)
|
||
|
{
|
||
|
delete m_pRightMost;
|
||
|
m_pRightMost = NULL;
|
||
|
}
|
||
|
else if ( dwRes & WBEM_DISPOSITION_FLAG_INVALIDATE )
|
||
|
{
|
||
|
delete m_pRightMost;
|
||
|
m_pRightMost = CValueNode::GetStandardInvalid();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return CBranchingNode::ApplyPredicate(pPred);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
template<class TPropType>
|
||
|
HRESULT CFullCompareNode<TPropType>::Optimize(CContextMetaData* pNamespace,
|
||
|
CEvalNode** ppNew)
|
||
|
{
|
||
|
CEvalNode* pNew = NULL;
|
||
|
HRESULT hres;
|
||
|
|
||
|
// Optimize all branches
|
||
|
// =====================
|
||
|
|
||
|
for(TTestPointIterator it = m_aTestPoints.Begin();
|
||
|
it != m_aTestPoints.End(); it++)
|
||
|
{
|
||
|
if (it->m_pLeftOf)
|
||
|
{
|
||
|
hres = it->m_pLeftOf->Optimize(pNamespace, &pNew);
|
||
|
if(FAILED(hres))
|
||
|
return hres;
|
||
|
|
||
|
if(pNew != it->m_pLeftOf)
|
||
|
{
|
||
|
delete it->m_pLeftOf;
|
||
|
it->m_pLeftOf = pNew;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (it->m_pAt)
|
||
|
{
|
||
|
hres = it->m_pAt->Optimize(pNamespace, &pNew);
|
||
|
|
||
|
if(FAILED(hres))
|
||
|
return hres;
|
||
|
|
||
|
if(pNew != it->m_pAt)
|
||
|
{
|
||
|
delete it->m_pAt;
|
||
|
it->m_pAt = pNew;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (m_pRightMost)
|
||
|
{
|
||
|
hres = m_pRightMost->Optimize(pNamespace, &pNew);
|
||
|
if(FAILED(hres))
|
||
|
return hres;
|
||
|
|
||
|
if(pNew != m_pRightMost)
|
||
|
{
|
||
|
delete m_pRightMost;
|
||
|
m_pRightMost = pNew;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (m_pNullBranch)
|
||
|
{
|
||
|
hres = m_pNullBranch->Optimize(pNamespace, &pNew);
|
||
|
|
||
|
if(FAILED(hres))
|
||
|
return hres;
|
||
|
|
||
|
if(pNew != m_pNullBranch)
|
||
|
{
|
||
|
delete m_pNullBranch;
|
||
|
m_pNullBranch = pNew;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Optimize ourselves
|
||
|
// ==================
|
||
|
|
||
|
hres = OptimizeSelf();
|
||
|
if(FAILED(hres))
|
||
|
return hres;
|
||
|
|
||
|
*ppNew = this;
|
||
|
|
||
|
//
|
||
|
// Check if this node has become superflous
|
||
|
//
|
||
|
|
||
|
if( m_aTestPoints.GetSize() == 0 )
|
||
|
{
|
||
|
if ( !CEvalNode::IsInvalid( m_pRightMost ) )
|
||
|
{
|
||
|
if ( !CEvalNode::IsInvalid( m_pNullBranch ) )
|
||
|
{
|
||
|
if ( CEvalTree::Compare(m_pNullBranch, m_pRightMost) == 0 )
|
||
|
{
|
||
|
//
|
||
|
// both the null and rightmost are the same. Optimize
|
||
|
// this node out and return the rightmost branch.
|
||
|
//
|
||
|
*ppNew = m_pRightMost;
|
||
|
|
||
|
//
|
||
|
// Untie m_pRightMost (so it is not deleted when we are)
|
||
|
//
|
||
|
m_pRightMost = NULL;
|
||
|
}
|
||
|
}
|
||
|
else if ( m_pRightMost == NULL )
|
||
|
{
|
||
|
//
|
||
|
// the right branch is false and the null branch is invalid.
|
||
|
// Optimize this node to false.
|
||
|
//
|
||
|
*ppNew = NULL;
|
||
|
}
|
||
|
}
|
||
|
else if ( m_pNullBranch == NULL )
|
||
|
{
|
||
|
//
|
||
|
// the null branch is false and the rightmost is invalid.
|
||
|
// Optimize this node to false.
|
||
|
//
|
||
|
*ppNew = NULL;
|
||
|
}
|
||
|
else if ( CEvalNode::IsInvalid( m_pNullBranch ) )
|
||
|
{
|
||
|
//
|
||
|
// both are invalid, but we can't invalidate the whole node
|
||
|
// because we're not sure what we optimized out in the test
|
||
|
// points, so just optimize this node to false.
|
||
|
//
|
||
|
*ppNew = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
template<class TPropType>
|
||
|
HRESULT CFullCompareNode<TPropType>::SetNullTest(int nOperator)
|
||
|
{
|
||
|
if(nOperator == QL1_OPERATOR_EQUALS)
|
||
|
{
|
||
|
m_pRightMost = CValueNode::GetStandardFalse();
|
||
|
|
||
|
CEvalNode* pNode = CValueNode::GetStandardTrue();
|
||
|
if(pNode == NULL)
|
||
|
return WBEM_E_OUT_OF_MEMORY;
|
||
|
SetNullBranch(pNode);
|
||
|
}
|
||
|
else if(nOperator == QL1_OPERATOR_NOTEQUALS)
|
||
|
{
|
||
|
m_pRightMost = CValueNode::GetStandardTrue();
|
||
|
if(m_pRightMost == NULL)
|
||
|
return WBEM_E_OUT_OF_MEMORY;
|
||
|
SetNullBranch(CValueNode::GetStandardFalse());
|
||
|
}
|
||
|
else
|
||
|
return WBEM_E_INVALID_QUERY;
|
||
|
|
||
|
return WBEM_S_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
template<class TPropType>
|
||
|
HRESULT CFullCompareNode<TPropType>::SetOperator(int nOperator)
|
||
|
{
|
||
|
HRESULT hr = WBEM_S_NO_ERROR;
|
||
|
|
||
|
#define GET_STD_TRUE CValueNode::GetStandardTrue()
|
||
|
#define GET_STD_FALSE CValueNode::GetStandardFalse()
|
||
|
|
||
|
#define SET_TRUE(NODE) { \
|
||
|
NODE = GET_STD_TRUE; \
|
||
|
if(NODE == NULL) { \
|
||
|
hr = WBEM_E_OUT_OF_MEMORY; \
|
||
|
break; } }
|
||
|
|
||
|
#define SET_FALSE(NODE) {NODE = GET_STD_FALSE;}
|
||
|
|
||
|
CTestPoint<TPropType> NewNode;
|
||
|
|
||
|
switch(nOperator)
|
||
|
{
|
||
|
case QL1_OPERATOR_EQUALS:
|
||
|
SET_FALSE(NewNode.m_pLeftOf);
|
||
|
SET_TRUE(NewNode.m_pAt);
|
||
|
SET_FALSE(m_pRightMost);
|
||
|
break;
|
||
|
|
||
|
case QL1_OPERATOR_NOTEQUALS:
|
||
|
SET_TRUE(NewNode.m_pLeftOf);
|
||
|
SET_FALSE(NewNode.m_pAt);
|
||
|
SET_TRUE(m_pRightMost);
|
||
|
break;
|
||
|
|
||
|
case QL1_OPERATOR_LESS:
|
||
|
SET_TRUE(NewNode.m_pLeftOf);
|
||
|
SET_FALSE(NewNode.m_pAt);
|
||
|
SET_FALSE(m_pRightMost);
|
||
|
break;
|
||
|
|
||
|
case QL1_OPERATOR_GREATER:
|
||
|
SET_FALSE(NewNode.m_pLeftOf);
|
||
|
SET_FALSE(NewNode.m_pAt);
|
||
|
SET_TRUE(m_pRightMost);
|
||
|
break;
|
||
|
|
||
|
case QL1_OPERATOR_LESSOREQUALS:
|
||
|
SET_TRUE(NewNode.m_pLeftOf);
|
||
|
SET_TRUE(NewNode.m_pAt);
|
||
|
SET_FALSE(m_pRightMost);
|
||
|
break;
|
||
|
|
||
|
case QL1_OPERATOR_GREATEROREQUALS:
|
||
|
SET_FALSE(NewNode.m_pLeftOf);
|
||
|
SET_TRUE(NewNode.m_pAt);
|
||
|
SET_TRUE(m_pRightMost);
|
||
|
break;
|
||
|
default:
|
||
|
hr = WBEM_E_CRITICAL_ERROR;
|
||
|
}
|
||
|
|
||
|
if ( SUCCEEDED(hr) )
|
||
|
{
|
||
|
m_aTestPoints.Append(NewNode);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
NewNode.Destruct();
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
//******************************************************************************
|
||
|
//******************************************************************************
|
||
|
// SCALAR PROPERTY NODE
|
||
|
//******************************************************************************
|
||
|
//******************************************************************************
|
||
|
|
||
|
template<class TPropType>
|
||
|
HRESULT CScalarPropNode<TPropType>::Evaluate(CObjectInfo& ObjInfo,
|
||
|
INTERNAL CEvalNode** ppNext)
|
||
|
{
|
||
|
HRESULT hres;
|
||
|
_IWmiObject* pObj;
|
||
|
hres = GetContainerObject(ObjInfo, &pObj);
|
||
|
if(FAILED(hres)) return hres;
|
||
|
|
||
|
// Get the property from the object
|
||
|
// ================================
|
||
|
|
||
|
long lRead;
|
||
|
TPropType Value;
|
||
|
hres = pObj->ReadPropertyValue(m_lPropHandle, sizeof(TPropType),
|
||
|
&lRead, (BYTE*)&Value);
|
||
|
if( S_OK != hres )
|
||
|
{
|
||
|
if(hres == WBEM_S_FALSE)
|
||
|
{
|
||
|
*ppNext = m_pNullBranch;
|
||
|
return WBEM_S_NO_ERROR;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return hres;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Search for the value
|
||
|
// ====================
|
||
|
|
||
|
TTestPointIterator it;
|
||
|
bool bMatch = m_aTestPoints.Find(Value, &it);
|
||
|
if(bMatch)
|
||
|
*ppNext = it->m_pAt;
|
||
|
else if(it == m_aTestPoints.End())
|
||
|
*ppNext = m_pRightMost;
|
||
|
else
|
||
|
*ppNext = it->m_pLeftOf;
|
||
|
|
||
|
return WBEM_S_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
template<class TPropType>
|
||
|
void CScalarPropNode<TPropType>::Dump(FILE* f, int nOffset)
|
||
|
{
|
||
|
CBranchingNode::Dump(f, nOffset);
|
||
|
PrintOffset(f, nOffset);
|
||
|
fprintf(f, "LastPropName = (0x%x), size=%d\n",
|
||
|
m_lPropHandle, sizeof(TPropType));
|
||
|
|
||
|
TConstTestPointIterator it;
|
||
|
for(it = m_aTestPoints.Begin();
|
||
|
it != m_aTestPoints.End(); it++)
|
||
|
{
|
||
|
PrintOffset(f, nOffset);
|
||
|
if (it != m_aTestPoints.Begin())
|
||
|
{
|
||
|
TConstTestPointIterator itPrev(it);
|
||
|
itPrev--;
|
||
|
fprintf(f, "%d < ", (int)(itPrev->m_Test));
|
||
|
}
|
||
|
fprintf(f, "X < %d\n", (int)(it->m_Test));
|
||
|
DumpNode(f, nOffset+1, it->m_pLeftOf);
|
||
|
|
||
|
PrintOffset(f, nOffset);
|
||
|
fprintf(f, "X = %d\n", (int)(it->m_Test));
|
||
|
DumpNode(f, nOffset+1, it->m_pAt);
|
||
|
}
|
||
|
|
||
|
PrintOffset(f, nOffset);
|
||
|
if (it != m_aTestPoints.Begin())
|
||
|
{
|
||
|
TConstTestPointIterator itPrev(it);
|
||
|
itPrev--;
|
||
|
fprintf(f, "X > %d\n", (int)(itPrev->m_Test));
|
||
|
}
|
||
|
else
|
||
|
fprintf(f, "ANY\n");
|
||
|
DumpNode(f, nOffset+1, m_pRightMost);
|
||
|
|
||
|
|
||
|
PrintOffset(f, nOffset);
|
||
|
fprintf(f, "NULL->\n");
|
||
|
DumpNode(f, nOffset+1, m_pNullBranch);
|
||
|
}
|