xref: /freebsd/contrib/llvm-project/llvm/include/llvm/Support/VersionTuple.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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/Compiler.h"
20 #include <optional>
21 #include <string>
22 #include <tuple>
23 
24 namespace llvm {
25 template <typename HasherT, llvm::endianness Endianness> class HashBuilder;
26 class raw_ostream;
27 class StringRef;
28 
29 /// Represents a version number in the form major[.minor[.subminor[.build]]].
30 class VersionTuple {
31   unsigned Major : 32;
32 
33   unsigned Minor : 31;
34   unsigned HasMinor : 1;
35 
36   unsigned Subminor : 31;
37   unsigned HasSubminor : 1;
38 
39   unsigned Build : 31;
40   unsigned HasBuild : 1;
41 
42 public:
VersionTuple()43   constexpr VersionTuple()
44       : Major(0), Minor(0), HasMinor(false), Subminor(0), HasSubminor(false),
45         Build(0), HasBuild(false) {}
46 
VersionTuple(unsigned Major)47   explicit constexpr VersionTuple(unsigned Major)
48       : Major(Major), Minor(0), HasMinor(false), Subminor(0),
49         HasSubminor(false), Build(0), HasBuild(false) {}
50 
VersionTuple(unsigned Major,unsigned Minor)51   explicit constexpr VersionTuple(unsigned Major, unsigned Minor)
52       : Major(Major), Minor(Minor), HasMinor(true), Subminor(0),
53         HasSubminor(false), Build(0), HasBuild(false) {}
54 
VersionTuple(unsigned Major,unsigned Minor,unsigned Subminor)55   explicit constexpr VersionTuple(unsigned Major, unsigned Minor,
56                                   unsigned Subminor)
57       : Major(Major), Minor(Minor), HasMinor(true), Subminor(Subminor),
58         HasSubminor(true), Build(0), HasBuild(false) {}
59 
VersionTuple(unsigned Major,unsigned Minor,unsigned Subminor,unsigned Build)60   explicit constexpr VersionTuple(unsigned Major, unsigned Minor,
61                                   unsigned Subminor, 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).
empty()67   bool empty() const {
68     return Major == 0 && Minor == 0 && Subminor == 0 && Build == 0;
69   }
70 
71   /// Retrieve the major version number.
getMajor()72   unsigned getMajor() const { return Major; }
73 
74   /// Retrieve the minor version number, if provided.
getMinor()75   std::optional<unsigned> getMinor() const {
76     if (!HasMinor)
77       return std::nullopt;
78     return Minor;
79   }
80 
81   /// Retrieve the subminor version number, if provided.
getSubminor()82   std::optional<unsigned> getSubminor() const {
83     if (!HasSubminor)
84       return std::nullopt;
85     return Subminor;
86   }
87 
88   /// Retrieve the build version number, if provided.
getBuild()89   std::optional<unsigned> getBuild() const {
90     if (!HasBuild)
91       return std::nullopt;
92     return Build;
93   }
94 
95   /// Return a version tuple that contains only the first 3 version components.
withoutBuild()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   LLVM_ABI VersionTuple withMajorReplaced(unsigned NewMajor) const;
105 
106   /// Return a version tuple that contains only components that are non-zero.
normalize()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 
hash_value(const VersionTuple & VT)170   friend hash_code hash_value(const VersionTuple &VT) {
171     return hash_combine(VT.Major, VT.Minor, VT.Subminor, VT.Build);
172   }
173 
174   template <typename HasherT, llvm::endianness Endianness>
addHash(HashBuilder<HasherT,Endianness> & HBuilder,const VersionTuple & VT)175   friend void addHash(HashBuilder<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   LLVM_ABI 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   LLVM_ABI bool tryParse(StringRef string);
187 };
188 
189 /// Print a version number.
190 LLVM_ABI 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