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 only components that are non-zero. 101 VersionTuple normalize() const { 102 VersionTuple Result = *this; 103 if (Result.Build == 0) { 104 Result.HasBuild = false; 105 if (Result.Subminor == 0) { 106 Result.HasSubminor = false; 107 if (Result.Minor == 0) 108 Result.HasMinor = false; 109 } 110 } 111 return Result; 112 } 113 114 /// Determine if two version numbers are equivalent. If not 115 /// provided, minor and subminor version numbers are considered to be zero. 116 friend bool operator==(const VersionTuple &X, const VersionTuple &Y) { 117 return X.Major == Y.Major && X.Minor == Y.Minor && 118 X.Subminor == Y.Subminor && X.Build == Y.Build; 119 } 120 121 /// Determine if two version numbers are not equivalent. 122 /// 123 /// If not provided, minor and subminor version numbers are considered to be 124 /// zero. 125 friend bool operator!=(const VersionTuple &X, const VersionTuple &Y) { 126 return !(X == Y); 127 } 128 129 /// Determine whether one version number precedes another. 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 std::tie(X.Major, X.Minor, X.Subminor, X.Build) < 135 std::tie(Y.Major, Y.Minor, Y.Subminor, Y.Build); 136 } 137 138 /// Determine whether one version number follows 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 Y < X; 144 } 145 146 /// Determine whether one version number precedes or is 147 /// equivalent to 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 follows 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 !(X < Y); 162 } 163 164 friend llvm::hash_code hash_value(const VersionTuple &VT) { 165 return llvm::hash_combine(VT.Major, VT.Minor, VT.Subminor, VT.Build); 166 } 167 168 template <typename HasherT, llvm::support::endianness Endianness> 169 friend void addHash(HashBuilderImpl<HasherT, Endianness> &HBuilder, 170 const VersionTuple &VT) { 171 HBuilder.add(VT.Major, VT.Minor, VT.Subminor, VT.Build); 172 } 173 174 /// Retrieve a string representation of the version number. 175 std::string getAsString() const; 176 177 /// Try to parse the given string as a version number. 178 /// \returns \c true if the string does not match the regular expression 179 /// [0-9]+(\.[0-9]+){0,3} 180 bool tryParse(StringRef string); 181 }; 182 183 /// Print a version number. 184 raw_ostream &operator<<(raw_ostream &Out, const VersionTuple &V); 185 186 // Provide DenseMapInfo for version tuples. 187 template <> struct DenseMapInfo<VersionTuple> { 188 static inline VersionTuple getEmptyKey() { return VersionTuple(0x7FFFFFFF); } 189 static inline VersionTuple getTombstoneKey() { 190 return VersionTuple(0x7FFFFFFE); 191 } 192 static unsigned getHashValue(const VersionTuple &Value) { 193 unsigned Result = Value.getMajor(); 194 if (auto Minor = Value.getMinor()) 195 Result = detail::combineHashValue(Result, *Minor); 196 if (auto Subminor = Value.getSubminor()) 197 Result = detail::combineHashValue(Result, *Subminor); 198 if (auto Build = Value.getBuild()) 199 Result = detail::combineHashValue(Result, *Build); 200 201 return Result; 202 } 203 204 static bool isEqual(const VersionTuple &LHS, const VersionTuple &RHS) { 205 return LHS == RHS; 206 } 207 }; 208 209 } // end namespace llvm 210 #endif // LLVM_SUPPORT_VERSIONTUPLE_H 211