1 //===- VersionTuple.cpp - 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 // This file implements the VersionTuple class, which represents a version in 10 // the form major[.minor[.subminor]]. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/Support/VersionTuple.h" 15 #include "llvm/ADT/StringRef.h" 16 #include "llvm/Support/raw_ostream.h" 17 #include <cassert> 18 19 using namespace llvm; 20 21 std::string VersionTuple::getAsString() const { 22 std::string Result; 23 { 24 llvm::raw_string_ostream Out(Result); 25 Out << *this; 26 } 27 return Result; 28 } 29 30 raw_ostream &llvm::operator<<(raw_ostream &Out, const VersionTuple &V) { 31 Out << V.getMajor(); 32 if (std::optional<unsigned> Minor = V.getMinor()) 33 Out << '.' << *Minor; 34 if (std::optional<unsigned> Subminor = V.getSubminor()) 35 Out << '.' << *Subminor; 36 if (std::optional<unsigned> Build = V.getBuild()) 37 Out << '.' << *Build; 38 return Out; 39 } 40 41 static bool parseInt(StringRef &input, unsigned &value) { 42 assert(value == 0); 43 if (input.empty()) 44 return true; 45 46 char next = input[0]; 47 input = input.substr(1); 48 if (next < '0' || next > '9') 49 return true; 50 value = (unsigned)(next - '0'); 51 52 while (!input.empty()) { 53 next = input[0]; 54 if (next < '0' || next > '9') 55 return false; 56 input = input.substr(1); 57 value = value * 10 + (unsigned)(next - '0'); 58 } 59 60 return false; 61 } 62 63 bool VersionTuple::tryParse(StringRef input) { 64 unsigned major = 0, minor = 0, micro = 0, build = 0; 65 66 // Parse the major version, [0-9]+ 67 if (parseInt(input, major)) 68 return true; 69 70 if (input.empty()) { 71 *this = VersionTuple(major); 72 return false; 73 } 74 75 // If we're not done, parse the minor version, \.[0-9]+ 76 if (input[0] != '.') 77 return true; 78 input = input.substr(1); 79 if (parseInt(input, minor)) 80 return true; 81 82 if (input.empty()) { 83 *this = VersionTuple(major, minor); 84 return false; 85 } 86 87 // If we're not done, parse the micro version, \.[0-9]+ 88 if (!input.consume_front(".")) 89 return true; 90 if (parseInt(input, micro)) 91 return true; 92 93 if (input.empty()) { 94 *this = VersionTuple(major, minor, micro); 95 return false; 96 } 97 98 // If we're not done, parse the micro version, \.[0-9]+ 99 if (!input.consume_front(".")) 100 return true; 101 if (parseInt(input, build)) 102 return true; 103 104 // If we have characters left over, it's an error. 105 if (!input.empty()) 106 return true; 107 108 *this = VersionTuple(major, minor, micro, build); 109 return false; 110 } 111