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