1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtXmlPatterns module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40//
41// W A R N I N G
42// -------------
43//
44// This file is not part of the Qt API. It exists purely as an
45// implementation detail. This header file may change from version to
46// version without notice, or even be removed.
47//
48// We mean it.
49//
50
51/**
52 * @file qcomparingaggregator.cpp
53 * @short This file is included by qcomparingaggregator_p.h.
54 * If you need includes in this file, put them in qcomparingaggregator_p.h, outside of the namespace.
55 */
56
57template <AtomicComparator::Operator oper, AtomicComparator::ComparisonResult result>
58inline Item
59ComparingAggregator<oper, result>::applyNumericPromotion(const Item &old,
60 const Item &nev,
61 const Item &newVal) const
62{
63 Q_ASSERT(old);
64 Q_ASSERT(nev);
65 Q_ASSERT(newVal);
66 const ItemType::Ptr to(old.type());
67 const ItemType::Ptr tn(nev.type());
68
69 if(!(BuiltinTypes::numeric->xdtTypeMatches(other: to) && BuiltinTypes::numeric->xdtTypeMatches(other: tn)))
70 return newVal; /* At least one of them isn't numeric. */
71 else if(BuiltinTypes::xsDouble->xdtTypeMatches(other: to) || BuiltinTypes::xsDouble->xdtTypeMatches(other: tn))
72 return toItem(atomicValue: Double::fromValue(num: newVal.as<Numeric>()->toDouble()));
73 else if(BuiltinTypes::xsFloat->xdtTypeMatches(other: to) || BuiltinTypes::xsFloat->xdtTypeMatches(other: tn))
74 return toItem(atomicValue: Float::fromValue(num: newVal.as<Numeric>()->toDouble()));
75 else if(BuiltinTypes::xsInteger->xdtTypeMatches(other: to) &&
76 BuiltinTypes::xsInteger->xdtTypeMatches(other: tn))
77 return newVal; /* Both must be xs:integer. */
78 else
79 return toItem(atomicValue: Decimal::fromValue(num: newVal.as<Numeric>()->toDecimal()));
80}
81
82template <AtomicComparator::Operator oper, AtomicComparator::ComparisonResult result>
83Item
84ComparingAggregator<oper, result>::evaluateSingleton(const DynamicContext::Ptr &context) const
85{
86 const Item::Iterator::Ptr it(m_operands.first()->evaluateSequence(context));
87 Item largest;
88
89 while(true)
90 {
91 Item next(it->next());
92
93 if(!next)
94 {
95 return largest;
96 }
97
98 AtomicComparator::Ptr comp(comparator());
99
100 if(!comp)
101 {
102 ItemType::Ptr t1(next.type());
103 Q_ASSERT(t1);
104
105 if(BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(other: t1))
106 {
107 next = cast(next, context);
108 t1 = BuiltinTypes::xsDouble;
109 }
110
111 if(!largest)
112 {
113 largest = next;
114 continue;
115 }
116
117 Q_ASSERT(largest);
118 comp = fetchComparator(largest.type(), t1, context);
119 Q_ASSERT(comp);
120 }
121 else if(!largest)
122 {
123 largest = next;
124 continue;
125 }
126
127 if(comp->compare(op1: next, op: operatorID(), op2: largest) == result)
128 {
129 largest = applyNumericPromotion(old: largest, nev: next, newVal: next);
130 continue;
131 }
132
133 const ItemType::Ptr t(next.type());
134
135 if(BuiltinTypes::xsDouble->xdtTypeMatches(other: t) &&
136 next.as<Numeric>()->isNaN())
137 {
138 return CommonValues::DoubleNaN;
139 }
140 else if(BuiltinTypes::xsFloat->xdtTypeMatches(other: t) &&
141 next.as<Numeric>()->isNaN())
142 {
143 if(BuiltinTypes::xsDouble->xdtTypeMatches(other: largest.type()))
144 return CommonValues::DoubleNaN;
145
146 /* If we have a xs:double somewhere, we must promote the NaN value to xs:double,
147 * and we really should raise error on invalid value. */
148 largest = it->next();
149
150 while(largest)
151 {
152 const ItemType::Ptr tf(largest.type());
153 if(BuiltinTypes::xsDouble->xdtTypeMatches(other: tf))
154 return CommonValues::DoubleNaN;
155 else if(BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(other: tf))
156 {
157 /* Attempt a convert, which will raise an error if it doesn't work out. */
158 cast(largest, context);
159 return CommonValues::DoubleNaN;
160 }
161 else if(!BuiltinTypes::numeric->xdtTypeMatches(other: tf))
162 {
163 fetchComparator(BuiltinTypes::xsFloat, tf, context);
164 }
165 else
166 largest = it->next();
167 };
168
169 return CommonValues::FloatNaN;
170 }
171 else
172 largest = applyNumericPromotion(old: largest, nev: next, newVal: largest);
173 }
174}
175
176template <AtomicComparator::Operator oper, AtomicComparator::ComparisonResult result>
177Expression::Ptr
178ComparingAggregator<oper, result>::typeCheck(const StaticContext::Ptr &context,
179 const SequenceType::Ptr &reqType)
180{
181 Q_ASSERT(oper == AtomicComparator::OperatorGreaterThan ||
182 oper == AtomicComparator::OperatorLessThan);
183 const Expression::Ptr me(FunctionCall::typeCheck(context, reqType));
184
185 ItemType::Ptr t1(m_operands.first()->staticType()->itemType());
186
187 if(*CommonSequenceTypes::Empty == *t1)
188 return EmptySequence::create(replacementFor: this, context);
189 else if(*BuiltinTypes::xsAnyAtomicType == *t1 ||
190 BuiltinTypes::numeric->xdtTypeMatches(other: t1))
191 return me;
192 else if(BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(other: t1))
193 {
194 m_operands.replace(i: 0, t: Expression::Ptr(new UntypedAtomicConverter(m_operands.first(),
195 BuiltinTypes::xsDouble)));
196 t1 = m_operands.first()->staticType()->itemType();
197 }
198 else if(!BuiltinTypes::xsString->xdtTypeMatches(other: t1) &&
199 !BuiltinTypes::xsAnyURI->xdtTypeMatches(other: t1) &&
200 !BuiltinTypes::xsDayTimeDuration->xdtTypeMatches(other: t1) &&
201 !BuiltinTypes::xsDate->xdtTypeMatches(other: t1) &&
202 !BuiltinTypes::xsTime->xdtTypeMatches(other: t1) &&
203 !BuiltinTypes::xsDateTime->xdtTypeMatches(other: t1) &&
204 !BuiltinTypes::xsYearMonthDuration->xdtTypeMatches(other: t1))
205 {
206 context->error(QtXmlPatterns::tr(sourceText: "The first argument to %1 cannot be of type %2.")
207 .arg(QPatternist::formatFunction(np: context->namePool(), func: signature()))
208 .arg(formatType(context->namePool(), m_operands.first()->staticType())),
209 ReportContext::FORG0006, this);
210 return me;
211 }
212
213 if(!m_operands.first()->staticType()->cardinality().allowsMany())
214 return m_operands.first();
215
216 // explicit scope needed in RVCT
217 ComparingAggregator<oper, result>::prepareComparison(fetchComparator(t1, t1, context));
218
219 return me;
220}
221
222

source code of qtxmlpatterns/src/xmlpatterns/functions/qcomparingaggregator_tpl_p.h