src/xmlpatterns/functions/qcomparingaggregator.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
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 /**
       
    43  * @file qcomparingaggregator.cpp
       
    44  * @short This file is included by qcomparingaggregator_p.h.
       
    45  * If you need includes in this file, put them in qcomparingaggregator_p.h, outside of the namespace.
       
    46  */
       
    47 
       
    48 template <AtomicComparator::Operator oper, AtomicComparator::ComparisonResult result>
       
    49 inline Item
       
    50 ComparingAggregator<oper, result>::applyNumericPromotion(const Item &old,
       
    51                                                          const Item &nev,
       
    52                                                          const Item &newVal) const
       
    53 {
       
    54     Q_ASSERT(old);
       
    55     Q_ASSERT(nev);
       
    56     Q_ASSERT(newVal);
       
    57     const ItemType::Ptr to(old.type());
       
    58     const ItemType::Ptr tn(nev.type());
       
    59 
       
    60     if(!(BuiltinTypes::numeric->xdtTypeMatches(to) && BuiltinTypes::numeric->xdtTypeMatches(tn)))
       
    61         return newVal; /* At least one of them isn't numeric. */
       
    62     else if(BuiltinTypes::xsDouble->xdtTypeMatches(to) || BuiltinTypes::xsDouble->xdtTypeMatches(tn))
       
    63         return toItem(Double::fromValue(newVal.as<Numeric>()->toDouble()));
       
    64     else if(BuiltinTypes::xsFloat->xdtTypeMatches(to) || BuiltinTypes::xsFloat->xdtTypeMatches(tn))
       
    65         return toItem(Float::fromValue(newVal.as<Numeric>()->toDouble()));
       
    66     else if(BuiltinTypes::xsInteger->xdtTypeMatches(to) &&
       
    67             BuiltinTypes::xsInteger->xdtTypeMatches(tn))
       
    68         return newVal; /* Both must be xs:integer. */
       
    69     else
       
    70         return toItem(Decimal::fromValue(newVal.as<Numeric>()->toDecimal()));
       
    71 }
       
    72 
       
    73 template <AtomicComparator::Operator oper, AtomicComparator::ComparisonResult result>
       
    74 Item
       
    75 ComparingAggregator<oper, result>::evaluateSingleton(const DynamicContext::Ptr &context) const
       
    76 {
       
    77     const Item::Iterator::Ptr it(m_operands.first()->evaluateSequence(context));
       
    78     Item largest;
       
    79 
       
    80     while(true)
       
    81     {
       
    82         Item next(it->next());
       
    83 
       
    84         if(!next)
       
    85         {
       
    86             return largest;
       
    87         }
       
    88 
       
    89         AtomicComparator::Ptr comp(comparator());
       
    90 
       
    91         if(!comp)
       
    92         {
       
    93             ItemType::Ptr t1(next.type());
       
    94             Q_ASSERT(t1);
       
    95 
       
    96             if(BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(t1))
       
    97             {
       
    98                 next = cast(next, context);
       
    99                 t1 = BuiltinTypes::xsDouble;
       
   100             }
       
   101 
       
   102             if(!largest)
       
   103             {
       
   104                 largest = next;
       
   105                 continue;
       
   106             }
       
   107 
       
   108             Q_ASSERT(largest);
       
   109             comp = fetchComparator(largest.type(), t1, context);
       
   110             Q_ASSERT(comp);
       
   111         }
       
   112         else if(!largest)
       
   113         {
       
   114             largest = next;
       
   115             continue;
       
   116         }
       
   117 
       
   118         if(comp->compare(next, operatorID(), largest) == result)
       
   119         {
       
   120             largest = applyNumericPromotion(largest, next, next);
       
   121             continue;
       
   122         }
       
   123 
       
   124         const ItemType::Ptr t(next.type());
       
   125 
       
   126         if(BuiltinTypes::xsDouble->xdtTypeMatches(t) &&
       
   127            next.as<Numeric>()->isNaN())
       
   128         {
       
   129             return CommonValues::DoubleNaN;
       
   130         }
       
   131         else if(BuiltinTypes::xsFloat->xdtTypeMatches(t) &&
       
   132                 next.as<Numeric>()->isNaN())
       
   133         {
       
   134             if(BuiltinTypes::xsDouble->xdtTypeMatches(largest.type()))
       
   135                 return CommonValues::DoubleNaN;
       
   136 
       
   137             /* If we have a xs:double somewhere, we must promote the NaN value to xs:double,
       
   138              * and we really should raise error on invalid value. */
       
   139             largest = it->next();
       
   140 
       
   141             while(largest)
       
   142             {
       
   143                 const ItemType::Ptr tf(largest.type());
       
   144                 if(BuiltinTypes::xsDouble->xdtTypeMatches(tf))
       
   145                     return CommonValues::DoubleNaN;
       
   146                 else if(BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(tf))
       
   147                 {
       
   148                     /* Attempt a convert, which will raise an error if it doesn't work out. */
       
   149                     cast(largest, context);
       
   150                     return CommonValues::DoubleNaN;
       
   151                 }
       
   152                 else if(!BuiltinTypes::numeric->xdtTypeMatches(tf))
       
   153                 {
       
   154                     fetchComparator(BuiltinTypes::xsFloat, tf, context);
       
   155                 }
       
   156                 else
       
   157                     largest = it->next();
       
   158             };
       
   159 
       
   160             return CommonValues::FloatNaN;
       
   161         }
       
   162         else
       
   163             largest = applyNumericPromotion(largest, next, largest);
       
   164     }
       
   165 }
       
   166 
       
   167 template <AtomicComparator::Operator oper, AtomicComparator::ComparisonResult result>
       
   168 Expression::Ptr
       
   169 ComparingAggregator<oper, result>::typeCheck(const StaticContext::Ptr &context,
       
   170                                              const SequenceType::Ptr &reqType)
       
   171 {
       
   172     Q_ASSERT(oper == AtomicComparator::OperatorGreaterThan ||
       
   173              oper == AtomicComparator::OperatorLessThan);
       
   174     const Expression::Ptr me(FunctionCall::typeCheck(context, reqType));
       
   175 
       
   176     ItemType::Ptr t1(m_operands.first()->staticType()->itemType());
       
   177 
       
   178     if(*CommonSequenceTypes::Empty == *t1)
       
   179         return EmptySequence::create(this, context);
       
   180     else if(*BuiltinTypes::xsAnyAtomicType == *t1 ||
       
   181             BuiltinTypes::numeric->xdtTypeMatches(t1))
       
   182         return me;
       
   183     else if(BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(t1))
       
   184     {
       
   185         m_operands.replace(0, Expression::Ptr(new UntypedAtomicConverter(m_operands.first(),
       
   186                            BuiltinTypes::xsDouble)));
       
   187         t1 = m_operands.first()->staticType()->itemType();
       
   188     }
       
   189     else if(!BuiltinTypes::xsString->xdtTypeMatches(t1) &&
       
   190             !BuiltinTypes::xsAnyURI->xdtTypeMatches(t1) &&
       
   191             !BuiltinTypes::xsDayTimeDuration->xdtTypeMatches(t1) &&
       
   192             !BuiltinTypes::xsDate->xdtTypeMatches(t1) &&
       
   193             !BuiltinTypes::xsTime->xdtTypeMatches(t1) &&
       
   194             !BuiltinTypes::xsDateTime->xdtTypeMatches(t1) &&
       
   195             !BuiltinTypes::xsYearMonthDuration->xdtTypeMatches(t1))
       
   196     {
       
   197         context->error(QtXmlPatterns::tr("The first argument to %1 cannot be of type %2.")
       
   198                           .arg(formatFunction(context->namePool(), signature()))
       
   199                           .arg(formatType(context->namePool(), m_operands.first()->staticType())),
       
   200                        ReportContext::FORG0006, this);
       
   201         return me;
       
   202     }
       
   203 
       
   204     if(!m_operands.first()->staticType()->cardinality().allowsMany())
       
   205         return m_operands.first();
       
   206     
       
   207     // explicit scope needed in RVCT
       
   208     ComparingAggregator<oper, result>::prepareComparison(fetchComparator(t1, t1, context));
       
   209 
       
   210     return me;
       
   211 }
       
   212