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 { 24*5f757f3fSDimitry 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: 42bdd1243dSDimitry Andric constexpr VersionTuple() 430b57cec5SDimitry Andric : Major(0), Minor(0), HasMinor(false), Subminor(0), HasSubminor(false), 440b57cec5SDimitry Andric Build(0), HasBuild(false) {} 450b57cec5SDimitry Andric 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 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 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 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). 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. 710b57cec5SDimitry Andric unsigned getMajor() const { return Major; } 720b57cec5SDimitry Andric 730b57cec5SDimitry Andric /// Retrieve the minor version number, if provided. 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. 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. 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. 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. 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. 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 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 175*5f757f3fSDimitry Andric template <typename HasherT, llvm::endianness Endianness> 176*5f757f3fSDimitry 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