5670ebb854718785d6578e12225d402193b4b3b8
[profile/ivi/qtxmlpatterns.git] / src / xmlpatterns / data / qatomiccomparators.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtXmlPatterns module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
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
51 QT_BEGIN_NAMESPACE
52
53 using namespace QPatternist;
54
55 /* -------------------------------------------------- */
56 AtomicComparator::ComparisonResult
57 StringComparator::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
74 bool StringComparator::equals(const Item &o1,
75                               const Item &o2) const
76 {
77     return o1.stringValue() == o2.stringValue();
78 }
79 /* -------------------------------------------------- */
80
81 /* -------------------------------------------------- */
82 AtomicComparator::ComparisonResult
83 CaseInsensitiveStringComparator::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
102 bool 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 /* -------------------------------------------------- */
114 bool 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 /* -------------------------------------------------- */
123 AtomicComparator::ComparisonResult
124 BooleanComparator::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
146 bool 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 /* -------------------------------------------------- */
155 AtomicComparator::ComparisonResult
156 AbstractFloatComparator::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
183 bool 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 /* -------------------------------------------------- */
191 AtomicComparator::ComparisonResult
192 DecimalComparator::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
207 bool 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 /* -------------------------------------------------- */
215 AtomicComparator::ComparisonResult
216 IntegerComparator::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
261 bool 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 /* -------------------------------------------------- */
270 bool 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 /* -------------------------------------------------- */
279 bool 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
297 AtomicComparator::ComparisonResult
298 AbstractDateTimeComparator::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 /* -------------------------------------------------- */
315 bool 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
323 QDateTime 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
345 AtomicComparator::ComparisonResult
346 AbstractDurationComparator::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 /* -------------------------------------------------- */
386 QT_END_NAMESPACE