summaryrefslogtreecommitdiff
path: root/src/xmlpatterns/data/qatomiccomparators.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/xmlpatterns/data/qatomiccomparators.cpp')
-rw-r--r--src/xmlpatterns/data/qatomiccomparators.cpp386
1 files changed, 386 insertions, 0 deletions
diff --git a/src/xmlpatterns/data/qatomiccomparators.cpp b/src/xmlpatterns/data/qatomiccomparators.cpp
new file mode 100644
index 0000000..38d7092
--- /dev/null
+++ b/src/xmlpatterns/data/qatomiccomparators.cpp
@@ -0,0 +1,386 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "qabstractduration_p.h"
+#include "qabstractdatetime_p.h"
+#include "qbase64binary_p.h"
+#include "qboolean_p.h"
+#include "qdynamiccontext_p.h"
+#include "qqnamevalue_p.h"
+
+#include "qatomiccomparators_p.h"
+
+QT_BEGIN_NAMESPACE
+
+using namespace QPatternist;
+
+/* -------------------------------------------------- */
+AtomicComparator::ComparisonResult
+StringComparator::compare(const Item &o1,
+ const AtomicComparator::Operator,
+ const Item &o2) const
+{
+ const int result = QString::compare(o1.stringValue(), o2.stringValue());
+
+ if(result > 0)
+ return GreaterThan;
+ else if(result < 0)
+ return LessThan;
+ else
+ {
+ Q_ASSERT(result == 0);
+ return Equal;
+ }
+}
+
+bool StringComparator::equals(const Item &o1,
+ const Item &o2) const
+{
+ return o1.stringValue() == o2.stringValue();
+}
+/* -------------------------------------------------- */
+
+/* -------------------------------------------------- */
+AtomicComparator::ComparisonResult
+CaseInsensitiveStringComparator::compare(const Item &o1,
+ const AtomicComparator::Operator,
+ const Item &o2) const
+{
+ const QString i1(o1.stringValue().toLower());
+ const QString i2(o2.stringValue().toLower());
+ const int result = QString::compare(i1, i2);
+
+ if(result > 0)
+ return GreaterThan;
+ else if(result < 0)
+ return LessThan;
+ else
+ {
+ Q_ASSERT(result == 0);
+ return Equal;
+ }
+}
+
+bool CaseInsensitiveStringComparator::equals(const Item &o1,
+ const Item &o2) const
+{
+ const QString s1(o1.stringValue());
+ const QString s2(o2.stringValue());
+
+ return s1.length() == s2.length() &&
+ s1.startsWith(s2, Qt::CaseInsensitive);
+}
+/* -------------------------------------------------- */
+
+/* -------------------------------------------------- */
+bool BinaryDataComparator::equals(const Item &o1,
+ const Item &o2) const
+{
+ return o1.as<Base64Binary>()->asByteArray() ==
+ o2.as<Base64Binary>()->asByteArray();
+}
+/* -------------------------------------------------- */
+
+/* -------------------------------------------------- */
+AtomicComparator::ComparisonResult
+BooleanComparator::compare(const Item &o1,
+ const AtomicComparator::Operator,
+ const Item &o2) const
+{
+ /* We know Boolean::evaluateEBV doesn't use the DynamicContext. */
+ const bool v1 = o1.as<AtomicValue>()->evaluateEBV(QExplicitlySharedDataPointer<DynamicContext>());
+ const bool v2 = o2.as<AtomicValue>()->evaluateEBV(QExplicitlySharedDataPointer<DynamicContext>());
+
+ if(v1 == v2)
+ return Equal;
+ else if(v1 == false)
+ {
+ Q_ASSERT(v2 == true);
+ return LessThan;
+ }
+ else
+ {
+ Q_ASSERT(v1 == true && v2 == false);
+ return GreaterThan;
+ }
+}
+
+bool BooleanComparator::equals(const Item &o1,
+ const Item &o2) const
+{
+ /* Boolean is an atomic class. */
+ return o1.as<AtomicValue>() == o2.as<AtomicValue>();
+}
+/* -------------------------------------------------- */
+
+/* -------------------------------------------------- */
+AtomicComparator::ComparisonResult
+AbstractFloatComparator::compare(const Item &o1,
+ const AtomicComparator::Operator op,
+ const Item &o2) const
+{
+ const xsDouble v1 = o1.as<Numeric>()->toDouble();
+ const xsDouble v2 = o2.as<Numeric>()->toDouble();
+
+ if(Double::isEqual(v1, v2))
+ return Equal;
+ else if(v1 < v2)
+ return LessThan;
+ else if(v1 > v2)
+ return GreaterThan;
+ else
+ {
+ /* We have NaN values. Make sure we don't return a result which would
+ * signify success for the operator in question. */
+ if((op & OperatorGreaterThan) == OperatorGreaterThan)
+ return LessThan;
+ else
+ {
+ Q_ASSERT((op & OperatorLessThan) == OperatorLessThan);
+ return GreaterThan;
+ }
+ }
+}
+
+bool AbstractFloatComparator::equals(const Item &o1,
+ const Item &o2) const
+{
+ return Double::isEqual(o1.as<Numeric>()->toDouble(), o2.as<Numeric>()->toDouble());
+}
+/* -------------------------------------------------- */
+
+/* -------------------------------------------------- */
+AtomicComparator::ComparisonResult
+DecimalComparator::compare(const Item &o1,
+ const AtomicComparator::Operator,
+ const Item &o2) const
+{
+ const xsDecimal v1 = o1.as<Numeric>()->toDecimal();
+ const xsDecimal v2 = o2.as<Numeric>()->toDecimal();
+
+ if(Double::isEqual(v1, v2))
+ return Equal;
+ else if(v1 < v2)
+ return LessThan;
+ else
+ return GreaterThan;
+}
+
+bool DecimalComparator::equals(const Item &o1,
+ const Item &o2) const
+{
+ return Double::isEqual(o1.as<Numeric>()->toDecimal(), o2.as<Numeric>()->toDecimal());
+}
+/* -------------------------------------------------- */
+
+/* -------------------------------------------------- */
+AtomicComparator::ComparisonResult
+IntegerComparator::compare(const Item &o1,
+ const AtomicComparator::Operator,
+ const Item &o2) const
+{
+ const Numeric *const num1 = o1.as<Numeric>();
+ const Numeric *const num2 = o1.as<Numeric>();
+
+ /**
+ * Consider:
+ * xs:unsignedLong("100") > xs:unsignedLong("18446744073709551615")
+ *
+ * If we perform math on the values as if they were xsInteger, the right
+ * operand overflows, wraps around, and the expression evaluates to false.
+ * Hence we have this code to deal with it.
+ *
+ * This is runtime code, it would have been better if we had separate
+ * AtomicComparator classes for signed and unsigned values, but the changes
+ * required to the lookup code are extensive.
+ */
+ if(num1->isSigned() || num2->isSigned())
+ {
+ const xsInteger v1 = o1.as<Numeric>()->toInteger();
+ const xsInteger v2 = o2.as<Numeric>()->toInteger();
+
+ if(v1 == v2)
+ return Equal;
+ else if(v1 < v2)
+ return LessThan;
+ else
+ return GreaterThan;
+ }
+ else
+ {
+ const qulonglong v1 = o1.as<Numeric>()->toUnsignedInteger();
+ const qulonglong v2 = o2.as<Numeric>()->toUnsignedInteger();
+
+ if(v1 == v2)
+ return Equal;
+ else if(v1 < v2)
+ return LessThan;
+ else
+ return GreaterThan;
+ }
+}
+
+bool IntegerComparator::equals(const Item &o1,
+ const Item &o2) const
+{
+ return o1.as<Numeric>()->toInteger() == o2.as<Numeric>()->toInteger();
+}
+
+/* -------------------------------------------------- */
+
+/* -------------------------------------------------- */
+bool QNameComparator::equals(const Item &o1,
+ const Item &o2) const
+{
+ return o1.as<QNameValue>()->m_qName ==
+ o2.as<QNameValue>()->m_qName;
+}
+/* -------------------------------------------------- */
+
+/* -------------------------------------------------- */
+bool AbstractDateTimeComparator::equals(const Item &o1,
+ const Item &o2) const
+{
+ const QDateTime dt1(o1.as<AbstractDateTime>()->toDateTime());
+ const QDateTime dt2(o2.as<AbstractDateTime>()->toDateTime());
+
+ /*
+ pDebug() << "COMPARING:"
+ << o1->as<AbstractDateTime>()->toDateTime().toString()
+ << o2->as<AbstractDateTime>()->toDateTime().toString();
+ pDebug() << "DATE ONLY:"
+ << o1->as<AbstractDateTime>()->toDateTime().isDateOnly()
+ << o2->as<AbstractDateTime>()->toDateTime().isDateOnly();
+ */
+ return dt1 == dt2 &&
+ dt1.timeSpec() == dt2.timeSpec();
+}
+
+AtomicComparator::ComparisonResult
+AbstractDateTimeComparator::compare(const Item &operand1,
+ const AtomicComparator::Operator,
+ const Item &operand2) const
+{
+ const QDateTime &dt1 = operand1.as<AbstractDateTime>()->toDateTime();
+ const QDateTime &dt2 = operand2.as<AbstractDateTime>()->toDateTime();
+
+ if(dt1 == dt2)
+ return Equal;
+ else if(dt1 < dt2)
+ return LessThan;
+ else
+ return GreaterThan;
+}
+/* -------------------------------------------------- */
+
+/* -------------------------------------------------- */
+bool AbstractDurationComparator::equals(const Item &o1,
+ const Item &o2) const
+{
+ /* We use AbstractDuration::operator==() */
+ return *o1.as<AbstractDuration>() ==
+ *o2.as<AbstractDuration>();
+}
+
+QDateTime AbstractDurationComparator::addDurationToDateTime(const QDateTime &dateTime,
+ const AbstractDuration *const duration)
+{
+ QDateTime result(dateTime);
+ qint64 seconds = 0;
+
+ const qint8 signMultiplier = (duration->isPositive() ? 1 : -1);
+
+ result = result.addYears(signMultiplier * duration->years());
+ result = result.addMonths(signMultiplier * duration->months());
+ result = result.addDays(signMultiplier * duration->days());
+
+ seconds = 60 * 60 * duration->hours();
+ seconds += 60 * duration->minutes();
+ seconds += duration->seconds();
+
+ result = result.addSecs(signMultiplier * seconds);
+ result = result.addMSecs(signMultiplier * duration->mseconds());
+
+ return result;
+}
+
+AtomicComparator::ComparisonResult
+AbstractDurationComparator::compare(const Item &o1,
+ const AtomicComparator::Operator,
+ const Item &o2) const
+{
+ const AbstractDuration *const duration = o1.as<AbstractDuration>();
+ const AbstractDuration *const otherDuration = o2.as<AbstractDuration>();
+
+ const QDateTime dateTime1(QDate(1696, 9, 1), QTime(0, 0, 0), Qt::UTC);
+ const QDateTime dateTime2(QDate(1697, 2, 1), QTime(0, 0, 0), Qt::UTC);
+ const QDateTime dateTime3(QDate(1903, 3, 1), QTime(0, 0, 0), Qt::UTC);
+ const QDateTime dateTime4(QDate(1903, 7, 1), QTime(0, 0, 0), Qt::UTC);
+
+ const QDateTime durationDateTime1 = addDurationToDateTime(dateTime1, duration);
+ const QDateTime durationDateTime2 = addDurationToDateTime(dateTime2, duration);
+ const QDateTime durationDateTime3 = addDurationToDateTime(dateTime3, duration);
+ const QDateTime durationDateTime4 = addDurationToDateTime(dateTime4, duration);
+
+ const QDateTime otherDurationDateTime1 = addDurationToDateTime(dateTime1, otherDuration);
+ const QDateTime otherDurationDateTime2 = addDurationToDateTime(dateTime2, otherDuration);
+ const QDateTime otherDurationDateTime3 = addDurationToDateTime(dateTime3, otherDuration);
+ const QDateTime otherDurationDateTime4 = addDurationToDateTime(dateTime4, otherDuration);
+
+ if (durationDateTime1 > otherDurationDateTime1 &&
+ durationDateTime2 > otherDurationDateTime2 &&
+ durationDateTime3 > otherDurationDateTime3 &&
+ durationDateTime4 > otherDurationDateTime4) {
+ return GreaterThan;
+ } else if (durationDateTime1 < otherDurationDateTime1 &&
+ durationDateTime2 < otherDurationDateTime2 &&
+ durationDateTime3 < otherDurationDateTime3 &&
+ durationDateTime4 < otherDurationDateTime4) {
+ return LessThan;
+ } else if (*duration == *otherDuration) {
+ return Equal;
+ } else {
+ return Incomparable;
+ }
+}
+
+/* -------------------------------------------------- */
+QT_END_NAMESPACE