Hue Preserving Color Blending
SemVersion.cs
1 /*
2 Copyright (c) 2013 Max Hauser
3 
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10 
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21 
22 From: https://github.com/maxhauser/semver
23 */
24 
25 using System;
26 #if !NETSTANDARD
27 using System.Globalization;
28 using System.Runtime.Serialization;
29 using System.Security.Permissions;
30 #endif
31 using System.Text.RegularExpressions;
32 
33 namespace Semver
34 {
39 #if NETSTANDARD
40  public sealed class SemVersion : IComparable<SemVersion>, IComparable
41 #else
42  [Serializable]
43  internal sealed class SemVersion : IComparable<SemVersion>, IComparable, ISerializable
44 #endif
45  {
46  static Regex parseEx =
47  new Regex(@"^(?<major>\d+)" +
48  @"(\.(?<minor>\d+))?" +
49  @"(\.(?<patch>\d+))?" +
50  @"(\-(?<pre>[0-9A-Za-z\-\.]+))?" +
51  @"(\+(?<build>[0-9A-Za-z\-\.]+))?$",
52 #if NETSTANDARD
53  RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture);
54 #else
55  RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.ExplicitCapture);
56 #endif
57 
58 #if !NETSTANDARD
59  private SemVersion(SerializationInfo info, StreamingContext context)
66  {
67  if (info == null) throw new ArgumentNullException("info");
68  var semVersion = Parse(info.GetString("SemVersion"));
69  Major = semVersion.Major;
70  Minor = semVersion.Minor;
71  Patch = semVersion.Patch;
72  Prerelease = semVersion.Prerelease;
73  Build = semVersion.Build;
74  }
75 #endif
76 
85  public SemVersion(int major, int minor = 0, int patch = 0, string prerelease = "", string build = "")
86  {
87  this.Major = major;
88  this.Minor = minor;
89  this.Patch = patch;
90 
91  this.Prerelease = prerelease ?? "";
92  this.Build = build ?? "";
93  }
94 
100  public SemVersion(Version version)
101  {
102  if (version == null)
103  throw new ArgumentNullException("version");
104 
105  this.Major = version.Major;
106  this.Minor = version.Minor;
107 
108  if (version.Revision >= 0)
109  {
110  this.Patch = version.Revision;
111  }
112 
113  this.Prerelease = String.Empty;
114 
115  if (version.Build > 0)
116  {
117  this.Build = version.Build.ToString();
118  }
119  else
120  {
121  this.Build = String.Empty;
122  }
123  }
124 
132  public static SemVersion Parse(string version, bool strict = false)
133  {
134  var match = parseEx.Match(version);
135  if (!match.Success)
136  {
137  return new SemVersion(0);
138  }
139 
140 #if NETSTANDARD
141  var major = int.Parse(match.Groups["major"].Value);
142 #else
143  var major = int.Parse(match.Groups["major"].Value, CultureInfo.InvariantCulture);
144 #endif
145 
146  var minorMatch = match.Groups["minor"];
147  int minor = 0;
148  if (minorMatch.Success)
149  {
150 #if NETSTANDARD
151  minor = int.Parse(minorMatch.Value);
152 #else
153  minor = int.Parse(minorMatch.Value, CultureInfo.InvariantCulture);
154 #endif
155  }
156  else if (strict)
157  {
158  throw new InvalidOperationException("Invalid version (no minor version given in strict mode)");
159  }
160 
161  var patchMatch = match.Groups["patch"];
162  int patch = 0;
163  if (patchMatch.Success)
164  {
165 #if NETSTANDARD
166  patch = int.Parse(patchMatch.Value);
167 #else
168  patch = int.Parse(patchMatch.Value, CultureInfo.InvariantCulture);
169 #endif
170  }
171  else if (strict)
172  {
173  throw new InvalidOperationException("Invalid version (no patch version given in strict mode)");
174  }
175 
176  var prerelease = match.Groups["pre"].Value;
177  var build = match.Groups["build"].Value;
178 
179  return new SemVersion(major, minor, patch, prerelease, build);
180  }
181 
191  public static bool TryParse(string version, out SemVersion semver, bool strict = false)
192  {
193  try
194  {
195  semver = Parse(version, strict);
196  return true;
197  }
198  catch (Exception)
199  {
200  semver = null;
201  return false;
202  }
203  }
204 
211  public static bool Equals(SemVersion versionA, SemVersion versionB)
212  {
213  if (ReferenceEquals(versionA, null))
214  return ReferenceEquals(versionB, null);
215  return versionA.Equals(versionB);
216  }
217 
225  public static int Compare(SemVersion versionA, SemVersion versionB)
226  {
227  if (ReferenceEquals(versionA, null))
228  return ReferenceEquals(versionB, null) ? 0 : -1;
229  return versionA.CompareTo(versionB);
230  }
231 
241  public SemVersion Change(int? major = null, int? minor = null, int? patch = null,
242  string prerelease = null, string build = null)
243  {
244  return new SemVersion(
245  major ?? this.Major,
246  minor ?? this.Minor,
247  patch ?? this.Patch,
248  prerelease ?? this.Prerelease,
249  build ?? this.Build);
250  }
251 
258  public int Major { get; private set; }
259 
266  public int Minor { get; private set; }
267 
274  public int Patch { get; private set; }
275 
282  public string Prerelease { get; private set; }
283 
290  public string Build { get; private set; }
291 
298  public override string ToString()
299  {
300  var version = "" + Major + "." + Minor + "." + Patch;
301  if (!String.IsNullOrEmpty(Prerelease))
302  version += "-" + Prerelease;
303  if (!String.IsNullOrEmpty(Build))
304  version += "+" + Build;
305  return version;
306  }
307 
321  public int CompareTo(object obj)
322  {
323  return CompareTo((SemVersion)obj);
324  }
325 
339  public int CompareTo(SemVersion other)
340  {
341  if (ReferenceEquals(other, null))
342  return 1;
343 
344  var r = this.CompareByPrecedence(other);
345  if (r != 0)
346  return r;
347 
348  r = CompareComponent(this.Build, other.Build);
349  return r;
350  }
351 
357  public bool PrecedenceMatches(SemVersion other)
358  {
359  return CompareByPrecedence(other) == 0;
360  }
361 
373  public int CompareByPrecedence(SemVersion other)
374  {
375  if (ReferenceEquals(other, null))
376  return 1;
377 
378  var r = this.Major.CompareTo(other.Major);
379  if (r != 0) return r;
380 
381  r = this.Minor.CompareTo(other.Minor);
382  if (r != 0) return r;
383 
384  r = this.Patch.CompareTo(other.Patch);
385  if (r != 0) return r;
386 
387  r = CompareComponent(this.Prerelease, other.Prerelease, true);
388  return r;
389  }
390 
391  static int CompareComponent(string a, string b, bool lower = false)
392  {
393  var aEmpty = String.IsNullOrEmpty(a);
394  var bEmpty = String.IsNullOrEmpty(b);
395  if (aEmpty && bEmpty)
396  return 0;
397 
398  if (aEmpty)
399  return lower ? 1 : -1;
400  if (bEmpty)
401  return lower ? -1 : 1;
402 
403  var aComps = a.Split('.');
404  var bComps = b.Split('.');
405 
406  var minLen = Math.Min(aComps.Length, bComps.Length);
407  for (int i = 0; i < minLen; i++)
408  {
409  var ac = aComps[i];
410  var bc = bComps[i];
411  int anum, bnum;
412  var isanum = Int32.TryParse(ac, out anum);
413  var isbnum = Int32.TryParse(bc, out bnum);
414  int r;
415  if (isanum && isbnum)
416  {
417  r = anum.CompareTo(bnum);
418  if (r != 0) return anum.CompareTo(bnum);
419  }
420  else
421  {
422  if (isanum)
423  return -1;
424  if (isbnum)
425  return 1;
426  r = String.CompareOrdinal(ac, bc);
427  if (r != 0)
428  return r;
429  }
430  }
431 
432  return aComps.Length.CompareTo(bComps.Length);
433  }
434 
442  public override bool Equals(object obj)
443  {
444  if (ReferenceEquals(obj, null))
445  return false;
446 
447  if (ReferenceEquals(this, obj))
448  return true;
449 
450  var other = (SemVersion)obj;
451 
452  return this.Major == other.Major &&
453  this.Minor == other.Minor &&
454  this.Patch == other.Patch &&
455  string.Equals(this.Prerelease, other.Prerelease, StringComparison.Ordinal) &&
456  string.Equals(this.Build, other.Build, StringComparison.Ordinal);
457  }
458 
465  public override int GetHashCode()
466  {
467  unchecked
468  {
469  int result = this.Major.GetHashCode();
470  result = result * 31 + this.Minor.GetHashCode();
471  result = result * 31 + this.Patch.GetHashCode();
472  result = result * 31 + this.Prerelease.GetHashCode();
473  result = result * 31 + this.Build.GetHashCode();
474  return result;
475  }
476  }
477 
478 #if !NETSTANDARD
479  [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
480  public void GetObjectData(SerializationInfo info, StreamingContext context)
481  {
482  if (info == null) throw new ArgumentNullException("info");
483  info.AddValue("SemVersion", ToString());
484  }
485 #endif
486 
492  public static implicit operator SemVersion(string version)
493  {
494  return SemVersion.Parse(version);
495  }
496 
503  public static bool operator ==(SemVersion left, SemVersion right)
504  {
505  return SemVersion.Equals(left, right);
506  }
507 
514  public static bool operator !=(SemVersion left, SemVersion right)
515  {
516  return !SemVersion.Equals(left, right);
517  }
518 
525  public static bool operator >(SemVersion left, SemVersion right)
526  {
527  return SemVersion.Compare(left, right) > 0;
528  }
529 
536  public static bool operator >=(SemVersion left, SemVersion right)
537  {
538  return left == right || left > right;
539  }
540 
547  public static bool operator <(SemVersion left, SemVersion right)
548  {
549  return SemVersion.Compare(left, right) < 0;
550  }
551 
558  public static bool operator <=(SemVersion left, SemVersion right)
559  {
560  return left == right || left < right;
561  }
562  }
563 }
static bool operator<=(SemVersion left, SemVersion right)
The override of the less than or equal operator.
Definition: SemVersion.cs:558
int CompareTo(object obj)
Compares the current instance with another object of the same type and returns an integer that indica...
Definition: SemVersion.cs:321
static int Compare(SemVersion versionA, SemVersion versionB)
Compares the specified versions.
Definition: SemVersion.cs:225
A semantic version implementation. Conforms to v2.0.0 of http://semver.org/
Definition: SemVersion.cs:43
SemVersion(int major, int minor=0, int patch=0, string prerelease="", string build="")
Initializes a new instance of the SemVersion class.
Definition: SemVersion.cs:85
int Major
Gets the major version.
Definition: SemVersion.cs:258
SemVersion Change(int? major=null, int? minor=null, int? patch=null, string prerelease=null, string build=null)
Make a copy of the current instance with optional altered fields.
Definition: SemVersion.cs:241
override bool Equals(object obj)
Determines whether the specified System.Object is equal to this instance.
Definition: SemVersion.cs:442
int CompareByPrecedence(SemVersion other)
Compares to semantic versions by precedence. This does the same as a Equals, but ignores the build in...
Definition: SemVersion.cs:373
static SemVersion Parse(string version, bool strict=false)
Parses the specified string to a semantic version.
Definition: SemVersion.cs:132
static bool operator<(SemVersion left, SemVersion right)
The override of the less operator.
Definition: SemVersion.cs:547
string Build
Gets the build version.
Definition: SemVersion.cs:290
static bool Equals(SemVersion versionA, SemVersion versionB)
Tests the specified versions for equality.
Definition: SemVersion.cs:211
override string ToString()
Returns a System.String that represents this instance.
Definition: SemVersion.cs:298
int CompareTo(SemVersion other)
Compares the current instance with another object of the same type and returns an integer that indica...
Definition: SemVersion.cs:339
bool PrecedenceMatches(SemVersion other)
Compares to semantic versions by precedence. This does the same as a Equals, but ignores the build in...
Definition: SemVersion.cs:357
int Patch
Gets the patch version.
Definition: SemVersion.cs:274
static bool operator==(SemVersion left, SemVersion right)
The override of the equals operator.
Definition: SemVersion.cs:503
override int GetHashCode()
Returns a hash code for this instance.
Definition: SemVersion.cs:465
static bool TryParse(string version, out SemVersion semver, bool strict=false)
Parses the specified string to a semantic version.
Definition: SemVersion.cs:191
string Prerelease
Gets the pre-release version.
Definition: SemVersion.cs:282
static bool operator >=(SemVersion left, SemVersion right)
The override of the greater than or equal operator.
Definition: SemVersion.cs:536
static bool operator >(SemVersion left, SemVersion right)
The override of the greater operator.
Definition: SemVersion.cs:525
SemVersion(SerializationInfo info, StreamingContext context)
Initializes a new instance of the SemVersion class.
Definition: SemVersion.cs:65
static bool operator !=(SemVersion left, SemVersion right)
The override of the un-equal operator.
Definition: SemVersion.cs:514
int Minor
Gets the minor version.
Definition: SemVersion.cs:266
SemVersion(Version version)
Initializes a new instance of the SemVersion class.
Definition: SemVersion.cs:100