summaryrefslogtreecommitdiff
path: root/src/xmlpatterns/data/qabstractfloat.cpp
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commite1b2c9deb5943faae2b29be6a5c006f75bb73f06 (patch)
treefc79e45367c0a8fc71185e9afc33f7503a58653c /src/xmlpatterns/data/qabstractfloat.cpp
downloadqtxmlpatterns-e1b2c9deb5943faae2b29be6a5c006f75bb73f06.tar.gz
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'src/xmlpatterns/data/qabstractfloat.cpp')
-rw-r--r--src/xmlpatterns/data/qabstractfloat.cpp321
1 files changed, 321 insertions, 0 deletions
diff --git a/src/xmlpatterns/data/qabstractfloat.cpp b/src/xmlpatterns/data/qabstractfloat.cpp
new file mode 100644
index 0000000..4f0c175
--- /dev/null
+++ b/src/xmlpatterns/data/qabstractfloat.cpp
@@ -0,0 +1,321 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtXmlPatterns module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/**
+ * @file
+ * @short This file is included by qabstractfloat_p.h.
+ * If you need includes in this file, put them in qabstractfloat_p.h, outside of the namespace.
+ */
+
+template <const bool isDouble>
+AbstractFloat<isDouble>::AbstractFloat(const xsDouble num) : m_value(num)
+{
+}
+
+template <const bool isDouble>
+Numeric::Ptr AbstractFloat<isDouble>::fromValue(const xsDouble num)
+{
+ return Numeric::Ptr(new AbstractFloat<isDouble>(num));
+}
+
+template <const bool isDouble>
+AtomicValue::Ptr AbstractFloat<isDouble>::fromLexical(const QString &strNumeric)
+{
+ /* QString::toDouble() handles the whitespace facet. */
+
+ if(strNumeric == QLatin1String("NaN"))
+ return isDouble ? CommonValues::DoubleNaN : CommonValues::FloatNaN;
+ else if(strNumeric == QLatin1String("-INF"))
+ return isDouble ? CommonValues::NegativeInfDouble : CommonValues::NegativeInfFloat;
+ else if(strNumeric == QLatin1String("INF"))
+ return isDouble ? CommonValues::InfDouble : CommonValues::InfFloat;
+
+ /* QString::toDouble() supports any case as well as +INF, but we don't. */
+ const QString toUpper(strNumeric.toUpper());
+ if(toUpper == QLatin1String("-INF") ||
+ toUpper == QLatin1String("INF") ||
+ toUpper == QLatin1String("+INF") ||
+ toUpper == QLatin1String("NAN"))
+ {
+ return ValidationError::createError();
+ }
+
+ bool conversionOk = false;
+ const xsDouble num = strNumeric.toDouble(&conversionOk);
+
+ if(conversionOk)
+ return AtomicValue::Ptr(new AbstractFloat<isDouble>(num));
+ else
+ return ValidationError::createError();
+}
+
+template <const bool isDouble>
+int AbstractFloat<isDouble>::internalSignbit(const xsDouble num)
+{
+ Q_ASSERT_X(sizeof(xsDouble) == 8 || sizeof(xsDouble) == 4, Q_FUNC_INFO,
+ "This implementation of signbit assumes xsDouble, that is qreal, is 64 bits large.");
+
+ union
+ {
+ xsDouble asDouble;
+ qint64 asInt;
+ } value;
+
+ value.asDouble = num;
+
+ /* The highest bit, the 64'th for those who have 64bit floats, is the sign bit. So we pull it down until that bit is the
+ * only one left. */
+ if(sizeof(xsDouble) == 8)
+ return value.asInt >> 63;
+ else
+ return value.asInt >> 31;
+}
+
+template <const bool isDouble>
+bool AbstractFloat<isDouble>::isEqual(const xsDouble a, const xsDouble b)
+{
+ if(qIsInf(a))
+ return qIsInf(b) && internalSignbit(a) == internalSignbit(b);
+ else if(qIsInf(b))
+ return qIsInf(a) && internalSignbit(a) == internalSignbit(b);
+ else
+ {
+ /* Preferably, we would use std::numeric_limits<xsDouble>::espilon(), but
+ * we cannot since we cannot depend on the STL. The small xs:double value below,
+ * was extracted by printing the std::numeric_limits<xsDouble>::epsilon() using
+ * gdb. */
+ return qAbs(a - b) <= 2.2204460492503131e-16 * qAbs(a);
+ }
+}
+
+template <const bool isDouble>
+bool AbstractFloat<isDouble>::isZero() const
+{
+ return AbstractFloat<isDouble>::isEqual(m_value, 0.0);
+}
+
+template <const bool isDouble>
+bool AbstractFloat<isDouble>::evaluateEBV(const QExplicitlySharedDataPointer<DynamicContext> &) const
+{
+ if(isZero() || qIsNaN(m_value))
+ return false;
+ else
+ return true;
+}
+
+template <const bool isDouble>
+QString AbstractFloat<isDouble>::stringValue() const
+{
+ if(qIsNaN(m_value))
+ return QLatin1String("NaN");
+ else if(qIsInf(m_value))
+ return internalSignbit(m_value) == 0 ? QLatin1String("INF") : QLatin1String("-INF");
+ /*
+ * If SV has an absolute value that is greater than or equal to 0.000001
+ * (one millionth) and less than 1000000 (one million),
+ * then the value is converted to an xs:decimal and the resulting xs:decimal
+ * is converted to an xs:string according to the rules above.
+ */
+ else if(0.000001 <= qAbs(m_value) && qAbs(m_value) < 1000000.0)
+ return Decimal::toString(toDecimal());
+ /*
+ * If SV has the value positive or negative zero, TV is "0" or "-0" respectively.
+ */
+ else if(isZero())
+ return internalSignbit(m_value) == 0 ? QLatin1String("0") : QLatin1String("-0");
+ else
+ {
+ /*
+ * Besides these special values, the general form of the canonical form for
+ * xs:float and xs:double is a mantissa, which is a xs:decimal, followed by
+ * the letter "E", followed by an exponent which is an xs:integer.
+ */
+ int sign;
+ int decimalPoint;
+ char *result = 0;
+ static_cast<void>(qdtoa(m_value, -1, 0, &decimalPoint, &sign, 0, &result));
+
+ /* If the copy constructor is used instead of QString::operator=(),
+ * it doesn't compile. I have no idea why. */
+ const QString qret(QString::fromLatin1(result));
+
+ /* We use free() instead of delete here, because qlocale.cpp use malloc(). Spotted
+ * by valgrind. */
+ free(result);
+
+ QString valueAsString;
+
+ if(sign)
+ valueAsString += QLatin1Char('-');
+
+ valueAsString += qret.at(0);
+ valueAsString += QLatin1Char('.');
+
+ if(1 == qret.size())
+ valueAsString += QLatin1Char('0');
+ else
+ valueAsString += qret.mid(1);
+
+ valueAsString += QLatin1Char('E');
+ decimalPoint--;
+ valueAsString += QString::number(decimalPoint);
+ return valueAsString;
+ }
+}
+
+template <const bool isDouble>
+xsDouble AbstractFloat<isDouble>::toDouble() const
+{
+ return m_value;
+}
+
+template <const bool isDouble>
+xsInteger AbstractFloat<isDouble>::toInteger() const
+{
+ return static_cast<xsInteger>(m_value);
+}
+
+template <const bool isDouble>
+xsFloat AbstractFloat<isDouble>::toFloat() const
+{
+ /* No cast, since xsFloat and xsDouble are typedef'ed with the same type. */
+ return m_value;
+}
+
+template <const bool isDouble>
+xsDecimal AbstractFloat<isDouble>::toDecimal() const
+{
+ return static_cast<xsDecimal>(m_value);
+}
+
+template <const bool isDouble>
+Numeric::Ptr AbstractFloat<isDouble>::round() const
+{
+ return AbstractFloat<isDouble>::fromValue(static_cast<xsDouble>(roundFloat(m_value)));
+}
+
+template <const bool isDouble>
+Numeric::Ptr AbstractFloat<isDouble>::roundHalfToEven(const xsInteger precision) const
+{
+ if(isNaN() || isInf() || isZero())
+ return Numeric::Ptr(const_cast<AbstractFloat<isDouble> *>(this));
+ else
+ {
+ /* The cast to double helps finding the correct pow() version on irix-cc. */
+ const xsDouble powered = pow(double(10), double(precision));
+ xsDouble val = powered * m_value;
+ bool isHalf = false;
+
+ if(val - 0.5 == ::floor(val))
+ isHalf = true;
+
+ val = m_value * powered + 0.5;
+ val = ::floor(val);
+
+ if(isHalf /*&& isOdd(val) or? TODO */)
+ val -= 1;
+
+ val /= powered;
+
+ return fromValue(val);
+ }
+}
+
+template <const bool isDouble>
+Numeric::Ptr AbstractFloat<isDouble>::floor() const
+{
+ return AbstractFloat<isDouble>::fromValue(static_cast<xsDouble>(::floor(m_value)));
+}
+
+template <const bool isDouble>
+Numeric::Ptr AbstractFloat<isDouble>::ceiling() const
+{
+ return AbstractFloat<isDouble>::fromValue(static_cast<xsDouble>(ceil(m_value)));
+}
+
+template <const bool isDouble>
+Numeric::Ptr AbstractFloat<isDouble>::abs() const
+{
+ /* We must use fabs() instead of qAbs() because qAbs()
+ * doesn't return 0 for -0.0. */
+ return AbstractFloat<isDouble>::fromValue(static_cast<xsDouble>(fabs(m_value)));
+}
+
+template <const bool isDouble>
+bool AbstractFloat<isDouble>::isNaN() const
+{
+ return qIsNaN(m_value);
+}
+
+template <const bool isDouble>
+bool AbstractFloat<isDouble>::isInf() const
+{
+ return qIsInf(m_value);
+}
+
+template <const bool isDouble>
+ItemType::Ptr AbstractFloat<isDouble>::type() const
+{
+ return isDouble ? BuiltinTypes::xsDouble : BuiltinTypes::xsFloat;
+}
+
+template <const bool isDouble>
+Item AbstractFloat<isDouble>::toNegated() const
+{
+ return fromValue(-m_value).data();
+}
+
+template <const bool isDouble>
+bool AbstractFloat<isDouble>::isSigned() const
+{
+ Q_ASSERT_X(false, Q_FUNC_INFO,
+ "It makes no sense to call this function, see Numeric::isSigned().");
+ return false;
+}
+
+template <const bool isDouble>
+qulonglong AbstractFloat<isDouble>::toUnsignedInteger() const
+{
+ Q_ASSERT_X(false, Q_FUNC_INFO,
+ "It makes no sense to call this function, see Numeric::toUnsignedInteger().");
+ return 0;
+}
+