1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
|
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2016 Intel Corporation.
** Copyright (C) 2014 Keith Gardner <kreios4004@gmail.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QVERSIONNUMBER_H
#define QVERSIONNUMBER_H
#include <QtCore/qnamespace.h>
#include <QtCore/qstring.h>
#include <QtCore/qvector.h>
#include <QtCore/qmetatype.h>
#include <QtCore/qtypeinfo.h>
QT_BEGIN_NAMESPACE
class QVersionNumber;
Q_CORE_EXPORT uint qHash(const QVersionNumber &key, uint seed = 0);
#ifndef QT_NO_DATASTREAM
Q_CORE_EXPORT QDataStream& operator<<(QDataStream &out, const QVersionNumber &version);
Q_CORE_EXPORT QDataStream& operator>>(QDataStream &in, QVersionNumber &version);
#endif
class QVersionNumber
{
/*
* QVersionNumber stores small values inline, without memory allocation.
* We do that by setting the LSB in the pointer that would otherwise hold
* the longer form of the segments.
* The constants below help us deal with the permutations for 32- and 64-bit,
* little- and big-endian architectures.
*/
enum {
// in little-endian, inline_segments[0] is shared with the pointer's LSB, while
// in big-endian, it's inline_segments[7]
InlineSegmentMarker = Q_BYTE_ORDER == Q_LITTLE_ENDIAN ? 0 : sizeof(void*) - 1,
InlineSegmentStartIdx = !InlineSegmentMarker, // 0 for BE, 1 for LE
InlineSegmentCount = sizeof(void*) - 1
};
Q_STATIC_ASSERT(InlineSegmentCount >= 3); // at least major, minor, micro
struct SegmentStorage {
// Note: we alias the use of dummy and inline_segments in the use of the
// union below. This is undefined behavior in C++98, but most compilers implement
// the C++11 behavior. The one known exception is older versions of Sun Studio.
union {
quintptr dummy;
qint8 inline_segments[sizeof(void*)];
QVector<int> *pointer_segments;
};
// set the InlineSegmentMarker and set length to zero
SegmentStorage() Q_DECL_NOTHROW : dummy(1) {}
SegmentStorage(const QVector<int> &seg)
{
if (dataFitsInline(seg.begin(), seg.size()))
setInlineData(seg.begin(), seg.size());
else
pointer_segments = new QVector<int>(seg);
}
SegmentStorage(const SegmentStorage &other)
{
if (other.isUsingPointer())
pointer_segments = new QVector<int>(*other.pointer_segments);
else
dummy = other.dummy;
}
SegmentStorage &operator=(const SegmentStorage &other)
{
if (isUsingPointer() && other.isUsingPointer()) {
*pointer_segments = *other.pointer_segments;
} else if (other.isUsingPointer()) {
pointer_segments = new QVector<int>(*other.pointer_segments);
} else {
if (isUsingPointer())
delete pointer_segments;
dummy = other.dummy;
}
return *this;
}
#ifdef Q_COMPILER_RVALUE_REFS
SegmentStorage(SegmentStorage &&other) Q_DECL_NOTHROW
: dummy(other.dummy)
{
other.dummy = 1;
}
SegmentStorage &operator=(SegmentStorage &&other) Q_DECL_NOTHROW
{
qSwap(dummy, other.dummy);
return *this;
}
explicit SegmentStorage(QVector<int> &&seg)
{
if (dataFitsInline(seg.begin(), seg.size()))
setInlineData(seg.begin(), seg.size());
else
pointer_segments = new QVector<int>(std::move(seg));
}
#endif
#ifdef Q_COMPILER_INITIALIZER_LISTS
SegmentStorage(std::initializer_list<int> args)
{
if (dataFitsInline(args.begin(), int(args.size()))) {
setInlineData(args.begin(), int(args.size()));
} else {
pointer_segments = new QVector<int>(args);
}
}
#endif
~SegmentStorage() { if (isUsingPointer()) delete pointer_segments; }
bool isUsingPointer() const Q_DECL_NOTHROW
{ return (inline_segments[InlineSegmentMarker] & 1) == 0; }
int size() const Q_DECL_NOTHROW
{ return isUsingPointer() ? pointer_segments->size() : (inline_segments[InlineSegmentMarker] >> 1); }
void setInlineSize(int len)
{ inline_segments[InlineSegmentMarker] = 1 + 2 * len; }
void resize(int len)
{
if (isUsingPointer())
pointer_segments->resize(len);
else
setInlineSize(len);
}
int at(int index) const
{
return isUsingPointer() ?
pointer_segments->at(index) :
inline_segments[InlineSegmentStartIdx + index];
}
void setSegments(int len, int maj, int min = 0, int mic = 0)
{
if (maj == qint8(maj) && min == qint8(min) && mic == qint8(mic)) {
int data[] = { maj, min, mic };
setInlineData(data, len);
} else {
setVector(len, maj, min, mic);
}
}
private:
static bool dataFitsInline(const int *data, int len)
{
if (len > InlineSegmentCount)
return false;
for (int i = 0; i < len; ++i)
if (data[i] != qint8(data[i]))
return false;
return true;
}
void setInlineData(const int *data, int len)
{
dummy = 1 + len * 2;
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
for (int i = 0; i < len; ++i)
dummy |= quintptr(data[i] & 0xFF) << (8 * (i + 1));
#elif Q_BYTE_ORDER == Q_BIG_ENDIAN
for (int i = 0; i < len; ++i)
dummy |= quintptr(data[i] & 0xFF) << (8 * (sizeof(void *) - i - 1));
#else
// the code above is equivalent to:
setInlineSize(len);
for (int i = 0; i < len; ++i)
inline_segments[InlineSegmentStartIdx + i] = data[i] & 0xFF;
#endif
}
Q_CORE_EXPORT void setVector(int len, int maj, int min, int mic);
} m_segments;
public:
inline QVersionNumber() Q_DECL_NOTHROW
: m_segments()
{}
inline explicit QVersionNumber(const QVector<int> &seg)
: m_segments(seg)
{}
// compiler-generated copy/move ctor/assignment operators and the destructor are ok
#ifdef Q_COMPILER_RVALUE_REFS
explicit QVersionNumber(QVector<int> &&seg)
: m_segments(std::move(seg))
{}
#endif
#ifdef Q_COMPILER_INITIALIZER_LISTS
inline QVersionNumber(std::initializer_list<int> args)
: m_segments(args)
{}
#endif
inline explicit QVersionNumber(int maj)
{ m_segments.setSegments(1, maj); }
inline explicit QVersionNumber(int maj, int min)
{ m_segments.setSegments(2, maj, min); }
inline explicit QVersionNumber(int maj, int min, int mic)
{ m_segments.setSegments(3, maj, min, mic); }
Q_REQUIRED_RESULT inline bool isNull() const Q_DECL_NOTHROW
{ return segmentCount() == 0; }
Q_REQUIRED_RESULT inline bool isNormalized() const Q_DECL_NOTHROW
{ return isNull() || segmentAt(segmentCount() - 1) != 0; }
Q_REQUIRED_RESULT inline int majorVersion() const Q_DECL_NOTHROW
{ return segmentAt(0); }
Q_REQUIRED_RESULT inline int minorVersion() const Q_DECL_NOTHROW
{ return segmentAt(1); }
Q_REQUIRED_RESULT inline int microVersion() const Q_DECL_NOTHROW
{ return segmentAt(2); }
Q_REQUIRED_RESULT Q_CORE_EXPORT QVersionNumber normalized() const;
Q_REQUIRED_RESULT Q_CORE_EXPORT QVector<int> segments() const;
Q_REQUIRED_RESULT inline int segmentAt(int index) const Q_DECL_NOTHROW
{ return (m_segments.size() > index) ? m_segments.at(index) : 0; }
Q_REQUIRED_RESULT inline int segmentCount() const Q_DECL_NOTHROW
{ return m_segments.size(); }
Q_REQUIRED_RESULT Q_CORE_EXPORT bool isPrefixOf(const QVersionNumber &other) const Q_DECL_NOTHROW;
Q_REQUIRED_RESULT Q_CORE_EXPORT static int compare(const QVersionNumber &v1, const QVersionNumber &v2) Q_DECL_NOTHROW;
Q_REQUIRED_RESULT Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber commonPrefix(const QVersionNumber &v1, const QVersionNumber &v2);
Q_REQUIRED_RESULT Q_CORE_EXPORT QString toString() const;
#if QT_STRINGVIEW_LEVEL < 2
Q_REQUIRED_RESULT Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber fromString(const QString &string, int *suffixIndex = nullptr);
#endif
Q_REQUIRED_RESULT Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber fromString(QLatin1String string, int *suffixIndex = nullptr);
Q_REQUIRED_RESULT Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber fromString(QStringView string, int *suffixIndex = nullptr);
private:
#ifndef QT_NO_DATASTREAM
friend Q_CORE_EXPORT QDataStream& operator>>(QDataStream &in, QVersionNumber &version);
#endif
friend Q_CORE_EXPORT uint qHash(const QVersionNumber &key, uint seed);
};
Q_DECLARE_TYPEINFO(QVersionNumber, Q_MOVABLE_TYPE);
#ifndef QT_NO_DEBUG_STREAM
Q_CORE_EXPORT QDebug operator<<(QDebug, const QVersionNumber &version);
#endif
Q_REQUIRED_RESULT inline bool operator> (const QVersionNumber &lhs, const QVersionNumber &rhs) Q_DECL_NOTHROW
{ return QVersionNumber::compare(lhs, rhs) > 0; }
Q_REQUIRED_RESULT inline bool operator>=(const QVersionNumber &lhs, const QVersionNumber &rhs) Q_DECL_NOTHROW
{ return QVersionNumber::compare(lhs, rhs) >= 0; }
Q_REQUIRED_RESULT inline bool operator< (const QVersionNumber &lhs, const QVersionNumber &rhs) Q_DECL_NOTHROW
{ return QVersionNumber::compare(lhs, rhs) < 0; }
Q_REQUIRED_RESULT inline bool operator<=(const QVersionNumber &lhs, const QVersionNumber &rhs) Q_DECL_NOTHROW
{ return QVersionNumber::compare(lhs, rhs) <= 0; }
Q_REQUIRED_RESULT inline bool operator==(const QVersionNumber &lhs, const QVersionNumber &rhs) Q_DECL_NOTHROW
{ return QVersionNumber::compare(lhs, rhs) == 0; }
Q_REQUIRED_RESULT inline bool operator!=(const QVersionNumber &lhs, const QVersionNumber &rhs) Q_DECL_NOTHROW
{ return QVersionNumber::compare(lhs, rhs) != 0; }
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QVersionNumber)
#endif //QVERSIONNUMBER_H
|