0ef5b51095682e27969db255d52a81a1037195f6
[profile/ivi/qtxmlpatterns.git] / src / xmlpatterns / data / qderivedinteger_p.h
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 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 //  W A R N I N G
44 //  -------------
45 //
46 // This file is not part of the Qt API.  It exists purely as an
47 // implementation detail.  This header file may change from version to
48 // version without notice, or even be removed.
49 //
50 // We mean it.
51
52 #ifndef Patternist_DerivedInteger_H
53 #define Patternist_DerivedInteger_H
54
55 #include "qbuiltintypes_p.h"
56 #include "qinteger_p.h"
57 #include "qpatternistlocale_p.h"
58 #include "qvalidationerror_p.h"
59
60 QT_BEGIN_HEADER
61
62 QT_BEGIN_NAMESPACE
63
64 namespace QPatternist
65 {
66     /**
67      * @relates DerivedInteger
68      */
69     enum DerivedIntegerLimitsUsage
70     {
71         None            = 1,
72         LimitUpwards    = 2,
73         LimitDownwards  = 4,
74         LimitBoth       = LimitUpwards | LimitDownwards
75     };
76
77     enum
78     {
79         IgnorableSignedValue = 0,
80         IgnorableUnsignedValue = 0
81     };
82
83     template<TypeOfDerivedInteger DerivedType> class DerivedInteger;
84
85     template<TypeOfDerivedInteger DerivedType> class DerivedIntegerDetails;
86
87     template<>
88     class DerivedIntegerDetails<TypeByte>
89     {
90     private:
91         friend class DerivedInteger<TypeByte>;
92         typedef qint8                           StorageType;
93         typedef xsInteger                       TemporaryStorageType;
94         static const StorageType                maxInclusive = 127;
95         static const StorageType                minInclusive = -128;
96         static const DerivedIntegerLimitsUsage  limitsUsage = LimitBoth;
97
98         /**
99          * Disable the default constructor.
100          */
101         DerivedIntegerDetails() {}
102
103         Q_DISABLE_COPY(DerivedIntegerDetails)
104     };
105
106     template<>
107     class DerivedIntegerDetails<TypeInt>
108     {
109     private:
110         friend class DerivedInteger<TypeInt>;
111         typedef qint32                          StorageType;
112         typedef xsInteger                       TemporaryStorageType;
113         static const StorageType                maxInclusive = Q_INT64_C(2147483647);
114         static const StorageType                minInclusive = Q_INT64_C(-2147483648);
115         static const DerivedIntegerLimitsUsage  limitsUsage = LimitBoth;
116
117         /**
118          * Disable the default constructor.
119          */
120         DerivedIntegerDetails() {}
121
122         Q_DISABLE_COPY(DerivedIntegerDetails)
123     };
124
125     template<>
126     class DerivedIntegerDetails<TypeLong>
127     {
128     private:
129         friend class DerivedInteger<TypeLong>;
130         typedef qint64                          StorageType;
131         typedef StorageType                     TemporaryStorageType;
132         static const StorageType                maxInclusive = Q_INT64_C(9223372036854775807);
133
134         /**
135          * This messy arithmetic expression ensures that we don't get a warning
136          * on neither GCC nor MSVC.
137          */
138         static const StorageType                minInclusive = -(Q_INT64_C(9223372036854775807)) - 1;
139
140         static const DerivedIntegerLimitsUsage  limitsUsage = LimitBoth;
141
142         /**
143          * Disable the default constructor.
144          */
145         DerivedIntegerDetails() {}
146
147         Q_DISABLE_COPY(DerivedIntegerDetails)
148     };
149
150     template<>
151     class DerivedIntegerDetails<TypeNegativeInteger>
152     {
153     private:
154         friend class DerivedInteger<TypeNegativeInteger>;
155         typedef xsInteger                       StorageType;
156         typedef StorageType                     TemporaryStorageType;
157         static const StorageType                maxInclusive = -1;
158         static const StorageType                minInclusive = IgnorableSignedValue;
159         static const DerivedIntegerLimitsUsage  limitsUsage = LimitUpwards;
160
161         /**
162          * Disable the default constructor.
163          */
164         DerivedIntegerDetails() {}
165
166         Q_DISABLE_COPY(DerivedIntegerDetails)
167     };
168
169     template<>
170     class DerivedIntegerDetails<TypeNonNegativeInteger>
171     {
172     private:
173         friend class DerivedInteger<TypeNonNegativeInteger>;
174         typedef xsInteger                       StorageType;
175         typedef StorageType                     TemporaryStorageType;
176         static const StorageType                maxInclusive = IgnorableSignedValue;
177         static const StorageType                minInclusive = 0;
178         static const DerivedIntegerLimitsUsage  limitsUsage = LimitDownwards;
179
180         /**
181          * Disable the default constructor.
182          */
183         DerivedIntegerDetails() {}
184
185         Q_DISABLE_COPY(DerivedIntegerDetails)
186     };
187
188     template<>
189     class DerivedIntegerDetails<TypeNonPositiveInteger>
190     {
191     private:
192         friend class DerivedInteger<TypeNonPositiveInteger>;
193         typedef xsInteger                       StorageType;
194         typedef StorageType                     TemporaryStorageType;
195         static const StorageType                maxInclusive = 0;
196         static const StorageType                minInclusive = IgnorableSignedValue;
197         static const DerivedIntegerLimitsUsage  limitsUsage = LimitUpwards;
198
199         /**
200          * Disable the default constructor.
201          */
202         DerivedIntegerDetails() {}
203
204         Q_DISABLE_COPY(DerivedIntegerDetails)
205     };
206
207     template<>
208     class DerivedIntegerDetails<TypePositiveInteger>
209     {
210     private:
211         friend class DerivedInteger<TypePositiveInteger>;
212         typedef xsInteger                       StorageType;
213         typedef StorageType                     TemporaryStorageType;
214         static const StorageType                maxInclusive = IgnorableSignedValue;
215         static const StorageType                minInclusive = 1;
216         static const DerivedIntegerLimitsUsage  limitsUsage = LimitDownwards;
217
218         /**
219          * Disable the default constructor.
220          */
221         DerivedIntegerDetails() {}
222
223         Q_DISABLE_COPY(DerivedIntegerDetails)
224     };
225
226     template<>
227     class DerivedIntegerDetails<TypeShort>
228     {
229     private:
230         friend class DerivedInteger<TypeShort>;
231         typedef qint16                          StorageType;
232         typedef xsInteger                       TemporaryStorageType;
233         static const StorageType                maxInclusive = 32767;
234         static const StorageType                minInclusive = -32768;
235         static const DerivedIntegerLimitsUsage  limitsUsage = LimitBoth;
236
237         /**
238          * Disable the default constructor.
239          */
240         DerivedIntegerDetails() {}
241
242         Q_DISABLE_COPY(DerivedIntegerDetails)
243     };
244
245     template<>
246     class DerivedIntegerDetails<TypeUnsignedByte>
247     {
248     private:
249         friend class DerivedInteger<TypeUnsignedByte>;
250         typedef quint8                          StorageType;
251         typedef qint64                          TemporaryStorageType;
252         static const StorageType                maxInclusive = 255;
253         static const StorageType                minInclusive = 0;
254         static const DerivedIntegerLimitsUsage  limitsUsage = LimitBoth;
255
256         /**
257          * Disable the default constructor.
258          */
259         DerivedIntegerDetails() {}
260
261         Q_DISABLE_COPY(DerivedIntegerDetails)
262     };
263
264     template<>
265     class DerivedIntegerDetails<TypeUnsignedInt>
266     {
267     private:
268         friend class DerivedInteger<TypeUnsignedInt>;
269         typedef quint32                         StorageType;
270         typedef qint64                          TemporaryStorageType;
271         static const StorageType                maxInclusive = Q_UINT64_C(4294967295);
272         static const StorageType                minInclusive = 0;
273         static const DerivedIntegerLimitsUsage  limitsUsage = LimitBoth;
274
275         /**
276          * Disable the default constructor.
277          */
278         DerivedIntegerDetails() {}
279
280         Q_DISABLE_COPY(DerivedIntegerDetails)
281     };
282
283     template<>
284     class DerivedIntegerDetails<TypeUnsignedLong>
285     {
286     private:
287         friend class DerivedInteger<TypeUnsignedLong>;
288         typedef quint64                         StorageType;
289         typedef StorageType                     TemporaryStorageType;
290         static const StorageType                maxInclusive = Q_UINT64_C(18446744073709551615);
291         static const StorageType                minInclusive = 0;
292         static const DerivedIntegerLimitsUsage  limitsUsage = LimitBoth;
293
294         /**
295          * Disable the default constructor.
296          */
297         DerivedIntegerDetails() {}
298
299         Q_DISABLE_COPY(DerivedIntegerDetails)
300     };
301
302     template<>
303     class DerivedIntegerDetails<TypeUnsignedShort>
304     {
305     private:
306         friend class DerivedInteger<TypeUnsignedShort>;
307         typedef quint16                         StorageType;
308         typedef qint64                          TemporaryStorageType;
309         static const StorageType                maxInclusive = 65535;
310         static const StorageType                minInclusive = 0;
311         static const DerivedIntegerLimitsUsage  limitsUsage = LimitBoth;
312
313         /**
314          * Disable the default constructor.
315          */
316         DerivedIntegerDetails() {}
317
318         Q_DISABLE_COPY(DerivedIntegerDetails)
319     };
320
321     /**
322      * @short Represents instances of derived @c xs:integer types, such as @c
323      * xs:byte.
324      *
325      * @author Frans Englich <frans.englich@nokia.com>
326      * @ingroup Patternist_xdm
327      */
328     template<TypeOfDerivedInteger DerivedType>
329     class DerivedInteger : public Numeric
330     {
331     private:
332         typedef typename DerivedIntegerDetails<DerivedType>::StorageType StorageType;
333         typedef typename DerivedIntegerDetails<DerivedType>::TemporaryStorageType TemporaryStorageType;
334
335         static const StorageType                maxInclusive        = DerivedIntegerDetails<DerivedType>::maxInclusive;
336         static const StorageType                minInclusive        = DerivedIntegerDetails<DerivedType>::minInclusive;
337         static const DerivedIntegerLimitsUsage  limitsUsage         = DerivedIntegerDetails<DerivedType>::limitsUsage;
338
339         const StorageType m_value;
340
341         inline DerivedInteger(const StorageType num) : m_value(num)
342         {
343         }
344
345         /**
346          * By refactoring out the simple comparison below into a template
347          * function, we avoid the warning "warning: comparison of unsigned expression < 0 is always false" with gcc
348          * when the class is instantiated with TypeUnsignedLong. The warning is
349          * a false positive since we check wehther LimitUpwards is set before
350          * instantiating.
351          *
352          * This template function exists for no other reason. */
353         template<typename A, typename B>
354         static bool lessThan(const A &a, const B &b)
355         {
356             return a < b;
357         }
358
359         /**
360          * This function exists for the same reason that lessThan() do.
361          */
362         template<typename A, typename B>
363         static bool largerOrEqual(const A &a, const B &b)
364         {
365             return qint64(a) >= b;
366         }
367
368     public:
369
370         static ItemType::Ptr itemType()
371         {
372             switch(DerivedType)
373             {
374                 case TypeByte:                  return BuiltinTypes::xsByte;
375                 case TypeInt:                   return BuiltinTypes::xsInt;
376                 case TypeLong:                  return BuiltinTypes::xsLong;
377                 case TypeNegativeInteger:       return BuiltinTypes::xsNegativeInteger;
378                 case TypeNonNegativeInteger:    return BuiltinTypes::xsNonNegativeInteger;
379                 case TypeNonPositiveInteger:    return BuiltinTypes::xsNonPositiveInteger;
380                 case TypePositiveInteger:       return BuiltinTypes::xsPositiveInteger;
381                 case TypeShort:                 return BuiltinTypes::xsShort;
382                 case TypeUnsignedByte:          return BuiltinTypes::xsUnsignedByte;
383                 case TypeUnsignedInt:           return BuiltinTypes::xsUnsignedInt;
384                 case TypeUnsignedLong:          return BuiltinTypes::xsUnsignedLong;
385                 case TypeUnsignedShort:         return BuiltinTypes::xsUnsignedShort;
386             }
387
388             Q_ASSERT(false);
389             return ItemType::Ptr();
390         }
391
392         static AtomicValue::Ptr fromValue(const NamePool::Ptr &np, const TemporaryStorageType num)
393         {
394             /* If we use minInclusive when calling lessThan(), we for some
395              * reason get a linker error with GCC. Using this temporary
396              * variable solves it. */
397             const StorageType minimum = minInclusive;
398
399             if((limitsUsage & LimitUpwards) &&
400                num > maxInclusive)
401             {
402                 return ValidationError::createError(QtXmlPatterns::tr(
403                     "Value %1 of type %2 exceeds maximum (%3).")
404                     .arg(QPatternist::formatData(static_cast<xsInteger>(num)))
405                     .arg(formatType(np, itemType()))
406                     .arg(QPatternist::formatData(static_cast<xsInteger>(maxInclusive))));
407             }
408             else if((limitsUsage & LimitDownwards) &&
409                     lessThan(num, minimum))
410             {
411                 return ValidationError::createError(QtXmlPatterns::tr(
412                     "Value %1 of type %2 is below minimum (%3).")
413                     .arg(QPatternist::formatData(static_cast<xsInteger>(num)))
414                     .arg(formatType(np, itemType()))
415                     .arg(QPatternist::formatData(static_cast<xsInteger>(minInclusive))));
416             }
417             else
418                 return AtomicValue::Ptr(new DerivedInteger(num));
419         }
420
421         static AtomicValue::Ptr fromValueUnchecked(const TemporaryStorageType num)
422         {
423             return AtomicValue::Ptr(new DerivedInteger(num));
424         }
425
426         /**
427          * Constructs an instance from the lexical
428          * representation @p strNumeric.
429          */
430         static AtomicValue::Ptr fromLexical(const NamePool::Ptr &np, const QString &strNumeric)
431         {
432             bool conversionOk = false;
433             TemporaryStorageType num;
434
435             /* Depending on the type, we need to call different conversion
436              * functions on QString. */
437             switch(DerivedType)
438             {
439                 case TypeUnsignedLong:
440                 {
441                     /* Qt decides to flag '-' as invalid, so remove it before. */
442                     if(strNumeric.contains(QLatin1Char('-')))
443                     {
444                         num = QString(strNumeric).remove(QLatin1Char('-')).toULongLong(&conversionOk);
445
446                         if(num != 0)
447                             conversionOk = false;
448                     }
449                     else
450                         num = strNumeric.toULongLong(&conversionOk);
451
452                     break;
453                 }
454                 default:
455                 {
456                     num = strNumeric.toLongLong(&conversionOk);
457                     break;
458                 }
459             }
460
461             if(conversionOk)
462                 return fromValue(np, num);
463             else
464                 return ValidationError::createError();
465         }
466
467         inline StorageType storedValue() const
468         {
469             return m_value;
470         }
471
472         /**
473          * Determines the Effective %Boolean Value of this number.
474          *
475          * @returns @c false if the number is 0, otherwise @c true.
476          */
477         bool evaluateEBV(const QExplicitlySharedDataPointer<DynamicContext> &) const
478         {
479             return m_value != 0;
480         }
481
482         virtual QString stringValue() const
483         {
484             return QString::number(m_value);
485         }
486
487         virtual ItemType::Ptr type() const
488         {
489             return itemType();
490         }
491
492         virtual xsDouble toDouble() const
493         {
494             return static_cast<xsDouble>(m_value);
495         }
496
497         virtual xsInteger toInteger() const
498         {
499             return m_value;
500         }
501
502         virtual xsFloat toFloat() const
503         {
504             return static_cast<xsFloat>(m_value);
505         }
506
507         virtual xsDecimal toDecimal() const
508         {
509             return static_cast<xsDecimal>(m_value);
510         }
511
512         virtual Numeric::Ptr round() const
513         {
514             /* xs:integerS never have a mantissa. */
515             return Numeric::Ptr(static_cast<Numeric *>(const_cast<AtomicValue *>(Integer::fromValue(m_value).asAtomicValue())));
516         }
517
518         virtual Numeric::Ptr roundHalfToEven(const xsInteger) const
519         {
520             return Numeric::Ptr(static_cast<Numeric *>(const_cast<AtomicValue *>(Integer::fromValue(m_value).asAtomicValue())));
521         }
522
523         virtual Numeric::Ptr floor() const
524         {
525             return Numeric::Ptr(static_cast<Numeric *>(const_cast<AtomicValue *>(Integer::fromValue(m_value).asAtomicValue())));
526         }
527
528         virtual Numeric::Ptr ceiling() const
529         {
530             return Numeric::Ptr(static_cast<Numeric *>(const_cast<AtomicValue *>(Integer::fromValue(m_value).asAtomicValue())));
531         }
532
533         virtual Numeric::Ptr abs() const
534         {
535             /* We unconditionally create an Integer even if we're a positive
536              * value, because one part of this is the type change to
537              * xs:integer.
538              *
539              * We've manually inlined qAbs() and invoke xsInteger's
540              * constructor. The reason being that we other gets truncation down
541              * to StorageType. See for instance XQTS test case absint1args-1. */
542             return Numeric::Ptr(static_cast<Numeric *>(const_cast<AtomicValue *>(Integer::fromValue(largerOrEqual(m_value, 0) ? xsInteger(m_value) : -xsInteger(m_value)).asAtomicValue())));
543         }
544
545         /**
546          * @returns always @c false, @c xs:DerivedInteger doesn't have
547          * not-a-number in its value space.
548          */
549         virtual bool isNaN() const
550         {
551             return false;
552         }
553
554         /**
555          * @returns always @c false, @c xs:DerivedInteger doesn't have
556          * infinity in its value space.
557          */
558         virtual bool isInf() const
559         {
560             return false;
561         }
562
563         virtual Item toNegated() const
564         {
565             return Integer::fromValue(-xsInteger(m_value));
566         }
567
568         virtual bool isSigned() const
569         {
570             switch(DerivedType)
571             {
572                 /* Fallthrough all these. */
573                 case TypeByte:
574                 case TypeInt:
575                 case TypeLong:
576                 case TypeNegativeInteger:
577                 case TypeNonNegativeInteger:
578                 case TypeNonPositiveInteger:
579                 case TypePositiveInteger:
580                 case TypeShort:
581                     return true;
582                 /* Fallthrough all these. */
583                 case TypeUnsignedByte:
584                 case TypeUnsignedInt:
585                 case TypeUnsignedLong:
586                 case TypeUnsignedShort:
587                     return false;
588             }
589             return false;
590         }
591
592         virtual qulonglong toUnsignedInteger() const
593         {
594             switch(DerivedType)
595             {
596                 /* Fallthrough all these. */
597                 case TypeByte:
598                 case TypeInt:
599                 case TypeLong:
600                 case TypeNegativeInteger:
601                 case TypeNonNegativeInteger:
602                 case TypeNonPositiveInteger:
603                 case TypePositiveInteger:
604                 case TypeShort:
605                     Q_ASSERT_X(false, Q_FUNC_INFO,
606                                "It makes no sense to call this function, see Numeric::toUnsignedInteger().");
607                 /* Fallthrough all these. */
608                 case TypeUnsignedByte:
609                 case TypeUnsignedInt:
610                 case TypeUnsignedLong:
611                 case TypeUnsignedShort:
612                     return m_value;
613             }
614             return 0;
615         }
616
617     };
618 }
619
620 QT_END_NAMESPACE
621
622 QT_END_HEADER
623
624 #endif