#include "../../config/pathan_config.h" /* * Copyright (c) 2001, DecisionSoft Limited All rights reserved. * Please see LICENSE.TXT for more information. */ #include #include #include #include #include #include #include "../../exceptions/XPath2TypeCastException.hpp" #include "../../exceptions/InvalidLexicalSpaceException.hpp" #include #include #include #include #include // defines X() and XMLCh* #include #include #include #include #include ATDecimalOrDerivedImpl:: ATDecimalOrDerivedImpl(const XMLCh* typeURI, const XMLCh* typeName, const XMLCh* value, XPath2MemoryManager* memMgr, const DynamicContext* context): ATDecimalOrDerived(memMgr), _typeName(typeName), _typeURI(typeURI) { setDecimal(value); if(this->isInstanceOfType (XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_INTEGER, context)) { _isInteger = true; } else { _isInteger = false; } memMgr->markForRelease(this); } ATDecimalOrDerivedImpl:: ATDecimalOrDerivedImpl(const XMLCh* typeURI, const XMLCh* typeName, const MAPM value, XPath2MemoryManager* memMgr, const DynamicContext* context): ATDecimalOrDerived(memMgr), _typeName(typeName), _typeURI(typeURI) { _decimal = value; if(this->isInstanceOfType (XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_INTEGER, context)) { _isInteger = true; } else { _isInteger = false; } memMgr->markForRelease(this); } /* Get the name of the primitive type (basic type) of this type * (ie "decimal" for xs:decimal) */ const XMLCh* ATDecimalOrDerivedImpl::getPrimitiveTypeName() const { return getPrimitiveName(); } const XMLCh* ATDecimalOrDerivedImpl::getPrimitiveName() { return XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_DECIMAL; } /* Get the name of this type (ie "integer" for xs:integer) */ const XMLCh* ATDecimalOrDerivedImpl::getTypeName() const { return _typeName; } /* Get the namespace URI for this type */ const XMLCh* ATDecimalOrDerivedImpl::getTypeURI() const { return _typeURI; } AnyAtomicType::AtomicObjectType ATDecimalOrDerivedImpl::getTypeIndex() { return AnyAtomicType::DECIMAL; } const AnyAtomicType* ATDecimalOrDerivedImpl::castAsInternal(const XMLCh* targetURI, const XMLCh* targetType, const DynamicContext* context) const { if(context->isTypeOrDerivedFromType(targetURI, targetType, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_INTEGER)) { return DatatypeFactory::POD2AT::createDecimalOrDerived(context->getMemoryManager(), targetURI, targetType, _decimal, context); } else if (context->isTypeOrDerivedFromType(targetURI, targetType, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_BOOLEAN)) { if (this->isZero()) { return DatatypeFactory::POD2AT::createBooleanOrDerived(context->getMemoryManager(), targetURI, targetType, false, context); } else { return DatatypeFactory::POD2AT::createBooleanOrDerived(context->getMemoryManager(), targetURI, targetType, true, context); } } else { return AnyAtomicType::castAsInternal(targetURI, targetType, context); } } /* returns the XMLCh* (canonical) representation of this type */ const XMLCh* ATDecimalOrDerivedImpl::asString(const DynamicContext* context) const { char obuf[1024]; if(_decimal.is_integer()) _decimal.toIntegerString(obuf); else _decimal.toFixPtString(obuf, DECIMAL_MAX_DIGITS); // Note in the canonical representation the decimal point is required // and there must be at least one digit to the right and one digit to // the left of the decimal point (which may be 0) if(strchr(obuf,'.')!=0) { // remove trailing 0's char* lastChar=obuf+strlen(obuf)-1; while(*lastChar=='0') { *lastChar--=0; } } return context->getMemoryManager()->getPooledString(obuf); } /* returns an XMLCh* representation of this Numeric with precision signinficant digits */ const XMLCh* ATDecimalOrDerivedImpl::asString(int precision, const DynamicContext* context) const { MAPM decimal = _decimal.abs(); char obuf[1024]; if(decimal.is_integer()) { decimal.toFixPtString(obuf, 0); // no significant digits int length = strlen(obuf); if(lengthgetMemoryManager()); if(this->isNegative()) { buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); } for(int i = length; igetMemoryManager()->getPooledString(obuf)); return context->getMemoryManager()->getPooledString(buf.getRawBuffer()); } else if (length>precision) { // chop off the end char* lastChar=obuf+length-1; for(int i = precision; iisNegative()) { XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer buf(1023, context->getMemoryManager()); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); buf.append(context->getMemoryManager()->getPooledString(obuf)); return context->getMemoryManager()->getPooledString(buf.getRawBuffer()); } } else { if(this->isNegative()) { XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer buf(1023, context->getMemoryManager()); buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); buf.append(context->getMemoryManager()->getPooledString(obuf)); return context->getMemoryManager()->getPooledString(buf.getRawBuffer()); } } } else { // Don't support this for now, unless we see a need for it return this->asString(context); /*decimal.toFixPtString(obuf, precision); int digitsBeforeDot = 2; //strchr(obuf, '.'); // TODO: FIX THIS! Find an index of for char* if(digitsBeforeDot > precision) { // chop off the end obuf[precision] = 0; } else if (digitsBeforeDot < precision) { // then we want precision - digitsBeforeDot significant digits obuf[digitsBeforeDot+1+precision] = 0; // +1 for the . if(this->isNegative()) { XERCES_CPP_NAMESPACE_QUALIFIER XMLBuffer buf; buf.append(XERCES_CPP_NAMESPACE_QUALIFIER chDash); buf.append(context->getMemoryManager()->getPooledString(obuf)); return context->getMemoryManager()->getPooledString(buf.getRawBuffer()); } }*/ } return context->getMemoryManager()->getPooledString(obuf); } /* Promote this to the given type, if possible */ const Numeric* ATDecimalOrDerivedImpl::promoteTypeIfApplicable(const XMLCh* typeURI, const XMLCh* typeName, const DynamicContext* context) const { // if target is instance of xs:decimal, or if typeName == double or if typeName == float, cast if( this->isInstanceOfType(typeURI, typeName, context) ) { return this; // no need to promote, we are already a decimal (or possibly anyAtomicType, anySimpleType, anyType) } else if( (XERCES_CPP_NAMESPACE_QUALIFIER XMLString::equals(typeName, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_DOUBLE) && XERCES_CPP_NAMESPACE_QUALIFIER XMLString::equals(typeURI, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA)) || (XERCES_CPP_NAMESPACE_QUALIFIER XMLString::equals(typeName, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_FLOAT) && XERCES_CPP_NAMESPACE_QUALIFIER XMLString::equals(typeURI, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA)) ) { return (const Numeric*)this->castAs(typeURI, typeName, context); } else { return 0; } } /* returns true if the two objects' value are equal * false otherwise */ bool ATDecimalOrDerivedImpl::equals(const AnyAtomicType* target, const DynamicContext* context) const { if(!target->isNumericValue()) { DSLthrow(IllegalArgumentException,X("ATDecimalOrDerivedImpl::equals"), X("Equality operator for given types not supported")); } if(this->getPrimitiveTypeIndex() != target->getPrimitiveTypeIndex()) { // if targer is not a decimal, then we need to promote this to a float or double return this->castAs(target->getPrimitiveTypeURI(), target->getPrimitiveTypeName(), context)->equals(target, context); } else { ATDecimalOrDerivedImpl* otherImpl = (ATDecimalOrDerivedImpl*)target; return _decimal == otherImpl->_decimal; } } /** Returns true if this is less than other, false otherwise */ bool ATDecimalOrDerivedImpl::lessThan(const Numeric* other, const DynamicContext* context) const { if(this->getPrimitiveTypeIndex() != other->getPrimitiveTypeIndex()) { // if other is not a decimal, then we need to promote this to a float or double return ((const Numeric*)this->castAs(other->getPrimitiveTypeURI(), other->getPrimitiveTypeName(), context))->lessThan(other, context); } else { ATDecimalOrDerivedImpl* otherImpl = (ATDecimalOrDerivedImpl*)other; return _decimal < otherImpl->_decimal; } } /** Returns true if this is greater than other, false otherwise */ bool ATDecimalOrDerivedImpl::greaterThan(const Numeric* other, const DynamicContext* context) const { if(this->getPrimitiveTypeIndex() != other->getPrimitiveTypeIndex()) { // if other is not a decimal, then we need to promote this to a float or double return ((const Numeric*)this->castAs(other->getPrimitiveTypeURI(), other->getPrimitiveTypeName(), context))->greaterThan(other, context); } else { ATDecimalOrDerivedImpl* otherImpl = (ATDecimalOrDerivedImpl*)other; return _decimal > otherImpl->_decimal; } } /** Returns a Numeric object which is the sum of this and other */ const Numeric* ATDecimalOrDerivedImpl::add(const Numeric* other, const DynamicContext* context) const { if(this->isOfType(other->getTypeURI(), other->getTypeName(), context)) { // if both are of the same type exactly, we can perform addition ATDecimalOrDerivedImpl* otherImpl = (ATDecimalOrDerivedImpl*)other; // if integer, return xs:integer, otherwise xs:decimal if(_isInteger) { return DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), _decimal + otherImpl->_decimal, context); } return DatatypeFactory::POD2AT::createDecimal(context->getMemoryManager(), _decimal + otherImpl->_decimal, context); } else if(this->getPrimitiveTypeIndex() != other->getPrimitiveTypeIndex()) { // if other is not a decimal, then we need to promote this to a float or double return ((const Numeric*)this->castAs(other->getPrimitiveTypeURI(), other->getPrimitiveTypeName(), context))->add(other, context); } else if (this->isInstanceOfType(other->getTypeURI(), other->getTypeName(), context)) { // here we know we have two decimals, and this is 'lower' in the hierarchy than other // so cast this to other's type return ((const Numeric*)this->castAs(other->getTypeURI(), other->getTypeName(), context))->add(other, context); } else if (other->isInstanceOfType(this->getTypeURI(), this->getTypeName(), context)) { // here we have two decimals, and this is 'higher' in the hierarchy than other // so cast other to this' type return this->add((const Numeric*)other->castAs(this->getTypeURI(), this->getTypeName(), context), context); } else { // we have two separate branches. if either is instance of integer, cast it to integer, otherwise, cast to decimal // revisit: this is not the prettiest way to do it. You would want to go up the tree one by one instead of // jumping to integer and decimal const ATDecimalOrDerived* first; const ATDecimalOrDerived* second; if(this->_isInteger) { first = (const ATDecimalOrDerived*)this->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_INTEGER, context); } else { first = (const ATDecimalOrDerived*)this->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_DECIMAL, context); } if(((const ATDecimalOrDerivedImpl*)other)->_isInteger) { second = (const ATDecimalOrDerived*)other->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_INTEGER, context); } else { second = (const ATDecimalOrDerived*)other->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_DECIMAL, context); } return first->add(second, context); } } /** Returns a Numeric object which is the difference of this and * other */ const Numeric* ATDecimalOrDerivedImpl::subtract(const Numeric* other, const DynamicContext* context) const { if(this->isOfType(other->getTypeURI(), other->getTypeName(), context)) { // if both are of the same type exactly, we can perform subtraction ATDecimalOrDerivedImpl* otherImpl = (ATDecimalOrDerivedImpl*)other; // if integer, return xs:integer, otherwise xs:decimal if(_isInteger) { return DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), _decimal - otherImpl->_decimal, context); } return DatatypeFactory::POD2AT::createDecimal(context->getMemoryManager(), _decimal - otherImpl->_decimal, context); } else if(this->getPrimitiveTypeIndex() != other->getPrimitiveTypeIndex()) { // if other is not a decimal, then we need to promote this to a float or double return ((const Numeric*)this->castAs(other->getPrimitiveTypeURI(), other->getPrimitiveTypeName(), context))->subtract(other, context); } else if (this->isInstanceOfType(other->getTypeURI(), other->getTypeName(), context)) { // here we know we have two decimals, and this is 'lower' in the hierarchy than other // so cast this to other's type return ((const Numeric*)this->castAs(other->getTypeURI(), other->getTypeName(), context))->subtract(other, context); } else if (other->isInstanceOfType(this->getTypeURI(), this->getTypeName(), context)) { // here we have two decimals, and this is 'higher' in the hierarchy than other // so cast other to this' type return this->subtract((const Numeric*)other->castAs(this->getTypeURI(), this->getTypeName(), context), context); } else { // we have two separate branches. if either is instance of integer, cast it to integer, otherwise, cast to decimal // revisit: this is not the prettiest way to do it. You would want to go up the tree one by one instead of // jumping to integer and decimal const ATDecimalOrDerived* first; const ATDecimalOrDerived* second; if(this->_isInteger) { first = (const ATDecimalOrDerived*)this->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_INTEGER, context); } else { first = (const ATDecimalOrDerived*)this->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_DECIMAL, context); } if(((const ATDecimalOrDerivedImpl*)other)->_isInteger) { second = (const ATDecimalOrDerived*)other->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_INTEGER, context); } else { second = (const ATDecimalOrDerived*)other->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_DECIMAL, context); } return first->subtract(second, context); } } /** Returns a Numeric object which is the product of this and other */ const Numeric* ATDecimalOrDerivedImpl::multiply(const Numeric* other, const DynamicContext* context) const { if(this->isOfType(other->getTypeURI(), other->getTypeName(), context)) { // if both are of the same type exactly, we can perform multiplication ATDecimalOrDerivedImpl* otherImpl = (ATDecimalOrDerivedImpl*)other; // if integer, return xs:integer, otherwise xs:decimal if(_isInteger) { return DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), _decimal * otherImpl->_decimal, context); } return DatatypeFactory::POD2AT::createDecimal(context->getMemoryManager(), _decimal * otherImpl->_decimal, context); } else if(this->getPrimitiveTypeIndex() != other->getPrimitiveTypeIndex()) { // if other is not a decimal, then we need to promote this to a float or double return ((const Numeric*)this->castAs(other->getPrimitiveTypeURI(), other->getPrimitiveTypeName(), context))->multiply(other, context); } else if (this->isInstanceOfType(other->getTypeURI(), other->getTypeName(), context)) { // here we know we have two decimals, and this is 'lower' in the hierarchy than other // so cast this to other's type return ((const Numeric*)this->castAs(other->getTypeURI(), other->getTypeName(), context))->multiply(other, context); } else if (other->isInstanceOfType(this->getTypeURI(), this->getTypeName(), context)) { // here we have two decimals, and this is 'higher' in the hierarchy than other // so cast other to this' type return this->multiply((const Numeric*)other->castAs(this->getTypeURI(), this->getTypeName(), context), context); } else { // we have two separate branches. if either is instance of integer, cast it to integer, otherwise, cast to decimal // revisit: this is not the prettiest way to do it. You would want to go up the tree one by one instead of // jumping to integer and decimal const ATDecimalOrDerived* first; const ATDecimalOrDerived* second; if(this->_isInteger) { first = (const ATDecimalOrDerived*)this->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_INTEGER, context); } else { first = (const ATDecimalOrDerived*)this->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_DECIMAL, context); } if(((const ATDecimalOrDerivedImpl*)other)->_isInteger) { second = (const ATDecimalOrDerived*)other->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_INTEGER, context); } else { second = (const ATDecimalOrDerived*)other->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_DECIMAL, context); } return first->multiply(second, context); } } /** Returns a Numeric object which is the quotient of this and other */ const Numeric* ATDecimalOrDerivedImpl::divide(const Numeric* other, const DynamicContext* context) const { if(this->isOfType(other->getTypeURI(), other->getTypeName(), context)) { // if both are of the same type exactly, we can perform division ATDecimalOrDerivedImpl* otherImpl = (ATDecimalOrDerivedImpl*)other; if(otherImpl->_decimal == MM_Zero) { DSLthrow(XPath2ErrorException, X("ATDecimalOrDerivedImpl::divide"), X("Division by zero")); } // return a xs:decimal, regardless of the actual types of the operands return DatatypeFactory::POD2AT::createDecimal(context->getMemoryManager(), _decimal / otherImpl->_decimal, context); } else if(this->getPrimitiveTypeIndex() != other->getPrimitiveTypeIndex()) { // if other is not a decimal, then we need to promote this to a float or double return ((const Numeric*)this->castAs(other->getPrimitiveTypeURI(), other->getPrimitiveTypeName(), context))->divide(other, context); } else if (this->isInstanceOfType(other->getTypeURI(), other->getTypeName(), context)) { // here we know we have two decimals, and this is 'lower' in the hierarchy than other // so cast this to other's type return ((const Numeric*)this->castAs(other->getTypeURI(), other->getTypeName(), context))->divide(other, context); } else if (other->isInstanceOfType(this->getTypeURI(), this->getTypeName(), context)) { // here we have two decimals, and this is 'higher' in the hierarchy than other // so cast other to this' type return this->divide((const Numeric*)other->castAs(this->getTypeURI(), this->getTypeName(), context), context); } else { // we have two separate branches. if either is instance of integer, cast it to integer, otherwise, cast to decimal // revisit: this is not the prettiest way to do it. You would want to go up the tree one by one instead of // jumping to integer and decimal const ATDecimalOrDerived* first; const ATDecimalOrDerived* second; if(this->_isInteger) { first = (const ATDecimalOrDerived*)this->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_INTEGER, context); } else { first = (const ATDecimalOrDerived*)this->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_DECIMAL, context); } if(((const ATDecimalOrDerivedImpl*)other)->_isInteger) { second = (const ATDecimalOrDerived*)other->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_INTEGER, context); } else { second = (const ATDecimalOrDerived*)other->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_DECIMAL, context); } return first->divide(second, context); } } /** Returns a ATDecimalOrDerived (integer) object which is the quotient of this and other */ const ATDecimalOrDerived* ATDecimalOrDerivedImpl::integerDivide(const ATDecimalOrDerived* other, const DynamicContext* context) const { if(this->_isInteger && ((const ATDecimalOrDerivedImpl*)other)->_isInteger) { ATDecimalOrDerivedImpl* otherImpl = (ATDecimalOrDerivedImpl*)other; if(otherImpl->isZero()) { DSLthrow(XPath2ErrorException, X("ATDecimalOrDerivedImpl::integerDivide"), X("Division by zero")); } // return a xs:integer return DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), _decimal.integer_divide(otherImpl->_decimal), context); } else { DSLthrow(IllegalArgumentException,X("ATDecimalOrDerivedImpl::integerDivide"), X("integer division for types given is not supported")); } } /** Returns the arithmetic product of its operands as a Numeric */ const Numeric* ATDecimalOrDerivedImpl::mod(const Numeric* other, const DynamicContext* context) const { if(this->isOfType(other->getTypeURI(), other->getTypeName(), context)) { // if both are of the same type exactly, we can perform the modulo const ATDecimalOrDerivedImpl* otherImpl = (const ATDecimalOrDerivedImpl*)other; if(otherImpl->isZero()) { DSLthrow(IllegalArgumentException, X("ATDecimalOrDerivedImpl::mod"), X("Division by zero")); } MAPM result = _decimal; MAPM r; r = result.integer_divide(otherImpl->_decimal); result -= r * otherImpl->_decimal; // if integer, return xs:integer, otherwise xs:decimal if(_isInteger) { return DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), result, context); } return DatatypeFactory::POD2AT::createDecimal(context->getMemoryManager(), result, context); } else if(this->getPrimitiveTypeIndex() != other->getPrimitiveTypeIndex()) { // if other is not a decimal, then we need to promote this to a float or double return ((const Numeric*)this->castAs(other->getPrimitiveTypeURI(), other->getPrimitiveTypeName(), context))->mod(other, context); } else if (this->isInstanceOfType(other->getTypeURI(), other->getTypeName(), context)) { // here we know we have two decimals, and this is 'lower' in the hierarchy than other // so cast this to other's type return ((const Numeric*)this->castAs(other->getTypeURI(), other->getTypeName(), context))->mod(other, context); } else if (other->isInstanceOfType(this->getTypeURI(), this->getTypeName(), context)) { // here we have two decimals, and this is 'higher' in the hierarchy than other // so cast other to this' type return this->mod((const Numeric*)other->castAs(this->getTypeURI(), this->getTypeName(), context), context); } else { // we have two separate branches. if either is instance of integer, cast it to integer, otherwise, cast to decimal // revisit: this is not the prettiest way to do it. You would want to go up the tree one by one instead of // jumping to integer and decimal const ATDecimalOrDerived* first; const ATDecimalOrDerived* second; if(this->_isInteger) { first = (const ATDecimalOrDerived*)this->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_INTEGER, context); } else { first = (const ATDecimalOrDerived*)this->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_DECIMAL, context); } if(((const ATDecimalOrDerivedImpl*)other)->_isInteger) { second = (const ATDecimalOrDerived*)other->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_INTEGER, context); } else { second = (const ATDecimalOrDerived*)other->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_DECIMAL, context); } return first->mod(second, context); } } /** Returns the floor of this Numeric */ const Numeric* ATDecimalOrDerivedImpl::floor(const DynamicContext* context) const { // if integer, return xs:integer, otherwise xs:decimal if(_isInteger) { return (const Numeric*)this->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_INTEGER, context); } return DatatypeFactory::POD2AT::createDecimal(context->getMemoryManager(), _decimal.floor(), context); } /** Returns the ceiling of this Numeric */ const Numeric* ATDecimalOrDerivedImpl::ceiling(const DynamicContext* context) const { // if integer, return xs:integer, otherwise xs:decimal if(_isInteger) { return (const Numeric*)this->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_INTEGER, context); } return DatatypeFactory::POD2AT::createDecimal(context->getMemoryManager(), _decimal.ceil(), context); } /** Rounds this Numeric */ const Numeric* ATDecimalOrDerivedImpl::round(const DynamicContext* context) const { // if integer, return xs:integer, otherwise xs:decimal if(_isInteger) { return (const Numeric*)this->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_INTEGER, context); } MAPM value = _decimal + 0.5; return DatatypeFactory::POD2AT::createDecimal(context->getMemoryManager(), value.floor(), context); } /** Rounds this Numeric to the given precision, and rounds a half to even */ const Numeric* ATDecimalOrDerivedImpl::roundHalfToEven(const ATDecimalOrDerived* &precision, const DynamicContext* context) const { const ATDecimalOrDerivedImpl* decimal_precision = (const ATDecimalOrDerivedImpl*)precision; MAPM exp = MAPM(MM_Ten).pow(decimal_precision->_decimal); MAPM value = _decimal * exp; bool halfVal = false; // check if we're rounding on a half value if((value-0.5) == (value.floor())) { halfVal = true; } value = _decimal * exp + 0.5; value = value.floor(); // if halfVal make sure what we return has the least significant digit even if (halfVal) { if(value.is_odd()) { value = value - 1; } } value = value / exp; // if integer, return xs:integer, otherwise xs:decimal if(_isInteger) { return DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), value, context); } return DatatypeFactory::POD2AT::createDecimal(context->getMemoryManager(), value, context); } /** Returns the Additive inverse of this Numeric */ const Numeric* ATDecimalOrDerivedImpl::invert(const DynamicContext* context) const { if(_isInteger) { return DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), _decimal.neg(), context); } return DatatypeFactory::POD2AT::createDecimal(context->getMemoryManager(), _decimal.neg(), context); } /** Returns the absolute value of this Numeric */ const Numeric* ATDecimalOrDerivedImpl::abs(const DynamicContext* context) const { return DatatypeFactory::POD2AT::createDecimal(context->getMemoryManager(), _decimal.abs(), context); } /** Does this Numeric have value 0? */ bool ATDecimalOrDerivedImpl::isZero() const { return _decimal == MM_Zero; } /** Is this Numeric negative? */ bool ATDecimalOrDerivedImpl::isNegative() const { return _decimal < MM_Zero; } /** Is this Numeric positive? */ bool ATDecimalOrDerivedImpl::isPositive() const { return _decimal > MM_Zero; } /** Treat this decimal (must be integer) as a codepoint **/ XMLCh ATDecimalOrDerivedImpl::treatAsCodepoint(const DynamicContext* context) const { if(_isInteger) { char out_string[256]; _decimal.toIntegerString(out_string); int integer = atoi(out_string); XMLCh ch = (XMLCh)integer; if(integer<=0 || (int)ch != integer) { // negative or lost some info DSLthrow(XPath2ErrorException, X("ATDecimalOrDerivedImpl::treatAsCodepoint"), X("codepoint not legal.")); } return ch; } else { DSLthrow(XPath2ErrorException, X("ATDecimalOrDerivedImpl::treatAsCodepoint"), X("Only integers can be treated as codepoints.")); } } AnyAtomicType::AtomicObjectType ATDecimalOrDerivedImpl::getPrimitiveTypeIndex() const { return this->getTypeIndex(); } /** Releases the memory used by this Item */ void ATDecimalOrDerivedImpl::release() const { //TODO needs to check for ownership before releasing! _decimal.~MAPM(); getMemoryManager()->deallocate((void*)this); } ////////////////////////////////////// // Horrible Hack to make Dates // // work for now. Loss of Precision! // ////////////////////////////////////// MAPM ATDecimalOrDerivedImpl::asMAPM() const { return _decimal; } void ATDecimalOrDerivedImpl::setDecimal(const XMLCh* const value) { const XMLCh *s = value; unsigned int length; length = XERCES_CPP_NAMESPACE_QUALIFIER XMLString::stringLen(value); if(s == 0) { DSLthrow(XPath2TypeCastException,X("ATDecimalOrDerivedImpl::setDecimal"), X("Invalid representation of decimal")); } // State variables etc. bool gotPoint = false; bool gotSign = false; bool gotDigit = false; bool stop = false; bool munchWS = true; bool trailWS = false; unsigned int pos = 0; XMLCh tmpChar; int sign = 1; int wdigit = 0; int fdigit = 0; MAPM whole = MM_Zero; MAPM fraction = MM_Zero; MAPM fractiondiv = MM_One; while(!stop && pos < length) { tmpChar = s[pos]; pos++; switch(tmpChar) {/*{{{*/ case L'+': { if(gotSign) { stop = true; gotDigit = false; } else { sign = 1; gotSign = true; break; } } case L'-': { if(gotSign) { stop = true; gotDigit = false; } else { sign = -1; gotSign = true; break; } } //This is '.' case 0x002e: { if ( wdigit == 0 ) { // we have an implicit '0' wdigit=1; whole=MM_Zero; } if(gotPoint) { stop = true; gotDigit = false; } else { gotPoint = true; gotDigit = false; } break; } /* All the numerals defined by XML standard */ case 0x0030: case 0x0031: case 0x0032: case 0x0033: case 0x0034: case 0x0035: case 0x0036: case 0x0037: case 0x0038: case 0x0039: { gotDigit = true; if(!gotPoint) { whole *= MM_Ten; whole += static_cast(tmpChar - 0x0030); wdigit++; } else { fractiondiv *= MM_Ten; fraction *= MM_Ten; fraction += static_cast(tmpChar - 0x0030); fdigit ++; } break; } // whitespace at start or end of string... case 0x0020: case 0x0009: case 0x000d: case 0x000a: { if ( gotDigit && !munchWS && trailWS) { stop = true; break; } bool endOfWS = false; while(!endOfWS && pos < length) { tmpChar = s[pos]; pos++; switch(tmpChar) { case 0x0020: case 0x0009: case 0x000d: case 0x000a: { break; } default: { endOfWS = true; pos--; if(munchWS) { //end of leading whitespace munchWS = false; } else { //trailing whitespace is followed by other characters - so return NaN. trailWS = true; } } }//switch }//while break; } default: stop = true; break; }//switch /*}}}*/ }//while if(!gotDigit || stop) { DSLthrow(XPath2TypeCastException,X("ATDecimalOrDerivedImpl::setDecimal"), X("Invalid representation of decimal")); } fraction /= fractiondiv; _decimal = whole + fraction; _decimal *= sign; }