qBittorrent
version.h
Go to the documentation of this file.
1 /*
2  * Bittorrent Client using Qt and libtorrent.
3  * Copyright (C) 2016 Eugene Shalygin
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  *
19  * In addition, as a special exception, the copyright holders give permission to
20  * link this program with the OpenSSL project's "OpenSSL" library (or with
21  * modified versions of it that use the same license as the "OpenSSL" library),
22  * and distribute the linked executables. You must obey the GNU General Public
23  * License in all respects for all of the code used other than "OpenSSL". If you
24  * modify file(s), you may extend this exception to your version of the file(s),
25  * but you are not obligated to do so. If you do not wish to do so, delete this
26  * exception statement from your version.
27  */
28 
29 #pragma once
30 
31 #include <array>
32 
33 #include <QDebug>
34 #include <QString>
35 
36 #include "base/exceptions.h"
37 
38 namespace Utils
39 {
40  template <typename T, std::size_t N, std::size_t Mandatory = N>
41  class Version
42  {
43  static_assert(N > 0, "The number of version components may not be smaller than 1");
44  static_assert(N >= Mandatory,
45  "The number of mandatory components may not be larger than the total number of components");
46 
47  public:
48  typedef T ComponentType;
50 
51  constexpr Version() = default;
52 
53  template <typename ... Other>
54  constexpr Version(Other ... components)
55  : m_components {{static_cast<T>(components) ...}}
56  {
57  }
58 
65  Version(const QString &version)
66  : Version {version.split(QLatin1Char('.'))}
67  {
68  }
69 
76  Version(const QByteArray &version)
77  : Version {version.split('.')}
78  {
79  }
80 
81  constexpr ComponentType majorNumber() const
82  {
83  static_assert(N >= 1, "The number of version components is too small");
84  return m_components[0];
85  }
86 
87  constexpr ComponentType minorNumber() const
88  {
89  static_assert(N >= 2, "The number of version components is too small");
90  return m_components[1];
91  }
92 
93  constexpr ComponentType revisionNumber() const
94  {
95  static_assert(N >= 3, "The number of version components is too small");
96  return m_components[2];
97  }
98 
99  constexpr ComponentType patchNumber() const
100  {
101  static_assert(N >= 4, "The number of version components is too small");
102  return m_components[3];
103  }
104 
105  constexpr ComponentType operator[](const std::size_t i) const
106  {
107  return m_components.at(i);
108  }
109 
110  operator QString() const
111  {
112  // find the last one non-zero component
113  std::size_t lastSignificantIndex = N - 1;
114  while ((lastSignificantIndex > 0) && ((*this)[lastSignificantIndex] == 0))
115  --lastSignificantIndex;
116 
117  if (lastSignificantIndex + 1 < Mandatory) // lastSignificantIndex >= 0
118  lastSignificantIndex = Mandatory - 1; // and Mandatory >= 1
119 
120  QString res = QString::number((*this)[0]);
121  for (std::size_t i = 1; i <= lastSignificantIndex; ++i)
122  res += QLatin1Char('.') + QString::number((*this)[i]);
123  return res;
124  }
125 
126  constexpr bool isValid() const
127  {
128  return (*this != ThisType {});
129  }
130 
131  // TODO: remove manually defined operators and use compiler generated `operator<=>()` in C++20
132  friend bool operator==(const ThisType &left, const ThisType &right)
133  {
134  return (left.m_components == right.m_components);
135  }
136 
137  friend bool operator<(const ThisType &left, const ThisType &right)
138  {
139  return (left.m_components < right.m_components);
140  }
141 
142  template <typename StringClassWithSplitMethod>
143  static Version tryParse(const StringClassWithSplitMethod &s, const Version &defaultVersion)
144  {
145  try
146  {
147  return Version(s);
148  }
149  catch (const RuntimeError &error)
150  {
151  qDebug() << "Error parsing version:" << error.message();
152  return defaultVersion;
153  }
154  }
155 
156  private:
157  using ComponentsArray = std::array<T, N>;
158 
159  template <typename StringsList>
160  static ComponentsArray parseList(const StringsList &versionParts)
161  {
162  if ((static_cast<std::size_t>(versionParts.size()) > N)
163  || (static_cast<std::size_t>(versionParts.size()) < Mandatory))
164  {
165  throw RuntimeError(QLatin1String("Incorrect number of version components"));
166  }
167 
168  bool ok = false;
169  ComponentsArray res {{}};
170  for (std::size_t i = 0; i < static_cast<std::size_t>(versionParts.size()); ++i)
171  {
172  res[i] = static_cast<T>(versionParts[static_cast<typename StringsList::size_type>(i)].toInt(&ok));
173  if (!ok)
174  throw RuntimeError(QLatin1String("Can not parse version component"));
175  }
176  return res;
177  }
178 
179  template <typename StringsList>
180  Version(const StringsList &versionParts)
181  : m_components (parseList(versionParts)) // GCC 4.8.4 has problems with the uniform initializer here
182  {
183  }
184 
185  ComponentsArray m_components {{}};
186  };
187 
188  template <typename T, std::size_t N, std::size_t Mandatory>
189  constexpr bool operator!=(const Version<T, N, Mandatory> &left, const Version<T, N, Mandatory> &right)
190  {
191  return !(left == right);
192  }
193 
194  template <typename T, std::size_t N, std::size_t Mandatory>
195  constexpr bool operator>(const Version<T, N, Mandatory> &left, const Version<T, N, Mandatory> &right)
196  {
197  return (right < left);
198  }
199 
200  template <typename T, std::size_t N, std::size_t Mandatory>
201  constexpr bool operator<=(const Version<T, N, Mandatory> &left, const Version<T, N, Mandatory> &right)
202  {
203  return !(left > right);
204  }
205 
206  template <typename T, std::size_t N, std::size_t Mandatory>
207  constexpr bool operator>=(const Version<T, N, Mandatory> &left, const Version<T, N, Mandatory> &right)
208  {
209  return !(left < right);
210  }
211 }
QString message() const noexcept
Definition: exceptions.cpp:36
static ComponentsArray parseList(const StringsList &versionParts)
Definition: version.h:160
static Version tryParse(const StringClassWithSplitMethod &s, const Version &defaultVersion)
Definition: version.h:143
friend bool operator<(const ThisType &left, const ThisType &right)
Definition: version.h:137
Version(const QByteArray &version)
Creates version from byte array in format "x.y.z".
Definition: version.h:76
ComponentsArray m_components
Definition: version.h:185
constexpr ComponentType minorNumber() const
Definition: version.h:87
Version(const StringsList &versionParts)
Definition: version.h:180
Version< T, N, Mandatory > ThisType
Definition: version.h:49
Version(const QString &version)
Creates version from string in format "x.y.z".
Definition: version.h:65
std::array< T, N > ComponentsArray
Definition: version.h:157
friend bool operator==(const ThisType &left, const ThisType &right)
Definition: version.h:132
constexpr Version(Other ... components)
Definition: version.h:54
constexpr ComponentType patchNumber() const
Definition: version.h:99
constexpr ComponentType operator[](const std::size_t i) const
Definition: version.h:105
constexpr bool isValid() const
Definition: version.h:126
constexpr ComponentType revisionNumber() const
Definition: version.h:93
constexpr ComponentType majorNumber() const
Definition: version.h:81
constexpr Version()=default
bool operator!=(const Digest32< N > &left, const Digest32< N > &right)
Definition: digest32.h:104
constexpr bool operator>(const Version< T, N, Mandatory > &left, const Version< T, N, Mandatory > &right)
Definition: version.h:195
constexpr bool operator>=(const Version< T, N, Mandatory > &left, const Version< T, N, Mandatory > &right)
Definition: version.h:207
constexpr bool operator<=(const Version< T, N, Mandatory > &left, const Version< T, N, Mandatory > &right)
Definition: version.h:201