AppInstallerVersions.h (12158B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #pragma once 4 #include <string> 5 #include <string_view> 6 #include <vector> 7 8 namespace AppInstaller::Utility 9 { 10 using namespace std::string_view_literals; 11 12 // Creates a comparable version object from a string. 13 // Versions are parsed by: 14 // 1. Parse approximate comparator sign if applicable 15 // 2. Splitting the string based on the given splitChars (or DefaultSplitChars) 16 // 3. Parsing a leading, positive integer from each split part 17 // 4. Saving any remaining, non-digits as a supplemental value 18 // 19 // Versions are compared by: 20 // for each part in each version 21 // if one side has no more parts, perform the remaining comparisons against an empty part 22 // if integers not equal, return comparison of integers 23 // else if only one side has a non-empty string part, it is less 24 // else if string parts not equal, return comparison of strings 25 // if each part has been compared, use approximate comparator if applicable 26 // 27 // Note: approximate to another approximate version is invalid. 28 // approximate to Unknown is invalid. 29 struct Version 30 { 31 // Used in approximate version to indicate the relation to the base version. 32 enum class ApproximateComparator 33 { 34 None, 35 LessThan, 36 GreaterThan, 37 }; 38 39 // The default characters to split a version string on. 40 constexpr static std::string_view DefaultSplitChars = "."sv; 41 42 Version() = default; 43 44 Version(const std::string& version, std::string_view splitChars = DefaultSplitChars) : 45 Version(std::string(version), splitChars) {} 46 Version(std::string&& version, std::string_view splitChars = DefaultSplitChars); 47 48 // Constructing an approximate version from a base version. 49 Version(Version baseVersion, ApproximateComparator approximateComparator); 50 51 // Resets the version's value to the input. 52 virtual void Assign(std::string version, std::string_view splitChars = DefaultSplitChars); 53 54 // Gets the full version string used to construct the Version. 55 const std::string& ToString() const { return m_version; } 56 57 bool operator<(const Version& other) const; 58 bool operator>(const Version& other) const; 59 bool operator<=(const Version& other) const; 60 bool operator>=(const Version& other) const; 61 bool operator==(const Version& other) const; 62 bool operator!=(const Version& other) const; 63 64 // Determines if this version is the sentinel value defining the 'Latest' version 65 bool IsLatest() const; 66 67 // Returns a Version that will return true for IsLatest 68 static Version CreateLatest(); 69 70 // Determines if this version is the sentinel value defining an 'Unknown' version 71 bool IsUnknown() const; 72 73 // Returns a Version that will return true for IsUnknown 74 static Version CreateUnknown(); 75 76 // Gets a bool indicating whether the full version string is empty. 77 // Does not indicate that Parts is empty; for instance when "0.0" is given, 78 // this will be false while GetParts().empty() would be true. 79 bool IsEmpty() const { return m_version.empty(); } 80 81 // An individual version part in between split characters. 82 struct Part 83 { 84 Part() = default; 85 Part(uint64_t integer) : Integer(integer) {} 86 Part(const std::string& part); 87 Part(uint64_t integer, std::string other); 88 89 bool operator<(const Part& other) const; 90 bool operator==(const Part& other) const; 91 bool operator!=(const Part& other) const; 92 93 uint64_t Integer = 0; 94 std::string Other; 95 96 private: 97 std::string m_foldedOther; 98 }; 99 100 // Gets the part breakdown for a given version. 101 const std::vector<Part>& GetParts() const { return m_parts; } 102 103 // Gets the part at the given index; or the implied zero part if past the end. 104 const Part& PartAt(size_t index) const; 105 106 // Returns if the version is an approximate version. 107 bool IsApproximate() const { return m_approximateComparator != ApproximateComparator::None; } 108 109 // Get the base version from approximate version, or return a copy if the version is not approximate. 110 Version GetBaseVersion() const; 111 112 protected: 113 114 bool IsBaseVersionLatest() const; 115 bool IsBaseVersionUnknown() const; 116 // Called by overloaded less than operator implementation when base version already compared and equal, less than determined by approximate comparator. 117 bool ApproximateCompareLessThan(const Version& other) const; 118 119 std::string m_version; 120 std::vector<Part> m_parts; 121 bool m_trimPrefix = true; 122 ApproximateComparator m_approximateComparator = ApproximateComparator::None; 123 124 // Remove trailing empty parts (0 or empty) 125 void Trim(); 126 }; 127 128 // Version that does not have leading non-digit characters trimmed 129 struct RawVersion : protected Version 130 { 131 RawVersion() { m_trimPrefix = false; } 132 RawVersion(std::string version, std::string_view splitChars = DefaultSplitChars); 133 134 using Version::GetParts; 135 }; 136 137 // Four parts version number: 16-bits.16-bits.16-bits.16-bits 138 struct UInt64Version : public Version 139 { 140 UInt64Version() = default; 141 UInt64Version(UINT64 version); 142 UInt64Version(uint16_t major, uint16_t minor, uint16_t build, uint16_t revision); 143 UInt64Version(std::string&& version, std::string_view splitChars = DefaultSplitChars); 144 UInt64Version(const std::string& version, std::string_view splitChars = DefaultSplitChars) : 145 UInt64Version(std::string(version), splitChars) {} 146 147 void Assign(std::string version, std::string_view splitChars = DefaultSplitChars) override; 148 void Assign(UINT64 version); 149 void Assign(uint16_t major, uint16_t minor, uint16_t build, uint16_t revision); 150 151 UINT64 Major() const { return m_parts.size() > 0 ? m_parts[0].Integer : 0; } 152 UINT64 Minor() const { return m_parts.size() > 1 ? m_parts[1].Integer : 0; } 153 UINT64 Build() const { return m_parts.size() > 2 ? m_parts[2].Integer : 0; } 154 UINT64 Revision() const { return m_parts.size() > 3 ? m_parts[3].Integer : 0; } 155 }; 156 157 // A semantic version as defined by semver.org 158 // This is currently fairly loose in its restrictions on a version, and is largely to separate out the prelease and build metadata portions. 159 struct SemanticVersion : public Version 160 { 161 SemanticVersion() = default; 162 SemanticVersion(std::string&& version); 163 SemanticVersion(const std::string& version) : 164 SemanticVersion(std::string(version)) {} 165 166 void Assign(std::string version, std::string_view splitChars = DefaultSplitChars) override; 167 168 // Indicates that the version is pre-release 169 bool IsPrerelease() const; 170 // The pre-release version 171 const Version& PrereleaseVersion() const; 172 173 // Indicates that the version has build metadata 174 bool HasBuildMetadata() const; 175 // The build metadata version 176 const Version& BuildMetadata() const; 177 178 private: 179 Version m_prerelease; 180 Version m_buildMetadata; 181 }; 182 183 // Version range represented by a min version and max version, both inclusive. 184 struct VersionRange 185 { 186 VersionRange() { m_isEmpty = true; }; 187 VersionRange(Version minVersion, Version maxVersion); 188 189 bool IsEmpty() const { return m_isEmpty; } 190 191 // Checks if version ranges overlap. Empty version range does not overlap with any version range. 192 bool Overlaps(const VersionRange& other) const; 193 194 // Checks if the version range is effectively the same as a single version. 195 bool IsSameAsSingleVersion(const Version& version) const; 196 197 // Checks if a version is within the version range 198 bool ContainsVersion(const Version& version) const; 199 200 // < operator will thow if compared with an empty range or an overlapped range 201 bool operator<(const VersionRange& other) const; 202 203 const Version& GetMinVersion() const; 204 const Version& GetMaxVersion() const; 205 206 private: 207 Version m_minVersion; 208 Version m_maxVersion; 209 bool m_isEmpty = false; 210 }; 211 212 // A range of versions indicated by a version and optionally a wildcard at the end. 213 struct GatedVersion 214 { 215 GatedVersion() {} 216 GatedVersion(Version&& version) : m_version(std::move(version)) {} 217 GatedVersion(const Version& version) : m_version(version) {} 218 GatedVersion(std::string_view versionString) : m_version(std::string{ versionString }) {} 219 GatedVersion(const std::string& versionString) : m_version(versionString) {} 220 221 // Determines whether a given version falls within this Gated version. 222 // I.e., whether it matches up to the wildcard 223 bool IsValidVersion(Version version) const; 224 225 bool operator==(const GatedVersion& other) const { return m_version == other.m_version; } 226 const std::string& ToString() const { return m_version.ToString(); } 227 228 private: 229 // Hold the version string as a Version object that makes it easy to access each of 230 // the version's parts. The real magic is in IsValidVersion() 231 Version m_version; 232 }; 233 234 // A channel string; existing solely to give a type. 235 // 236 // Compared lexicographically. 237 struct Channel 238 { 239 Channel() = default; 240 Channel(const std::string& channel) : m_channel(channel) {} 241 Channel(std::string&& channel) : m_channel(std::move(channel)) {} 242 243 const std::string& ToString() const { return m_channel; } 244 245 bool operator<(const Channel& other) const; 246 247 private: 248 std::string m_channel; 249 }; 250 251 // Contains a version and channel. 252 // These are compared by: 253 // if channel not equal, return compare channel 254 // else return !compare version 255 // 256 // The implication of this is that the default less sort will be: 257 // 2.0, "" 258 // 1.0, "" 259 // 3.0, "alpha" 260 // 2.0, "alpha" 261 struct VersionAndChannel 262 { 263 VersionAndChannel() = default; 264 VersionAndChannel(Version&& version, Channel&& channel); 265 266 const Version& GetVersion() const { return m_version; } 267 const Channel& GetChannel() const { return m_channel; } 268 269 std::string ToString() const; 270 271 bool operator<(const VersionAndChannel& other) const; 272 273 // A convenience function to make more semantic sense at call sites over the somewhat awkward less than ordering. 274 bool IsUpdatedBy(const VersionAndChannel& other) const; 275 276 private: 277 Version m_version; 278 Channel m_channel; 279 }; 280 281 // Checks if there are overlaps within the list of version ranges 282 bool HasOverlapInVersionRanges(const std::vector<VersionRange>& ranges); 283 284 // The OpenType font version. 285 // The format of this version type is 'Version 1.234 ;567' 286 // The only part that is of importance is the 'Major.Minor' parts. 287 // The 'Version' string is typically found at the beginning of the version string. 288 // Any value after a digit that is not a '.' represents some other meaning. 289 struct OpenTypeFontVersion : Version 290 { 291 OpenTypeFontVersion() = default; 292 293 OpenTypeFontVersion(std::string&& version); 294 OpenTypeFontVersion(const std::string& version) : 295 OpenTypeFontVersion(std::string(version)) {} 296 297 void Assign(std::string version, std::string_view splitChars = DefaultSplitChars) override; 298 }; 299 }