source: trunk/src/xmlpatterns/data/qatomiccomparators.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 13.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtXmlPatterns module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
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"
48
49#include "qatomiccomparators_p.h"
50
51QT_BEGIN_NAMESPACE
52
53using namespace QPatternist;
54
55/* -------------------------------------------------- */
56AtomicComparator::ComparisonResult
57StringComparator::compare(const Item &o1,
58 const AtomicComparator::Operator,
59 const Item &o2) const
60{
61 const int result = QString::compare(o1.stringValue(), o2.stringValue());
62
63 if(result > 0)
64 return GreaterThan;
65 else if(result < 0)
66 return LessThan;
67 else
68 {
69 Q_ASSERT(result == 0);
70 return Equal;
71 }
72}
73
74bool StringComparator::equals(const Item &o1,
75 const Item &o2) const
76{
77 return o1.stringValue() == o2.stringValue();
78}
79/* -------------------------------------------------- */
80
81/* -------------------------------------------------- */
82AtomicComparator::ComparisonResult
83CaseInsensitiveStringComparator::compare(const Item &o1,
84 const AtomicComparator::Operator,
85 const Item &o2) const
86{
87 const QString i1(o1.stringValue().toLower());
88 const QString i2(o2.stringValue().toLower());
89 const int result = QString::compare(i1, i2);
90
91 if(result > 0)
92 return GreaterThan;
93 else if(result < 0)
94 return LessThan;
95 else
96 {
97 Q_ASSERT(result == 0);
98 return Equal;
99 }
100}
101
102bool CaseInsensitiveStringComparator::equals(const Item &o1,
103 const Item &o2) const
104{
105 const QString s1(o1.stringValue());
106 const QString s2(o2.stringValue());
107
108 return s1.length() == s2.length() &&
109 s1.startsWith(s2, Qt::CaseInsensitive);
110}
111/* -------------------------------------------------- */
112
113/* -------------------------------------------------- */
114bool BinaryDataComparator::equals(const Item &o1,
115 const Item &o2) const
116{
117 return o1.as<Base64Binary>()->asByteArray() ==
118 o2.as<Base64Binary>()->asByteArray();
119}
120/* -------------------------------------------------- */
121
122/* -------------------------------------------------- */
123AtomicComparator::ComparisonResult
124BooleanComparator::compare(const Item &o1,
125 const AtomicComparator::Operator,
126 const Item &o2) const
127{
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>());
131
132 if(v1 == v2)
133 return Equal;
134 else if(v1 == false)
135 {
136 Q_ASSERT(v2 == true);
137 return LessThan;
138 }
139 else
140 {
141 Q_ASSERT(v1 == true && v2 == false);
142 return GreaterThan;
143 }
144}
145
146bool BooleanComparator::equals(const Item &o1,
147 const Item &o2) const
148{
149 /* Boolean is an atomic class. */
150 return o1.as<AtomicValue>() == o2.as<AtomicValue>();
151}
152/* -------------------------------------------------- */
153
154/* -------------------------------------------------- */
155AtomicComparator::ComparisonResult
156AbstractFloatComparator::compare(const Item &o1,
157 const AtomicComparator::Operator op,
158 const Item &o2) const
159{
160 const xsDouble v1 = o1.as<Numeric>()->toDouble();
161 const xsDouble v2 = o2.as<Numeric>()->toDouble();
162
163 if(Double::isEqual(v1, v2))
164 return Equal;
165 else if(v1 < v2)
166 return LessThan;
167 else if(v1 > v2)
168 return GreaterThan;
169 else
170 {
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)
174 return LessThan;
175 else
176 {
177 Q_ASSERT((op & OperatorLessThan) == OperatorLessThan);
178 return GreaterThan;
179 }
180 }
181}
182
183bool AbstractFloatComparator::equals(const Item &o1,
184 const Item &o2) const
185{
186 return Double::isEqual(o1.as<Numeric>()->toDouble(), o2.as<Numeric>()->toDouble());
187}
188/* -------------------------------------------------- */
189
190/* -------------------------------------------------- */
191AtomicComparator::ComparisonResult
192DecimalComparator::compare(const Item &o1,
193 const AtomicComparator::Operator,
194 const Item &o2) const
195{
196 const xsDecimal v1 = o1.as<Numeric>()->toDecimal();
197 const xsDecimal v2 = o2.as<Numeric>()->toDecimal();
198
199 if(Double::isEqual(v1, v2))
200 return Equal;
201 else if(v1 < v2)
202 return LessThan;
203 else
204 return GreaterThan;
205}
206
207bool DecimalComparator::equals(const Item &o1,
208 const Item &o2) const
209{
210 return Double::isEqual(o1.as<Numeric>()->toDecimal(), o2.as<Numeric>()->toDecimal());
211}
212/* -------------------------------------------------- */
213
214/* -------------------------------------------------- */
215AtomicComparator::ComparisonResult
216IntegerComparator::compare(const Item &o1,
217 const AtomicComparator::Operator,
218 const Item &o2) const
219{
220 const Numeric *const num1 = o1.as<Numeric>();
221 const Numeric *const num2 = o1.as<Numeric>();
222
223 /**
224 * Consider:
225 * xs:unsignedLong("100") > xs:unsignedLong("18446744073709551615")
226 *
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.
230 *
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.
234 */
235 if(num1->isSigned() || num2->isSigned())
236 {
237 const xsInteger v1 = o1.as<Numeric>()->toInteger();
238 const xsInteger v2 = o2.as<Numeric>()->toInteger();
239
240 if(v1 == v2)
241 return Equal;
242 else if(v1 < v2)
243 return LessThan;
244 else
245 return GreaterThan;
246 }
247 else
248 {
249 const qulonglong v1 = o1.as<Numeric>()->toUnsignedInteger();
250 const qulonglong v2 = o2.as<Numeric>()->toUnsignedInteger();
251
252 if(v1 == v2)
253 return Equal;
254 else if(v1 < v2)
255 return LessThan;
256 else
257 return GreaterThan;
258 }
259}
260
261bool IntegerComparator::equals(const Item &o1,
262 const Item &o2) const
263{
264 return o1.as<Numeric>()->toInteger() == o2.as<Numeric>()->toInteger();
265}
266
267/* -------------------------------------------------- */
268
269/* -------------------------------------------------- */
270bool QNameComparator::equals(const Item &o1,
271 const Item &o2) const
272{
273 return o1.as<QNameValue>()->m_qName ==
274 o2.as<QNameValue>()->m_qName;
275}
276/* -------------------------------------------------- */
277
278/* -------------------------------------------------- */
279bool AbstractDateTimeComparator::equals(const Item &o1,
280 const Item &o2) const
281{
282 const QDateTime dt1(o1.as<AbstractDateTime>()->toDateTime());
283 const QDateTime dt2(o2.as<AbstractDateTime>()->toDateTime());
284
285 /*
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();
292 */
293 return dt1 == dt2 &&
294 dt1.timeSpec() == dt2.timeSpec();
295}
296
297AtomicComparator::ComparisonResult
298AbstractDateTimeComparator::compare(const Item &operand1,
299 const AtomicComparator::Operator,
300 const Item &operand2) const
301{
302 const QDateTime &dt1 = operand1.as<AbstractDateTime>()->toDateTime();
303 const QDateTime &dt2 = operand2.as<AbstractDateTime>()->toDateTime();
304
305 if(dt1 == dt2)
306 return Equal;
307 else if(dt1 < dt2)
308 return LessThan;
309 else
310 return GreaterThan;
311}
312/* -------------------------------------------------- */
313
314/* -------------------------------------------------- */
315bool AbstractDurationComparator::equals(const Item &o1,
316 const Item &o2) const
317{
318 /* We use AbstractDuration::operator==() */
319 return *o1.as<AbstractDuration>() ==
320 *o2.as<AbstractDuration>();
321}
322
323QDateTime AbstractDurationComparator::addDurationToDateTime(const QDateTime &dateTime,
324 const AbstractDuration *const duration)
325{
326 QDateTime result(dateTime);
327 qint64 seconds = 0;
328
329 const qint8 signMultiplier = (duration->isPositive() ? 1 : -1);
330
331 result = result.addYears(signMultiplier * duration->years());
332 result = result.addMonths(signMultiplier * duration->months());
333 result = result.addDays(signMultiplier * duration->days());
334
335 seconds = 60 * 60 * duration->hours();
336 seconds += 60 * duration->minutes();
337 seconds += duration->seconds();
338
339 result = result.addSecs(signMultiplier * seconds);
340 result = result.addMSecs(signMultiplier * duration->mseconds());
341
342 return result;
343}
344
345AtomicComparator::ComparisonResult
346AbstractDurationComparator::compare(const Item &o1,
347 const AtomicComparator::Operator,
348 const Item &o2) const
349{
350 const AbstractDuration *const duration = o1.as<AbstractDuration>();
351 const AbstractDuration *const otherDuration = o2.as<AbstractDuration>();
352
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);
357
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);
362
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);
367
368 if (durationDateTime1 > otherDurationDateTime1 &&
369 durationDateTime2 > otherDurationDateTime2 &&
370 durationDateTime3 > otherDurationDateTime3 &&
371 durationDateTime4 > otherDurationDateTime4) {
372 return GreaterThan;
373 } else if (durationDateTime1 < otherDurationDateTime1 &&
374 durationDateTime2 < otherDurationDateTime2 &&
375 durationDateTime3 < otherDurationDateTime3 &&
376 durationDateTime4 < otherDurationDateTime4) {
377 return LessThan;
378 } else if (*duration == *otherDuration) {
379 return Equal;
380 } else {
381 return Incomparable;
382 }
383}
384
385/* -------------------------------------------------- */
386QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.