xrpld
Toggle main menu visibility
Loading...
Searching...
No Matches
libxrpl
beast
core
libxrpl/beast/core/SemanticVersion.cpp
1
#include <xrpl/beast/core/SemanticVersion.h>
2
3
#include <xrpl/beast/core/LexicalCast.h>
4
#include <xrpl/beast/utility/instrumentation.h>
5
6
#include <
algorithm
>
7
#include <
cctype
>
8
#include <
limits
>
9
#include <
locale
>
10
#include <
ranges
>
11
#include <
stdexcept
>
12
#include <
string
>
13
#include <
string_view
>
14
15
namespace
beast
{
16
17
std::string
18
printIdentifiers
(
SemanticVersion::IdentifierList
const
& list)
19
{
20
std::string
ret;
21
22
for
(
auto
const
& x : list)
23
{
24
if
(!ret.
empty
())
25
ret +=
"."
;
26
ret += x;
27
}
28
29
return
ret;
30
}
31
32
bool
33
isNumeric
(
std::string
const
& s)
34
{
35
int
n = 0;
36
37
// Must be convertible to an integer
38
if
(!
lexicalCastChecked
(n, s))
39
return
false
;
40
41
// Must not have leading zeroes
42
return
std::to_string
(n) == s;
43
}
44
45
bool
46
chop
(
std::string
const
& what,
std::string
& input)
47
{
48
auto
ret = input.
find
(what);
49
50
if
(ret != 0)
51
return
false
;
52
53
input.
erase
(0, what.
size
());
54
return
true
;
55
}
56
57
bool
58
chopUInt
(
int
& value,
int
limit,
std::string
& input)
59
{
60
// Must not be empty
61
if
(input.
empty
())
62
return
false
;
63
64
auto
leftIter =
std::ranges::find_if_not
(
65
input, [](std::string::value_type c) {
return
std::isdigit(c,
std::locale::classic
()); });
66
67
std::string
const
item(input.
begin
(), leftIter);
68
69
// Must not be empty
70
if
(item.empty())
71
return
false
;
72
73
int
n = 0;
74
75
// Must be convertible to an integer
76
if
(!
lexicalCastChecked
(n, item))
77
return
false
;
78
79
// Must not have leading zeroes
80
if
(
std::to_string
(n) != item)
81
return
false
;
82
83
// Must not be out of range
84
if
(n < 0 || n > limit)
85
return
false
;
86
87
input.
erase
(input.
begin
(), leftIter);
88
value = n;
89
90
return
true
;
91
}
92
93
bool
94
extractIdentifier
(
std::string
& value,
bool
allowLeadingZeroes,
std::string
& input)
95
{
96
// Must not be empty
97
if
(input.
empty
())
98
return
false
;
99
100
// Must not have a leading 0
101
if
(!allowLeadingZeroes && input[0] ==
'0'
)
102
return
false
;
103
104
auto
last =
105
input.
find_first_not_of
(
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-"
);
106
107
// Must not be empty
108
if
(last == 0)
109
return
false
;
110
111
value = input.
substr
(0, last);
112
input.
erase
(0, last);
113
return
true
;
114
}
115
116
bool
117
extractIdentifiers
(
118
SemanticVersion::IdentifierList
& identifiers,
119
bool
allowLeadingZeroes,
120
std::string
& input)
121
{
122
if
(input.
empty
())
123
return
false
;
124
125
do
126
{
127
std::string
s;
128
129
if
(!
extractIdentifier
(s, allowLeadingZeroes, input))
130
return
false
;
131
identifiers.
push_back
(s);
132
}
while
(
chop
(
"."
, input));
133
134
return
true
;
135
}
136
137
//------------------------------------------------------------------------------
138
139
SemanticVersion::SemanticVersion
() :
majorVersion
(0),
minorVersion
(0),
patchVersion
(0)
140
{
141
}
142
143
SemanticVersion::SemanticVersion
(
std::string_view
version) :
SemanticVersion
()
144
{
145
if
(!
parse
(version))
146
throw
std::invalid_argument
(
"invalid version string"
);
147
}
148
149
bool
150
SemanticVersion::parse
(
std::string_view
input)
151
{
152
// May not have leading or trailing whitespace
153
auto
leftIter =
std::ranges::find_if_not
(
154
input, [](std::string::value_type c) {
return
std::isspace(c,
std::locale::classic
()); });
155
156
auto
rightIter =
157
std::ranges::find_if_not
(std::ranges::reverse_view(input), [](std::string::value_type c) {
158
return
std::isspace(c,
std::locale::classic
());
159
}).base();
160
161
// Must not be empty!
162
if
(leftIter >= rightIter)
163
return
false
;
164
165
std::string
version(leftIter, rightIter);
166
167
// May not have leading or trailing whitespace
168
if
(version != input)
169
return
false
;
170
171
// Must have major version number
172
if
(!
chopUInt
(
majorVersion
,
std::numeric_limits<int>::max
(), version))
173
return
false
;
174
if
(!
chop
(
"."
, version))
175
return
false
;
176
177
// Must have minor version number
178
if
(!
chopUInt
(
minorVersion
,
std::numeric_limits<int>::max
(), version))
179
return
false
;
180
if
(!
chop
(
"."
, version))
181
return
false
;
182
183
// Must have patch version number
184
if
(!
chopUInt
(
patchVersion
,
std::numeric_limits<int>::max
(), version))
185
return
false
;
186
187
// May have pre-release identifier list
188
if
(
chop
(
"-"
, version))
189
{
190
if
(!
extractIdentifiers
(
preReleaseIdentifiers
,
false
, version))
191
return
false
;
192
193
// Must not be empty
194
if
(
preReleaseIdentifiers
.empty())
195
return
false
;
196
}
197
198
// May have metadata identifier list
199
if
(
chop
(
"+"
, version))
200
{
201
if
(!
extractIdentifiers
(
metaData
,
true
, version))
202
return
false
;
203
204
// Must not be empty
205
if
(
metaData
.empty())
206
return
false
;
207
}
208
209
return
version.
empty
();
210
}
211
212
std::string
213
SemanticVersion::print
()
const
214
{
215
std::string
s;
216
217
s =
std::to_string
(
majorVersion
) +
"."
+
std::to_string
(
minorVersion
) +
"."
+
218
std::to_string
(
patchVersion
);
219
220
if
(!
preReleaseIdentifiers
.empty())
221
{
222
s +=
"-"
;
223
s +=
printIdentifiers
(
preReleaseIdentifiers
);
224
}
225
226
if
(!
metaData
.empty())
227
{
228
s +=
"+"
;
229
s +=
printIdentifiers
(
metaData
);
230
}
231
232
return
s;
233
}
234
235
int
236
compare
(
SemanticVersion
const
& lhs,
SemanticVersion
const
& rhs)
237
{
238
if
(lhs.
majorVersion
> rhs.
majorVersion
)
239
{
240
return
1;
241
}
242
if
(lhs.
majorVersion
< rhs.
majorVersion
)
243
{
244
return
-1;
245
}
246
247
if
(lhs.
minorVersion
> rhs.
minorVersion
)
248
{
249
return
1;
250
}
251
if
(lhs.
minorVersion
< rhs.
minorVersion
)
252
{
253
return
-1;
254
}
255
256
if
(lhs.
patchVersion
> rhs.
patchVersion
)
257
{
258
return
1;
259
}
260
if
(lhs.
patchVersion
< rhs.
patchVersion
)
261
{
262
return
-1;
263
}
264
265
if
(lhs.
isPreRelease
() || rhs.
isPreRelease
())
266
{
267
// Pre-releases have a lower precedence
268
if
(lhs.
isRelease
() && rhs.
isPreRelease
())
269
{
270
return
1;
271
}
272
if
(lhs.
isPreRelease
() && rhs.
isRelease
())
273
{
274
return
-1;
275
}
276
277
// Compare pre-release identifiers
278
for
(
int
i = 0;
279
i <
std::max
(lhs.
preReleaseIdentifiers
.
size
(), rhs.
preReleaseIdentifiers
.
size
());
280
++i)
281
{
282
// A larger list of identifiers has a higher precedence
283
if
(i >= rhs.
preReleaseIdentifiers
.
size
())
284
{
285
return
1;
286
}
287
if
(i >= lhs.
preReleaseIdentifiers
.
size
())
288
{
289
return
-1;
290
}
291
292
std::string
const
& left(lhs.
preReleaseIdentifiers
[i]);
293
std::string
const
& right(rhs.
preReleaseIdentifiers
[i]);
294
295
// Numeric identifiers have lower precedence
296
if
(!
isNumeric
(left) &&
isNumeric
(right))
297
{
298
return
1;
299
}
300
if
(
isNumeric
(left) && !
isNumeric
(right))
301
{
302
return
-1;
303
}
304
305
if
(
isNumeric
(left))
306
{
307
XRPL_ASSERT(
isNumeric
(right),
"beast::compare : both inputs numeric"
);
308
309
int
const
iLeft(
lexicalCastThrow<int>
(left));
310
int
const
iRight(
lexicalCastThrow<int>
(right));
311
312
if
(iLeft > iRight)
313
{
314
return
1;
315
}
316
if
(iLeft < iRight)
317
{
318
return
-1;
319
}
320
}
321
else
322
{
323
XRPL_ASSERT(!
isNumeric
(right),
"beast::compare : both inputs non-numeric"
);
324
325
int
const
result = left.compare(right);
326
327
if
(result != 0)
328
return
result;
329
}
330
}
331
}
332
333
// metadata is ignored
334
335
return
0;
336
}
337
338
}
// namespace beast
algorithm
std::string
std::string_view
std::string::begin
T begin(T... args)
cctype
beast::SemanticVersion
A Semantic Version number.
Definition
SemanticVersion.h:18
beast::SemanticVersion::metaData
IdentifierList metaData
Definition
SemanticVersion.h:27
beast::SemanticVersion::preReleaseIdentifiers
IdentifierList preReleaseIdentifiers
Definition
SemanticVersion.h:26
beast::SemanticVersion::majorVersion
int majorVersion
Definition
SemanticVersion.h:22
beast::SemanticVersion::minorVersion
int minorVersion
Definition
SemanticVersion.h:23
beast::SemanticVersion::patchVersion
int patchVersion
Definition
SemanticVersion.h:24
beast::SemanticVersion::isPreRelease
bool isPreRelease() const noexcept
Definition
SemanticVersion.h:53
beast::SemanticVersion::parse
bool parse(std::string_view input)
Parse a semantic version string.
Definition
libxrpl/beast/core/SemanticVersion.cpp:150
beast::SemanticVersion::print
std::string print() const
Produce a string from semantic version components.
Definition
libxrpl/beast/core/SemanticVersion.cpp:213
beast::SemanticVersion::SemanticVersion
SemanticVersion()
Definition
libxrpl/beast/core/SemanticVersion.cpp:139
beast::SemanticVersion::isRelease
bool isRelease() const noexcept
Definition
SemanticVersion.h:48
beast::SemanticVersion::IdentifierList
std::vector< std::string > IdentifierList
Definition
SemanticVersion.h:20
std::locale::classic
T classic(T... args)
std::string::empty
T empty(T... args)
std::string::erase
T erase(T... args)
std::string::find_first_not_of
T find_first_not_of(T... args)
std::string::find
T find(T... args)
std::invalid_argument
limits
locale
std::numeric_limits::max
T max(T... args)
beast
Definition
base_uint.h:697
beast::compare
int compare(SemanticVersion const &lhs, SemanticVersion const &rhs)
Compare two SemanticVersions against each other.
Definition
libxrpl/beast/core/SemanticVersion.cpp:236
beast::lexicalCastThrow
constexpr Out lexicalCastThrow(In in)
Convert from one type to another, throw on error.
Definition
LexicalCast.h:195
beast::isNumeric
bool isNumeric(std::string const &s)
Definition
libxrpl/beast/core/SemanticVersion.cpp:33
beast::extractIdentifiers
bool extractIdentifiers(SemanticVersion::IdentifierList &identifiers, bool allowLeadingZeroes, std::string &input)
Definition
libxrpl/beast/core/SemanticVersion.cpp:117
beast::chop
bool chop(std::string const &what, std::string &input)
Definition
libxrpl/beast/core/SemanticVersion.cpp:46
beast::extractIdentifier
bool extractIdentifier(std::string &value, bool allowLeadingZeroes, std::string &input)
Definition
libxrpl/beast/core/SemanticVersion.cpp:94
beast::printIdentifiers
std::string printIdentifiers(SemanticVersion::IdentifierList const &list)
Definition
libxrpl/beast/core/SemanticVersion.cpp:18
beast::lexicalCastChecked
constexpr bool lexicalCastChecked(Out &out, In in)
Intelligently convert from one type to another.
Definition
LexicalCast.h:181
beast::chopUInt
bool chopUInt(int &value, int limit, std::string &input)
Definition
libxrpl/beast/core/SemanticVersion.cpp:58
std::vector::push_back
T push_back(T... args)
ranges
std::string::size
T size(T... args)
stdexcept
string
string_view
std::string::substr
T substr(T... args)
std::to_string
T to_string(T... args)
Generated by
1.17.0