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

source code of qtxmlpatterns/src/xmlpatterns/data/qderivedinteger_p.h