Bug 203229: Use strings better by using existing stringobjects inside ExprResults if one exists.

r=Pike sr=peterv a=asa
This commit is contained in:
sicking%bigfoot.com 2005-11-02 07:40:21 +00:00
Родитель 3eddff3181
Коммит a3fd4a5067
9 изменённых файлов: 201 добавлений и 228 удалений

Просмотреть файл

@ -62,6 +62,15 @@ void BooleanResult::stringValue(nsAString& str) {
else str.Append(NS_LITERAL_STRING("false"));
} //-- toString
nsAString*
BooleanResult::stringValuePointer()
{
// In theory we could set strings containing "true" and "false" somewhere,
// but most stylesheets never get the stringvalue of a bool so that won't
// really buy us anything.
return nsnull;
}
MBool BooleanResult::booleanValue() {
return this->value;
} //-- toBoolean

Просмотреть файл

@ -517,11 +517,8 @@ private:
class RelationalExpr : public Expr {
public:
//-- RelationalExpr Types
//-- LF, changed from static const short to enum
enum _RelationalExprType {
EQUAL = 1,
enum RelationalExprType {
EQUAL,
NOT_EQUAL,
LESS_THAN,
GREATER_THAN,
@ -529,18 +526,17 @@ public:
GREATER_OR_EQUAL
};
RelationalExpr(Expr* leftExpr, Expr* rightExpr, short op);
~RelationalExpr();
RelationalExpr(Expr* aLeftExpr, Expr* aRightExpr, RelationalExprType aOp);
TX_DECL_EXPR;
private:
short op;
Expr* leftExpr;
Expr* rightExpr;
PRBool compareResults(ExprResult* aLeft, ExprResult* aRight);
MBool compareResults(ExprResult* left, ExprResult* right);
}; //-- RelationalExpr
nsAutoPtr<Expr> mLeftExpr;
nsAutoPtr<Expr> mRightExpr;
RelationalExprType mOp;
};
/**
* VariableRefExpr

Просмотреть файл

@ -74,6 +74,12 @@ public:
**/
virtual void stringValue(nsAString& str) = 0;
/**
* Returns a pointer to the stringvalue if possible. Otherwise null is
* returned.
*/
virtual nsAString* stringValuePointer() = 0;
/**
* Converts this ExprResult to a Boolean (MBool) value
* @return the Boolean value
@ -88,6 +94,15 @@ public:
};
#define TX_DECL_EXPRRESULT \
virtual ExprResult* clone(); \
virtual short getResultType(); \
virtual void stringValue(nsAString& str); \
virtual nsAString* stringValuePointer(); \
virtual PRBool booleanValue(); \
virtual double numberValue(); \
class BooleanResult : public ExprResult {
public:
@ -95,11 +110,7 @@ public:
BooleanResult();
BooleanResult(MBool boolean);
virtual ExprResult* clone();
virtual short getResultType();
virtual void stringValue(nsAString& str);
virtual MBool booleanValue();
virtual double numberValue();
TX_DECL_EXPRRESULT
private:
MBool value;
@ -112,11 +123,7 @@ public:
NumberResult();
NumberResult(double dbl);
virtual ExprResult* clone();
virtual short getResultType();
virtual void stringValue(nsAString& str);
virtual MBool booleanValue();
virtual double numberValue();
TX_DECL_EXPRRESULT
private:
double value;
@ -129,11 +136,7 @@ public:
StringResult();
StringResult(const nsAString& str);
virtual ExprResult* clone();
virtual short getResultType();
virtual void stringValue(nsAString& str);
virtual MBool booleanValue();
virtual double numberValue();
TX_DECL_EXPRRESULT
nsString mValue;
};

Просмотреть файл

@ -63,6 +63,12 @@ void NumberResult::stringValue(nsAString& str) {
Double::toString(value, str);
} //-- stringValue
nsAString*
NumberResult::stringValuePointer()
{
return nsnull;
}
MBool NumberResult::booleanValue() {
// OG+
// As per the XPath spec, the boolean value of a number is true if and only if

Просмотреть файл

@ -31,217 +31,160 @@
#include "NodeSet.h"
#include "XMLDOMUtils.h"
//------------------/
//- RelationalExpr -/
//------------------/
RelationalExpr::RelationalExpr(Expr* leftExpr, Expr* rightExpr, short op) {
this->op = op;
this->leftExpr = leftExpr;
this->rightExpr = rightExpr;
} //-- RelationalExpr
RelationalExpr::~RelationalExpr() {
delete leftExpr;
delete rightExpr;
} //-- ~RelationalExpr
RelationalExpr::RelationalExpr(Expr* aLeftExpr, Expr* aRightExpr,
RelationalExprType aOp)
: mLeftExpr(aLeftExpr), mRightExpr(aRightExpr), mOp(aOp)
{
}
/**
* Compares the two ExprResults based on XPath 1.0 Recommendation (section 3.4)
**/
MBool RelationalExpr::compareResults(ExprResult* left, ExprResult* right) {
*/
PRBool
RelationalExpr::compareResults(ExprResult* aLeft, ExprResult* aRight)
{
short ltype = aLeft->getResultType();
short rtype = aRight->getResultType();
short ltype = left->getResultType();
short rtype = right->getResultType();
MBool result = MB_FALSE;
//-- handle case for just Left NodeSet or Both NodeSets
// Handle case for just Left NodeSet or Both NodeSets
if (ltype == ExprResult::NODESET) {
if (rtype == ExprResult::BOOLEAN) {
BooleanResult leftBool(left->booleanValue());
return compareResults(&leftBool, right);
BooleanResult leftBool(aLeft->booleanValue());
return compareResults(&leftBool, aRight);
}
NodeSet* nodeSet = (NodeSet*)left;
for ( int i = 0; i < nodeSet->size(); i++) {
nsAutoString str;
Node* node = nodeSet->get(i);
XMLDOMUtils::getNodeValue(node, str);
StringResult strResult(str);
result = compareResults(&strResult, right);
if ( result ) break;
NodeSet* nodeSet = NS_STATIC_CAST(NodeSet*, aLeft);
StringResult strResult;
int i;
for (i = 0; i < nodeSet->size(); ++i) {
Node* node = nodeSet->get(i);
strResult.mValue.Truncate();
XMLDOMUtils::getNodeValue(node, strResult.mValue);
if (compareResults(&strResult, aRight)) {
return PR_TRUE;
}
}
return PR_FALSE;
}
//-- handle case for Just Right NodeSet
else if ( rtype == ExprResult::NODESET) {
// Handle case for Just Right NodeSet
if (rtype == ExprResult::NODESET) {
if (ltype == ExprResult::BOOLEAN) {
BooleanResult rightBool(right->booleanValue());
return compareResults(left, &rightBool);
BooleanResult rightBool(aRight->booleanValue());
return compareResults(aLeft, &rightBool);
}
NodeSet* nodeSet = (NodeSet*)right;
for ( int i = 0; i < nodeSet->size(); i++) {
nsAutoString str;
Node* node = nodeSet->get(i);
XMLDOMUtils::getNodeValue(node, str);
StringResult strResult(str);
result = compareResults(left, &strResult);
if ( result ) break;
NodeSet* nodeSet = NS_STATIC_CAST(NodeSet*, aRight);
StringResult strResult;
int i;
for (i = 0; i < nodeSet->size(); ++i) {
Node* node = nodeSet->get(i);
strResult.mValue.Truncate();
XMLDOMUtils::getNodeValue(node, strResult.mValue);
if (compareResults(aLeft, &strResult)) {
return PR_TRUE;
}
}
return PR_FALSE;
}
//-- neither NodeSet
else {
if ( op == NOT_EQUAL) {
if ((ltype == ExprResult::BOOLEAN)
|| (rtype == ExprResult::BOOLEAN)) {
result = (left->booleanValue() != right->booleanValue());
}
else if ((ltype == ExprResult::NUMBER) ||
(rtype == ExprResult::NUMBER)) {
double lval = left->numberValue();
double rval = right->numberValue();
// Neither is a NodeSet
if (mOp == EQUAL || mOp == NOT_EQUAL) {
PRBool result;
nsAString *lString, *rString;
// If either is a bool, compare as bools.
if (ltype == ExprResult::BOOLEAN || rtype == ExprResult::BOOLEAN) {
result = aLeft->booleanValue() == aRight->booleanValue();
}
// If either is a number, compare as numbers.
else if (ltype == ExprResult::NUMBER || rtype == ExprResult::NUMBER) {
double lval = aLeft->numberValue();
double rval = aRight->numberValue();
#if defined(XP_WIN) || defined(XP_OS2)
if (Double::isNaN(lval) || Double::isNaN(rval))
result = MB_TRUE;
else
result = (lval != rval);
if (Double::isNaN(lval) || Double::isNaN(rval))
result = PR_FALSE;
else
result = lval == rval;
#else
result = (lval != rval);
result = lval == rval;
#endif
}
// Otherwise compare as strings. Try to use the stringobject in
// StringResult if possible since that is a common case.
else if ((lString = aLeft->stringValuePointer())) {
if ((rString = aRight->stringValuePointer())) {
result = lString->Equals(*rString);
}
else {
nsAutoString lStr;
left->stringValue(lStr);
nsAutoString rStr;
right->stringValue(rStr);
result = !lStr.Equals(rStr);
aRight->stringValue(rStr);
result = rStr.Equals(*lString);
}
}
else if ( op == EQUAL) {
if ((ltype == ExprResult::BOOLEAN)
|| (rtype == ExprResult::BOOLEAN)) {
result = (left->booleanValue() == right->booleanValue());
}
else if ((ltype == ExprResult::NUMBER) ||
(rtype == ExprResult::NUMBER)) {
double lval = left->numberValue();
double rval = right->numberValue();
#if defined(XP_WIN) || defined(XP_OS2)
if (Double::isNaN(lval) || Double::isNaN(rval))
result = MB_FALSE;
else
result = (lval == rval);
#else
result = (lval == rval);
#endif
}
else {
nsAutoString lStr;
left->stringValue(lStr);
nsAutoString rStr;
right->stringValue(rStr);
result = lStr.Equals(rStr);
}
else if ((rString = aRight->stringValuePointer())) {
nsAutoString lStr;
aLeft->stringValue(lStr);
result = rString->Equals(lStr);
}
else {
double leftDbl = left->numberValue();
double rightDbl = right->numberValue();
switch( op ) {
case LESS_THAN:
#if defined(XP_WIN) || defined(XP_OS2)
if (Double::isNaN(leftDbl) || Double::isNaN(rightDbl))
result = MB_FALSE;
else
result = (leftDbl < rightDbl);
#else
result = (leftDbl < rightDbl);
#endif
break;
case LESS_OR_EQUAL:
#if defined(XP_WIN) || defined(XP_OS2)
if (Double::isNaN(leftDbl) || Double::isNaN(rightDbl))
result = MB_FALSE;
else
result = (leftDbl <= rightDbl);
#else
result = (leftDbl <= rightDbl);
#endif
break;
case GREATER_THAN :
#if defined(XP_WIN) || defined(XP_OS2)
if (Double::isNaN(leftDbl) || Double::isNaN(rightDbl))
result = MB_FALSE;
else
result = (leftDbl > rightDbl);
#else
result = (leftDbl > rightDbl);
#endif
break;
case GREATER_OR_EQUAL:
#if defined(XP_WIN) || defined(XP_OS2)
if (Double::isNaN(leftDbl) || Double::isNaN(rightDbl))
result = MB_FALSE;
else
result = (leftDbl >= rightDbl);
#else
result = (leftDbl >= rightDbl);
#endif
break;
}
nsAutoString lStr, rStr;
aLeft->stringValue(lStr);
aRight->stringValue(rStr);
result = lStr.Equals(rStr);
}
}
return result;
} //-- compareResult
/**
* Evaluates this Expr based on the given context node and processor state
* @param context the context node for evaluation of this Expr
* @param ps the ContextState containing the stack information needed
* for evaluation
* @return the result of the evaluation
**/
ExprResult* RelationalExpr::evaluate(txIEvalContext* aContext)
return mOp == EQUAL ? result : !result;
}
double leftDbl = aLeft->numberValue();
double rightDbl = aRight->numberValue();
#if defined(XP_WIN) || defined(XP_OS2)
if (Double::isNaN(leftDbl) || Double::isNaN(rightDbl))
return PR_FALSE;
#endif
switch (mOp) {
case LESS_THAN:
return leftDbl < rightDbl;
case LESS_OR_EQUAL:
return leftDbl <= rightDbl;
case GREATER_THAN :
return leftDbl > rightDbl;
case GREATER_OR_EQUAL:
return leftDbl >= rightDbl;
}
NS_NOTREACHED("We should have cought all cases");
return PR_FALSE;
}
ExprResult*
RelationalExpr::evaluate(txIEvalContext* aContext)
{
//-- get result of left expression
ExprResult* lResult = 0;
if (leftExpr)
lResult = leftExpr->evaluate(aContext);
else
return new BooleanResult();
nsAutoPtr<ExprResult> lResult(mLeftExpr->evaluate(aContext));
NS_ENSURE_TRUE(lResult, nsnull);
//-- get result of right expr
ExprResult* rResult = 0;
if (rightExpr)
rResult = rightExpr->evaluate(aContext);
else {
delete lResult;
return new BooleanResult();
}
BooleanResult* boolResult = new BooleanResult(compareResults(lResult, rResult));
delete lResult;
delete rResult;
return boolResult;
} //-- evaluate
nsAutoPtr<ExprResult> rResult(mRightExpr->evaluate(aContext));
NS_ENSURE_TRUE(rResult, nsnull);
/**
* Returns the String representation of this Expr.
* @param dest the String to use when creating the String
* representation. The String representation will be appended to
* any data in the destination String, to allow cascading calls to
* other #toString() methods for Expressions.
* @return the String representation of this Expr.
**/
void RelationalExpr::toString(nsAString& str) {
return new BooleanResult(compareResults(lResult, rResult));
}
if ( leftExpr ) leftExpr->toString(str);
else str.Append(NS_LITERAL_STRING("null"));
void
RelationalExpr::toString(nsAString& str)
{
mLeftExpr->toString(str);
switch ( op ) {
switch (mOp) {
case NOT_EQUAL:
str.Append(NS_LITERAL_STRING("!="));
break;
@ -262,8 +205,5 @@ void RelationalExpr::toString(nsAString& str) {
break;
}
if ( rightExpr ) rightExpr->toString(str);
else str.Append(NS_LITERAL_STRING("null"));
} //-- toString
mRightExpr->toString(str);
}

Просмотреть файл

@ -61,6 +61,12 @@ void StringResult::stringValue(nsAString& str) {
str.Append(mValue);
} //-- stringValue
nsAString*
StringResult::stringValuePointer()
{
return &mValue;
}
MBool StringResult::booleanValue() {
return !mValue.IsEmpty();
} //-- booleanValue

Просмотреть файл

@ -575,14 +575,18 @@ txLREAttribute::execute(txExecutionState& aEs)
mLocalName->ToString(nodeName);
}
ExprResult* exprRes = mValue->evaluate(aEs.getEvalContext());
nsAutoPtr<ExprResult> exprRes = mValue->evaluate(aEs.getEvalContext());
NS_ENSURE_TRUE(exprRes, NS_ERROR_FAILURE);
nsAutoString value;
exprRes->stringValue(value);
delete exprRes;
aEs.mResultHandler->attribute(nodeName, mNamespaceID, value);
nsAString* value = exprRes->stringValuePointer();
if (value) {
aEs.mResultHandler->attribute(nodeName, mNamespaceID, *value);
}
else {
nsAutoString valueStr;
exprRes->stringValue(valueStr);
aEs.mResultHandler->attribute(nodeName, mNamespaceID, valueStr);
}
return NS_OK;
}
@ -1040,15 +1044,23 @@ txValueOf::txValueOf(nsAutoPtr<Expr> aExpr, PRBool aDOE)
nsresult
txValueOf::execute(txExecutionState& aEs)
{
ExprResult* exprRes = mExpr->evaluate(aEs.getEvalContext());
nsAutoPtr<ExprResult> exprRes = mExpr->evaluate(aEs.getEvalContext());
NS_ENSURE_TRUE(exprRes, NS_ERROR_FAILURE);
nsAutoString value;
exprRes->stringValue(value);
delete exprRes;
if (!value.IsEmpty()) {
aEs.mResultHandler->characters(value, mDOE);
nsAString* value = exprRes->stringValuePointer();
if (value) {
if (!value->IsEmpty()) {
aEs.mResultHandler->characters(*value, mDOE);
}
}
else {
nsAutoString valueStr;
exprRes->stringValue(valueStr);
if (!valueStr.IsEmpty()) {
aEs.mResultHandler->characters(valueStr, mDOE);
}
}
return NS_OK;
}

Просмотреть файл

@ -67,6 +67,11 @@ void txResultTreeFragment::stringValue(nsAString& aResult)
aResult.Append(mBuffer->mStringValue);
}
nsAString* txResultTreeFragment::stringValuePointer()
{
return mBuffer ? &mBuffer->mStringValue : nsnull;
}
PRBool txResultTreeFragment::booleanValue()
{
return PR_TRUE;

Просмотреть файл

@ -49,11 +49,7 @@ public:
txResultTreeFragment(txResultBuffer* aBuffer);
~txResultTreeFragment();
virtual ExprResult* clone();
virtual short getResultType();
virtual void stringValue(nsAString& aResult);
virtual MBool booleanValue();
virtual double numberValue();
TX_DECL_EXPRRESULT
nsresult flushToHandler(txAXMLEventHandler* aHandler);