fdad93f30837add46b7258c4184e3dcf049148ae
[profile/ivi/qtxmlpatterns.git] / src / xmlpatterns / data / qatomicmathematicians.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 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 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
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
56 QT_BEGIN_NAMESPACE
57
58 using namespace QPatternist;
59
60 /* The translation strings is place here once, in order to reduce work for translators,
61  * and provide consistency. */
62
63 static 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
70 static 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
77 static 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
84 Item 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
134 Item 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
183 Item 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
267 Item 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
291 OperandSwitcherMathematician::
292 OperandSwitcherMathematician(const AtomicMathematician::Ptr &mathematician) : m_mather(mathematician)
293 {
294     Q_ASSERT(mathematician);
295 }
296
297 Item 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
306 Item 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
338 Item 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
352 QT_END_NAMESPACE