IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
ModuleVersion.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Generic;
3using System.Collections.Immutable;
4using System.Linq;
6
8
10{
11
15 internal readonly struct ModuleVersion : IComparable<ModuleVersion>
16 {
17
18 public static bool operator ==(ModuleVersion x, ModuleVersion y) => x.Equals(y);
19
20 public static bool operator !=(ModuleVersion x, ModuleVersion y) => x.Equals(y) == false;
21
22 public static bool operator <(ModuleVersion x, ModuleVersion y) => Compare(x, y) < 0;
23
24 public static bool operator >(ModuleVersion x, ModuleVersion y) => Compare(x, y) > 0;
25
26 public static bool operator <=(ModuleVersion x, ModuleVersion y) => Compare(x, y) <= 0;
27
28 public static bool operator >=(ModuleVersion x, ModuleVersion y) => Compare(x, y) >= 0;
29
30 public static int Compare(ModuleVersion x, ModuleVersion y) => x.CompareTo(y);
31
37 public static bool TryParse(string value, out ModuleVersion parsed)
38 {
39 return TryParse(value.AsSpan(), out parsed);
40 }
41
47 public static bool TryParse(ReadOnlySpan<char> value, out ModuleVersion parsed)
48 {
49 return TryParse(value, out parsed, out _);
50 }
51
58 public static bool TryParse(ReadOnlySpan<char> value, out ModuleVersion parsed, out string? error)
59 {
60 parsed = default;
61 error = null;
62
63 int n = value.Length;
64 if (n == 0)
65 {
66 error = "Empty version string";
67 return false;
68 }
69
70 int i = 0;
71 char c = value[i];
72 if (!(c >= '0' && c <= '9'))
73 {
74 error = $"{value}: Version string does not start with a number";
75 return false;
76 }
77
78 var sequence = ImmutableArray.CreateBuilder<ModuleVersionComponent>(3);
79 var pre = ImmutableArray.CreateBuilder<ModuleVersionComponent>(0);
80 var build = ImmutableArray.CreateBuilder<ModuleVersionComponent>(0);
81
82 i = TakeNumber(value, i, sequence);
83
84 while (i < n)
85 {
86 c = value[i];
87 if (c == '.')
88 {
89 i++;
90 continue;
91 }
92 if (c == '-' || c == '+')
93 {
94 i++;
95 break;
96 }
97 if (c >= '0' && c <= '9')
98 i = TakeNumber(value, i, sequence);
99 else
100 i = TakeString(value, i, sequence);
101 }
102
103 if (c == '-' && i >= n)
104 {
105 error = $"{value}: Empty pre-release";
106 return false;
107 }
108
109 while (i < n)
110 {
111 c = value[i];
112 if (c == '.' || c == '-')
113 {
114 i++;
115 continue;
116 }
117 if (c == '+')
118 {
119 i++;
120 break;
121 }
122
123 if (c >= '0' && c <= '9')
124 i = TakeNumber(value, i, pre);
125 else
126 i = TakeString(value, i, pre);
127 }
128
129 if (c == '+' && i >= n)
130 {
131 error = $"{value}: Empty pre-release";
132 return false;
133 }
134
135 while (i < n)
136 {
137 c = value[i];
138 if (c == '.' || c == '-' || c == '+')
139 {
140 i++;
141 continue;
142 }
143 if (c >= '0' && c <= '9')
144 i = TakeNumber(value, i, build);
145 else
146 i = TakeString(value, i, build);
147 }
148
149 parsed = new ModuleVersion(value.ToString(), sequence.DrainToImmutable(), pre.DrainToImmutable(), build.DrainToImmutable());
150 return true;
151 }
152
159 public static ModuleVersion Parse(ReadOnlySpan<char> version)
160 {
161 if (TryParse(version, out var parsed, out var error))
162 return parsed;
163
164 throw new ArgumentException(error, nameof(version));
165 }
166
173 public static ModuleVersion Parse(string version)
174 {
175 if (version is null)
176 throw new ArgumentNullException(nameof(version));
177
178 return Parse(version.AsSpan());
179 }
180
188 static int TakeNumber(ReadOnlySpan<char> s, int i, ImmutableArray<ModuleVersionComponent>.Builder list)
189 {
190 char c = s[i];
191 int d = (c - '0');
192 int n = s.Length;
193 while (++i < n)
194 {
195 c = s[i];
196 if (c >= '0' && c <= '9')
197 {
198 d = d * 10 + (c - '0');
199 continue;
200 }
201
202 break;
203 }
204
205 list.Add(new ModuleVersionComponent(d));
206 return i;
207 }
208
216 static int TakeString(ReadOnlySpan<char> s, int i, ImmutableArray<ModuleVersionComponent>.Builder list)
217 {
218 int b = i;
219 int n = s.Length;
220 while (++i < n)
221 {
222 char c = s[i];
223 if (c != '.' && c != '-' && c != '+' && !(c >= '0' && c <= '9'))
224 continue;
225
226 break;
227 }
228
229 AddModuleVersionComponent(list, s.Slice(b, i - b).ToString());
230 return i;
231 }
232
238 [MethodImpl(MethodImplOptions.NoInlining)]
239 static void AddModuleVersionComponent(ImmutableArray<ModuleVersionComponent>.Builder builder, string value)
240 {
241 builder.Add(new ModuleVersionComponent(value));
242 }
243
244 readonly string _rawValue;
245 readonly ImmutableArray<ModuleVersionComponent> _sequence;
246 readonly ImmutableArray<ModuleVersionComponent> _pre;
247 readonly ImmutableArray<ModuleVersionComponent> _build;
248
256 public ModuleVersion(string rawValue, ImmutableArray<ModuleVersionComponent> sequence, ImmutableArray<ModuleVersionComponent> pre, ImmutableArray<ModuleVersionComponent> build)
257 {
258 _rawValue = rawValue ?? throw new ArgumentNullException(nameof(rawValue));
259 _sequence = sequence;
260 _pre = pre;
261 _build = build;
262 }
263
267 public readonly bool IsValid => _sequence.IsDefaultOrEmpty == false;
268
272 public readonly string RawValue => _rawValue;
273
277 public readonly ImmutableArray<ModuleVersionComponent> Sequence => _sequence;
278
282 public readonly ImmutableArray<ModuleVersionComponent> Pre => _pre;
283
287 public readonly ImmutableArray<ModuleVersionComponent> Build => _build;
288
295 readonly int CompareComponents(ImmutableArray<ModuleVersionComponent> x, ImmutableArray<ModuleVersionComponent> y)
296 {
298 }
299
301 public readonly int CompareTo(ModuleVersion other)
302 {
303 if (IsValid && other.IsValid == false)
304 return +1;
305 if (IsValid == false && other.IsValid)
306 return -1;
307
308 // initially compare sequence components
309 int c = CompareComponents(_sequence, other._sequence);
310 if (c != 0)
311 return c;
312
313 // compare pre components
314 if (_pre.IsEmpty)
315 {
316 if (other._pre.IsEmpty == false)
317 return +1;
318 }
319 else
320 {
321 if (other._pre.IsEmpty)
322 return -1;
323 }
324
325 // compare pre components
326 c = CompareComponents(_pre, other._pre);
327 if (c != 0)
328 return c;
329
330 // fallback to build components
331 return CompareComponents(_build, other._build);
332 }
333
335 public readonly override int GetHashCode()
336 {
337 if (IsValid == false)
338 return 0;
339
340 var hc = new HashCode();
341
342 foreach (var i in _sequence)
343 hc.Add(i);
344
345 foreach (var i in _pre)
346 hc.Add(i);
347
348 foreach (var i in _build)
349 hc.Add(i);
350
351 return hc.ToHashCode();
352 }
353
355 public readonly override bool Equals(object? other)
356 {
357 return other is ModuleVersion v && Equals(v);
358 }
359
365 public readonly bool Equals(ModuleVersion other)
366 {
367 // both are invalid
368 if (IsValid == false && other.IsValid == false)
369 return true;
370
371 // both are valid, actually compare
372 if (IsValid && other.IsValid)
373 return _sequence.SequenceEqual(other._sequence) && _pre.SequenceEqual(other._pre) && _build.SequenceEqual(other._build);
374
375 return false;
376 }
377
379 public readonly override string? ToString()
380 {
381 return _rawValue;
382 }
383
384 }
385
386}
Implements an IComparer<T> which lexicographically compares a two lists.
static new readonly LexicographicListComparer< T > Default
Returns a default LexicographicListComparer<T> instance.