Clean up NumberFunctionCall.cpp: make all numberfunctions NaN and Inf safe, make round() work on windows, make all numberfunctions out-of-mem safe

b=102185 r=Pike sr=shaver
This commit is contained in:
sicking%bigfoot.com 2001-10-12 20:38:23 +00:00
Родитель 4f03a1f2f0
Коммит c40e0a6111
2 изменённых файлов: 118 добавлений и 141 удалений

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

@ -316,39 +316,37 @@ private:
}; //-- StringFunctionCall
// OG+
/**
/*
* Represents the XPath Number Function Calls
**/
*/
class NumberFunctionCall : public FunctionCall {
public:
enum numberFunctions {
NUMBER = 1, //-- number()
ROUND, //-- round()
FLOOR, //-- floor()
CEILING, //-- ceiling()
SUM //-- sum()
enum NumberFunctions {
NUMBER, // number()
ROUND, // round()
FLOOR, // floor()
CEILING, // ceiling()
SUM // sum()
};
/**
/*
* Creates a Number function of the given type
**/
NumberFunctionCall(short type);
*/
NumberFunctionCall(NumberFunctions type);
/**
/*
* 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
**/
*/
virtual ExprResult* evaluate(Node* context, ContextState* cs);
private:
short type;
}; //-- NumberFunctionCall
// OG-
NumberFunctions mType;
};
#endif

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

@ -1,4 +1,5 @@
/*
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
@ -28,151 +29,129 @@
*/
/*
NumberFunctionCall
A representation of the XPath Number funtions
*/
* NumberFunctionCall
* A representation of the XPath Number funtions
*/
#include "FunctionLib.h"
#include "XMLUtils.h"
#include "XMLDOMUtils.h"
#include <math.h>
/**
/*
* Creates a NumberFunctionCall of the given type
**/
NumberFunctionCall::NumberFunctionCall(short type) : FunctionCall() {
this->type = type;
switch ( type ) {
case ROUND :
*/
NumberFunctionCall::NumberFunctionCall(NumberFunctions aType) {
mType = aType;
switch (mType) {
case ROUND:
name = XPathNames::ROUND_FN;
break;
case CEILING :
case CEILING:
name = XPathNames::CEILING_FN;
break;
case FLOOR :
case FLOOR:
name = XPathNames::FLOOR_FN;
break;
case SUM :
case SUM:
name = XPathNames::SUM_FN;
break;
case NUMBER :
default :
case NUMBER:
name = XPathNames::NUMBER_FN;
break;
}
} //-- NumberFunctionCall
#if !defined(HAVE_RINT)
static double rint(double r)
{
double integerPart = 0;
double fraction = 0;
fraction = modf(r, &integerPart);
if (fraction >= 0.5)
integerPart++;
return integerPart;
}
#endif
/**
/*
* 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
* @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* NumberFunctionCall::evaluate(Node* context, ContextState* cs) {
NumberResult* result = 0;
ListIterator* iter = params.iterator();
Expr* param = 0;
String err;
ListIterator iter(&params);
switch ( type ) {
case CEILING :
if ( requireParams(1, 1, cs) ) {
double dbl = evaluateToNumber((Expr*)iter->next(), context, cs);
result = new NumberResult(ceil(dbl));
}
else {
result = new NumberResult(0.0);
}
break;
case FLOOR :
if ( requireParams(1, 1, cs) ) {
double dbl = evaluateToNumber((Expr*)iter->next(), context, cs);
result = new NumberResult(floor(dbl));
}
else {
result = new NumberResult(0.0);
}
break;
case ROUND :
if ( requireParams(1, 1, cs) ) {
double dbl = evaluateToNumber((Expr*)iter->next(), context, cs);
double res = rint(dbl);
if ((dbl>0.0) && (res == dbl-0.5)) {
// fix for native round function from math library (rint()) which does not
// match the XPath spec for positive half values
result = new NumberResult(res+1.0);
}
else
result = new NumberResult(res);
break;
}
else result = new NumberResult(0.0);
break;
case SUM :
double numResult;
numResult = 0 ;
if ( requireParams(1, 1, cs) ) {
param = (Expr*)iter->next();
ExprResult* exprResult = param->evaluate(context, cs);
if ( exprResult->getResultType() == ExprResult::NODESET ) {
NodeSet *lNList = (NodeSet *)exprResult;
NodeSet tmp;
for (int i=0; i<lNList->size(); i++){
tmp.add(0,lNList->get(i));
numResult += tmp.numberValue();
};
};
delete exprResult;
exprResult=0;
};
result = new NumberResult(numResult);
break;
case NUMBER :
default : //-- number( object? )
if ( requireParams(0, 1, cs) ) {
if (iter->hasNext()) {
param = (Expr*) iter->next();
ExprResult* exprResult = param->evaluate(context, cs);
result = new NumberResult(exprResult->numberValue());
delete exprResult;
}
else {
String resultStr;
XMLDOMUtils::getNodeValue(context, &resultStr);
if ( cs->isStripSpaceAllowed(context) &&
XMLUtils::shouldStripTextnode(resultStr)) {
result = new NumberResult(Double::NaN);
}
else {
Double dbl(resultStr);
result = new NumberResult(dbl.doubleValue());
}
}
}
else {
result = new NumberResult(Double::NaN);
}
break;
if (mType == NUMBER) {
if (!requireParams(0, 1, cs))
return new NumberResult(Double::NaN);
}
else {
if (!requireParams(1, 1, cs))
return new NumberResult(Double::NaN);
}
delete iter;
return result;
} //-- evaluate
switch (mType) {
case CEILING:
{
double dbl = evaluateToNumber((Expr*)iter.next(), context, cs);
if (Double::isNaN(dbl) || Double::isInfinite(dbl))
return new NumberResult(dbl);
if (Double::isNeg(dbl) && dbl > -1)
return new NumberResult(0 * dbl);
return new NumberResult(ceil(dbl));
}
case FLOOR:
{
double dbl = evaluateToNumber((Expr*)iter.next(), context, cs);
if (Double::isNaN(dbl) ||
Double::isInfinite(dbl) ||
(dbl == 0 && Double::isNeg(dbl)))
return new NumberResult(dbl);
return new NumberResult(floor(dbl));
}
case ROUND:
{
double dbl = evaluateToNumber((Expr*)iter.next(), context, cs);
if (Double::isNaN(dbl) || Double::isInfinite(dbl))
return new NumberResult(dbl);
if (Double::isNeg(dbl) && dbl >= -0.5)
return new NumberResult(0 * dbl);
return new NumberResult(floor(dbl + 0.5));
}
case SUM:
{
ExprResult* exprResult =
((Expr*)iter.next())->evaluate(context, cs);
if (!exprResult)
return 0;
if (exprResult->getResultType() != ExprResult::NODESET) {
String err("NodeSet expected in call to sum(): ");
toString(err);
cs->recieveError(err);
return new NumberResult(Double::NaN);
}
double res = 0;
NodeSet* nodes = (NodeSet*)exprResult;
int i;
for (i = 0; i < nodes->size(); i++) {
String resultStr;
XMLDOMUtils::getNodeValue(nodes->get(i), &resultStr);
Double dbl(resultStr);
res += dbl.doubleValue();
}
delete exprResult;
return new NumberResult(res);
}
case NUMBER:
{
if (iter.hasNext())
return new NumberResult(
evaluateToNumber((Expr*)iter.next(), context, cs));
String resultStr;
XMLDOMUtils::getNodeValue(context, &resultStr);
Double dbl(resultStr);
return new NumberResult(dbl.doubleValue());
}
}
return new NumberResult(Double::NaN);
}