1 //===- VersionTuple.h - Version Number Handling -----------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// 9 /// \file 10 /// Defines the llvm::VersionTuple class, which represents a version in 11 /// the form major[.minor[.subminor]]. 12 /// 13 //===----------------------------------------------------------------------===// 14 #ifndef LLVM_SUPPORT_VERSIONTUPLE_H 15 #define LLVM_SUPPORT_VERSIONTUPLE_H 16 17 #include "llvm/ADT/DenseMapInfo.h" 18 #include "llvm/ADT/Hashing.h" 19 #include "llvm/Support/Endian.h" 20 #include <optional> 21 #include <string> 22 #include <tuple> 23 24 namespace llvm { 25 template <typename HasherT, support::endianness Endianness> 26 class HashBuilderImpl; 27 class raw_ostream; 28 class StringRef; 29 30 /// Represents a version number in the form major[.minor[.subminor[.build]]]. 31 class VersionTuple { 32 unsigned Major : 32; 33 34 unsigned Minor : 31; 35 unsigned HasMinor : 1; 36 37 unsigned Subminor : 31; 38 unsigned HasSubminor : 1; 39 40 unsigned Build : 31; 41 unsigned HasBuild : 1; 42 43 public: 44 constexpr VersionTuple() 45 : Major(0), Minor(0), HasMinor(false), Subminor(0), HasSubminor(false), 46 Build(0), HasBuild(false) {} 47 48 explicit constexpr VersionTuple(unsigned Major) 49 : Major(Major), Minor(0), HasMinor(false), Subminor(0), 50 HasSubminor(false), Build(0), HasBuild(false) {} 51 52 explicit constexpr VersionTuple(unsigned Major, unsigned Minor) 53 : Major(Major), Minor(Minor), HasMinor(true), Subminor(0), 54 HasSubminor(false), Build(0), HasBuild(false) {} 55 56 explicit constexpr VersionTuple(unsigned Major, unsigned Minor, 57 unsigned Subminor) 58 : Major(Major), Minor(Minor), HasMinor(true), Subminor(Subminor), 59 HasSubminor(true), Build(0), HasBuild(false) {} 60 61 explicit constexpr VersionTuple(unsigned Major, unsigned Minor, 62 unsigned Subminor, unsigned Build) 63 : Major(Major), Minor(Minor), HasMinor(true), Subminor(Subminor), 64 HasSubminor(true), Build(Build), HasBuild(true) {} 65 66 /// Determine whether this version information is empty 67 /// (e.g., all version components are zero). 68 bool empty() const { 69 return Major == 0 && Minor == 0 && Subminor == 0 && Build == 0; 70 } 71 72 /// Retrieve the major version number. 73 unsigned getMajor() const { return Major; } 74 75 /// Retrieve the minor version number, if provided. 76 std::optional<unsigned> getMinor() const { 77 if (!HasMinor) 78 return std::nullopt; 79 return Minor; 80 } 81 82 /// Retrieve the subminor version number, if provided. 83 std::optional<unsigned> getSubminor() const { 84 if (!HasSubminor) 85 return std::nullopt; 86 return Subminor; 87 } 88 89 /// Retrieve the build version number, if provided. 90 std::optional<unsigned> getBuild() const { 91 if (!HasBuild) 92 return std::nullopt; 93 return Build; 94 } 95 96 /// Return a version tuple that contains only the first 3 version components. 97 VersionTuple withoutBuild() const { 98 if (HasBuild) 99 return VersionTuple(Major, Minor, Subminor); 100 return *this; 101 } 102 103 /// Return a version tuple that contains a different major version but 104 /// everything else is the same. 105 VersionTuple withMajorReplaced(unsigned NewMajor) const { 106 return VersionTuple(NewMajor, Minor, Subminor, Build); 107 } 108 109 /// Return a version tuple that contains only components that are non-zero. 110 VersionTuple normalize() const { 111 VersionTuple Result = *this; 112 if (Result.Build == 0) { 113 Result.HasBuild = false; 114 if (Result.Subminor == 0) { 115 Result.HasSubminor = false; 116 if (Result.Minor == 0) 117 Result.HasMinor = false; 118 } 119 } 120 return Result; 121 } 122 123 /// Determine if two version numbers are equivalent. If not 124 /// provided, minor and subminor version numbers are considered to be zero. 125 friend bool operator==(const VersionTuple &X, const VersionTuple &Y) { 126 return X.Major == Y.Major && X.Minor == Y.Minor && 127 X.Subminor == Y.Subminor && X.Build == Y.Build; 128 } 129 130 /// Determine if two version numbers are not equivalent. 131 /// 132 /// If not provided, minor and subminor version numbers are considered to be 133 /// zero. 134 friend bool operator!=(const VersionTuple &X, const VersionTuple &Y) { 135 return !(X == Y); 136 } 137 138 /// Determine whether one version number precedes another. 139 /// 140 /// If not provided, minor and subminor version numbers are considered to be 141 /// zero. 142 friend bool operator<(const VersionTuple &X, const VersionTuple &Y) { 143 return std::tie(X.Major, X.Minor, X.Subminor, X.Build) < 144 std::tie(Y.Major, Y.Minor, Y.Subminor, Y.Build); 145 } 146 147 /// Determine whether one version number follows another. 148 /// 149 /// If not provided, minor and subminor version numbers are considered to be 150 /// zero. 151 friend bool operator>(const VersionTuple &X, const VersionTuple &Y) { 152 return Y < X; 153 } 154 155 /// Determine whether one version number precedes or is 156 /// equivalent to another. 157 /// 158 /// If not provided, minor and subminor version numbers are considered to be 159 /// zero. 160 friend bool operator<=(const VersionTuple &X, const VersionTuple &Y) { 161 return !(Y < X); 162 } 163 164 /// Determine whether one version number follows or is 165 /// equivalent to another. 166 /// 167 /// If not provided, minor and subminor version numbers are considered to be 168 /// zero. 169 friend bool operator>=(const VersionTuple &X, const VersionTuple &Y) { 170 return !(X < Y); 171 } 172 173 friend hash_code hash_value(const VersionTuple &VT) { 174 return hash_combine(VT.Major, VT.Minor, VT.Subminor, VT.Build); 175 } 176 177 template <typename HasherT, llvm::support::endianness Endianness> 178 friend void addHash(HashBuilderImpl<HasherT, Endianness> &HBuilder, 179 const VersionTuple &VT) { 180 HBuilder.add(VT.Major, VT.Minor, VT.Subminor, VT.Build); 181 } 182 183 /// Retrieve a string representation of the version number. 184 std::string getAsString() const; 185 186 /// Try to parse the given string as a version number. 187 /// \returns \c true if the string does not match the regular expression 188 /// [0-9]+(\.[0-9]+){0,3} 189 bool tryParse(StringRef string); 190 }; 191 192 /// Print a version number. 193 raw_ostream &operator<<(raw_ostream &Out, const VersionTuple &V); 194 195 // Provide DenseMapInfo for version tuples. 196 template <> struct DenseMapInfo<VersionTuple> { 197 static inline VersionTuple getEmptyKey() { return VersionTuple(0x7FFFFFFF); } 198 static inline VersionTuple getTombstoneKey() { 199 return VersionTuple(0x7FFFFFFE); 200 } 201 static unsigned getHashValue(const VersionTuple &Value) { 202 unsigned Result = Value.getMajor(); 203 if (auto Minor = Value.getMinor()) 204 Result = detail::combineHashValue(Result, *Minor); 205 if (auto Subminor = Value.getSubminor()) 206 Result = detail::combineHashValue(Result, *Subminor); 207 if (auto Build = Value.getBuild()) 208 Result = detail::combineHashValue(Result, *Build); 209 210 return Result; 211 } 212 213 static bool isEqual(const VersionTuple &LHS, const VersionTuple &RHS) { 214 return LHS == RHS; 215 } 216 }; 217 218 } // end namespace llvm 219 #endif // LLVM_SUPPORT_VERSIONTUPLE_H 220