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 | |
58 | QT_BEGIN_NAMESPACE |
59 | |
60 | namespace 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 | |
618 | QT_END_NAMESPACE |
619 | |
620 | #endif |
621 | |