1 /*
2 * Version.hpp
3 *
4 * Copyright (C) 2021 by RStudio, PBC
5 *
6 * Unless you have received this program directly from RStudio pursuant
7 * to the terms of a commercial license agreement with RStudio, then
8 * this program is licensed to you under the terms of version 3 of the
9 * GNU Affero General Public License. This program is distributed WITHOUT
10 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
11 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
12 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
13 *
14 */
15
16 #ifndef CORE_VERSION_HPP
17 #define CORE_VERSION_HPP
18
19 #include <string>
20
21 #include <boost/regex.hpp>
22
23 #include <core/Algorithm.hpp>
24 #include <shared_core/Error.hpp>
25 #include <shared_core/SafeConvert.hpp>
26 #include <core/StringUtils.hpp>
27
28 namespace rstudio {
29 namespace core {
30
31 class Version
32 {
33
34 public:
35
Version()36 Version()
37 {
38 }
39
Version(std::string version)40 Version(std::string version)
41 {
42 try
43 {
44 // split version into components
45 static boost::regex reVersion("[._-]+");
46 version = core::string_utils::trimWhitespace(version);
47 boost::sregex_token_iterator it(version.begin(), version.end(), reVersion, -1);
48 boost::sregex_token_iterator end;
49 for (; it != end; ++it)
50 {
51 std::string component = *it;
52 int value = core::safe_convert::stringTo<int>(component, 0);
53 pieces_.push_back(value);
54 }
55 }
56 CATCH_UNEXPECTED_EXCEPTION;
57 }
58
Version(int versionMajor,int versionMinor,int versionPatch)59 Version(int versionMajor, int versionMinor, int versionPatch)
60 {
61 pieces_.push_back(versionMajor);
62 pieces_.push_back(versionMinor);
63 pieces_.push_back(versionPatch);
64 }
65
versionMajor() const66 int versionMajor() const
67 {
68 return extractVersion(0);
69 }
70
versionMinor() const71 int versionMinor() const
72 {
73 return extractVersion(1);
74 }
75
versionPatch() const76 int versionPatch() const
77 {
78 return extractVersion(2);
79 }
80
extractVersion(std::size_t index) const81 int extractVersion(std::size_t index) const
82 {
83 if (index < pieces_.size())
84 return pieces_[index];
85
86 return 0;
87 }
88
compare(const Version & other) const89 int compare(const Version& other) const
90 {
91 return compare(*this, other);
92 }
93
operator std::string() const94 operator std::string() const
95 {
96 if (pieces_.empty())
97 return std::string();
98
99 std::stringstream ss;
100 ss << boost::lexical_cast<std::string>(pieces_[0]);
101 for (std::size_t i = 1, n = pieces_.size(); i < n; ++i)
102 {
103 ss << ".";
104 ss << boost::lexical_cast<std::string>(pieces_[i]);
105 }
106
107 return ss.str();
108 }
109
110 private:
111
compare(Version lhs,Version rhs) const112 int compare(Version lhs, Version rhs) const
113 {
114 std::size_t n = std::max(lhs.size(), rhs.size());
115
116 for (std::size_t i = 0; i < n; ++i)
117 {
118 int vl = lhs.extractVersion(i);
119 int vr = rhs.extractVersion(i);
120 if (vl < vr)
121 return -1;
122 else if (vl > vr)
123 return 1;
124 }
125
126 return 0;
127 }
128
size() const129 std::size_t size() const { return pieces_.size(); }
130
131 std::vector<int> pieces_;
132 };
133
operator <(const Version & lhs,const Version & rhs)134 inline bool operator <(const Version& lhs, const Version& rhs)
135 {
136 return lhs.compare(rhs) < 0;
137 }
138
operator <=(const Version & lhs,const Version & rhs)139 inline bool operator <=(const Version& lhs, const Version& rhs)
140 {
141 return lhs.compare(rhs) <= 0;
142 }
143
operator ==(const Version & lhs,const Version & rhs)144 inline bool operator ==(const Version& lhs, const Version& rhs)
145 {
146 return lhs.compare(rhs) == 0;
147 }
148
operator !=(const Version & lhs,const Version & rhs)149 inline bool operator !=(const Version& lhs, const Version& rhs)
150 {
151 return lhs.compare(rhs) != 0;
152 }
153
operator >=(const Version & lhs,const Version & rhs)154 inline bool operator >=(const Version& lhs, const Version& rhs)
155 {
156 return lhs.compare(rhs) >= 0;
157 }
158
operator >(const Version & lhs,const Version & rhs)159 inline bool operator >(const Version& lhs, const Version& rhs)
160 {
161 return lhs.compare(rhs) > 0;
162 }
163
164
165 } // end namespace core
166 } // end namespace rstudio
167
168 #endif /* CORE_VERSION_HPP */
169