| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the QtXmlPatterns module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU Lesser General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Lesser |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
| ** packaging of this file. Please review the following information to |
| ** ensure the GNU Lesser General Public License version 3 requirements |
| ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 2.0 or (at your option) the GNU General |
| ** Public license version 3 or any later version approved by the KDE Free |
| ** Qt Foundation. The licenses are as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
| ** https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $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 = o2.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 |