labath created this revision.
labath added reviewers: zturner, erik.pilkington.
Herald added a subscriber: mgorny.

This kind of functionality is useful to other project apart from clang.
LLDB works with version numbers a lot, but it does not have a convenient
abstraction for this. Moving this class to a lower level library allows
it to be freely used within LLDB.

The code is an identical copy of the version from clang (apart from
namespace change and re-clang-formatting).

I didn't find any tests specific for this class, so I wrote a couple of
quick ones for the more interesting bits of functionality.


Repository:
  rL LLVM

https://reviews.llvm.org/D47887

Files:
  include/llvm/Support/VersionTuple.h
  lib/Support/CMakeLists.txt
  lib/Support/VersionTuple.cpp
  unittests/Support/CMakeLists.txt
  unittests/Support/VersionTupleTest.cpp

Index: unittests/Support/VersionTupleTest.cpp
===================================================================
--- /dev/null
+++ unittests/Support/VersionTupleTest.cpp
@@ -0,0 +1,50 @@
+//===- VersionTupleTests.cpp - Version Number Handling Tests --------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/VersionTuple.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+TEST(VersionTuple, getAsString) {
+  EXPECT_EQ("0", VersionTuple().getAsString());
+  EXPECT_EQ("1", VersionTuple(1).getAsString());
+  EXPECT_EQ("1.2", VersionTuple(1, 2).getAsString());
+  EXPECT_EQ("1.2.3", VersionTuple(1, 2, 3).getAsString());
+  EXPECT_EQ("1.2.3.4", VersionTuple(1, 2, 3, 4).getAsString());
+}
+
+TEST(VersionTuple, tryParse) {
+  VersionTuple VT;
+
+  EXPECT_FALSE(VT.tryParse("1"));
+  EXPECT_EQ("1", VT.getAsString());
+
+  EXPECT_FALSE(VT.tryParse("1.2"));
+  EXPECT_EQ("1.2", VT.getAsString());
+
+  EXPECT_FALSE(VT.tryParse("1.2.3"));
+  EXPECT_EQ("1.2.3", VT.getAsString());
+
+  EXPECT_FALSE(VT.tryParse("1.2.3.4"));
+  EXPECT_EQ("1.2.3.4", VT.getAsString());
+
+  EXPECT_TRUE(VT.tryParse(""));
+  EXPECT_TRUE(VT.tryParse("1."));
+  EXPECT_TRUE(VT.tryParse("1.2."));
+  EXPECT_TRUE(VT.tryParse("1.2.3."));
+  EXPECT_TRUE(VT.tryParse("1.2.3.4."));
+  EXPECT_TRUE(VT.tryParse("1.2.3.4.5"));
+  EXPECT_TRUE(VT.tryParse("1-2"));
+  EXPECT_TRUE(VT.tryParse("1+2"));
+  EXPECT_TRUE(VT.tryParse(".1"));
+  EXPECT_TRUE(VT.tryParse(" 1"));
+  EXPECT_TRUE(VT.tryParse("1 "));
+  EXPECT_TRUE(VT.tryParse("."));
+}
Index: unittests/Support/CMakeLists.txt
===================================================================
--- unittests/Support/CMakeLists.txt
+++ unittests/Support/CMakeLists.txt
@@ -61,6 +61,7 @@
   TrailingObjectsTest.cpp
   TrigramIndexTest.cpp
   UnicodeTest.cpp
+  VersionTupleTest.cpp
   YAMLIOTest.cpp
   YAMLParserTest.cpp
   formatted_raw_ostream_test.cpp
Index: lib/Support/VersionTuple.cpp
===================================================================
--- /dev/null
+++ lib/Support/VersionTuple.cpp
@@ -0,0 +1,110 @@
+//===- VersionTuple.cpp - Version Number Handling ---------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the VersionTuple class, which represents a version in
+// the form major[.minor[.subminor]].
+//
+//===----------------------------------------------------------------------===//
+#include "llvm/Support/VersionTuple.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+std::string VersionTuple::getAsString() const {
+  std::string Result;
+  {
+    llvm::raw_string_ostream Out(Result);
+    Out << *this;
+  }
+  return Result;
+}
+
+raw_ostream &llvm::operator<<(raw_ostream &Out, const VersionTuple &V) {
+  Out << V.getMajor();
+  if (Optional<unsigned> Minor = V.getMinor())
+    Out << '.' << *Minor;
+  if (Optional<unsigned> Subminor = V.getSubminor())
+    Out << '.' << *Subminor;
+  if (Optional<unsigned> Build = V.getBuild())
+    Out << '.' << *Build;
+  return Out;
+}
+
+static bool parseInt(StringRef &input, unsigned &value) {
+  assert(value == 0);
+  if (input.empty())
+    return true;
+
+  char next = input[0];
+  input = input.substr(1);
+  if (next < '0' || next > '9')
+    return true;
+  value = (unsigned)(next - '0');
+
+  while (!input.empty()) {
+    next = input[0];
+    if (next < '0' || next > '9')
+      return false;
+    input = input.substr(1);
+    value = value * 10 + (unsigned)(next - '0');
+  }
+
+  return false;
+}
+
+bool VersionTuple::tryParse(StringRef input) {
+  unsigned major = 0, minor = 0, micro = 0, build = 0;
+
+  // Parse the major version, [0-9]+
+  if (parseInt(input, major))
+    return true;
+
+  if (input.empty()) {
+    *this = VersionTuple(major);
+    return false;
+  }
+
+  // If we're not done, parse the minor version, \.[0-9]+
+  if (input[0] != '.')
+    return true;
+  input = input.substr(1);
+  if (parseInt(input, minor))
+    return true;
+
+  if (input.empty()) {
+    *this = VersionTuple(major, minor);
+    return false;
+  }
+
+  // If we're not done, parse the micro version, \.[0-9]+
+  if (input[0] != '.')
+    return true;
+  input = input.substr(1);
+  if (parseInt(input, micro))
+    return true;
+
+  if (input.empty()) {
+    *this = VersionTuple(major, minor, micro);
+    return false;
+  }
+
+  // If we're not done, parse the micro version, \.[0-9]+
+  if (input[0] != '.')
+    return true;
+  input = input.substr(1);
+  if (parseInt(input, build))
+    return true;
+
+  // If we have characters left over, it's an error.
+  if (!input.empty())
+    return true;
+
+  *this = VersionTuple(major, minor, micro, build);
+  return false;
+}
Index: lib/Support/CMakeLists.txt
===================================================================
--- lib/Support/CMakeLists.txt
+++ lib/Support/CMakeLists.txt
@@ -121,6 +121,7 @@
   Twine.cpp
   Unicode.cpp
   UnicodeCaseFold.cpp
+  VersionTuple.cpp
   WithColor.cpp
   YAMLParser.cpp
   YAMLTraits.cpp
Index: include/llvm/Support/VersionTuple.h
===================================================================
--- /dev/null
+++ include/llvm/Support/VersionTuple.h
@@ -0,0 +1,154 @@
+//===- VersionTuple.h - Version Number Handling -----------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Defines the llvm::VersionTuple class, which represents a version in
+/// the form major[.minor[.subminor]].
+///
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_SUPPORT_VERSIONTUPLE_H
+#define LLVM_SUPPORT_VERSIONTUPLE_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/raw_ostream.h"
+#include <string>
+#include <tuple>
+
+namespace llvm {
+
+/// Represents a version number in the form major[.minor[.subminor[.build]]].
+class VersionTuple {
+  unsigned Major : 32;
+
+  unsigned Minor : 31;
+  unsigned HasMinor : 1;
+
+  unsigned Subminor : 31;
+  unsigned HasSubminor : 1;
+
+  unsigned Build : 31;
+  unsigned HasBuild : 1;
+
+public:
+  VersionTuple()
+      : Major(0), Minor(0), HasMinor(false), Subminor(0), HasSubminor(false),
+        Build(0), HasBuild(false) {}
+
+  explicit VersionTuple(unsigned Major)
+      : Major(Major), Minor(0), HasMinor(false), Subminor(0),
+        HasSubminor(false), Build(0), HasBuild(false) {}
+
+  explicit VersionTuple(unsigned Major, unsigned Minor)
+      : Major(Major), Minor(Minor), HasMinor(true), Subminor(0),
+        HasSubminor(false), Build(0), HasBuild(false) {}
+
+  explicit VersionTuple(unsigned Major, unsigned Minor, unsigned Subminor)
+      : Major(Major), Minor(Minor), HasMinor(true), Subminor(Subminor),
+        HasSubminor(true), Build(0), HasBuild(false) {}
+
+  explicit VersionTuple(unsigned Major, unsigned Minor, unsigned Subminor,
+                        unsigned Build)
+      : Major(Major), Minor(Minor), HasMinor(true), Subminor(Subminor),
+        HasSubminor(true), Build(Build), HasBuild(true) {}
+
+  /// Determine whether this version information is empty
+  /// (e.g., all version components are zero).
+  bool empty() const {
+    return Major == 0 && Minor == 0 && Subminor == 0 && Build == 0;
+  }
+
+  /// Retrieve the major version number.
+  unsigned getMajor() const { return Major; }
+
+  /// Retrieve the minor version number, if provided.
+  Optional<unsigned> getMinor() const {
+    if (!HasMinor)
+      return None;
+    return Minor;
+  }
+
+  /// Retrieve the subminor version number, if provided.
+  Optional<unsigned> getSubminor() const {
+    if (!HasSubminor)
+      return None;
+    return Subminor;
+  }
+
+  /// Retrieve the build version number, if provided.
+  Optional<unsigned> getBuild() const {
+    if (!HasBuild)
+      return None;
+    return Build;
+  }
+
+  /// Determine if two version numbers are equivalent. If not
+  /// provided, minor and subminor version numbers are considered to be zero.
+  friend bool operator==(const VersionTuple &X, const VersionTuple &Y) {
+    return X.Major == Y.Major && X.Minor == Y.Minor &&
+           X.Subminor == Y.Subminor && X.Build == Y.Build;
+  }
+
+  /// Determine if two version numbers are not equivalent.
+  ///
+  /// If not provided, minor and subminor version numbers are considered to be
+  /// zero.
+  friend bool operator!=(const VersionTuple &X, const VersionTuple &Y) {
+    return !(X == Y);
+  }
+
+  /// Determine whether one version number precedes another.
+  ///
+  /// If not provided, minor and subminor version numbers are considered to be
+  /// zero.
+  friend bool operator<(const VersionTuple &X, const VersionTuple &Y) {
+    return std::tie(X.Major, X.Minor, X.Subminor, X.Build) <
+           std::tie(Y.Major, Y.Minor, Y.Subminor, Y.Build);
+  }
+
+  /// Determine whether one version number follows another.
+  ///
+  /// If not provided, minor and subminor version numbers are considered to be
+  /// zero.
+  friend bool operator>(const VersionTuple &X, const VersionTuple &Y) {
+    return Y < X;
+  }
+
+  /// Determine whether one version number precedes or is
+  /// equivalent to another.
+  ///
+  /// If not provided, minor and subminor version numbers are considered to be
+  /// zero.
+  friend bool operator<=(const VersionTuple &X, const VersionTuple &Y) {
+    return !(Y < X);
+  }
+
+  /// Determine whether one version number follows or is
+  /// equivalent to another.
+  ///
+  /// If not provided, minor and subminor version numbers are considered to be
+  /// zero.
+  friend bool operator>=(const VersionTuple &X, const VersionTuple &Y) {
+    return !(X < Y);
+  }
+
+  /// Retrieve a string representation of the version number.
+  std::string getAsString() const;
+
+  /// Try to parse the given string as a version number.
+  /// \returns \c true if the string does not match the regular expression
+  ///   [0-9]+(\.[0-9]+){0,3}
+  bool tryParse(StringRef string);
+};
+
+/// Print a version number.
+raw_ostream &operator<<(raw_ostream &Out, const VersionTuple &V);
+
+} // end namespace llvm
+#endif // LLVM_SUPPORT_VERSIONTUPLE_H
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to