10b57cec5SDimitry Andric //===- VersionTuple.h - Version Number Handling -----------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric ///
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric /// Defines the llvm::VersionTuple class, which represents a version in
110b57cec5SDimitry Andric /// the form major[.minor[.subminor]].
120b57cec5SDimitry Andric ///
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric #ifndef LLVM_SUPPORT_VERSIONTUPLE_H
150b57cec5SDimitry Andric #define LLVM_SUPPORT_VERSIONTUPLE_H
160b57cec5SDimitry Andric 
17fe6060f1SDimitry Andric #include "llvm/ADT/DenseMapInfo.h"
185ffd83dbSDimitry Andric #include "llvm/ADT/Hashing.h"
19bdd1243dSDimitry Andric #include <optional>
200b57cec5SDimitry Andric #include <string>
210b57cec5SDimitry Andric #include <tuple>
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric namespace llvm {
245f757f3fSDimitry Andric template <typename HasherT, llvm::endianness Endianness> class HashBuilder;
255ffd83dbSDimitry Andric class raw_ostream;
265ffd83dbSDimitry Andric class StringRef;
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric /// Represents a version number in the form major[.minor[.subminor[.build]]].
290b57cec5SDimitry Andric class VersionTuple {
300b57cec5SDimitry Andric   unsigned Major : 32;
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric   unsigned Minor : 31;
330b57cec5SDimitry Andric   unsigned HasMinor : 1;
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric   unsigned Subminor : 31;
360b57cec5SDimitry Andric   unsigned HasSubminor : 1;
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric   unsigned Build : 31;
390b57cec5SDimitry Andric   unsigned HasBuild : 1;
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric public:
VersionTuple()42bdd1243dSDimitry Andric   constexpr VersionTuple()
430b57cec5SDimitry Andric       : Major(0), Minor(0), HasMinor(false), Subminor(0), HasSubminor(false),
440b57cec5SDimitry Andric         Build(0), HasBuild(false) {}
450b57cec5SDimitry Andric 
VersionTuple(unsigned Major)46bdd1243dSDimitry Andric   explicit constexpr VersionTuple(unsigned Major)
470b57cec5SDimitry Andric       : Major(Major), Minor(0), HasMinor(false), Subminor(0),
480b57cec5SDimitry Andric         HasSubminor(false), Build(0), HasBuild(false) {}
490b57cec5SDimitry Andric 
VersionTuple(unsigned Major,unsigned Minor)50bdd1243dSDimitry Andric   explicit constexpr VersionTuple(unsigned Major, unsigned Minor)
510b57cec5SDimitry Andric       : Major(Major), Minor(Minor), HasMinor(true), Subminor(0),
520b57cec5SDimitry Andric         HasSubminor(false), Build(0), HasBuild(false) {}
530b57cec5SDimitry Andric 
VersionTuple(unsigned Major,unsigned Minor,unsigned Subminor)54bdd1243dSDimitry Andric   explicit constexpr VersionTuple(unsigned Major, unsigned Minor,
55bdd1243dSDimitry Andric                                   unsigned Subminor)
560b57cec5SDimitry Andric       : Major(Major), Minor(Minor), HasMinor(true), Subminor(Subminor),
570b57cec5SDimitry Andric         HasSubminor(true), Build(0), HasBuild(false) {}
580b57cec5SDimitry Andric 
VersionTuple(unsigned Major,unsigned Minor,unsigned Subminor,unsigned Build)59bdd1243dSDimitry Andric   explicit constexpr VersionTuple(unsigned Major, unsigned Minor,
60bdd1243dSDimitry Andric                                   unsigned Subminor, unsigned Build)
610b57cec5SDimitry Andric       : Major(Major), Minor(Minor), HasMinor(true), Subminor(Subminor),
620b57cec5SDimitry Andric         HasSubminor(true), Build(Build), HasBuild(true) {}
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric   /// Determine whether this version information is empty
650b57cec5SDimitry Andric   /// (e.g., all version components are zero).
empty()660b57cec5SDimitry Andric   bool empty() const {
670b57cec5SDimitry Andric     return Major == 0 && Minor == 0 && Subminor == 0 && Build == 0;
680b57cec5SDimitry Andric   }
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric   /// Retrieve the major version number.
getMajor()710b57cec5SDimitry Andric   unsigned getMajor() const { return Major; }
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric   /// Retrieve the minor version number, if provided.
getMinor()74bdd1243dSDimitry Andric   std::optional<unsigned> getMinor() const {
750b57cec5SDimitry Andric     if (!HasMinor)
76bdd1243dSDimitry Andric       return std::nullopt;
770b57cec5SDimitry Andric     return Minor;
780b57cec5SDimitry Andric   }
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric   /// Retrieve the subminor version number, if provided.
getSubminor()81bdd1243dSDimitry Andric   std::optional<unsigned> getSubminor() const {
820b57cec5SDimitry Andric     if (!HasSubminor)
83bdd1243dSDimitry Andric       return std::nullopt;
840b57cec5SDimitry Andric     return Subminor;
850b57cec5SDimitry Andric   }
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric   /// Retrieve the build version number, if provided.
getBuild()88bdd1243dSDimitry Andric   std::optional<unsigned> getBuild() const {
890b57cec5SDimitry Andric     if (!HasBuild)
90bdd1243dSDimitry Andric       return std::nullopt;
910b57cec5SDimitry Andric     return Build;
920b57cec5SDimitry Andric   }
930b57cec5SDimitry Andric 
94480093f4SDimitry Andric   /// Return a version tuple that contains only the first 3 version components.
withoutBuild()95480093f4SDimitry Andric   VersionTuple withoutBuild() const {
96480093f4SDimitry Andric     if (HasBuild)
97480093f4SDimitry Andric       return VersionTuple(Major, Minor, Subminor);
98480093f4SDimitry Andric     return *this;
99480093f4SDimitry Andric   }
100480093f4SDimitry Andric 
10181ad6265SDimitry Andric   /// Return a version tuple that contains a different major version but
10281ad6265SDimitry Andric   /// everything else is the same.
withMajorReplaced(unsigned NewMajor)10381ad6265SDimitry Andric   VersionTuple withMajorReplaced(unsigned NewMajor) const {
10481ad6265SDimitry Andric     return VersionTuple(NewMajor, Minor, Subminor, Build);
10581ad6265SDimitry Andric   }
10681ad6265SDimitry Andric 
107fe6060f1SDimitry Andric   /// Return a version tuple that contains only components that are non-zero.
normalize()108fe6060f1SDimitry Andric   VersionTuple normalize() const {
109fe6060f1SDimitry Andric     VersionTuple Result = *this;
110fe6060f1SDimitry Andric     if (Result.Build == 0) {
111fe6060f1SDimitry Andric       Result.HasBuild = false;
112fe6060f1SDimitry Andric       if (Result.Subminor == 0) {
113fe6060f1SDimitry Andric         Result.HasSubminor = false;
114fe6060f1SDimitry Andric         if (Result.Minor == 0)
115fe6060f1SDimitry Andric           Result.HasMinor = false;
116fe6060f1SDimitry Andric       }
117fe6060f1SDimitry Andric     }
118fe6060f1SDimitry Andric     return Result;
119fe6060f1SDimitry Andric   }
120fe6060f1SDimitry Andric 
1210b57cec5SDimitry Andric   /// Determine if two version numbers are equivalent. If not
1220b57cec5SDimitry Andric   /// provided, minor and subminor version numbers are considered to be zero.
1230b57cec5SDimitry Andric   friend bool operator==(const VersionTuple &X, const VersionTuple &Y) {
1240b57cec5SDimitry Andric     return X.Major == Y.Major && X.Minor == Y.Minor &&
1250b57cec5SDimitry Andric            X.Subminor == Y.Subminor && X.Build == Y.Build;
1260b57cec5SDimitry Andric   }
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric   /// Determine if two version numbers are not equivalent.
1290b57cec5SDimitry Andric   ///
1300b57cec5SDimitry Andric   /// If not provided, minor and subminor version numbers are considered to be
1310b57cec5SDimitry Andric   /// zero.
1320b57cec5SDimitry Andric   friend bool operator!=(const VersionTuple &X, const VersionTuple &Y) {
1330b57cec5SDimitry Andric     return !(X == Y);
1340b57cec5SDimitry Andric   }
1350b57cec5SDimitry Andric 
1360b57cec5SDimitry Andric   /// Determine whether one version number precedes another.
1370b57cec5SDimitry Andric   ///
1380b57cec5SDimitry Andric   /// If not provided, minor and subminor version numbers are considered to be
1390b57cec5SDimitry Andric   /// zero.
1400b57cec5SDimitry Andric   friend bool operator<(const VersionTuple &X, const VersionTuple &Y) {
1410b57cec5SDimitry Andric     return std::tie(X.Major, X.Minor, X.Subminor, X.Build) <
1420b57cec5SDimitry Andric            std::tie(Y.Major, Y.Minor, Y.Subminor, Y.Build);
1430b57cec5SDimitry Andric   }
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric   /// Determine whether one version number follows another.
1460b57cec5SDimitry Andric   ///
1470b57cec5SDimitry Andric   /// If not provided, minor and subminor version numbers are considered to be
1480b57cec5SDimitry Andric   /// zero.
1490b57cec5SDimitry Andric   friend bool operator>(const VersionTuple &X, const VersionTuple &Y) {
1500b57cec5SDimitry Andric     return Y < X;
1510b57cec5SDimitry Andric   }
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric   /// Determine whether one version number precedes or is
1540b57cec5SDimitry Andric   /// equivalent to another.
1550b57cec5SDimitry Andric   ///
1560b57cec5SDimitry Andric   /// If not provided, minor and subminor version numbers are considered to be
1570b57cec5SDimitry Andric   /// zero.
1580b57cec5SDimitry Andric   friend bool operator<=(const VersionTuple &X, const VersionTuple &Y) {
1590b57cec5SDimitry Andric     return !(Y < X);
1600b57cec5SDimitry Andric   }
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric   /// Determine whether one version number follows or is
1630b57cec5SDimitry Andric   /// equivalent to another.
1640b57cec5SDimitry Andric   ///
1650b57cec5SDimitry Andric   /// If not provided, minor and subminor version numbers are considered to be
1660b57cec5SDimitry Andric   /// zero.
1670b57cec5SDimitry Andric   friend bool operator>=(const VersionTuple &X, const VersionTuple &Y) {
1680b57cec5SDimitry Andric     return !(X < Y);
1690b57cec5SDimitry Andric   }
1700b57cec5SDimitry Andric 
hash_value(const VersionTuple & VT)17181ad6265SDimitry Andric   friend hash_code hash_value(const VersionTuple &VT) {
17281ad6265SDimitry Andric     return hash_combine(VT.Major, VT.Minor, VT.Subminor, VT.Build);
1735ffd83dbSDimitry Andric   }
1745ffd83dbSDimitry Andric 
1755f757f3fSDimitry Andric   template <typename HasherT, llvm::endianness Endianness>
addHash(HashBuilder<HasherT,Endianness> & HBuilder,const VersionTuple & VT)1765f757f3fSDimitry Andric   friend void addHash(HashBuilder<HasherT, Endianness> &HBuilder,
177349cc55cSDimitry Andric                       const VersionTuple &VT) {
178349cc55cSDimitry Andric     HBuilder.add(VT.Major, VT.Minor, VT.Subminor, VT.Build);
179349cc55cSDimitry Andric   }
180349cc55cSDimitry Andric 
1810b57cec5SDimitry Andric   /// Retrieve a string representation of the version number.
1820b57cec5SDimitry Andric   std::string getAsString() const;
1830b57cec5SDimitry Andric 
1840b57cec5SDimitry Andric   /// Try to parse the given string as a version number.
1850b57cec5SDimitry Andric   /// \returns \c true if the string does not match the regular expression
1860b57cec5SDimitry Andric   ///   [0-9]+(\.[0-9]+){0,3}
1870b57cec5SDimitry Andric   bool tryParse(StringRef string);
1880b57cec5SDimitry Andric };
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric /// Print a version number.
1910b57cec5SDimitry Andric raw_ostream &operator<<(raw_ostream &Out, const VersionTuple &V);
1920b57cec5SDimitry Andric 
193fe6060f1SDimitry Andric // Provide DenseMapInfo for version tuples.
194fe6060f1SDimitry Andric template <> struct DenseMapInfo<VersionTuple> {
195fe6060f1SDimitry Andric   static inline VersionTuple getEmptyKey() { return VersionTuple(0x7FFFFFFF); }
196fe6060f1SDimitry Andric   static inline VersionTuple getTombstoneKey() {
197fe6060f1SDimitry Andric     return VersionTuple(0x7FFFFFFE);
198fe6060f1SDimitry Andric   }
199fe6060f1SDimitry Andric   static unsigned getHashValue(const VersionTuple &Value) {
200fe6060f1SDimitry Andric     unsigned Result = Value.getMajor();
201fe6060f1SDimitry Andric     if (auto Minor = Value.getMinor())
202fe6060f1SDimitry Andric       Result = detail::combineHashValue(Result, *Minor);
203fe6060f1SDimitry Andric     if (auto Subminor = Value.getSubminor())
204fe6060f1SDimitry Andric       Result = detail::combineHashValue(Result, *Subminor);
205fe6060f1SDimitry Andric     if (auto Build = Value.getBuild())
206fe6060f1SDimitry Andric       Result = detail::combineHashValue(Result, *Build);
207fe6060f1SDimitry Andric 
208fe6060f1SDimitry Andric     return Result;
209fe6060f1SDimitry Andric   }
210fe6060f1SDimitry Andric 
211fe6060f1SDimitry Andric   static bool isEqual(const VersionTuple &LHS, const VersionTuple &RHS) {
212fe6060f1SDimitry Andric     return LHS == RHS;
213fe6060f1SDimitry Andric   }
214fe6060f1SDimitry Andric };
215fe6060f1SDimitry Andric 
2160b57cec5SDimitry Andric } // end namespace llvm
2170b57cec5SDimitry Andric #endif // LLVM_SUPPORT_VERSIONTUPLE_H
218