summaryrefslogtreecommitdiff
path: root/external/semver
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
parentccb0b2e4d6674a7a00c9bf491f08fc73b6898c54 (diff)
create tremded branch
Diffstat (limited to 'external/semver')
-rw-r--r--external/semver/.gitignore2
-rw-r--r--external/semver/.gitmodules6
-rw-r--r--external/semver/.travis.yml93
-rw-r--r--external/semver/CMakeLists.txt100
-rw-r--r--external/semver/LICENSE21
-rw-r--r--external/semver/README.md12
-rw-r--r--external/semver/appveyor.yml35
-rw-r--r--external/semver/install_libcxx.sh13
-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
21 files changed, 1611 insertions, 0 deletions
diff --git a/external/semver/.gitignore b/external/semver/.gitignore
new file mode 100644
index 0000000..d3b8be9
--- /dev/null
+++ b/external/semver/.gitignore
@@ -0,0 +1,2 @@
+build/
+TAGS
diff --git a/external/semver/.gitmodules b/external/semver/.gitmodules
new file mode 100644
index 0000000..4a99d01
--- /dev/null
+++ b/external/semver/.gitmodules
@@ -0,0 +1,6 @@
+[submodule "contrib/testinator"]
+ path = contrib/testinator
+ url = https://github.com/elbeno/testinator.git
+[submodule "contrib/gsl"]
+ path = contrib/gsl
+ url = https://github.com/Microsoft/GSL.git
diff --git a/external/semver/.travis.yml b/external/semver/.travis.yml
new file mode 100644
index 0000000..e8a599a
--- /dev/null
+++ b/external/semver/.travis.yml
@@ -0,0 +1,93 @@
+# adapted from https://github.com/ericniebler/range-v3
+
+language: cpp
+script: cmake
+
+matrix:
+ include:
+ - env: CLANG_VERSION=3.4 BUILD_TYPE=Debug CPP=1y SAN=On LIBCXX=On
+ os: linux
+ addons: &clang34
+ apt:
+ packages:
+ - util-linux
+ - clang-3.4
+ sources:
+ - ubuntu-toolchain-r-test
+ - llvm-toolchain-precise-3.4
+
+ - env: CLANG_VERSION=3.4 BUILD_TYPE=Release CPP=1y SAN=On LIBCXX=On
+ os: linux
+ addons: *clang34
+
+ - env: CLANG_VERSION=3.7 BUILD_TYPE=Debug CPP=14 SAN=Off LIBCXX=On
+ os: linux
+ addons: &clang37
+ apt:
+ packages:
+ - util-linux
+ - clang-3.7
+ sources:
+ - ubuntu-toolchain-r-test
+ - llvm-toolchain-precise-3.7
+
+ - env: CLANG_VERSION=3.7 BUILD_TYPE=Release CPP=14 SAN=Off LIBCXX=On
+ os: linux
+ addons: *clang37
+
+ # - env: GCC_VERSION=4.9 BUILD_TYPE=Debug CPP=14 SAN=Off LIBCXX=Off
+ # os: linux
+ # addons: &gcc49
+ # apt:
+ # packages:
+ # - g++-4.9
+ # sources:
+ # - ubuntu-toolchain-r-test
+
+ # - env: GCC_VERSION=4.9 BUILD_TYPE=Release CPP=14 SAN=Off LIBCXX=Off
+ # os: linux
+ # addons: *gcc49
+
+ - env: GCC_VERSION=5 BUILD_TYPE=Debug CPP=14 SAN=Off LIBCXX=Off
+ os: linux
+ addons: &gcc5
+ apt:
+ packages:
+ - g++-5
+ sources:
+ - ubuntu-toolchain-r-test
+
+ - env: GCC_VERSION=5 BUILD_TYPE=Release CPP=14 SAN=Off LIBCXX=Off
+ os: linux
+ addons: *gcc5
+
+before_install:
+ - export CHECKOUT_PATH=`pwd`;
+ - if [ -n "$GCC_VERSION" ]; then export CXX="g++-${GCC_VERSION}" CC="gcc-${GCC_VERSION}"; fi
+ - if [ -n "$CLANG_VERSION" ]; then export CXX="clang++-${CLANG_VERSION}" CC="clang-${CLANG_VERSION}"; fi
+ - if [ "$CLANG_VERSION" == "3.4" ]; then export CXX="/usr/local/clang-3.4/bin/clang++" CC="/usr/local/clang-3.4/bin/clang"; fi
+ - if [ "$LIBCXX" == "On" ]; then sudo CXX=$CXX CC=$CC ./install_libcxx.sh; fi
+
+install:
+ - cd $CHECKOUT_PATH
+
+ - if [ ! -d build ]; then mkdir build; fi
+ - cd build
+
+ - export CXX_FLAGS=""
+ - export CXX_LINKER_FLAGS=""
+
+ - if [ -z "$BUILD_TYPE" ]; then export BUILD_TYPE=Debug; fi
+
+ - if [ -n "$CLANG_VERSION" ]; then CXX_FLAGS="${CXX_FLAGS} -D__extern_always_inline=inline"; fi
+ - if [ "$LIBCXX" == "On" ]; then CXX_FLAGS="${CXX_FLAGS} -stdlib=libc++ -I/usr/include/c++/v1/"; fi
+ - if [ "$LIBCXX" == "On" ]; then CXX_LINKER_FLAGS="${CXX_FLAGS} -L/usr/lib/ -lc++"; fi
+
+ - cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_FLAGS="${CXX_FLAGS}" -DCMAKE_EXE_LINKER_FLAGS="${CXX_LINKER_FLAGS}" -DCXX_STD=$CPP -DCI_BUILD=1
+ - make VERBOSE=1
+
+script:
+ - if [ "$BUILD_TYPE" == "Debug" ]; then ctest -VV --schedule-random; fi
+
+notifications:
+ email: false
diff --git a/external/semver/CMakeLists.txt b/external/semver/CMakeLists.txt
new file mode 100644
index 0000000..2919ee3
--- /dev/null
+++ b/external/semver/CMakeLists.txt
@@ -0,0 +1,100 @@
+cmake_minimum_required (VERSION 2.8)
+project (semver)
+
+# Includes for this project
+include_directories ("${PROJECT_SOURCE_DIR}/src/include")
+
+# Include testinator and the GSL
+include_directories ("${PROJECT_SOURCE_DIR}/contrib/testinator/src/include")
+include_directories ("${PROJECT_SOURCE_DIR}/contrib/gsl/include")
+
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+
+# Default C++ standard: C++14
+if(CXX_STD)
+else()
+ set(CXX_STD 14)
+endif()
+
+# Set up tests
+enable_testing()
+include(CTest)
+
+if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
+ set(MY_CXX_FLAGS_LIST
+ )
+ string(REPLACE ";" " " MY_CXX_FLAGS "${MY_CXX_FLAGS_LIST}")
+
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MY_CXX_FLAGS}")
+else()
+ set(MY_CXX_FLAGS_LIST
+ -ftemplate-backtrace-limit=0
+ -ffunction-sections
+ -Wall -Wextra -Werror -pedantic-errors
+ -Wcast-align
+ -Wcast-qual
+ -Wctor-dtor-privacy
+ -Wdisabled-optimization
+ -Wformat=2
+ -Winit-self
+ -Wmissing-include-dirs
+ # -Wold-style-cast
+ -Woverloaded-virtual
+ -Wredundant-decls
+ # -Wshadow
+ # -Wsign-conversion
+ -Wsign-promo
+ -Wstrict-overflow=2
+ -Wswitch-default
+ -Wundef
+ )
+ string(REPLACE ";" " " MY_CXX_FLAGS "${MY_CXX_FLAGS_LIST}")
+
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++${CXX_STD} ${MY_CXX_FLAGS}")
+
+ # Debug/Release
+ set(CMAKE_CXX_FLAGS_DEBUG "-O0 -fno-inline -g3 -fstack-protector-all")
+ set(CMAKE_CXX_FLAGS_RELEASE "-Ofast -g0 -march=native -mtune=native -DNDEBUG")
+ set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_DEBUG} -fprofile-arcs -ftest-coverage")
+endif()
+
+# Clang/GCC specifics
+if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ if(SAN)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address,undefined,integer -fno-omit-frame-pointer -fno-sanitize=unsigned-integer-overflow")
+ endif()
+elseif(CMAKE_COMPILER_IS_GNUCXX)
+endif()
+
+# Pipe separate tests into ctest
+# Adapted from https://github.com/ChaiScript/ChaiScript/blob/develop/CMakeLists.txt
+macro(ADD_INDIVIDUAL_TESTS executable type suffix)
+ set(test_path $ENV{PATH})
+ get_target_property(target_files ${executable} SOURCES)
+ foreach(source ${target_files})
+ string(REGEX MATCH .*cpp source "${source}")
+ if(source)
+ file(READ "${source}" contents)
+ string(REGEX MATCHALL "DEF_${type}[ ]*[(][ ]*[^, ]+[ ]*,[ ]*[^,) ]+[ ]*[),]" found_tests ${contents})
+ foreach(hit ${found_tests})
+ string(REGEX REPLACE "DEF_${type}[ ]*[(][ ]*([^, ]+)[ ]*,[ ]*[^,) ]+[ ]*[),]" "\\1" tname ${hit})
+ string(REGEX REPLACE "DEF_${type}[ ]*[(][ ]*[^, ]+[ ]*,[ ]*([^,) ]+)[ ]*[),]" "\\1" sname ${hit})
+ set(test_name ${executable}.${sname}.${tname}${suffix})
+ add_test(NAME ${test_name}
+ COMMAND "${executable}" --testName=${tname}${suffix} --suiteName=${sname})
+ set_tests_properties(${test_name} PROPERTIES TIMEOUT 30 ENVIRONMENT "PATH=${test_path}")
+ endforeach()
+ endif()
+ endforeach()
+endmacro()
+
+macro(ADD_TESTINATOR_TESTS executable)
+ ADD_INDIVIDUAL_TESTS(${executable} "TEST" "")
+ ADD_INDIVIDUAL_TESTS(${executable} "TIMED_TEST" "")
+ ADD_INDIVIDUAL_TESTS(${executable} "PROPERTY" "Property")
+ ADD_INDIVIDUAL_TESTS(${executable} "COMPLEXITY_PROPERTY" "ComplexityProperty")
+endmacro()
+
+add_subdirectory (src/lib)
+add_subdirectory (src/test)
+add_subdirectory (src/quickcheck)
diff --git a/external/semver/LICENSE b/external/semver/LICENSE
new file mode 100644
index 0000000..58b7258
--- /dev/null
+++ b/external/semver/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014-2016 Ben Deane
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/external/semver/README.md b/external/semver/README.md
new file mode 100644
index 0000000..c2e1cc7
--- /dev/null
+++ b/external/semver/README.md
@@ -0,0 +1,12 @@
+# Semver
+
+A C++ class for handling semantic versioning as detailed at http://semver.org/.
+
+Bonus: experimental testing with Haskell's QuickCheck.
+
+### Status
+[![Build Status](https://travis-ci.org/elbeno/semver.svg?branch=master)](https
+://travis-ci.org/elbeno/semver)
+[![Build status](https://ci.appveyor.com/api/projects/status/ve1bvyxharcq9gv3?svg=true)](https://ci.appveyor.com/project/elbeno/semver)
+
+This project is distributed under some license. See LICENSE for details.
diff --git a/external/semver/appveyor.yml b/external/semver/appveyor.yml
new file mode 100644
index 0000000..70afe93
--- /dev/null
+++ b/external/semver/appveyor.yml
@@ -0,0 +1,35 @@
+platform:
+ - x86
+ - x64
+
+configuration:
+ - Debug
+ - Release
+
+os: Visual Studio 2015
+
+clone_folder: c:\projects\semver
+
+install:
+ - git submodule update --init --recursive
+
+build_script:
+ # show settings
+ - cmake -version
+ - echo %platform%
+ - echo %configuration%
+
+ # generate a solution file
+ - cd c:\projects\semver
+ - mkdir build
+ - cd build
+ - if "%platform%" == "x64" set cmake_platform=%platform%
+ - cmake -g "Visual Studio 14 2015" .. -DCMAKE_GENERATOR_PLATFORM=%cmake_platform%
+
+ # build it
+ - if "%platform%" == "x86" set msbuild_platform=Win32
+ - if "%platform%" == "x64" set msbuild_platform=%platform%
+ - msbuild semver.sln /p:Configuration=%configuration% /toolsversion:14.0 /p:PlatformToolset=v140 /p:Platform=%msbuild_platform%
+
+test_script:
+ - if "%configuration%" == "Debug" ctest -VV --schedule-random -C Debug
diff --git a/external/semver/install_libcxx.sh b/external/semver/install_libcxx.sh
new file mode 100644
index 0000000..dbdb579
--- /dev/null
+++ b/external/semver/install_libcxx.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+#
+# Install libc++ under travis
+# Copied from https://github.com/ericniebler/range-v3
+
+svn --quiet co http://llvm.org/svn/llvm-project/libcxx/trunk libcxx
+mkdir libcxx/build
+(cd libcxx/build && cmake .. -DLIBCXX_CXX_ABI=libstdc++ -DLIBCXX_CXX_ABI_INCLUDE_PATHS="/usr/include/c++/4.6;/usr/include/c++/4.6/x86_64-linux-gnu")
+make -C libcxx/build cxx -j2
+sudo cp libcxx/build/lib/libc++.so.1.0 /usr/lib/
+sudo cp -r libcxx/build/include/c++/v1 /usr/include/c++/v1/
+sudo ln -sf /usr/lib/libc++.so.1.0 /usr/lib/libc++.so
+sudo ln -sf /usr/lib/libc++.so.1.0 /usr/lib/libc++.so.1
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);
+}