1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtXmlPatterns module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qabstractduration_p.h"
43 #include "qabstractdatetime_p.h"
44 #include "qbase64binary_p.h"
45 #include "qboolean_p.h"
46 #include "qdynamiccontext_p.h"
47 #include "qqnamevalue_p.h"
49 #include "qatomiccomparators_p.h"
53 using namespace QPatternist;
55 /* -------------------------------------------------- */
56 AtomicComparator::ComparisonResult
57 StringComparator::compare(const Item &o1,
58 const AtomicComparator::Operator,
61 const int result = QString::compare(o1.stringValue(), o2.stringValue());
69 Q_ASSERT(result == 0);
74 bool StringComparator::equals(const Item &o1,
77 return o1.stringValue() == o2.stringValue();
79 /* -------------------------------------------------- */
81 /* -------------------------------------------------- */
82 AtomicComparator::ComparisonResult
83 CaseInsensitiveStringComparator::compare(const Item &o1,
84 const AtomicComparator::Operator,
87 const QString i1(o1.stringValue().toLower());
88 const QString i2(o2.stringValue().toLower());
89 const int result = QString::compare(i1, i2);
97 Q_ASSERT(result == 0);
102 bool CaseInsensitiveStringComparator::equals(const Item &o1,
103 const Item &o2) const
105 const QString s1(o1.stringValue());
106 const QString s2(o2.stringValue());
108 return s1.length() == s2.length() &&
109 s1.startsWith(s2, Qt::CaseInsensitive);
111 /* -------------------------------------------------- */
113 /* -------------------------------------------------- */
114 bool BinaryDataComparator::equals(const Item &o1,
115 const Item &o2) const
117 return o1.as<Base64Binary>()->asByteArray() ==
118 o2.as<Base64Binary>()->asByteArray();
120 /* -------------------------------------------------- */
122 /* -------------------------------------------------- */
123 AtomicComparator::ComparisonResult
124 BooleanComparator::compare(const Item &o1,
125 const AtomicComparator::Operator,
126 const Item &o2) const
128 /* We know Boolean::evaluateEBV doesn't use the DynamicContext. */
129 const bool v1 = o1.as<AtomicValue>()->evaluateEBV(QExplicitlySharedDataPointer<DynamicContext>());
130 const bool v2 = o2.as<AtomicValue>()->evaluateEBV(QExplicitlySharedDataPointer<DynamicContext>());
136 Q_ASSERT(v2 == true);
141 Q_ASSERT(v1 == true && v2 == false);
146 bool BooleanComparator::equals(const Item &o1,
147 const Item &o2) const
149 /* Boolean is an atomic class. */
150 return o1.as<AtomicValue>() == o2.as<AtomicValue>();
152 /* -------------------------------------------------- */
154 /* -------------------------------------------------- */
155 AtomicComparator::ComparisonResult
156 AbstractFloatComparator::compare(const Item &o1,
157 const AtomicComparator::Operator op,
158 const Item &o2) const
160 const xsDouble v1 = o1.as<Numeric>()->toDouble();
161 const xsDouble v2 = o2.as<Numeric>()->toDouble();
163 if(Double::isEqual(v1, v2))
171 /* We have NaN values. Make sure we don't return a result which would
172 * signify success for the operator in question. */
173 if((op & OperatorGreaterThan) == OperatorGreaterThan)
177 Q_ASSERT((op & OperatorLessThan) == OperatorLessThan);
183 bool AbstractFloatComparator::equals(const Item &o1,
184 const Item &o2) const
186 return Double::isEqual(o1.as<Numeric>()->toDouble(), o2.as<Numeric>()->toDouble());
188 /* -------------------------------------------------- */
190 /* -------------------------------------------------- */
191 AtomicComparator::ComparisonResult
192 DecimalComparator::compare(const Item &o1,
193 const AtomicComparator::Operator,
194 const Item &o2) const
196 const xsDecimal v1 = o1.as<Numeric>()->toDecimal();
197 const xsDecimal v2 = o2.as<Numeric>()->toDecimal();
199 if(Double::isEqual(v1, v2))
207 bool DecimalComparator::equals(const Item &o1,
208 const Item &o2) const
210 return Double::isEqual(o1.as<Numeric>()->toDecimal(), o2.as<Numeric>()->toDecimal());
212 /* -------------------------------------------------- */
214 /* -------------------------------------------------- */
215 AtomicComparator::ComparisonResult
216 IntegerComparator::compare(const Item &o1,
217 const AtomicComparator::Operator,
218 const Item &o2) const
220 const Numeric *const num1 = o1.as<Numeric>();
221 const Numeric *const num2 = o1.as<Numeric>();
225 * xs:unsignedLong("100") > xs:unsignedLong("18446744073709551615")
227 * If we perform math on the values as if they were xsInteger, the right
228 * operand overflows, wraps around, and the expression evaluates to false.
229 * Hence we have this code to deal with it.
231 * This is runtime code, it would have been better if we had separate
232 * AtomicComparator classes for signed and unsigned values, but the changes
233 * required to the lookup code are extensive.
235 if(num1->isSigned() || num2->isSigned())
237 const xsInteger v1 = o1.as<Numeric>()->toInteger();
238 const xsInteger v2 = o2.as<Numeric>()->toInteger();
249 const qulonglong v1 = o1.as<Numeric>()->toUnsignedInteger();
250 const qulonglong v2 = o2.as<Numeric>()->toUnsignedInteger();
261 bool IntegerComparator::equals(const Item &o1,
262 const Item &o2) const
264 return o1.as<Numeric>()->toInteger() == o2.as<Numeric>()->toInteger();
267 /* -------------------------------------------------- */
269 /* -------------------------------------------------- */
270 bool QNameComparator::equals(const Item &o1,
271 const Item &o2) const
273 return o1.as<QNameValue>()->m_qName ==
274 o2.as<QNameValue>()->m_qName;
276 /* -------------------------------------------------- */
278 /* -------------------------------------------------- */
279 bool AbstractDateTimeComparator::equals(const Item &o1,
280 const Item &o2) const
282 const QDateTime dt1(o1.as<AbstractDateTime>()->toDateTime());
283 const QDateTime dt2(o2.as<AbstractDateTime>()->toDateTime());
286 pDebug() << "COMPARING:"
287 << o1->as<AbstractDateTime>()->toDateTime().toString()
288 << o2->as<AbstractDateTime>()->toDateTime().toString();
289 pDebug() << "DATE ONLY:"
290 << o1->as<AbstractDateTime>()->toDateTime().isDateOnly()
291 << o2->as<AbstractDateTime>()->toDateTime().isDateOnly();
294 dt1.timeSpec() == dt2.timeSpec();
297 AtomicComparator::ComparisonResult
298 AbstractDateTimeComparator::compare(const Item &operand1,
299 const AtomicComparator::Operator,
300 const Item &operand2) const
302 const QDateTime &dt1 = operand1.as<AbstractDateTime>()->toDateTime();
303 const QDateTime &dt2 = operand2.as<AbstractDateTime>()->toDateTime();
312 /* -------------------------------------------------- */
314 /* -------------------------------------------------- */
315 bool AbstractDurationComparator::equals(const Item &o1,
316 const Item &o2) const
318 /* We use AbstractDuration::operator==() */
319 return *o1.as<AbstractDuration>() ==
320 *o2.as<AbstractDuration>();
323 QDateTime AbstractDurationComparator::addDurationToDateTime(const QDateTime &dateTime,
324 const AbstractDuration *const duration)
326 QDateTime result(dateTime);
329 const qint8 signMultiplier = (duration->isPositive() ? 1 : -1);
331 result = result.addYears(signMultiplier * duration->years());
332 result = result.addMonths(signMultiplier * duration->months());
333 result = result.addDays(signMultiplier * duration->days());
335 seconds = 60 * 60 * duration->hours();
336 seconds += 60 * duration->minutes();
337 seconds += duration->seconds();
339 result = result.addSecs(signMultiplier * seconds);
340 result = result.addMSecs(signMultiplier * duration->mseconds());
345 AtomicComparator::ComparisonResult
346 AbstractDurationComparator::compare(const Item &o1,
347 const AtomicComparator::Operator,
348 const Item &o2) const
350 const AbstractDuration *const duration = o1.as<AbstractDuration>();
351 const AbstractDuration *const otherDuration = o2.as<AbstractDuration>();
353 const QDateTime dateTime1(QDate(1696, 9, 1), QTime(0, 0, 0), Qt::UTC);
354 const QDateTime dateTime2(QDate(1697, 2, 1), QTime(0, 0, 0), Qt::UTC);
355 const QDateTime dateTime3(QDate(1903, 3, 1), QTime(0, 0, 0), Qt::UTC);
356 const QDateTime dateTime4(QDate(1903, 7, 1), QTime(0, 0, 0), Qt::UTC);
358 const QDateTime durationDateTime1 = addDurationToDateTime(dateTime1, duration);
359 const QDateTime durationDateTime2 = addDurationToDateTime(dateTime2, duration);
360 const QDateTime durationDateTime3 = addDurationToDateTime(dateTime3, duration);
361 const QDateTime durationDateTime4 = addDurationToDateTime(dateTime4, duration);
363 const QDateTime otherDurationDateTime1 = addDurationToDateTime(dateTime1, otherDuration);
364 const QDateTime otherDurationDateTime2 = addDurationToDateTime(dateTime2, otherDuration);
365 const QDateTime otherDurationDateTime3 = addDurationToDateTime(dateTime3, otherDuration);
366 const QDateTime otherDurationDateTime4 = addDurationToDateTime(dateTime4, otherDuration);
368 if (durationDateTime1 > otherDurationDateTime1 &&
369 durationDateTime2 > otherDurationDateTime2 &&
370 durationDateTime3 > otherDurationDateTime3 &&
371 durationDateTime4 > otherDurationDateTime4) {
373 } else if (durationDateTime1 < otherDurationDateTime1 &&
374 durationDateTime2 < otherDurationDateTime2 &&
375 durationDateTime3 < otherDurationDateTime3 &&
376 durationDateTime4 < otherDurationDateTime4) {
378 } else if (*duration == *otherDuration) {
385 /* -------------------------------------------------- */