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