121 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the VersionTuple class, which represents a version in10// 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 19using namespace llvm;20 21std::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 30raw_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 41static 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 63bool 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 112VersionTuple VersionTuple::withMajorReplaced(unsigned NewMajor) const {113 if (HasBuild)114 return VersionTuple(NewMajor, Minor, Subminor, Build);115 if (HasSubminor)116 return VersionTuple(NewMajor, Minor, Subminor);117 if (HasMinor)118 return VersionTuple(NewMajor, Minor);119 return VersionTuple(NewMajor);120}121