summaryrefslogtreecommitdiff
path: root/external/semver/src/include/semantic_version.h
blob: a6214f9156137319afa50a5f4cb978b4d46684ad (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#pragma once

// Semantic version - see http://semver.org/

// The major difference between v1::Version and v2::Version is that v1 includes
// the build identifier when calculating precedence of versions (see
// http://semver.org/spec/v2.0.0-rc.1.html points 10,11) while v2 omits the
// build identifier when calculating precedence of versions (see
// http://semver.org/spec/v2.0.0.html points 10,11).

#include <string>
#include <ostream>

namespace semver
{
  namespace v1
  {

    class Version
    {
    public:
      // By-parts (and default) version constructor: no validation.
      Version(
          unsigned int major = 0,
          unsigned int minor = 0,
          unsigned int patch = 1,
          const std::string& prerelease = std::string{},
          const std::string& build = std::string{});

      // Parse from a version string: no validation.
      explicit Version(const std::string& s);

      // Is a version well-formed according to the spec?
      // The semver spec stipulates a few properties of a well-formed version:
      // that both the dot-separated prerelease version and the build version
      // MUST comprise only [0-9A-Za-z-]; that numerical dot-separated
      // identifiers MUST NOT include leading zeroes; and that such identifiers
      // MUST NOT be empty.
      bool IsWellFormed() const;

      // Parse from a version string, with validation according to the spec.
      static Version Parse(const std::string& s, bool& wellformed);

      unsigned int GetMajorVersion() const { return m_majorVersion; }
      unsigned int GetMinorVersion() const { return m_minorVersion; }
      unsigned int GetPatchVersion() const { return m_patchVersion; }

      // Create a new version by incrementing a part of a version. Other parts
      // will be reset to 0, per the spec.
      Version NextMajorVersion() const;
      Version NextMinorVersion() const;
      Version NextPatchVersion() const;

      // A version satisfies another version if it is greater than or equal to
      // it in precedence. Additionally, pre-release versions and build versions
      // both satisfy their corresponding normal versions, and all pre-release
      // or build versions thereof.
      bool Satisfies(const Version& other) const;

      // Precedence is calculated by comparing the major, minor, patch,
      // pre-release and build parts in that order. Pre-release and build
      // strings are considered as lists of dot-separated identifiers, whereby
      // if an identifier is numeric, it is compared as such; otherwise
      // comparison is based on ASCII sort order.
      friend bool operator<(const Version& a, const Version& b);
      friend bool operator==(const Version& a, const Version& b);

      // A version is output as X.Y.Z (Major.Minor.Patch)
      // A pre-release string (eg alpha.1) may follow immediately, joined by a -
      // A build string may follow (eg 123.f83eaa931), joined by a +
      friend std::ostream& operator<<(std::ostream& s, const Version& v);

    private:
      unsigned int m_majorVersion = 0;
      unsigned int m_minorVersion = 0;
      unsigned int m_patchVersion = 1;
      std::string m_prereleaseVersion;
      std::string m_buildVersion;
    };

    inline bool operator!=(const Version& a, const Version& b)
    {
      return !(a == b);
    }

    inline bool operator>=(const Version& a, const Version& b)
    {
      return !(a < b);
    }

    inline bool operator<=(const Version& a, const Version& b)
    {
      return (a == b) || (a < b);
    }

    inline bool operator>(const Version& a, const Version& b)
    {
      return (a != b) && (a >= b);
    }
  }

  inline namespace v2
  {

    class Version
    {
    public:
      // By-parts (and default) version constructor: no validation.
      Version(
          unsigned int major = 0,
          unsigned int minor = 0,
          unsigned int patch = 1,
          const std::string& prerelease = std::string{},
          const std::string& build = std::string{});

      // Parse from a version string: no validation.
      explicit Version(const std::string& s);

      // Is a version well-formed according to the spec?
      // The semver spec stipulates a few properties of a well-formed version:
      // that both the dot-separated prerelease version and the build version
      // MUST comprise only [0-9A-Za-z-]; that numerical dot-separated
      // identifiers MUST NOT include leading zeroes; and that such identifiers
      // MUST NOT be empty.
      bool IsWellFormed() const;

      unsigned int GetMajorVersion() const { return m_majorVersion; }
      unsigned int GetMinorVersion() const { return m_minorVersion; }
      unsigned int GetPatchVersion() const { return m_patchVersion; }

      // Create a new version by incrementing a part of a version. Other parts
      // will be reset to 0, per the spec.
      Version NextMajorVersion() const;
      Version NextMinorVersion() const;
      Version NextPatchVersion() const;

      // A version satisfies another version if it is greater than or equal to
      // it in precedence. Additionally, pre-release versions and build versions
      // both satisfy their corresponding normal versions, and all pre-release
      // or build versions thereof.
      bool Satisfies(const Version& other) const;

      // Precedence is calculated by comparing the major, minor, patch, and
      // pre-release parts in that order. Pre-release strings are considered as
      // lists of dot-separated identifiers, whereby if an identifier is
      // numeric, it is compared as such; otherwise comparison is based on ASCII
      // sort order. Note: according to semver v2.0.0, build version is NOT
      // considered when determining precedence.
      friend bool operator<(const Version& a, const Version& b);
      friend bool operator==(const Version& a, const Version& b);

      // For exact equality (as opposed to precedence equality)
      bool Equals(const Version& other) const;

      // A version is output as X.Y.Z (Major.Minor.Patch)
      // A pre-release string (eg alpha.1) may follow immediately, joined by a -
      // A build string may follow (eg 123.f83eaa931), joined by a +
      friend std::ostream& operator<<(std::ostream& s, const Version& v);

    private:
      unsigned int m_majorVersion = 0;
      unsigned int m_minorVersion = 0;
      unsigned int m_patchVersion = 1;
      std::string m_prereleaseVersion;
      std::string m_buildVersion;
    };

    inline bool operator!=(const Version& a, const Version& b)
    {
      return !(a == b);
    }

    inline bool operator>=(const Version& a, const Version& b)
    {
      return !(a < b);
    }

    inline bool operator<=(const Version& a, const Version& b)
    {
      return (a == b) || (a < b);
    }

    inline bool operator>(const Version& a, const Version& b)
    {
      return (a != b) && (a >= b);
    }
  }
}