/*++ Copyright (C) 1996-1999 Microsoft Corporation Module Name: DUMBNODE.H Abstract: WBEM Evaluation Tree History: --*/ template CFullCompareNode::CFullCompareNode( const CFullCompareNode& 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 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 HRESULT CFullCompareNode::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 CFullCompareNode::~CFullCompareNode() { delete m_pRightMost; } template HRESULT CFullCompareNode::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 HRESULT CFullCompareNode::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 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 HRESULT CFullCompareNode::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 HRESULT CFullCompareNode::CombineBranchesWith( CBranchingNode* pRawArg2, int nOp, CContextMetaData* pNamespace, CImplicationList& Implications, bool bDeleteThis, bool bDeleteArg2, CEvalNode** ppRes) { HRESULT hres; CFullCompareNode* pArg2 = (CFullCompareNode*)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*)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 HRESULT CFullCompareNode::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* pNew = (CFullCompareNode*)*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 int CFullCompareNode::SubCompare(CEvalNode* pRawOther) { CFullCompareNode* pOther = (CFullCompareNode*)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 HRESULT CFullCompareNode::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 DWORD CFullCompareNode::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 HRESULT CFullCompareNode::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 HRESULT CFullCompareNode::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 HRESULT CFullCompareNode::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 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 HRESULT CScalarPropNode::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 void CScalarPropNode::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); }