From 8561af5a2551ec453c9888125de273f2cc2940c0 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 14 Aug 2018 14:09:32 +0200 Subject: Add support for parsing semantic and semantic-like versions --- libbutl/semantic-version.mxx | 187 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 libbutl/semantic-version.mxx (limited to 'libbutl/semantic-version.mxx') diff --git a/libbutl/semantic-version.mxx b/libbutl/semantic-version.mxx new file mode 100644 index 0000000..d64eb82 --- /dev/null +++ b/libbutl/semantic-version.mxx @@ -0,0 +1,187 @@ +// file : libbutl/semantic-version.mxx -*- C++ -*- +// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#ifndef __cpp_modules +#pragma once +#endif + +// C includes. + +#ifndef __cpp_lib_modules +#include +#include // size_t +#include // uint*_t +#include // move() +#include +#endif + +// Other includes. + +#ifdef __cpp_modules +export module butl.semantic_version; +#ifdef __cpp_lib_modules +import std.core; +import std.io; +#endif +import butl.optional; +#else +#include +#endif + +#include + +// FreeBSD defines these macros in its . +// +#ifdef major +# undef major +#endif + +#ifdef minor +# undef minor +#endif + +LIBBUTL_MODEXPORT namespace butl +{ + // Semantic or semantic-like version. + // + // .[.][] + // + // If the patch component is absent, then it defaults to 0. + // + // @@ Currently there is no way to enforce the three-component version. + // Supporting this will require changing allow_build to a bit-wise + // flag. See parse_semantic_version_impl() for some sketched code. + // We may also want to pass these flags to string() to not print + // 0 patch. + // + // By default, a version containing the component is considered + // valid only if separated from with '-' (semver pre-release) or '+' + // (semver build metadata). However, as discussed below, the list of valid + // separators can be customized to recognize other semver-like formats. + // + // Note also that the format of semver pre-release and build metadata are + // not validated. + // + struct LIBBUTL_SYMEXPORT semantic_version + { + std::uint64_t major = 0; + std::uint64_t minor = 0; + std::uint64_t patch = 0; + std::string build; + + // Construct the semantic version from various representations. Throw + // std::invalid_argument if the format is not recognizable or components + // are invalid. + // + semantic_version () = default; + + semantic_version (std::uint64_t major, + std::uint64_t minor, + std::uint64_t patch, + std::string build = ""); + + // The build_separators argument can be NULL (no build component allowed), + // empty (any build component allowed), or a string of characters to allow + // as separators. When allow_build is true build_separators defaults to + // "-+". + // + explicit + semantic_version (const std::string&, bool allow_build = true); + + semantic_version (const std::string&, const char* build_separators); + + // As above but parse from the specified position until the end of the + // string. + // + semantic_version (const std::string&, std::size_t pos, bool = true); + + semantic_version (const std::string&, std::size_t pos, const char*); + + std::string + string (bool ignore_build = false) const; + + // Numeric representation in the AAABBBCCC0000 form, where: + // + // AAA - major version number + // BBB - minor version number + // CCC - patch version number + // + // See standard version for details. + // + explicit + semantic_version (std::uint64_t numeric, std::string build = ""); + + // If any of the major/minor/patch components is greater than 999, then + // throw std::invalid_argument. The build component is ignored. + // + std::uint64_t + numeric () const; + + // Unless instructed to ignore, the build components are compared + // lexicographically. + // + int + compare (const semantic_version&, bool ignore_build = false) const; + }; + + // Try to parse a string as a semantic version returning nullopt if invalid. + // + optional + parse_semantic_version (const std::string&, bool allow_build = true); + + optional + parse_semantic_version (const std::string&, const char* build_separators); + + optional + parse_semantic_version (const std::string&, std::size_t pos, bool = true); + + optional + parse_semantic_version (const std::string&, std::size_t pos, const char*); + + // NOTE: comparison operators take the build component into account. + // + inline bool + operator< (const semantic_version& x, const semantic_version& y) noexcept + { + return x.compare (y) < 0; + } + + inline bool + operator> (const semantic_version& x, const semantic_version& y) noexcept + { + return x.compare (y) > 0; + } + + inline bool + operator== (const semantic_version& x, const semantic_version& y) noexcept + { + return x.compare (y) == 0; + } + + inline bool + operator<= (const semantic_version& x, const semantic_version& y) noexcept + { + return x.compare (y) <= 0; + } + + inline bool + operator>= (const semantic_version& x, const semantic_version& y) noexcept + { + return x.compare (y) >= 0; + } + + inline bool + operator!= (const semantic_version& x, const semantic_version& y) noexcept + { + return !(x == y); + } + + inline std::ostream& + operator<< (std::ostream& o, const semantic_version& x) + { + return o << x.string (); + } +} + +#include -- cgit v1.1