ritsuko
Helper utilities for ArtifactDB C++ code
Loading...
Searching...
No Matches
parse_version_string.hpp
Go to the documentation of this file.
1#ifndef RITSUKO_PARSE_VERSION_HPP
2#define RITSUKO_PARSE_VERSION_HPP
3
4#include <stdexcept>
5#include <string>
6
12namespace ritsuko {
13
19struct Version {
23 Version() = default;
24
25 Version(int ma, int mi, int pa) {
26 // Don't move to initializer list due to GCC's decision
27 // to define a major() macro... thanks guys.
28 major = ma;
29 minor = mi;
30 patch = pa;
31 }
39 int major = 0;
40
44 int minor = 0;
45
49 int patch = 0;
50
51public:
58 bool eq(int maj, int min, int pat) const {
59 return (major == maj && minor == min && patch == pat);
60 }
61
68 bool ne(int maj, int min, int pat) const {
69 return !eq(maj, min, pat);
70 }
71
78 bool le(int maj, int min, int pat) const {
79 if (major == maj) {
80 if (minor == min) {
81 return patch <= pat;
82 }
83 return minor <= min;
84 }
85 return major <= maj;
86 }
87
94 bool lt(int maj, int min, int pat) const {
95 if (major == maj) {
96 if (minor == min) {
97 return patch < pat;
98 }
99 return minor < min;
100 }
101 return major < maj;
102 }
103
110 bool ge(int maj, int min, int pat) const {
111 return !lt(maj, min, pat);
112 }
113
120 bool gt(int maj, int min, int pat) const {
121 return !le(maj, min, pat);
122 }
123
124public:
129 bool operator==(const Version& rhs) const {
130 return eq(rhs.major, rhs.minor, rhs.patch);
131 }
132
137 bool operator!=(const Version& rhs) const {
138 return ne(rhs.major, rhs.minor, rhs.patch);
139 }
140
145 bool operator<(const Version& rhs) const {
146 return lt(rhs.major, rhs.minor, rhs.patch);
147 }
148
153 bool operator<=(const Version& rhs) const {
154 return le(rhs.major, rhs.minor, rhs.patch);
155 }
156
161 bool operator>(const Version& rhs) const {
162 return gt(rhs.major, rhs.minor, rhs.patch);
163 }
164
169 bool operator>=(const Version& rhs) const {
170 return ge(rhs.major, rhs.minor, rhs.patch);
171 }
172};
173
177inline void throw_version_error(const char* version_string, size_t size, const char* reason) {
178 std::string message(version_string, version_string + size);
179 message = "invalid version string '" + message + "' ";
180 message += reason;
181 throw std::runtime_error(message.c_str());
182}
194inline Version parse_version_string(const char* version_string, size_t size, bool skip_patch = false) {
195 int major = 0, minor = 0, patch = 0;
196 size_t i = 0, end = size;
197
198 // MAJOR VERSION.
199 if (size == 0) {
200 throw std::runtime_error("version string is empty");
201 }
202 if (version_string[i] == '0') {
203 ++i;
204 if (i < end && version_string[i] != '.') {
205 throw_version_error(version_string, size, "has leading zeros in its major version");
206 }
207 } else {
208 while (i < end && version_string[i] != '.') {
209 if (!std::isdigit(version_string[i])) {
210 throw_version_error(version_string, size, "contains non-digit characters");
211 }
212 major *= 10;
213 major += version_string[i] - '0';
214 ++i;
215 }
216 }
217
218 // MINOR VERSION.
219 if (i == end) {
220 throw_version_error(version_string, size, "is missing a minor version");
221 }
222 ++i; // get past the period and check again.
223 if (i == end) {
224 throw_version_error(version_string, size, "is missing a minor version");
225 }
226
227 if (version_string[i] != '0') {
228 while (i < end && version_string[i] != '.') {
229 if (!std::isdigit(version_string[i])) {
230 throw_version_error(version_string, size, "contains non-digit characters");
231 }
232 minor *= 10;
233 minor += version_string[i] - '0';
234 ++i;
235 }
236
237 } else {
238 ++i;
239 if (i < end && version_string[i] != '.') {
240 throw_version_error(version_string, size, "has leading zeros in its minor version");
241 }
242 }
243
244 if (skip_patch) {
245 if (i != end) {
246 throw_version_error(version_string, size, "should not have a patch version");
247 }
248 return Version(major, minor, 0);
249 }
250
251 // PATCH VERSION.
252 if (i == end) {
253 throw_version_error(version_string, size, "is missing a patch version");
254 }
255 ++i; // get past the period and check again.
256 if (i == end) {
257 throw_version_error(version_string, size, "is missing a patch version");
258 }
259
260 if (version_string[i] == '0' && i + 1 < end) {
261 throw_version_error(version_string, size, "has leading zeros in its patch version");
262 }
263 while (i < end) {
264 if (!std::isdigit(version_string[i])) {
265 throw_version_error(version_string, size, "contains non-digit characters");
266 }
267 patch *= 10;
268 patch += version_string[i] - '0';
269 ++i;
270 }
271
272 return Version(major, minor, patch);
273}
274
275}
276
277#endif
Assorted helper functions for parsing and validation.
Definition choose_missing_placeholder.hpp:15
Version parse_version_string(const char *version_string, size_t size, bool skip_patch=false)
Definition parse_version_string.hpp:194
Version number.
Definition parse_version_string.hpp:19
bool eq(int maj, int min, int pat) const
Definition parse_version_string.hpp:58
bool operator>(const Version &rhs) const
Definition parse_version_string.hpp:161
bool operator>=(const Version &rhs) const
Definition parse_version_string.hpp:169
bool ne(int maj, int min, int pat) const
Definition parse_version_string.hpp:68
int major
Definition parse_version_string.hpp:39
bool ge(int maj, int min, int pat) const
Definition parse_version_string.hpp:110
bool operator<=(const Version &rhs) const
Definition parse_version_string.hpp:153
bool operator==(const Version &rhs) const
Definition parse_version_string.hpp:129
bool lt(int maj, int min, int pat) const
Definition parse_version_string.hpp:94
int minor
Definition parse_version_string.hpp:44
bool gt(int maj, int min, int pat) const
Definition parse_version_string.hpp:120
bool le(int maj, int min, int pat) const
Definition parse_version_string.hpp:78
int patch
Definition parse_version_string.hpp:49
bool operator<(const Version &rhs) const
Definition parse_version_string.hpp:145
bool operator!=(const Version &rhs) const
Definition parse_version_string.hpp:137