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