src/xmlpatterns/data/qatomiccomparators.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtXmlPatterns module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    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 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    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