summaryrefslogtreecommitdiff
path: root/external/semver/src
diff options
context:
space:
mode:
authorIronClawTrem <louie.nutman@gmail.com>2020-02-16 03:40:06 +0000
committerIronClawTrem <louie.nutman@gmail.com>2020-02-16 03:40:06 +0000
commit425decdf7e9284d15aa726e3ae96b9942fb0e3ea (patch)
tree6c0dd7edfefff1be7b9e75fe0b3a0a85fe1595f3 /external/semver/src
parentccb0b2e4d6674a7a00c9bf491f08fc73b6898c54 (diff)
create tremded branch
Diffstat (limited to 'external/semver/src')
-rw-r--r--external/semver/src/include/semantic_version.h189
-rw-r--r--external/semver/src/lib/CMakeLists.txt1
-rw-r--r--external/semver/src/lib/semantic_version_v1.cpp286
-rw-r--r--external/semver/src/lib/semantic_version_v2.cpp272
-rw-r--r--external/semver/src/quickcheck/CMakeLists.txt29
-rw-r--r--external/semver/src/quickcheck/Main.hibin0 -> 3353 bytes
-rw-r--r--external/semver/src/quickcheck/Main.hs80
-rw-r--r--external/semver/src/quickcheck/Main.obin0 -> 35952 bytes
-rw-r--r--external/semver/src/quickcheck/Semver.hsc87
-rw-r--r--external/semver/src/quickcheck/semantic_version_ffi.cpp58
-rw-r--r--external/semver/src/quickcheck/semantic_version_ffi.h27
-rw-r--r--external/semver/src/test/CMakeLists.txt3
-rw-r--r--external/semver/src/test/main.cpp297
13 files changed, 1329 insertions, 0 deletions
diff --git a/external/semver/src/include/semantic_version.h b/external/semver/src/include/semantic_version.h
new file mode 100644
index 0000000..a6214f9
--- /dev/null
+++ b/external/semver/src/include/semantic_version.h
@@ -0,0 +1,189 @@
+#pragma once
+
+// Semantic version - see http://semver.org/
+
+// The major difference between v1::Version and v2::Version is that v1 includes
+// the build identifier when calculating precedence of versions (see
+// http://semver.org/spec/v2.0.0-rc.1.html points 10,11) while v2 omits the
+// build identifier when calculating precedence of versions (see
+// http://semver.org/spec/v2.0.0.html points 10,11).
+
+#include <string>
+#include <ostream>
+
+namespace semver
+{
+ namespace v1
+ {
+
+ class Version
+ {
+ public:
+ // By-parts (and default) version constructor: no validation.
+ Version(
+ unsigned int major = 0,
+ unsigned int minor = 0,
+ unsigned int patch = 1,
+ const std::string& prerelease = std::string{},
+ const std::string& build = std::string{});
+
+ // Parse from a version string: no validation.
+ explicit Version(const std::string& s);
+
+ // Is a version well-formed according to the spec?
+ // The semver spec stipulates a few properties of a well-formed version:
+ // that both the dot-separated prerelease version and the build version
+ // MUST comprise only [0-9A-Za-z-]; that numerical dot-separated
+ // identifiers MUST NOT include leading zeroes; and that such identifiers
+ // MUST NOT be empty.
+ bool IsWellFormed() const;
+
+ // Parse from a version string, with validation according to the spec.
+ static Version Parse(const std::string& s, bool& wellformed);
+
+ unsigned int GetMajorVersion() const { return m_majorVersion; }
+ unsigned int GetMinorVersion() const { return m_minorVersion; }
+ unsigned int GetPatchVersion() const { return m_patchVersion; }
+
+ // Create a new version by incrementing a part of a version. Other parts
+ // will be reset to 0, per the spec.
+ Version NextMajorVersion() const;
+ Version NextMinorVersion() const;
+ Version NextPatchVersion() const;
+
+ // A version satisfies another version if it is greater than or equal to
+ // it in precedence. Additionally, pre-release versions and build versions
+ // both satisfy their corresponding normal versions, and all pre-release
+ // or build versions thereof.
+ bool Satisfies(const Version& other) const;
+
+ // Precedence is calculated by comparing the major, minor, patch,
+ // pre-release and build parts in that order. Pre-release and build
+ // strings are considered as lists of dot-separated identifiers, whereby
+ // if an identifier is numeric, it is compared as such; otherwise
+ // comparison is based on ASCII sort order.
+ friend bool operator<(const Version& a, const Version& b);
+ friend bool operator==(const Version& a, const Version& b);
+
+ // A version is output as X.Y.Z (Major.Minor.Patch)
+ // A pre-release string (eg alpha.1) may follow immediately, joined by a -
+ // A build string may follow (eg 123.f83eaa931), joined by a +
+ friend std::ostream& operator<<(std::ostream& s, const Version& v);
+
+ private:
+ unsigned int m_majorVersion = 0;
+ unsigned int m_minorVersion = 0;
+ unsigned int m_patchVersion = 1;
+ std::string m_prereleaseVersion;
+ std::string m_buildVersion;
+ };
+
+ inline bool operator!=(const Version& a, const Version& b)
+ {
+ return !(a == b);
+ }
+
+ inline bool operator>=(const Version& a, const Version& b)
+ {
+ return !(a < b);
+ }
+
+ inline bool operator<=(const Version& a, const Version& b)
+ {
+ return (a == b) || (a < b);
+ }
+
+ inline bool operator>(const Version& a, const Version& b)
+ {
+ return (a != b) && (a >= b);
+ }
+ }
+
+ inline namespace v2
+ {
+
+ class Version
+ {
+ public:
+ // By-parts (and default) version constructor: no validation.
+ Version(
+ unsigned int major = 0,
+ unsigned int minor = 0,
+ unsigned int patch = 1,
+ const std::string& prerelease = std::string{},
+ const std::string& build = std::string{});
+
+ // Parse from a version string: no validation.
+ explicit Version(const std::string& s);
+
+ // Is a version well-formed according to the spec?
+ // The semver spec stipulates a few properties of a well-formed version:
+ // that both the dot-separated prerelease version and the build version
+ // MUST comprise only [0-9A-Za-z-]; that numerical dot-separated
+ // identifiers MUST NOT include leading zeroes; and that such identifiers
+ // MUST NOT be empty.
+ bool IsWellFormed() const;
+
+ unsigned int GetMajorVersion() const { return m_majorVersion; }
+ unsigned int GetMinorVersion() const { return m_minorVersion; }
+ unsigned int GetPatchVersion() const { return m_patchVersion; }
+
+ // Create a new version by incrementing a part of a version. Other parts
+ // will be reset to 0, per the spec.
+ Version NextMajorVersion() const;
+ Version NextMinorVersion() const;
+ Version NextPatchVersion() const;
+
+ // A version satisfies another version if it is greater than or equal to
+ // it in precedence. Additionally, pre-release versions and build versions
+ // both satisfy their corresponding normal versions, and all pre-release
+ // or build versions thereof.
+ bool Satisfies(const Version& other) const;
+
+ // Precedence is calculated by comparing the major, minor, patch, and
+ // pre-release parts in that order. Pre-release strings are considered as
+ // lists of dot-separated identifiers, whereby if an identifier is
+ // numeric, it is compared as such; otherwise comparison is based on ASCII
+ // sort order. Note: according to semver v2.0.0, build version is NOT
+ // considered when determining precedence.
+ friend bool operator<(const Version& a, const Version& b);
+ friend bool operator==(const Version& a, const Version& b);
+
+ // For exact equality (as opposed to precedence equality)
+ bool Equals(const Version& other) const;
+
+ // A version is output as X.Y.Z (Major.Minor.Patch)
+ // A pre-release string (eg alpha.1) may follow immediately, joined by a -
+ // A build string may follow (eg 123.f83eaa931), joined by a +
+ friend std::ostream& operator<<(std::ostream& s, const Version& v);
+
+ private:
+ unsigned int m_majorVersion = 0;
+ unsigned int m_minorVersion = 0;
+ unsigned int m_patchVersion = 1;
+ std::string m_prereleaseVersion;
+ std::string m_buildVersion;
+ };
+
+ inline bool operator!=(const Version& a, const Version& b)
+ {
+ return !(a == b);
+ }
+
+ inline bool operator>=(const Version& a, const Version& b)
+ {
+ return !(a < b);
+ }
+
+ inline bool operator<=(const Version& a, const Version& b)
+ {
+ return (a == b) || (a < b);
+ }
+
+ inline bool operator>(const Version& a, const Version& b)
+ {
+ return (a != b) && (a >= b);
+ }
+ }
+}
+
diff --git a/external/semver/src/lib/CMakeLists.txt b/external/semver/src/lib/CMakeLists.txt
new file mode 100644
index 0000000..ad43505
--- /dev/null
+++ b/external/semver/src/lib/CMakeLists.txt
@@ -0,0 +1 @@
+add_library (${PROJECT_NAME} semantic_version_v1.cpp semantic_version_v2.cpp)
diff --git a/external/semver/src/lib/semantic_version_v1.cpp b/external/semver/src/lib/semantic_version_v1.cpp
new file mode 100644
index 0000000..4df8bef
--- /dev/null
+++ b/external/semver/src/lib/semantic_version_v1.cpp
@@ -0,0 +1,286 @@
+#include "semantic_version.h"
+
+#include <algorithm>
+#include <cctype>
+#include <cstdlib>
+#include <sstream>
+#include <tuple>
+#include <vector>
+
+using namespace std;
+
+//------------------------------------------------------------------------------
+// From http://semver.org/ - Version 2.0.0
+
+// Pre-release versions satisfy but have a lower precedence than the associated
+// normal version.
+
+// Build versions satisfy and have a higher precedence than the associated
+// normal version.
+
+// Precedence MUST be calculated by separating the version into major, minor,
+// patch, pre-release, and build identifiers in that order. Major, minor, and
+// patch versions are always compared numerically. Pre-release and build version
+// precedence MUST be determined by comparing each dot separated identifier as
+// follows: identifiers consisting of only digits are compared numerically and
+// identifiers with letters or dashes are compared lexically in ASCII sort
+// order. Numeric identifiers always have lower precedence than non-numeric
+// identifiers. Example: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-beta.2 <
+// 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0-rc.1+build.1 < 1.0.0 < 1.0.0+0.3.7 <
+// 1.3.7+build < 1.3.7+build.2.b8f12d7 < 1.3.7+build.11.e0f985a.
+
+namespace
+{
+ void SplitDottedString(const string& s, vector<string>& v)
+ {
+ istringstream ss(s);
+ for (string part; getline(ss, part, '.'); v.push_back(part));
+ }
+
+ int CompareIdentifiers(const string& s1, const string& s2)
+ {
+ // We need to split the dotted identifier list into individual identifiers,
+ // and treat purely numeric identifiers as the numbers they represent.
+
+ vector<string> v1;
+ SplitDottedString(s1, v1);
+
+ vector<string> v2;
+ SplitDottedString(s2, v2);
+
+ for (size_t i = 0; ; ++i)
+ {
+ // exhausted both vectors: they must be equal
+ if (i >= v1.size() && i >= v2.size())
+ {
+ return 0;
+ }
+
+ // exhausted one vector: it's the smaller one
+ if (i >= v1.size())
+ {
+ return -1;
+ }
+ if (i >= v2.size())
+ {
+ return 1;
+ }
+
+ // is either of v1[i] or v2[i] a number?
+ const string& id1 = v1[i];
+ bool id1IsNumber = all_of(id1.cbegin(), id1.cend(),
+ [] (char c) { return isdigit(c); });
+ const string& id2 = v2[i];
+ bool id2IsNumber = all_of(id2.cbegin(), id2.cend(),
+ [] (char c) { return isdigit(c); });
+
+ // if both numbers - compare them as such
+ if (id1IsNumber && id2IsNumber)
+ {
+ long num1 = atol(id1.c_str());
+ long num2 = atol(id2.c_str());
+ if (num1 - num2 != 0)
+ {
+ return num1 - num2;
+ }
+ else
+ {
+ continue;
+ }
+ }
+ // if one is a number - that one is lesser
+ if (id1IsNumber)
+ {
+ return -1;
+ }
+ if (id2IsNumber)
+ {
+ return 1;
+ }
+ // neither are numbers: compare them
+ int c = id1.compare(id2);
+ if (c != 0)
+ {
+ return c;
+ }
+ }
+ }
+
+ bool IdentifierIsValid(const string& i)
+ {
+ vector<string> v;
+ SplitDottedString(i, v);
+
+ for (const auto& s : v)
+ {
+ // Identifiers must not be empty.
+ if (s.empty())
+ {
+ return false;
+ }
+
+ // Identifiers must contain only alphanumerics and '-'.
+ if (any_of(s.cbegin(), s.cend(),
+ [] (char c) { return !isalnum(c) && c != '-'; }))
+ {
+ return false;
+ }
+
+ // Numeric identifiers must not contain leading zeroes.
+ bool numeric = all_of(s.cbegin(), s.cend(),
+ [] (char c) { return isdigit(c); });
+ if (numeric && s[0] == '0')
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
+
+namespace semver {
+ namespace v1 {
+
+//------------------------------------------------------------------------------
+Version::Version(
+ unsigned int major,
+ unsigned int minor,
+ unsigned int patch,
+ const std::string& prerelease,
+ const std::string& build)
+ : m_majorVersion(major)
+ , m_minorVersion(minor)
+ , m_patchVersion(patch)
+ , m_prereleaseVersion(prerelease)
+ , m_buildVersion(build)
+{
+}
+
+Version::Version(const string& s)
+{
+ // major.minor.patch-release+build
+
+ istringstream ss(s);
+ string part;
+
+ if (!getline(ss, part, '.')) return;
+ m_majorVersion = static_cast<unsigned int>(strtoul(part.c_str(), 0, 0));
+ if (!getline(ss, part, '.')) return;
+ m_minorVersion = static_cast<unsigned int>(strtoul(part.c_str(), 0, 0));
+ if (!getline(ss, part, '-')) return;
+ m_patchVersion = static_cast<unsigned int>(strtoul(part.c_str(), 0, 0));
+
+ if (!getline(ss, m_prereleaseVersion, '+')) return;
+ getline(ss, m_buildVersion, '\0');
+}
+
+//------------------------------------------------------------------------------
+bool Version::IsWellFormed() const
+{
+ return IdentifierIsValid(m_prereleaseVersion)
+ && IdentifierIsValid(m_buildVersion);
+}
+
+//------------------------------------------------------------------------------
+// When incrementing versions, all lower version parts are reset.
+
+Version Version::NextMajorVersion() const
+{
+ return Version(m_majorVersion + 1, 0, 0);
+}
+
+Version Version::NextMinorVersion() const
+{
+ return Version(m_majorVersion, m_minorVersion + 1, 0);
+}
+
+Version Version::NextPatchVersion() const
+{
+ return Version(m_majorVersion, m_minorVersion, m_patchVersion + 1);
+}
+
+
+//------------------------------------------------------------------------------
+bool Version::Satisfies(const Version& other) const
+{
+ return tie(m_majorVersion, m_minorVersion, m_patchVersion) >=
+ tie(other.m_majorVersion, other.m_minorVersion, other.m_patchVersion);
+}
+
+//------------------------------------------------------------------------------
+bool operator==(const Version& a, const Version& b)
+{
+ return
+ tie(a.m_majorVersion, a.m_minorVersion, a.m_patchVersion,
+ a.m_prereleaseVersion, a.m_buildVersion) ==
+ tie(b.m_majorVersion, b.m_minorVersion, b.m_patchVersion,
+ b.m_prereleaseVersion, b.m_buildVersion);
+}
+
+//------------------------------------------------------------------------------
+bool operator<(const Version& a, const Version& b)
+{
+ if (tie(a.m_majorVersion, a.m_minorVersion, a.m_patchVersion) <
+ tie(b.m_majorVersion, b.m_minorVersion, b.m_patchVersion))
+ {
+ return true;
+ }
+
+ // pre-release version < normal version
+ if (!a.m_prereleaseVersion.empty() && b.m_prereleaseVersion.empty())
+ {
+ return true;
+ }
+ if (a.m_prereleaseVersion.empty() && !b.m_prereleaseVersion.empty())
+ {
+ return false;
+ }
+
+ int prComp = CompareIdentifiers(a.m_prereleaseVersion, b.m_prereleaseVersion);
+ if (prComp < 0)
+ {
+ return true;
+ }
+ else if (prComp == 0)
+ {
+ // build version > normal version
+ if (a.m_buildVersion.empty() && !b.m_buildVersion.empty())
+ {
+ return true;
+ }
+ if (!a.m_buildVersion.empty() && b.m_buildVersion.empty())
+ {
+ return false;
+ }
+
+ int bComp = CompareIdentifiers(a.m_buildVersion, b.m_buildVersion);
+ if (bComp < 0)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+//------------------------------------------------------------------------------
+ostream& operator<<(ostream& s, const Version& v)
+{
+ s << v.m_majorVersion
+ << '.' << v.m_minorVersion
+ << '.' << v.m_patchVersion;
+
+ if (!v.m_prereleaseVersion.empty())
+ {
+ s << '-' << v.m_prereleaseVersion;
+ }
+ if (!v.m_buildVersion.empty())
+ {
+ s << '+' << v.m_buildVersion;
+ }
+
+ return s;
+}
+
+ }
+}
diff --git a/external/semver/src/lib/semantic_version_v2.cpp b/external/semver/src/lib/semantic_version_v2.cpp
new file mode 100644
index 0000000..7bada17
--- /dev/null
+++ b/external/semver/src/lib/semantic_version_v2.cpp
@@ -0,0 +1,272 @@
+#include "semantic_version.h"
+
+#include <algorithm>
+#include <cctype>
+#include <cstdlib>
+#include <sstream>
+#include <tuple>
+#include <vector>
+
+using namespace std;
+
+//------------------------------------------------------------------------------
+// From http://semver.org/ - Version 2.0.0
+
+// Pre-release versions satisfy but have a lower precedence than the associated
+// normal version.
+
+// Build versions satisfy and have a higher precedence than the associated
+// normal version.
+
+// Precedence MUST be calculated by separating the version into major, minor,
+// patch, pre-release, and build identifiers in that order. Major, minor, and
+// patch versions are always compared numerically. Pre-release and build version
+// precedence MUST be determined by comparing each dot separated identifier as
+// follows: identifiers consisting of only digits are compared numerically and
+// identifiers with letters or dashes are compared lexically in ASCII sort
+// order. Numeric identifiers always have lower precedence than non-numeric
+// identifiers. Example: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-beta.2 <
+// 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0-rc.1+build.1 < 1.0.0 < 1.0.0+0.3.7 <
+// 1.3.7+build < 1.3.7+build.2.b8f12d7 < 1.3.7+build.11.e0f985a.
+
+namespace
+{
+ void SplitDottedString(const string& s, vector<string>& v)
+ {
+ istringstream ss(s);
+ for (string part; getline(ss, part, '.'); v.push_back(part));
+ }
+
+ int CompareIdentifiers(const string& s1, const string& s2)
+ {
+ // We need to split the dotted identifier list into individual identifiers,
+ // and treat purely numeric identifiers as the numbers they represent.
+
+ vector<string> v1;
+ SplitDottedString(s1, v1);
+
+ vector<string> v2;
+ SplitDottedString(s2, v2);
+
+ for (size_t i = 0; ; ++i)
+ {
+ // exhausted both vectors: they must be equal
+ if (i >= v1.size() && i >= v2.size())
+ {
+ return 0;
+ }
+
+ // exhausted one vector: it's the smaller one
+ if (i >= v1.size())
+ {
+ return -1;
+ }
+ if (i >= v2.size())
+ {
+ return 1;
+ }
+
+ // is either of v1[i] or v2[i] a number?
+ const string& id1 = v1[i];
+ bool id1IsNumber = all_of(id1.cbegin(), id1.cend(),
+ [] (char c) { return isdigit(c); });
+ const string& id2 = v2[i];
+ bool id2IsNumber = all_of(id2.cbegin(), id2.cend(),
+ [] (char c) { return isdigit(c); });
+
+ // if both numbers - compare them as such
+ if (id1IsNumber && id2IsNumber)
+ {
+ long num1 = atol(id1.c_str());
+ long num2 = atol(id2.c_str());
+ if (num1 - num2 != 0)
+ {
+ return num1 - num2;
+ }
+ else
+ {
+ continue;
+ }
+ }
+ // if one is a number - that one is lesser
+ if (id1IsNumber)
+ {
+ return -1;
+ }
+ if (id2IsNumber)
+ {
+ return 1;
+ }
+ // neither are numbers: compare them
+ int c = id1.compare(id2);
+ if (c != 0)
+ {
+ return c;
+ }
+ }
+ }
+
+ bool IdentifierIsValid(const string& i)
+ {
+ vector<string> v;
+ SplitDottedString(i, v);
+
+ for (const auto& s : v)
+ {
+ // Identifiers must not be empty.
+ if (s.empty())
+ {
+ return false;
+ }
+
+ // Identifiers must contain only alphanumerics and '-'.
+ if (any_of(s.cbegin(), s.cend(),
+ [] (char c) { return !isalnum(c) && c != '-' && c != '.'; }))
+ {
+ return false;
+ }
+
+ // Numeric identifiers must not contain leading zeroes.
+ bool numeric = all_of(s.cbegin(), s.cend(),
+ [] (char c) { return isdigit(c); });
+ if (numeric && s[0] == '0')
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
+
+namespace semver {
+ inline namespace v2 {
+
+//------------------------------------------------------------------------------
+Version::Version(
+ unsigned int major,
+ unsigned int minor,
+ unsigned int patch,
+ const std::string& prerelease,
+ const std::string& build)
+ : m_majorVersion(major)
+ , m_minorVersion(minor)
+ , m_patchVersion(patch)
+ , m_prereleaseVersion(prerelease)
+ , m_buildVersion(build)
+{
+}
+
+Version::Version(const string& s)
+{
+ // major.minor.patch-release+build
+
+ istringstream ss(s);
+ string part;
+
+ if (!getline(ss, part, '.')) return;
+ m_majorVersion = static_cast<unsigned int>(strtoul(part.c_str(), 0, 0));
+ if (!getline(ss, part, '.')) return;
+ m_minorVersion = static_cast<unsigned int>(strtoul(part.c_str(), 0, 0));
+ if (!getline(ss, part, '-')) return;
+ m_patchVersion = static_cast<unsigned int>(strtoul(part.c_str(), 0, 0));
+
+ if (!getline(ss, m_prereleaseVersion, '+')) return;
+ getline(ss, m_buildVersion, '\0');
+}
+
+//------------------------------------------------------------------------------
+bool Version::IsWellFormed() const
+{
+ return IdentifierIsValid(m_prereleaseVersion)
+ && IdentifierIsValid(m_buildVersion);
+}
+
+//------------------------------------------------------------------------------
+// When incrementing versions, all lower version parts are reset.
+
+Version Version::NextMajorVersion() const
+{
+ return Version(m_majorVersion + 1, 0, 0);
+}
+
+Version Version::NextMinorVersion() const
+{
+ return Version(m_majorVersion, m_minorVersion + 1, 0);
+}
+
+Version Version::NextPatchVersion() const
+{
+ return Version(m_majorVersion, m_minorVersion, m_patchVersion + 1);
+}
+
+//------------------------------------------------------------------------------
+bool Version::Satisfies(const Version& other) const
+{
+ return tie(m_majorVersion, m_minorVersion, m_patchVersion) >=
+ tie(other.m_majorVersion, other.m_minorVersion, other.m_patchVersion);
+}
+
+//------------------------------------------------------------------------------
+bool operator==(const Version& a, const Version& b)
+{
+ return
+ tie(a.m_majorVersion, a.m_minorVersion, a.m_patchVersion,
+ a.m_prereleaseVersion) ==
+ tie(b.m_majorVersion, b.m_minorVersion, b.m_patchVersion,
+ b.m_prereleaseVersion);
+}
+
+//------------------------------------------------------------------------------
+bool operator<(const Version& a, const Version& b)
+{
+ const auto ta = tie(a.m_majorVersion, a.m_minorVersion, a.m_patchVersion);
+ const auto tb = tie(b.m_majorVersion, b.m_minorVersion, b.m_patchVersion);
+
+ if (ta < tb) return true;
+ if (ta > tb) return false;
+
+ // pre-release version < normal version
+ if (!a.m_prereleaseVersion.empty() && b.m_prereleaseVersion.empty())
+ {
+ return true;
+ }
+ if (a.m_prereleaseVersion.empty() && !b.m_prereleaseVersion.empty())
+ {
+ return false;
+ }
+
+ return CompareIdentifiers(a.m_prereleaseVersion, b.m_prereleaseVersion) <= 0;
+}
+
+//------------------------------------------------------------------------------
+bool Version::Equals(const Version& other) const
+{
+ return
+ tie(m_majorVersion, m_minorVersion, m_patchVersion,
+ m_prereleaseVersion, m_buildVersion) ==
+ tie(other.m_majorVersion, other.m_minorVersion, other.m_patchVersion,
+ other.m_prereleaseVersion, other.m_buildVersion);
+}
+
+//------------------------------------------------------------------------------
+ostream& operator<<(ostream& s, const Version& v)
+{
+ s << v.m_majorVersion
+ << '.' << v.m_minorVersion
+ << '.' << v.m_patchVersion;
+
+ if (!v.m_prereleaseVersion.empty())
+ {
+ s << '-' << v.m_prereleaseVersion;
+ }
+ if (!v.m_buildVersion.empty())
+ {
+ s << '+' << v.m_buildVersion;
+ }
+
+ return s;
+}
+
+ }
+}
diff --git a/external/semver/src/quickcheck/CMakeLists.txt b/external/semver/src/quickcheck/CMakeLists.txt
new file mode 100644
index 0000000..b8bb9b9
--- /dev/null
+++ b/external/semver/src/quickcheck/CMakeLists.txt
@@ -0,0 +1,29 @@
+find_program(HSC2HS hsc2hs)
+find_program(GHC ghc)
+
+if (HSC2HS AND GHC)
+
+ # the shared lib
+ add_library(${PROJECT_NAME}_ffi SHARED
+ ../lib/semantic_version_v1.cpp ../lib/semantic_version_v2.cpp semantic_version_ffi.cpp)
+ # the ffi bindings
+ add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Semver.hs
+ MAIN_DEPENDENCY Semver.hsc
+ DEPENDS semantic_version_ffi.h
+ COMMAND ${HSC2HS} ${CMAKE_CURRENT_SOURCE_DIR}/Semver.hsc -I ${CMAKE_CURRENT_SOURCE_DIR} -o ${CMAKE_CURRENT_BINARY_DIR}/Semver.hs)
+ # the quickcheck executable
+ add_custom_command(
+ OUTPUT quickcheck_${PROJECT_NAME}
+ MAIN_DEPENDENCY Main.hs
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Semver.hs
+ DEPENDS ${PROJECT_NAME}_ffi
+ COMMAND ${GHC} --make ${CMAKE_CURRENT_SOURCE_DIR}/Main -L. -lsemver_ffi -o quickcheck_${PROJECT_NAME})
+ add_custom_target(quickcheck ALL
+ DEPENDS quickcheck_${PROJECT_NAME})
+ # pipe to ctest
+ add_test(NAME quickcheck_${PROJECT_NAME}
+ COMMAND ${CMAKE_CURRENT_BINARY_DIR}/quickcheck_${PROJECT_NAME})
+ set_tests_properties(quickcheck_${PROJECT_NAME} PROPERTIES TIMEOUT 30 ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_CURRENT_BINARY_DIR}")
+
+endif()
diff --git a/external/semver/src/quickcheck/Main.hi b/external/semver/src/quickcheck/Main.hi
new file mode 100644
index 0000000..0739459
--- /dev/null
+++ b/external/semver/src/quickcheck/Main.hi
Binary files differ
diff --git a/external/semver/src/quickcheck/Main.hs b/external/semver/src/quickcheck/Main.hs
new file mode 100644
index 0000000..fc1d625
--- /dev/null
+++ b/external/semver/src/quickcheck/Main.hs
@@ -0,0 +1,80 @@
+module Main where
+
+import Semver
+import Test.QuickCheck
+
+import System.Environment
+import System.Console.GetOpt
+
+-- command line options
+data Options = Options { optVerbose :: Bool
+ , optNumTests :: Int
+ } deriving Show
+
+defaultOptions :: Options
+defaultOptions = Options { optVerbose = False
+ , optNumTests = 100
+ }
+
+options :: [OptDescr (Options -> Options)]
+options =
+ [ Option "v" ["verbose"] (NoArg (\opts -> opts { optVerbose = True }))
+ "run tests with verbose output"
+
+ , Option "n" ["numtests"] (ReqArg
+ (\d opts -> opts { optNumTests = read d })
+ "<num>")
+ "number of tests to run"
+ ]
+
+parseOpts :: [String] -> IO (Options, [String])
+parseOpts argv =
+ case getOpt Permute options argv of
+ (o, n, []) -> return (foldl (flip id) defaultOpts o, n)
+ where defaultOpts = defaultOptions
+ (_, _, errs) -> ioError (userError (concat errs ++ usageInfo header options))
+ where header = "Usage: test [options]"
+
+-- generate arbitrary Senvers
+instance Arbitrary Semver where
+ arbitrary = do
+ r1 <- arbitrary
+ r2 <- arbitrary
+ r3 <- arbitrary
+ return (Semver r1 r2 r3 "" "")
+
+-- properties
+-- a version always satisfies itself
+prop_satisfies :: Property
+prop_satisfies =
+ property $
+ \s -> satisfies s s
+
+-- a version is always less than its next {major, minor, patch} version
+prop_lessThanNext :: (Semver -> Semver) -> Property
+prop_lessThanNext f =
+ property $
+ \s -> let s' = f s in s `lessThan` s'
+
+prop_lessThanNextMajor :: Property
+prop_lessThanNextMajor = prop_lessThanNext nextMajor
+
+prop_lessThanNextMinor :: Property
+prop_lessThanNextMinor = prop_lessThanNext nextMinor
+
+prop_lessThanNextPatch :: Property
+prop_lessThanNextPatch = prop_lessThanNext nextPatch
+
+-- drive quickcheck
+main :: IO ()
+main = do
+ args <- getArgs
+ (o, _) <- parseOpts args
+ let numCheck = quickCheckWith stdArgs { maxSuccess = optNumTests o }
+ checker = if optVerbose o
+ then numCheck . verbose
+ else numCheck
+ in do checker prop_satisfies
+ checker prop_lessThanNextMajor
+ checker prop_lessThanNextMinor
+ checker prop_lessThanNextPatch
diff --git a/external/semver/src/quickcheck/Main.o b/external/semver/src/quickcheck/Main.o
new file mode 100644
index 0000000..3775e7b
--- /dev/null
+++ b/external/semver/src/quickcheck/Main.o
Binary files differ
diff --git a/external/semver/src/quickcheck/Semver.hsc b/external/semver/src/quickcheck/Semver.hsc
new file mode 100644
index 0000000..c96eb00
--- /dev/null
+++ b/external/semver/src/quickcheck/Semver.hsc
@@ -0,0 +1,87 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+module Semver where
+
+#include "semantic_version_ffi.h"
+
+import Foreign hiding (unsafePerformIO)
+import Foreign.C.String
+import Foreign.Storable
+import System.IO.Unsafe (unsafePerformIO)
+
+data Semver = Semver
+ { vMajor :: #{type unsigned int}
+ , vMinor :: #{type unsigned int}
+ , vPatch :: #{type unsigned int}
+ , vPrerelease :: String
+ , vBuild :: String
+ } deriving (Eq, Show)
+
+-- don't bother with the strings for now
+
+instance Storable Semver where
+ sizeOf _ = #{size semver_t}
+ alignment _ = alignment (undefined :: Word32)
+
+ peek ptr = do
+ r1 <- #{peek semver_t, major} ptr
+ r2 <- #{peek semver_t, minor} ptr
+ r3 <- #{peek semver_t, patch} ptr
+ return (Semver r1 r2 r3 "" "")
+
+ poke ptr (Semver r1 r2 r3 _ _) = do
+ #{poke semver_t, major} ptr r1
+ #{poke semver_t, minor} ptr r2
+ #{poke semver_t, patch} ptr r3
+
+-- c functions
+
+foreign import ccall "semantic_version_ffi.h satisfies"
+ c_satisfies :: Ptr Semver -> Ptr Semver -> IO Int
+foreign import ccall "semantic_version_ffi.h lessThan"
+ c_lessThan :: Ptr Semver -> Ptr Semver -> IO Int
+foreign import ccall "semantic_version_ffi.h nextMajor"
+ c_nextMajor :: Ptr Semver -> Ptr Semver -> IO ()
+foreign import ccall "semantic_version_ffi.h nextMinor"
+ c_nextMinor :: Ptr Semver -> Ptr Semver -> IO ()
+foreign import ccall "semantic_version_ffi.h nextPatch"
+ c_nextPatch :: Ptr Semver -> Ptr Semver -> IO ()
+
+-- haskell wrappers
+
+satisfies :: Semver -> Semver -> Bool
+satisfies a b =
+ unsafePerformIO $
+ alloca $ \a_ptr ->
+ alloca $ \b_ptr -> do
+ poke a_ptr a
+ poke b_ptr b
+ r <- c_satisfies a_ptr b_ptr
+ return $ if (r == 1) then True else False
+
+lessThan :: Semver -> Semver -> Bool
+lessThan a b =
+ unsafePerformIO $
+ alloca $ \a_ptr ->
+ alloca $ \b_ptr -> do
+ poke a_ptr a
+ poke b_ptr b
+ r <- c_lessThan a_ptr b_ptr
+ return $ if (r == 1) then True else False
+
+nextFunc :: (Ptr Semver -> Ptr Semver -> IO ()) -> Semver -> Semver
+nextFunc f a =
+ unsafePerformIO $
+ alloca $ \a_ptr ->
+ alloca $ \b_ptr -> do
+ poke a_ptr a
+ f a_ptr b_ptr
+ peek b_ptr
+
+nextMajor :: Semver -> Semver
+nextMajor = nextFunc c_nextMajor
+
+nextMinor :: Semver -> Semver
+nextMinor = nextFunc c_nextMinor
+
+nextPatch :: Semver -> Semver
+nextPatch = nextFunc c_nextPatch
diff --git a/external/semver/src/quickcheck/semantic_version_ffi.cpp b/external/semver/src/quickcheck/semantic_version_ffi.cpp
new file mode 100644
index 0000000..3c7d8fc
--- /dev/null
+++ b/external/semver/src/quickcheck/semantic_version_ffi.cpp
@@ -0,0 +1,58 @@
+#include "semantic_version_ffi.h"
+#include "semantic_version.h"
+
+using namespace semver;
+
+//------------------------------------------------------------------------------
+
+int satisfies(const semver_t* a, const semver_t* b)
+{
+ Version va(a->major, a->minor, a->patch,
+ a->prerelease, a->build);
+
+ Version vb(b->major, b->minor, b->patch,
+ b->prerelease, b->build);
+
+ return va.Satisfies(vb) ? 1 : 0;
+}
+
+int lessThan(const semver_t* a, const semver_t* b)
+{
+ Version va(a->major, a->minor, a->patch,
+ a->prerelease, a->build);
+
+ Version vb(b->major, b->minor, b->patch,
+ b->prerelease, b->build);
+
+ return (va < vb) ? 1 : 0;
+}
+
+void nextMajor(const semver_t* a, semver_t* b)
+{
+ Version va(a->major, a->minor, a->patch,
+ a->prerelease, a->build);
+ Version vb = va.NextMajorVersion();
+ b->major = vb.GetMajorVersion();
+ b->minor = vb.GetMinorVersion();
+ b->patch = vb.GetPatchVersion();
+}
+
+void nextMinor(const semver_t* a, semver_t* b)
+{
+ Version va(a->major, a->minor, a->patch,
+ a->prerelease, a->build);
+ Version vb = va.NextMinorVersion();
+ b->major = vb.GetMajorVersion();
+ b->minor = vb.GetMinorVersion();
+ b->patch = vb.GetPatchVersion();
+}
+
+void nextPatch(const semver_t* a, semver_t* b)
+{
+ Version va(a->major, a->minor, a->patch,
+ a->prerelease, a->build);
+ Version vb = va.NextPatchVersion();
+ b->major = vb.GetMajorVersion();
+ b->minor = vb.GetMinorVersion();
+ b->patch = vb.GetPatchVersion();
+}
diff --git a/external/semver/src/quickcheck/semantic_version_ffi.h b/external/semver/src/quickcheck/semantic_version_ffi.h
new file mode 100644
index 0000000..5a734af
--- /dev/null
+++ b/external/semver/src/quickcheck/semantic_version_ffi.h
@@ -0,0 +1,27 @@
+#pragma once
+
+// FFI for semantic version
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef struct Semver
+{
+ unsigned int major;
+ unsigned int minor;
+ unsigned int patch;
+ char prerelease[32];
+ char build[32];
+} semver_t;
+
+int satisfies(const semver_t* a, const semver_t* b);
+int lessThan(const semver_t* a, const semver_t* b);
+void nextMajor(const semver_t* a, semver_t* b);
+void nextMinor(const semver_t* a, semver_t* b);
+void nextPatch(const semver_t* a, semver_t* b);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/external/semver/src/test/CMakeLists.txt b/external/semver/src/test/CMakeLists.txt
new file mode 100644
index 0000000..ea04671
--- /dev/null
+++ b/external/semver/src/test/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_executable (test_${PROJECT_NAME} main.cpp)
+target_link_libraries(test_${PROJECT_NAME} ${PROJECT_NAME})
+ADD_TESTINATOR_TESTS (test_${PROJECT_NAME})
diff --git a/external/semver/src/test/main.cpp b/external/semver/src/test/main.cpp
new file mode 100644
index 0000000..47a48c5
--- /dev/null
+++ b/external/semver/src/test/main.cpp
@@ -0,0 +1,297 @@
+#include <semantic_version.h>
+
+using namespace semver;
+
+#define TESTINATOR_MAIN
+#include <testinator.h>
+
+#include <algorithm>
+#include <sstream>
+
+using namespace std;
+
+DEF_TEST(Init, SemanticVersion)
+{
+ Version v;
+ return v.GetMajorVersion() == 0
+ && v.GetMinorVersion() == 0
+ && v.GetPatchVersion() == 1;
+}
+
+DEF_TEST(NextMajor, SemanticVersion)
+{
+ Version v1(1, 2, 3);
+ Version v2(v1.NextMajorVersion());
+ return v2.GetMajorVersion() == 2
+ && v2.GetMinorVersion() == 0
+ && v2.GetPatchVersion() == 0;
+}
+
+DEF_TEST(NextMinor, SemanticVersion)
+{
+ Version v1(1, 2, 3);
+ Version v2(v1.NextMinorVersion());
+ return v2.GetMajorVersion() == 1
+ && v2.GetMinorVersion() == 3
+ && v2.GetPatchVersion() == 0;
+}
+
+DEF_TEST(NextPatch, SemanticVersion)
+{
+ Version v1(1, 2, 3);
+ Version v2(v1.NextPatchVersion());
+ return v2.GetMajorVersion() == 1
+ && v2.GetMinorVersion() == 2
+ && v2.GetPatchVersion() == 4;
+}
+
+DEF_TEST(LessThanMajor, SemanticVersion)
+{
+ Version v1(1, 2, 3);
+ Version v2(v1.NextMajorVersion());
+ return v1 < v2;
+}
+
+DEF_TEST(LessThanMinor, SemanticVersion)
+{
+ Version v1(1, 2, 3);
+ Version v2(v1.NextMinorVersion());
+ return v1 < v2;
+}
+
+DEF_TEST(LessThanPatch, SemanticVersion)
+{
+ Version v1(1, 2, 3);
+ Version v2(v1.NextPatchVersion());
+ return v1 < v2;
+}
+
+DEF_TEST(LessThanNumericString, SemanticVersion)
+{
+ Version v1(1, 2, 3, "alpha.2");
+ Version v2(1, 2, 3, "alpha.11");
+ return v1 < v2;
+}
+
+DEF_TEST(LessThanPrerelease, SemanticVersion)
+{
+ Version v1(1, 2, 3, "alpha");
+ Version v2(1, 2, 3, "beta");
+ return v1 < v2;
+}
+
+DEF_TEST(LessThanBuild, SemanticVersion)
+{
+ Version v1(1, 2, 3, "", "1");
+ Version v2(1, 2, 3, "", "2");
+ return v1 < v2;
+}
+
+DEF_TEST(PrereleaseLessThanNormal, SemanticVersion)
+{
+ Version v1(1, 2, 3, "alpha");
+ Version v2(1, 2, 3);
+ return v1 < v2;
+}
+
+DEF_TEST(NormalLessThanBuild, SemanticVersion)
+{
+ Version v1(1, 2, 3);
+ Version v2(1, 2, 3, "", "1");
+ return v1 < v2;
+}
+
+DEF_TEST(PrereleaseLessThanBuild, SemanticVersion)
+{
+ Version v1(1, 2, 3, "alpha");
+ Version v2(1, 2, 3, "", "1234");
+ return v1 < v2;
+}
+
+DEF_TEST(Output, SemanticVersion)
+{
+ Version v(1, 2, 3, "alpha.2", "1234");
+ ostringstream s;
+ s << v;
+ return s.str() == "1.2.3-alpha.2+1234";
+}
+
+DEF_TEST(SameSatisfy, SemanticVersion)
+{
+ Version v1(1, 2, 3);
+ Version v2(1, 2, 3);
+ return v1.Satisfies(v2);
+}
+
+DEF_TEST(GreaterMajorSatisfy, SemanticVersion)
+{
+ Version v1(2, 0, 0);
+ Version v2(1, 2, 3);
+ return v1.Satisfies(v2);
+}
+
+DEF_TEST(GreaterMinorSatisfy, SemanticVersion)
+{
+ Version v1(1, 3, 0);
+ Version v2(1, 2, 3);
+ return v1.Satisfies(v2);
+}
+
+DEF_TEST(GreaterPatchSatisfy, SemanticVersion)
+{
+ Version v1(1, 2, 4);
+ Version v2(1, 2, 3);
+ return v1.Satisfies(v2);
+}
+
+DEF_TEST(PrereleaseSatisfy, SemanticVersion)
+{
+ Version v1(1, 2, 3, "alpha");
+ Version v2(1, 2, 3);
+ return v1.Satisfies(v2);
+}
+
+DEF_TEST(BuildSatisfy, SemanticVersion)
+{
+ Version v1(1, 2, 3, "", "1234");
+ Version v2(1, 2, 3);
+ return v1.Satisfies(v2);
+}
+
+const vector<semver::v1::Version> s_precedences_v1 =
+{
+ semver::v1::Version(1, 0, 0, "alpha"),
+ semver::v1::Version(1, 0, 0, "alpha.1"),
+ semver::v1::Version(1, 0, 0, "alpha.beta"),
+ semver::v1::Version(1, 0, 0, "beta"),
+ semver::v1::Version(1, 0, 0, "beta.2"),
+ semver::v1::Version(1, 0, 0, "beta.11"),
+ semver::v1::Version(1, 0, 0, "rc.1"),
+ semver::v1::Version(1, 0, 0, "rc.1", "build.1"),
+ semver::v1::Version(1, 0, 0),
+ semver::v1::Version(1, 0, 0, "", "0.3.7"),
+ semver::v1::Version(1, 0, 0, "", "build"),
+ semver::v1::Version(1, 0, 0, "", "build.2.b8f12d7"),
+ semver::v1::Version(1, 0, 0, "", "build.11.e0f985a")
+};
+
+DEF_TEST(Precedences_v1, SemanticVersion)
+{
+ return adjacent_find(
+ s_precedences_v1.cbegin(), s_precedences_v1.cend(),
+ [] (const auto& a, const auto& b) { return a >= b; })
+ == s_precedences_v1.end();
+}
+
+DEF_TEST(Satisfies_v1, SemanticVersion)
+{
+ return adjacent_find(
+ s_precedences_v1.cbegin(), s_precedences_v1.cend(),
+ [] (const auto& a, const auto& b) { return !b.Satisfies(a) ; })
+ == s_precedences_v1.end();
+}
+
+const vector<semver::v2::Version> s_precedences_v2 =
+{
+ semver::v2::Version(1, 0, 0, "alpha"),
+ semver::v2::Version(1, 0, 0, "alpha.1"),
+ semver::v2::Version(1, 0, 0, "alpha.beta"),
+ semver::v2::Version(1, 0, 0, "beta"),
+ semver::v2::Version(1, 0, 0, "beta.2"),
+ semver::v2::Version(1, 0, 0, "beta.11"),
+ semver::v2::Version(1, 0, 0, "rc.1"),
+ semver::v2::Version(1, 0, 0)
+};
+
+DEF_TEST(Precedences_v2, SemanticVersion)
+{
+ return adjacent_find(
+ s_precedences_v2.cbegin(), s_precedences_v2.cend(),
+ [] (const auto& a, const auto& b) { return a >= b; })
+ == s_precedences_v2.end();
+}
+
+DEF_TEST(Satisfies_v2, SemanticVersion)
+{
+ return adjacent_find(
+ s_precedences_v2.cbegin(), s_precedences_v2.cend(),
+ [] (const auto& a, const auto& b) { return !b.Satisfies(a) ; })
+ == s_precedences_v2.end();
+}
+
+DEF_TEST(PrecedenceIncludesBuild_v1, SemanticVersion)
+{
+ semver::v1::Version a(1,0,0, "", "1");
+ semver::v1::Version b(1,0,0, "", "2");
+ return a < b;
+}
+
+DEF_TEST(PrecedenceOmitsBuild_v2, SemanticVersion)
+{
+ semver::v2::Version a(1,0,0, "", "1");
+ semver::v2::Version b(1,0,0, "", "2");
+ return a == b;
+}
+
+DEF_TEST(ConstructFromString, SemanticVersion)
+{
+ Version v("1.2.3-alpha.2+build.1234");
+ ostringstream s;
+ s << v;
+ return s.str() == "1.2.3-alpha.2+build.1234";
+}
+
+DEF_TEST(WellFormed, SemanticVersion)
+{
+ Version v("1.2.3-alpha.2+build.1234");
+ return v.IsWellFormed();
+}
+
+DEF_TEST(ParseIllFormed, SemanticVersion)
+{
+ Version v("1.2.3-alpha-2+build+1234");
+ return !v.IsWellFormed();
+}
+
+namespace testinator
+{
+ template <>
+ struct Arbitrary<semver::v2::Version>
+ {
+ using Version = semver::v2::Version;
+
+ static Version generate(std::size_t g, unsigned long int s)
+ {
+ // prerelease part shouldn't contain a +
+ string pre = Arbitrary<string>::generate(g, s);
+ replace(pre.begin(), pre.end(), '+', '_');
+
+ return Version {
+ Arbitrary<unsigned int>::generate(g, s),
+ Arbitrary<unsigned int>::generate(g, s>>1),
+ Arbitrary<unsigned int>::generate(g, s>>2),
+ pre,
+ Arbitrary<string>::generate(g, s>>1)
+ };
+ }
+ static vector<Version> shrink(const Version&)
+ {
+ return vector<Version>{};
+ }
+ };
+}
+
+DEF_PROPERTY(Roundtrip, SemanticVersion, const semver::v2::Version& before)
+{
+ ostringstream s;
+ s << before;
+ Version after(s.str());
+ return after.Equals(before);
+}
+
+DEF_TEST(LessThan_Issue2, SemanticVersion)
+{
+ Version a("4.5.6");
+ Version b("1.2.3");
+ return !(a < b);
+}