sl@0: // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0: // All rights reserved.
sl@0: // This component and the accompanying materials are made available
sl@0: // under the terms of "Eclipse Public License v1.0"
sl@0: // which accompanies this distribution, and is available
sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0: //
sl@0: // Initial Contributors:
sl@0: // Nokia Corporation - initial contribution.
sl@0: //
sl@0: // Contributors:
sl@0: //
sl@0: // Description:
sl@0: // SQL AND and OR node class
sl@0: // 
sl@0: //
sl@0: 
sl@0: #include "UQ_STD.H"
sl@0: 
sl@0: // class CSqlMultiNode
sl@0: 
sl@0: inline CSqlMultiNode::CSqlMultiNode( TType aType )
sl@0:  :	CSqlSearchCondition( aType )
sl@0: 	{ __ASSERT( aType == EOr || aType == EAnd ); }
sl@0: 
sl@0: inline TInt CSqlMultiNode::Size() const
sl@0: 	{ return ( const TUint8* )iEnd - ( const TUint8* )this; }
sl@0: 
sl@0: inline TBool CSqlMultiNode::IsFull() const
sl@0: 	{ return ( Size() & ( EGranularity - 1 ) ) == 0; }
sl@0: 
sl@0: inline TInt CSqlMultiNode::Size( TInt aLeaves )
sl@0: 	{ return _FOFF( CSqlMultiNode, iLeaves[ aLeaves ] ); }
sl@0: 
sl@0: CSqlMultiNode::~CSqlMultiNode()
sl@0: 	{
sl@0: 	TEntry* p = iLeaves;
sl@0: 	TEntry* e = iEnd;
sl@0: 	while ( p < e )
sl@0: 		delete *p++;
sl@0: 	}
sl@0: 
sl@0: CSqlMultiNode* CSqlMultiNode::New( TType aType, TInt aSize )
sl@0: 	{
sl@0: 	aSize = ( aSize + ( EGranularity - 1 ) ) & ~( EGranularity - 1 );
sl@0: 	__ASSERT( aSize >= static_cast<TInt>( sizeof( CSqlMultiNode ) ) );
sl@0: 	aSize -= sizeof( CSqlMultiNode );
sl@0: 	return new( aSize )  CSqlMultiNode( aType );	// get the extra size for the entries
sl@0: 	}
sl@0: 
sl@0: CSqlMultiNode* CSqlMultiNode::Grow( CSqlMultiNode* aNode, TInt aExtraSize )
sl@0: 	{
sl@0: 	TInt size = aNode->Size();
sl@0: 	CSqlMultiNode* self = New( aNode->NodeType(), size + aExtraSize );
sl@0: 	if ( self )
sl@0: 		{
sl@0: 		aNode->iEnd = aNode->iLeaves;
sl@0: 		self->iEnd = ( TEntry* )Mem::Copy( self->iLeaves, aNode->iLeaves, size - Size( 0 ) );
sl@0: 		}
sl@0: 	delete aNode;
sl@0: 	return self;
sl@0: 	}
sl@0: 
sl@0: CSqlMultiNode* CSqlMultiNode::Concatenate( CSqlMultiNode* aLeft, CSqlMultiNode* aRight )
sl@0: 	{
sl@0: 	TInt lsize = aLeft->Size();
sl@0: 	TInt rsize = aRight->Size();
sl@0: 	if ( rsize > lsize )
sl@0: 		return Concatenate( aRight, aLeft );	// right node larger--flip over
sl@0: 	rsize -= Size( 0 );
sl@0: 	if ( (aLeft->IsFull()) ||											// if left node is already full 
sl@0: 		 (( lsize & ( EGranularity - 1 ) ) + rsize > EGranularity ) )	// or available space in the left node is not enough for a new data
sl@0: 			aLeft = Grow( aLeft, rsize );								// then increase left node to accomadate right node
sl@0: 	if ( aLeft )
sl@0: 		{
sl@0: 		aRight->iEnd = aRight->iLeaves;
sl@0: 		aLeft->iEnd = ( TEntry* )Mem::Copy( aLeft->iEnd, aRight->iLeaves, rsize );
sl@0: 		}
sl@0: 	delete aRight;
sl@0: 	return aLeft;
sl@0: 	}
sl@0: 
sl@0: CSqlSearchCondition* CSqlMultiNode::New( TType aType, CSqlSearchCondition* aLeft, CSqlSearchCondition* aRight )
sl@0: //
sl@0: // Full NULL propagation, cleaning up any of either node on failure
sl@0: //
sl@0: 	{
sl@0: 	if ( aLeft && aRight )
sl@0: 		{
sl@0: 		if ( aLeft->NodeType() == aType )
sl@0: 			{	// we can merge into aLeft
sl@0: 			CSqlMultiNode* left = aLeft->MultiNode();
sl@0: 			if ( aRight->NodeType() == aType )
sl@0: 				return Concatenate( left, aRight->MultiNode() );
sl@0: 			
sl@0: 			// append right subnode onto left
sl@0: 			if ( left->IsFull() )
sl@0: 				{
sl@0: 				left = Grow( left, sizeof( TEntry ) );
sl@0: 				if ( !left )
sl@0: 					goto grow_failed;
sl@0: 				}
sl@0: 			TEntry* e = left->iEnd;
sl@0: 			*e++ = aRight;
sl@0: 			left->iEnd = e;
sl@0: 			return left;
sl@0: 			}
sl@0: 		else if ( aRight->NodeType() == aType )
sl@0: 			return New( aType, aRight, aLeft );	// swap left and right
sl@0: 		else
sl@0: 			{	// neither node is not of the required type
sl@0: 			CSqlMultiNode* self = New( aType, Size( 2 ) );
sl@0: 			if ( self )
sl@0: 				{
sl@0: 				TEntry* e = self->iLeaves;
sl@0: 				*e++ = aLeft;
sl@0: 				*e++ = aRight;
sl@0: 				self->iEnd = e;
sl@0: 				return self;
sl@0: 				}
sl@0: 			}
sl@0: 		}
sl@0: 	delete aLeft;
sl@0: grow_failed:
sl@0: 	delete aRight;
sl@0: 	return 0;
sl@0: 	}
sl@0: 
sl@0: void CSqlMultiNode::Remove( CSqlSearchCondition* aSubNode )
sl@0: //
sl@0: // Remove the subnode from the leaf-set
sl@0: //
sl@0: 	{
sl@0: 	TEntry* p = iLeaves - 1;
sl@0: 	TEntry* e = --iEnd;
sl@0: 	do
sl@0: 		{
sl@0: 		__ASSERT( p < e );
sl@0: 		} while ( *++p != aSubNode );
sl@0: 	while ( p<e )
sl@0: 		{
sl@0: 		TEntry e = *++p;
sl@0: 		p[ -1 ] = e;
sl@0: 		}
sl@0: 	delete aSubNode;
sl@0: 	}
sl@0: 
sl@0: CSqlSearchCondition* CSqlMultiNode::Reduce (CSqlMultiNode* aNode )
sl@0: //
sl@0: // If we have less than two leaves, then simplify the expression
sl@0: //
sl@0: 	{
sl@0: 	CSqlSearchCondition* node = aNode;
sl@0: 	if ( aNode->iEnd - aNode->iLeaves <= 1 )
sl@0: 		{
sl@0: 		if ( aNode->iEnd - aNode->iLeaves == 1 )
sl@0: 			{
sl@0: 			aNode->iEnd = aNode->iLeaves;
sl@0: 			node = aNode->iLeaves[ 0 ];
sl@0: 			}
sl@0: 		else
sl@0: 			node = 0;
sl@0: 		delete aNode;
sl@0: 		}
sl@0: 	return node;
sl@0: 	}
sl@0: 
sl@0: void CSqlMultiNode::BindL( const RDbTableRow& aSource )
sl@0: 	{
sl@0: 	__ASSERT( iEnd - iLeaves > 1 );
sl@0: 	const TEntry* p = iLeaves;
sl@0: 	const TEntry* e = iEnd;
sl@0: 	do ( *p++ )->BindL( aSource );
sl@0: 		while ( p < e );
sl@0: 	}
sl@0: 
sl@0: TBool CSqlMultiNode::EvaluateL( const TTextOps& aTextOp ) const
sl@0: 	{
sl@0: 	__ASSERT( iEnd - iLeaves > 1 );
sl@0: 	const TEntry* p = iLeaves;
sl@0: 	const TEntry* e = iEnd - 1;			// all except the last sub-node
sl@0: 	do
sl@0: 		{
sl@0: 		TBool b = ( *p++ )->EvaluateL( aTextOp );
sl@0: 		if ( NodeType() == EOr )
sl@0: 			{
sl@0: 			if ( b )
sl@0: 				return b;
sl@0: 			}
sl@0: 		else
sl@0: 			{
sl@0: 			if ( !b )
sl@0: 				return b;
sl@0: 			}
sl@0: 		} while ( p < e );
sl@0: 	return ( *p )->EvaluateL( aTextOp );	// the last subnode
sl@0: 	}