source: trunk/src/xmlpatterns/data/qatomicmathematicians.cpp@ 648

Last change on this file since 648 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

File size: 13.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 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 <math.h>
43
44#include <qnumeric.h>
45
46#include "qabstractdatetime_p.h"
47#include "qabstractduration_p.h"
48#include "qabstractfloat_p.h"
49#include "qdaytimeduration_p.h"
50#include "qdecimal_p.h"
51#include "qinteger_p.h"
52#include "qpatternistlocale_p.h"
53
54#include "qatomicmathematicians_p.h"
55
56QT_BEGIN_NAMESPACE
57
58using namespace QPatternist;
59
60/* The translation strings is place here once, in order to reduce work for translators,
61 * and provide consistency. */
62
63static inline QString idivZeroInvalid()
64{
65 return QtXmlPatterns::tr("Integer division (%1) by zero (%2) is undefined.")
66 .arg(formatKeyword("idiv"))
67 .arg(formatData("0"));
68}
69
70static inline QString divZeroInvalid()
71{
72 return QtXmlPatterns::tr("Division (%1) by zero (%2) is undefined.")
73 .arg(formatKeyword("div"))
74 .arg(formatData("0"));
75}
76
77static inline QString modZeroInvalid()
78{
79 return QtXmlPatterns::tr("Modulus division (%1) by zero (%2) is undefined.")
80 .arg(formatKeyword("mod"))
81 .arg(formatData("0"));
82}
83
84Item DecimalMathematician::calculate(const Item &o1,
85 const Operator op,
86 const Item &o2,
87 const QExplicitlySharedDataPointer<DynamicContext> &context) const
88{
89 switch(op)
90 {
91 case Div:
92 {
93 if(o2.as<Numeric>()->toInteger() == 0)
94 {
95 context->error(divZeroInvalid(), ReportContext::FOAR0001, this);
96 return Item(); /* Silences source code analyzer warning. */
97 }
98 else
99 return toItem(Decimal::fromValue(o1.as<Numeric>()->toDecimal() / o2.as<Numeric>()->toDecimal()));
100 }
101 case IDiv:
102 {
103 if(o2.as<Numeric>()->toInteger() == 0)
104 {
105 context->error(idivZeroInvalid(), ReportContext::FOAR0001, this);
106 return Item(); /* Silences source code analyzer warning. */
107 }
108 else
109 return Integer::fromValue(static_cast<xsInteger>(o1.as<Numeric>()->toDecimal() /
110 o2.as<Numeric>()->toDecimal()));
111 }
112 case Substract:
113 return toItem(Decimal::fromValue(o1.as<Numeric>()->toDecimal() - o2.as<Numeric>()->toDecimal()));
114 case Mod:
115 {
116 if(o2.as<Numeric>()->toInteger() == 0)
117 {
118 context->error(modZeroInvalid(), ReportContext::FOAR0001, this);
119 return Item(); /* Silences source code analyzer warning. */
120 }
121 else
122 return toItem(Decimal::fromValue(::fmod(o1.as<Numeric>()->toDecimal(), o2.as<Numeric>()->toDecimal())));
123 }
124 case Multiply:
125 return toItem(Decimal::fromValue(o1.as<Numeric>()->toDecimal() * o2.as<Numeric>()->toDecimal()));
126 case Add:
127 return toItem(Decimal::fromValue(o1.as<Numeric>()->toDecimal() + o2.as<Numeric>()->toDecimal()));
128 }
129
130 Q_ASSERT(false);
131 return Item(); /* GCC unbarfer. */
132}
133
134Item IntegerMathematician::calculate(const Item &o1,
135 const Operator op,
136 const Item &o2,
137 const QExplicitlySharedDataPointer<DynamicContext> &context) const
138{
139 switch(op)
140 {
141 case Div:
142 if(o2.as<Numeric>()->toInteger() == 0)
143 {
144 context->error(divZeroInvalid(), ReportContext::FOAR0001, this);
145 return Item(); /* Silences source code analyzer warning. */
146 }
147 else /* C++ automatically performs truncation of long integer(xsInteger). */
148 return toItem(Decimal::fromValue(o1.as<Numeric>()->toDecimal() / o2.as<Numeric>()->toDecimal()));
149 case IDiv:
150 {
151 if(o2.as<Numeric>()->toInteger() == 0)
152 {
153 context->error(idivZeroInvalid(), ReportContext::FOAR0001, this);
154 return Item(); /* Silences source code analyzer warning. */
155 }
156 else /* C++ automatically performs truncation of long integer(xsInteger). */
157 return Integer::fromValue(o1.as<Numeric>()->toInteger() / o2.as<Numeric>()->toInteger());
158 }
159 case Substract:
160 return Integer::fromValue(o1.as<Numeric>()->toInteger() - o2.as<Numeric>()->toInteger());
161 case Mod:
162 {
163 const xsInteger divisor = o2.as<Numeric>()->toInteger();
164
165 if(divisor == 0)
166 {
167 context->error(modZeroInvalid(), ReportContext::FOAR0001, this);
168 return Item(); /* Silences source code analyzer warning. */
169 }
170 else
171 return Integer::fromValue(o1.as<Numeric>()->toInteger() % divisor);
172 }
173 case Multiply:
174 return Integer::fromValue(o1.as<Numeric>()->toInteger() * o2.as<Numeric>()->toInteger());
175 case Add:
176 return Integer::fromValue(o1.as<Numeric>()->toInteger() + o2.as<Numeric>()->toInteger());
177 }
178
179 Q_ASSERT(false);
180 return Item(); /* GCC unbarfer. */
181}
182
183Item DurationNumericMathematician::calculate(const Item &o1,
184 const Operator op,
185 const Item &o2,
186 const QExplicitlySharedDataPointer<DynamicContext> &context) const
187{
188 Q_ASSERT(op == Div || op == Multiply);
189
190 const AbstractDuration::Ptr duration(o1.as<AbstractDuration>());
191 const xsDouble dbl = o2.as<Numeric>()->toDouble();
192
193 switch(op)
194 {
195 case Div:
196 {
197 if(qIsInf(dbl))
198 return duration->fromValue(0);
199 else if(qIsNaN(dbl))
200 {
201 context->error(QtXmlPatterns::tr(
202 "Dividing a value of type %1 by %2 (not-a-number) "
203 "is not allowed.")
204 .arg(formatType(context->namePool(),
205 duration->type()))
206 .arg(formatData("NaN")),
207 ReportContext::FOCA0005,
208 this);
209 return Item();
210 }
211 else if(Double::isEqual(dbl, 0))
212 {
213 context->error(QtXmlPatterns::tr(
214 "Dividing a value of type %1 by %2 or %3 (plus or "
215 "minus zero) is not allowed.")
216 .arg(formatType(context->namePool(),
217 duration->type()))
218 .arg(formatData("-0"))
219 .arg(formatData("0")),
220 ReportContext::FODT0002,
221 this);
222 return Item();
223 }
224
225 return duration->fromValue(static_cast<AbstractDuration::Value>(duration->value() / dbl));
226 }
227 case Multiply:
228 {
229 if(Double::isEqual(dbl, 0))
230 return duration->fromValue(0);
231 else if(qIsNaN(dbl))
232 {
233 context->error(QtXmlPatterns::tr(
234 "Dividing a value of type %1 by %2 (not-a-number) "
235 "is not allowed.")
236 .arg(formatType(context->namePool(),
237 duration->type()))
238 .arg(formatData("NaN")),
239 ReportContext::FOCA0005,
240 this);
241 return Item();
242 }
243 else if(qIsInf(dbl))
244 {
245 context->error(QtXmlPatterns::tr(
246 "Multiplication of a value of type %1 by %2 or %3 "
247 "(plus or minus infinity) is not allowed.")
248 .arg(formatType(context->namePool(),
249 duration->type()))
250 .arg(formatData("-INF"))
251 .arg(formatData("INF")),
252 ReportContext::FODT0002,
253 this);
254 return Item();
255 }
256
257 return duration->fromValue(static_cast<AbstractDuration::Value>(duration->value() * dbl));
258 }
259 default:
260 {
261 Q_ASSERT(false);
262 return Item(); /* Silence warning. */
263 }
264 }
265}
266
267Item DurationDurationMathematician::calculate(const Item &o1,
268 const Operator op,
269 const Item &o2,
270 const QExplicitlySharedDataPointer<DynamicContext> &) const
271{
272 const AbstractDuration::Ptr duration(o1.as<AbstractDuration>());
273 const AbstractDuration::Value op2 = o2.as<AbstractDuration>()->value();
274
275 switch(op)
276 {
277 case Div:
278 return toItem(Decimal::fromValue(static_cast<xsDecimal>(duration->value()) / op2));
279 case Substract:
280 return duration->fromValue(duration->value() - op2);
281 case Add:
282 return duration->fromValue(duration->value() + op2);
283 default:
284 {
285 Q_ASSERT(false);
286 return Item(); /* Silence warning. */
287 }
288 }
289}
290
291OperandSwitcherMathematician::
292OperandSwitcherMathematician(const AtomicMathematician::Ptr &mathematician) : m_mather(mathematician)
293{
294 Q_ASSERT(mathematician);
295}
296
297Item OperandSwitcherMathematician::calculate(const Item &o1,
298 const Operator op,
299 const Item &o2,
300 const QExplicitlySharedDataPointer<DynamicContext> &context) const
301{
302 return m_mather->calculate(o2, op, o1, context);
303}
304
305
306Item DateTimeDurationMathematician::calculate(const Item &o1,
307 const Operator op,
308 const Item &o2,
309 const QExplicitlySharedDataPointer<DynamicContext> &context) const
310{
311 Q_ASSERT(op == Substract || op == Add);
312
313 const AbstractDateTime::Ptr adt(o1.as<AbstractDateTime>());
314 const AbstractDuration::Ptr dur(o2.as<AbstractDuration>());
315 QDateTime dt(adt->toDateTime());
316 //pDebug() << "DateTimeDurationMathematician::calculate():" << dt.toString();
317 //dt.setDateOnly(false);
318 const qint8 sign = (op == Add ? 1 : -1) * (dur->isPositive() ? 1 : -1);
319
320 // TODO milli seconds
321 dt = dt.addSecs(sign * (dur->seconds() + dur->minutes() * 60 + dur->hours() * 60 * 60));
322 dt = dt.addDays(sign * dur->days());
323 dt = dt.addMonths(sign * dur->months());
324 dt = dt.addYears(sign * dur->years());
325
326 QString msg;
327
328 if(AbstractDateTime::isRangeValid(dt.date(), msg))
329 return adt->fromValue(dt);
330 else
331 {
332 context->error(msg, ReportContext::FODT0001,
333 this);
334 return Item();
335 }
336}
337
338Item AbstractDateTimeMathematician::calculate(const Item &o1,
339 const Operator op,
340 const Item &o2,
341 const QExplicitlySharedDataPointer<DynamicContext> &) const
342{
343 Q_ASSERT(op == Substract || op == Add);
344 QDateTime dt1(o1.as<AbstractDateTime>()->toDateTime());
345 QDateTime dt2(o2.as<AbstractDateTime>()->toDateTime());
346
347 const int diff = op == Add ? dt1.secsTo(dt2) : dt2.secsTo(dt1);
348
349 return toItem(DayTimeDuration::fromSeconds(diff));
350}
351
352QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.