1 | // Copyright (C) 2021 The Qt Company Ltd. |
2 | // Copyright (C) 2016 Intel Corporation. |
3 | // Copyright (C) 2014 Keith Gardner <kreios4004@gmail.com> |
4 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
5 | |
6 | #include <QtCore/qversionnumber.h> |
7 | #include <QtCore/qhash.h> |
8 | #include <QtCore/private/qlocale_tools_p.h> |
9 | #include <QtCore/qcollator.h> |
10 | |
11 | #ifndef QT_NO_DATASTREAM |
12 | # include <QtCore/qdatastream.h> |
13 | #endif |
14 | |
15 | #ifndef QT_NO_DEBUG_STREAM |
16 | # include <QtCore/qdebug.h> |
17 | #endif |
18 | |
19 | #include <algorithm> |
20 | #include <limits> |
21 | |
22 | QT_BEGIN_NAMESPACE |
23 | |
24 | QT_IMPL_METATYPE_EXTERN(QVersionNumber) |
25 | QT_IMPL_METATYPE_EXTERN(QTypeRevision) |
26 | |
27 | /*! |
28 | \class QVersionNumber |
29 | \inmodule QtCore |
30 | \since 5.6 |
31 | \brief The QVersionNumber class contains a version number with an arbitrary |
32 | number of segments. |
33 | |
34 | \snippet qversionnumber/main.cpp 0 |
35 | */ |
36 | |
37 | /*! |
38 | \fn QVersionNumber::QVersionNumber() |
39 | |
40 | Produces a null version. |
41 | |
42 | \sa isNull() |
43 | */ |
44 | |
45 | /*! |
46 | \fn QVersionNumber::QVersionNumber(int maj) |
47 | |
48 | Constructs a QVersionNumber consisting of just the major version number \a maj. |
49 | */ |
50 | |
51 | /*! |
52 | \fn QVersionNumber::QVersionNumber(int maj, int min) |
53 | |
54 | Constructs a QVersionNumber consisting of the major and minor |
55 | version numbers \a maj and \a min, respectively. |
56 | */ |
57 | |
58 | /*! |
59 | \fn QVersionNumber::QVersionNumber(int maj, int min, int mic) |
60 | |
61 | Constructs a QVersionNumber consisting of the major, minor, and |
62 | micro version numbers \a maj, \a min and \a mic, respectively. |
63 | */ |
64 | |
65 | /*! |
66 | \fn QVersionNumber::QVersionNumber(const QList<int> &seg) |
67 | |
68 | Constructs a version number from the list of numbers contained in \a seg. |
69 | */ |
70 | |
71 | /*! |
72 | \fn QVersionNumber::QVersionNumber(QList<int> &&seg) |
73 | |
74 | Move-constructs a version number from the list of numbers contained in \a seg. |
75 | |
76 | This constructor is only enabled if the compiler supports C++11 move semantics. |
77 | */ |
78 | |
79 | /*! |
80 | \fn QVersionNumber::QVersionNumber(std::initializer_list<int> args) |
81 | |
82 | Construct a version number from the std::initializer_list specified by |
83 | \a args. |
84 | |
85 | This constructor is only enabled if the compiler supports C++11 initializer |
86 | lists. |
87 | */ |
88 | |
89 | /*! |
90 | \fn template <qsizetype N> QVersionNumber::QVersionNumber(const QVarLengthArray<int, N> &seg) |
91 | \since 6.4 |
92 | |
93 | Constructs a version number from the list of numbers contained in \a seg. |
94 | */ |
95 | |
96 | /*! |
97 | \fn bool QVersionNumber::isNull() const |
98 | |
99 | Returns \c true if there are zero numerical segments, otherwise returns |
100 | \c false. |
101 | |
102 | \sa segments() |
103 | */ |
104 | |
105 | /*! |
106 | \fn bool QVersionNumber::isNormalized() const |
107 | |
108 | Returns \c true if the version number does not contain any trailing zeros, |
109 | otherwise returns \c false. |
110 | |
111 | \sa normalized() |
112 | */ |
113 | |
114 | /*! |
115 | \fn int QVersionNumber::majorVersion() const |
116 | |
117 | Returns the major version number, that is, the first segment. |
118 | This function is equivalent to segmentAt(0). If this QVersionNumber object |
119 | is null, this function returns 0. |
120 | |
121 | \sa isNull(), segmentAt() |
122 | */ |
123 | |
124 | /*! |
125 | \fn int QVersionNumber::minorVersion() const |
126 | |
127 | Returns the minor version number, that is, the second segment. |
128 | This function is equivalent to segmentAt(1). If this QVersionNumber object |
129 | does not contain a minor number, this function returns 0. |
130 | |
131 | \sa isNull(), segmentAt() |
132 | */ |
133 | |
134 | /*! |
135 | \fn int QVersionNumber::microVersion() const |
136 | |
137 | Returns the micro version number, that is, the third segment. |
138 | This function is equivalent to segmentAt(2). If this QVersionNumber object |
139 | does not contain a micro number, this function returns 0. |
140 | |
141 | \sa isNull(), segmentAt() |
142 | */ |
143 | |
144 | /*! |
145 | \fn QList<int> QVersionNumber::segments() const |
146 | |
147 | Returns all of the numerical segments. |
148 | |
149 | \sa majorVersion(), minorVersion(), microVersion() |
150 | */ |
151 | QList<int> QVersionNumber::segments() const |
152 | { |
153 | if (m_segments.isUsingPointer()) |
154 | return *m_segments.pointer_segments; |
155 | |
156 | QList<int> result; |
157 | result.resize(size: segmentCount()); |
158 | for (qsizetype i = 0; i < segmentCount(); ++i) |
159 | result[i] = segmentAt(index: i); |
160 | return result; |
161 | } |
162 | |
163 | /*! |
164 | \fn int QVersionNumber::segmentAt(qsizetype index) const |
165 | |
166 | Returns the segment value at \a index. If the index does not exist, |
167 | returns 0. |
168 | |
169 | \sa segments(), segmentCount() |
170 | */ |
171 | |
172 | /*! |
173 | \fn qsizetype QVersionNumber::segmentCount() const |
174 | |
175 | Returns the number of integers stored in segments(). |
176 | |
177 | \sa segments() |
178 | */ |
179 | |
180 | /*! |
181 | \fn QVersionNumber QVersionNumber::normalized() const |
182 | |
183 | Returns an equivalent version number but with all trailing zeros removed. |
184 | |
185 | To check if two numbers are equivalent, use normalized() on both version |
186 | numbers before performing the compare. |
187 | |
188 | \snippet qversionnumber/main.cpp 4 |
189 | */ |
190 | QVersionNumber QVersionNumber::normalized() const |
191 | { |
192 | qsizetype i; |
193 | for (i = m_segments.size(); i; --i) |
194 | if (m_segments.at(index: i - 1) != 0) |
195 | break; |
196 | |
197 | QVersionNumber result(*this); |
198 | result.m_segments.resize(len: i); |
199 | return result; |
200 | } |
201 | |
202 | /*! |
203 | \fn bool QVersionNumber::isPrefixOf(const QVersionNumber &other) const |
204 | |
205 | Returns \c true if the current version number is contained in the \a other |
206 | version number, otherwise returns \c false. |
207 | |
208 | \snippet qversionnumber/main.cpp 2 |
209 | |
210 | \sa commonPrefix() |
211 | */ |
212 | bool QVersionNumber::isPrefixOf(const QVersionNumber &other) const noexcept |
213 | { |
214 | if (segmentCount() > other.segmentCount()) |
215 | return false; |
216 | for (qsizetype i = 0; i < segmentCount(); ++i) { |
217 | if (segmentAt(index: i) != other.segmentAt(index: i)) |
218 | return false; |
219 | } |
220 | return true; |
221 | } |
222 | |
223 | /*! |
224 | \fn int QVersionNumber::compare(const QVersionNumber &v1, |
225 | const QVersionNumber &v2) |
226 | |
227 | Compares \a v1 with \a v2 and returns an integer less than, equal to, or |
228 | greater than zero, depending on whether \a v1 is less than, equal to, or |
229 | greater than \a v2, respectively. |
230 | |
231 | Comparisons are performed by comparing the segments of \a v1 and \a v2 |
232 | starting at index 0 and working towards the end of the longer list. |
233 | |
234 | \snippet qversionnumber/main.cpp 1 |
235 | */ |
236 | int QVersionNumber::compare(const QVersionNumber &v1, const QVersionNumber &v2) noexcept |
237 | { |
238 | qsizetype commonlen; |
239 | |
240 | if (Q_LIKELY(!v1.m_segments.isUsingPointer() && !v2.m_segments.isUsingPointer())) { |
241 | // we can't use memcmp because it interprets the data as unsigned bytes |
242 | const qint8 *ptr1 = v1.m_segments.inline_segments + InlineSegmentStartIdx; |
243 | const qint8 *ptr2 = v2.m_segments.inline_segments + InlineSegmentStartIdx; |
244 | commonlen = qMin(a: v1.m_segments.size(), |
245 | b: v2.m_segments.size()); |
246 | for (qsizetype i = 0; i < commonlen; ++i) |
247 | if (int x = ptr1[i] - ptr2[i]) |
248 | return x; |
249 | } else { |
250 | commonlen = qMin(a: v1.segmentCount(), b: v2.segmentCount()); |
251 | for (qsizetype i = 0; i < commonlen; ++i) { |
252 | if (v1.segmentAt(index: i) != v2.segmentAt(index: i)) |
253 | return v1.segmentAt(index: i) - v2.segmentAt(index: i); |
254 | } |
255 | } |
256 | |
257 | // ran out of segments in v1 and/or v2 and need to check the first trailing |
258 | // segment to finish the compare |
259 | if (v1.segmentCount() > commonlen) { |
260 | // v1 is longer |
261 | if (v1.segmentAt(index: commonlen) != 0) |
262 | return v1.segmentAt(index: commonlen); |
263 | else |
264 | return 1; |
265 | } else if (v2.segmentCount() > commonlen) { |
266 | // v2 is longer |
267 | if (v2.segmentAt(index: commonlen) != 0) |
268 | return -v2.segmentAt(index: commonlen); |
269 | else |
270 | return -1; |
271 | } |
272 | |
273 | // the two version numbers are the same |
274 | return 0; |
275 | } |
276 | |
277 | /*! |
278 | QVersionNumber QVersionNumber::commonPrefix(const QVersionNumber &v1, |
279 | const QVersionNumber &v2) |
280 | |
281 | Returns a version number that is a parent version of both \a v1 and \a v2. |
282 | |
283 | \sa isPrefixOf() |
284 | */ |
285 | QVersionNumber QVersionNumber::commonPrefix(const QVersionNumber &v1, |
286 | const QVersionNumber &v2) |
287 | { |
288 | qsizetype commonlen = qMin(a: v1.segmentCount(), b: v2.segmentCount()); |
289 | qsizetype i; |
290 | for (i = 0; i < commonlen; ++i) { |
291 | if (v1.segmentAt(index: i) != v2.segmentAt(index: i)) |
292 | break; |
293 | } |
294 | |
295 | if (i == 0) |
296 | return QVersionNumber(); |
297 | |
298 | // try to use the one with inline segments, if there's one |
299 | QVersionNumber result(!v1.m_segments.isUsingPointer() ? v1 : v2); |
300 | result.m_segments.resize(len: i); |
301 | return result; |
302 | } |
303 | |
304 | /*! |
305 | \fn bool QVersionNumber::operator<(const QVersionNumber &lhs, const QVersionNumber &rhs) |
306 | |
307 | Returns \c true if \a lhs is less than \a rhs; otherwise returns \c false. |
308 | |
309 | \sa QVersionNumber::compare() |
310 | */ |
311 | |
312 | /*! |
313 | \fn bool QVersionNumber::operator<=(const QVersionNumber &lhs, const QVersionNumber &rhs) |
314 | |
315 | Returns \c true if \a lhs is less than or equal to \a rhs; otherwise |
316 | returns \c false. |
317 | |
318 | \sa QVersionNumber::compare() |
319 | */ |
320 | |
321 | /*! |
322 | \fn bool QVersionNumber::operator>(const QVersionNumber &lhs, const QVersionNumber &rhs) |
323 | |
324 | Returns \c true if \a lhs is greater than \a rhs; otherwise returns \c |
325 | false. |
326 | |
327 | \sa QVersionNumber::compare() |
328 | */ |
329 | |
330 | /*! |
331 | \fn bool QVersionNumber::operator>=(const QVersionNumber &lhs, const QVersionNumber &rhs) |
332 | |
333 | Returns \c true if \a lhs is greater than or equal to \a rhs; otherwise |
334 | returns \c false. |
335 | |
336 | \sa QVersionNumber::compare() |
337 | */ |
338 | |
339 | /*! |
340 | \fn bool QVersionNumber::operator==(const QVersionNumber &lhs, const QVersionNumber &rhs) |
341 | |
342 | Returns \c true if \a lhs is equal to \a rhs; otherwise returns \c false. |
343 | |
344 | \sa QVersionNumber::compare() |
345 | */ |
346 | |
347 | /*! |
348 | \fn bool QVersionNumber::operator!=(const QVersionNumber &lhs, const QVersionNumber &rhs) |
349 | |
350 | Returns \c true if \a lhs is not equal to \a rhs; otherwise returns |
351 | \c false. |
352 | |
353 | \sa QVersionNumber::compare() |
354 | */ |
355 | |
356 | /*! |
357 | \fn QString QVersionNumber::toString() const |
358 | |
359 | Returns a string with all of the segments delimited by a period (\c{.}). |
360 | |
361 | \sa majorVersion(), minorVersion(), microVersion(), segments() |
362 | */ |
363 | QString QVersionNumber::toString() const |
364 | { |
365 | QString version; |
366 | version.reserve(asize: qMax(a: segmentCount() * 2 - 1, b: 0)); |
367 | bool first = true; |
368 | for (qsizetype i = 0; i < segmentCount(); ++i) { |
369 | if (!first) |
370 | version += u'.'; |
371 | version += QString::number(segmentAt(index: i)); |
372 | first = false; |
373 | } |
374 | return version; |
375 | } |
376 | |
377 | /*! |
378 | \fn QVersionNumber QVersionNumber::fromString(QAnyStringView string, qsizetype *suffixIndex) |
379 | \since 6.4 |
380 | |
381 | Constructs a QVersionNumber from a specially formatted \a string of |
382 | non-negative decimal numbers delimited by a period (\c{.}). |
383 | |
384 | Once the numerical segments have been parsed, the remainder of the string |
385 | is considered to be the suffix string. The start index of that string will be |
386 | stored in \a suffixIndex if it is not null. |
387 | |
388 | \snippet qversionnumber/main.cpp 3-latin1-1 |
389 | |
390 | \note In versions prior to Qt 6.4, this function was overloaded for QString, |
391 | QLatin1StringView and QStringView instead, and \a suffixIndex was an \c{int*}. |
392 | |
393 | \sa isNull() |
394 | */ |
395 | |
396 | static QVersionNumber from_string(QLatin1StringView string, qsizetype *suffixIndex) |
397 | { |
398 | // 32 should be more than enough, and, crucially, it means we're allocating |
399 | // not more (and often less) often when compared with direct QList usage |
400 | // for all possible segment counts (under the constraint that we don't want |
401 | // to keep more capacity around for the lifetime of the resulting |
402 | // QVersionNumber than required), esp. in the common case where the inline |
403 | // storage can be used. |
404 | QVarLengthArray<int, 32> seg; |
405 | |
406 | const char *start = string.begin(); |
407 | const char *lastGoodEnd = start; |
408 | const char *endOfString = string.end(); |
409 | |
410 | do { |
411 | // parsing as unsigned so a minus sign is rejected |
412 | auto [value, used] = qstrntoull(nptr: start, size: endOfString - start, base: 10); |
413 | if (used <= 0 || value > qulonglong(std::numeric_limits<int>::max())) |
414 | break; |
415 | seg.append(t: int(value)); |
416 | start += used + 1; |
417 | lastGoodEnd = start - 1; |
418 | } while (start < endOfString && *lastGoodEnd == '.'); |
419 | |
420 | if (suffixIndex) |
421 | *suffixIndex = lastGoodEnd - string.begin(); |
422 | |
423 | return QVersionNumber(seg); |
424 | } |
425 | |
426 | static QVersionNumber from_string(q_no_char8_t::QUtf8StringView string, qsizetype *suffixIndex) |
427 | { |
428 | return from_string(string: QLatin1StringView(string.data(), string.size()), suffixIndex); |
429 | } |
430 | |
431 | // in qstring.cpp |
432 | extern void qt_to_latin1(uchar *dst, const char16_t *uc, qsizetype len); |
433 | |
434 | static QVersionNumber from_string(QStringView string, qsizetype *suffixIndex) |
435 | { |
436 | QVarLengthArray<char> copy; |
437 | copy.resize(sz: string.size()); |
438 | qt_to_latin1(dst: reinterpret_cast<uchar*>(copy.data()), uc: string.utf16(), len: string.size()); |
439 | return from_string(string: QLatin1StringView(copy.data(), copy.size()), suffixIndex); |
440 | } |
441 | |
442 | QVersionNumber QVersionNumber::fromString(QAnyStringView string, qsizetype *suffixIndex) |
443 | { |
444 | return string.visit(v: [=] (auto string) { return from_string(string, suffixIndex); }); |
445 | } |
446 | |
447 | void QVersionNumber::SegmentStorage::setListData(const QList<int> &seg) |
448 | { |
449 | pointer_segments = new QList<int>(seg); |
450 | } |
451 | |
452 | void QVersionNumber::SegmentStorage::setListData(QList<int> &&seg) |
453 | { |
454 | pointer_segments = new QList<int>(std::move(seg)); |
455 | } |
456 | |
457 | void QVersionNumber::SegmentStorage::setListData(const int *first, const int *last) |
458 | { |
459 | pointer_segments = new QList<int>(first, last); |
460 | } |
461 | |
462 | void QVersionNumber::SegmentStorage::resize(qsizetype len) |
463 | { |
464 | if (isUsingPointer()) |
465 | pointer_segments->resize(size: len); |
466 | else |
467 | setInlineSize(len); |
468 | } |
469 | |
470 | void QVersionNumber::SegmentStorage::setVector(int len, int maj, int min, int mic) |
471 | { |
472 | pointer_segments = new QList<int>; |
473 | pointer_segments->resize(size: len); |
474 | pointer_segments->data()[0] = maj; |
475 | if (len > 1) { |
476 | pointer_segments->data()[1] = min; |
477 | if (len > 2) { |
478 | pointer_segments->data()[2] = mic; |
479 | } |
480 | } |
481 | } |
482 | |
483 | #ifndef QT_NO_DATASTREAM |
484 | /*! |
485 | \fn QDataStream& operator<<(QDataStream &out, |
486 | const QVersionNumber &version) |
487 | \relates QVersionNumber |
488 | |
489 | Writes the version number \a version to stream \a out. |
490 | |
491 | Note that this has nothing to do with QDataStream::version(). |
492 | */ |
493 | QDataStream& operator<<(QDataStream &out, const QVersionNumber &version) |
494 | { |
495 | out << version.segments(); |
496 | return out; |
497 | } |
498 | |
499 | /*! |
500 | \fn QDataStream& operator>>(QDataStream &in, QVersionNumber &version) |
501 | \relates QVersionNumber |
502 | |
503 | Reads a version number from stream \a in and stores it in \a version. |
504 | |
505 | Note that this has nothing to do with QDataStream::version(). |
506 | */ |
507 | QDataStream& operator>>(QDataStream &in, QVersionNumber &version) |
508 | { |
509 | if (!version.m_segments.isUsingPointer()) |
510 | version.m_segments.pointer_segments = new QList<int>; |
511 | in >> *version.m_segments.pointer_segments; |
512 | return in; |
513 | } |
514 | #endif |
515 | |
516 | #ifndef QT_NO_DEBUG_STREAM |
517 | QDebug operator<<(QDebug debug, const QVersionNumber &version) |
518 | { |
519 | QDebugStateSaver saver(debug); |
520 | debug.nospace().noquote(); |
521 | debug << "QVersionNumber(" << version.toString() << ")" ; |
522 | return debug; |
523 | } |
524 | #endif |
525 | |
526 | /*! |
527 | \relates QHash |
528 | \since 5.6 |
529 | |
530 | Returns the hash value for the \a key, using \a seed to seed the |
531 | calculation. |
532 | */ |
533 | size_t qHash(const QVersionNumber &key, size_t seed) |
534 | { |
535 | QtPrivate::QHashCombine hash; |
536 | for (int i = 0; i < key.segmentCount(); ++i) |
537 | seed = hash(seed, key.segmentAt(index: i)); |
538 | return seed; |
539 | } |
540 | |
541 | /*! |
542 | \class QTypeRevision |
543 | \inmodule QtCore |
544 | \since 6.0 |
545 | \brief The QTypeRevision class contains a lightweight representation of |
546 | a version number with two 8-bit segments, major and minor, either |
547 | of which can be unknown. |
548 | |
549 | Use this class to describe revisions of a type. Compatible revisions can be |
550 | expressed as increments of the minor version. Breaking changes can be |
551 | expressed as increments of the major version. The return values of |
552 | \l QMetaMethod::revision() and \l QMetaProperty::revision() can be passed to |
553 | \l QTypeRevision::fromEncodedVersion(). The resulting major and minor versions |
554 | specify in which Qt versions the properties and methods were added. |
555 | |
556 | \sa QMetaMethod::revision(), QMetaProperty::revision() |
557 | */ |
558 | |
559 | /*! |
560 | \fn template<typename Integer> static bool QTypeRevision::isValidSegment(Integer segment) |
561 | |
562 | Returns true if the given number can be used as either major or minor |
563 | version in a QTypeRevision. The valid range for \a segment is \c {>= 0} and \c {< 255}. |
564 | */ |
565 | |
566 | /*! |
567 | \fn QTypeRevision::QTypeRevision() |
568 | |
569 | Produces an invalid revision. |
570 | |
571 | \sa isValid() |
572 | */ |
573 | |
574 | /*! |
575 | \fn template <typename Major, typename Minor> static QTypeRevision QTypeRevision::fromVersion(Major majorVersion, Minor minorVersion) |
576 | |
577 | Produces a QTypeRevision from the given \a majorVersion and \a minorVersion, |
578 | both of which need to be a valid segments. |
579 | |
580 | \sa isValidSegment() |
581 | */ |
582 | |
583 | /*! |
584 | \fn template <typename Major> static QTypeRevision QTypeRevision::fromMajorVersion(Major majorVersion) |
585 | |
586 | Produces a QTypeRevision from the given \a majorVersion with an invalid minor |
587 | version. \a majorVersion needs to be a valid segment. |
588 | |
589 | \sa isValidSegment() |
590 | */ |
591 | |
592 | /*! |
593 | \fn template <typename Minor> static QTypeRevision QTypeRevision::fromMinorVersion(Minor minorVersion) |
594 | |
595 | Produces a QTypeRevision from the given \a minorVersion with an invalid major |
596 | version. \a minorVersion needs to be a valid segment. |
597 | |
598 | \sa isValidSegment() |
599 | */ |
600 | |
601 | /*! |
602 | \fn template <typename Integer> static QTypeRevision QTypeRevision::fromEncodedVersion(Integer value) |
603 | |
604 | Produces a QTypeRevision from the given \a value. \a value encodes both the |
605 | minor and major versions in the least significant and second least |
606 | significant byte, respectively. |
607 | |
608 | \a value must not have any bits outside the least significant two bytes set. |
609 | \c Integer needs to be at least 16 bits wide, and must not have a sign bit |
610 | in the least significant 16 bits. |
611 | |
612 | \sa toEncodedVersion() |
613 | */ |
614 | |
615 | /*! |
616 | \fn static QTypeRevision QTypeRevision::zero() |
617 | |
618 | Produces a QTypeRevision with major and minor version \c{0}. |
619 | */ |
620 | |
621 | /*! |
622 | \fn bool QTypeRevision::hasMajorVersion() const |
623 | |
624 | Returns true if the major version is known, otherwise false. |
625 | |
626 | \sa majorVersion(), hasMinorVersion() |
627 | */ |
628 | |
629 | /*! |
630 | \fn quint8 QTypeRevision::majorVersion() const |
631 | |
632 | Returns the major version encoded in the revision. |
633 | |
634 | \sa hasMajorVersion(), minorVersion() |
635 | */ |
636 | |
637 | /*! |
638 | \fn bool QTypeRevision::hasMinorVersion() const |
639 | |
640 | Returns true if the minor version is known, otherwise false. |
641 | |
642 | \sa minorVersion(), hasMajorVersion() |
643 | */ |
644 | |
645 | /*! |
646 | \fn quint8 QTypeRevision::minorVersion() const |
647 | |
648 | Returns the minor version encoded in the revision. |
649 | |
650 | \sa hasMinorVersion(), majorVersion() |
651 | */ |
652 | |
653 | /*! |
654 | \fn bool QTypeRevision::isValid() const |
655 | |
656 | Returns true if the major version or the minor version is known, |
657 | otherwise false. |
658 | |
659 | \sa hasMajorVersion(), hasMinorVersion() |
660 | */ |
661 | |
662 | /*! |
663 | \fn template<typename Integer> Integer QTypeRevision::toEncodedVersion() const |
664 | |
665 | Transforms the revision into an integer value, encoding the minor |
666 | version into the least significant byte, and the major version into |
667 | the second least significant byte. |
668 | |
669 | \c Integer needs to be at least 16 bits wide, and must not have a sign bit |
670 | in the least significant 16 bits. |
671 | |
672 | \sa fromEncodedVersion() |
673 | */ |
674 | |
675 | #ifndef QT_NO_DATASTREAM |
676 | /*! |
677 | \fn QDataStream& operator<<(QDataStream &out, const QTypeRevision &revision) |
678 | \relates QTypeRevision |
679 | \since 6.0 |
680 | |
681 | Writes the revision \a revision to stream \a out. |
682 | */ |
683 | QDataStream &operator<<(QDataStream &out, const QTypeRevision &revision) |
684 | { |
685 | return out << revision.toEncodedVersion<quint16>(); |
686 | } |
687 | |
688 | /*! |
689 | \fn QDataStream& operator>>(QDataStream &in, QTypeRevision &revision) |
690 | \relates QTypeRevision |
691 | \since 6.0 |
692 | |
693 | Reads a revision from stream \a in and stores it in \a revision. |
694 | */ |
695 | QDataStream &operator>>(QDataStream &in, QTypeRevision &revision) |
696 | { |
697 | quint16 value; |
698 | in >> value; |
699 | revision = QTypeRevision::fromEncodedVersion(value); |
700 | return in; |
701 | } |
702 | #endif |
703 | |
704 | #ifndef QT_NO_DEBUG_STREAM |
705 | QDebug operator<<(QDebug debug, const QTypeRevision &revision) |
706 | { |
707 | QDebugStateSaver saver(debug); |
708 | if (revision.hasMajorVersion()) { |
709 | if (revision.hasMinorVersion()) |
710 | debug.nospace() << revision.majorVersion() << '.' << revision.minorVersion(); |
711 | else |
712 | debug.nospace().noquote() << revision.majorVersion() << ".x" ; |
713 | } else { |
714 | if (revision.hasMinorVersion()) |
715 | debug << revision.minorVersion(); |
716 | else |
717 | debug.noquote() << "invalid" ; |
718 | } |
719 | return debug; |
720 | } |
721 | #endif |
722 | |
723 | /*! |
724 | \relates QHash |
725 | \since 6.0 |
726 | |
727 | Returns the hash value for the \a key, using \a seed to seed the |
728 | calculation. |
729 | */ |
730 | size_t qHash(const QTypeRevision &key, size_t seed) |
731 | { |
732 | return qHash(key: key.toEncodedVersion<quint16>(), seed); |
733 | } |
734 | |
735 | QT_END_NAMESPACE |
736 | |