From 5bb170316ebad036ee5b8b18dee7ce3d09c72df4 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Thu, 27 Apr 2017 19:36:58 +0300 Subject: Add support for standard version earliest pre-release --- butl/standard-version | 30 +++++++++++----- butl/standard-version.cxx | 88 ++++++++++++++++++++++++++++++----------------- butl/standard-version.ixx | 20 ++++++++--- 3 files changed, 94 insertions(+), 44 deletions(-) (limited to 'butl') diff --git a/butl/standard-version b/butl/standard-version index c9637d8..0c7b9bc 100644 --- a/butl/standard-version +++ b/butl/standard-version @@ -16,17 +16,20 @@ namespace butl { - // The build2 "standard version": + // The build2 "standard version" (specific and earliest): // // [~]..[-(a|b).[.[.]]][+] + // [~]..- // struct LIBBUTL_EXPORT standard_version { // Invariants: // - // 1. (E == 0) == (snapshot_sn == 0 && snapshot_id.empty ()) + // 1. allow_earliest + // ? (E == 1) || (snapshot_sn == 0) + // : (E == 0) == (snapshot_sn == 0) // - // 2. snapshot_sn != latest_sn || snapshot_id.empty () + // 2. snapshot_sn != latest_sn && snapshot_sn != 0 || snapshot_id.empty () // static const std::uint64_t latest_sn = std::uint64_t (~0); @@ -58,6 +61,13 @@ namespace butl bool beta () const noexcept; bool snapshot () const noexcept {return snapshot_sn != 0;} + // Is represented by DDDE being 0001 and snapshot_sn being 0. + // + // Note that the earliest version is a final alpha pre-release. + // + bool + earliest () const noexcept; + int compare (const standard_version&) const noexcept; @@ -65,23 +75,27 @@ namespace butl // recognizable or components are invalid. // explicit - standard_version (const std::string&); + standard_version (const std::string&, bool allow_earliest = false); explicit - standard_version (std::uint64_t version); + standard_version (std::uint64_t version, bool allow_earliest = false); - standard_version (std::uint64_t version, const std::string& snapshot); + standard_version (std::uint64_t version, + const std::string& snapshot, + bool allow_earliest = false); standard_version (std::uint16_t epoch, std::uint64_t version, const std::string& snapshot, - std::uint16_t revision); + std::uint16_t revision, + bool allow_earliest = false); standard_version (std::uint16_t epoch, std::uint64_t version, std::uint64_t snapshot_sn, std::string snapshot_id, - std::uint16_t revision); + std::uint16_t revision, + bool allow_earliest = false); // Create empty version. // diff --git a/butl/standard-version.cxx b/butl/standard-version.cxx index 552aac8..16095c0 100644 --- a/butl/standard-version.cxx +++ b/butl/standard-version.cxx @@ -38,7 +38,7 @@ namespace butl } static void - check_version (uint64_t version, bool snapshot) + check_version (uint64_t version, bool snapshot, bool allow_earliest) { // Check that the version isn't too large. // @@ -46,9 +46,18 @@ namespace butl bool r (version < 10000000000000ULL); // Check that E version component is consistent with the snapshot flag. + // Note that if the allow_earliest flag is true, then E can be 1 for the + // snapshot flag being false, denoting the earliest pre-release of the + // version. // if (r) - r = (version % 10) == (snapshot ? 1 : 0); + { + uint64_t e (version % 10); + if (!allow_earliest) + r = e == (snapshot ? 1 : 0); + else + r = e == 1 || (e == 0 && !snapshot); + } // Check that pre-release number is consistent with the snapshot flag. // @@ -78,7 +87,7 @@ namespace butl // standard_version // standard_version:: - standard_version (const std::string& s) + standard_version (const std::string& s, bool allow_earliest) { auto bail = [] (const char* m) {throw invalid_argument (m);}; @@ -127,56 +136,66 @@ namespace butl // Parse the pre-release component if present. // + bool earliest (false); if (s[p] == '-') { char k (s[++p]); - if (k != 'a' && k != 'b') - bail ("'a' or 'b' expected in pre-release"); + if (k == '\0' && allow_earliest) // Dash is the last string character. + earliest = true; + else + { + if (k != 'a' && k != 'b') + bail ("'a' or 'b' expected in pre-release"); - if (s[++p] != '.') - bail ("'.' expected after pre-release letter"); + if (s[++p] != '.') + bail ("'.' expected after pre-release letter"); - ab = parse_num (s, ++p, "invalid pre-release", 0, 499); + ab = parse_num (s, ++p, "invalid pre-release", 0, 499); - if (k == 'b') - ab += 500; + if (k == 'b') + ab += 500; - // Parse the snapshot components if present. Note that pre-release number - // can't be zero for the final pre-release. - // - if (s[p] == '.') - parse_snapshot (s, ++p); - else if (ab == 0 || ab == 500) - bail ("invalid final pre-release"); + // Parse the snapshot components if present. Note that pre-release number + // can't be zero for the final pre-release. + // + if (s[p] == '.') + parse_snapshot (s, ++p); + else if (ab == 0 || ab == 500) + bail ("invalid final pre-release"); + } } if (s[p] == '+') + { + assert (!earliest); // Would bail out earlier (a or b expected after -). + revision = parse_num (s, ++p, "invalid revision", 1, uint16_t (~0)); + } if (p != s.size ()) bail ("junk after version"); - if (ab != 0) + if (ab != 0 || snapshot_sn != 0 || earliest) version -= 10000 - ab * 10; - if (snapshot_sn != 0) + if (snapshot_sn != 0 || earliest) version += 1; } standard_version:: - standard_version (uint64_t v) + standard_version (uint64_t v, bool allow_earliest) : version (v) { - check_version (v, false); + check_version (v, false, allow_earliest); } standard_version:: - standard_version (uint64_t v, const std::string& s) + standard_version (uint64_t v, const std::string& s, bool allow_earliest) : version (v) { bool snapshot (!s.empty ()); - check_version (version, snapshot); + check_version (version, snapshot, allow_earliest); if (snapshot) { @@ -193,14 +212,15 @@ namespace butl uint64_t vr, uint64_t sn, std::string si, - uint16_t rv) + uint16_t rv, + bool allow_earliest) : epoch (ep), version (vr), snapshot_sn (sn), snapshot_id (move (si)), revision (rv) { - check_version (vr, true); + check_version (vr, true, allow_earliest); if (!snapshot_id.empty () && (snapshot_id.size () > 16 || snapshot_sn == 0 || @@ -244,7 +264,7 @@ namespace butl { std::string r; - if (alpha () || beta ()) + if ((alpha () && !earliest ()) || beta ()) { uint64_t ab (version / 10 % 1000); @@ -360,7 +380,7 @@ namespace butl try { - min_version = standard_version (s.substr (p, e - p)); + min_version = standard_version (s.substr (p, e - p), true); } catch (const invalid_argument& e) { @@ -377,7 +397,7 @@ namespace butl try { - max_version = standard_version (s.substr (p, e - p)); + max_version = standard_version (s.substr (p, e - p), true); } catch (const invalid_argument& e) { @@ -425,7 +445,7 @@ namespace butl try { - v = standard_version (s.substr (p)); + v = standard_version (s.substr (p), operation != comparison::eq); } catch (const invalid_argument& e) { @@ -482,8 +502,14 @@ namespace butl if (*min_version > *max_version) throw invalid_argument ("min version is greater than max version"); - if (*min_version == *max_version && (min_open || max_open)) - throw invalid_argument ("equal version endpoints not closed"); + if (*min_version == *max_version) + { + if (min_open || max_open) + throw invalid_argument ("equal version endpoints not closed"); + + if (min_version->earliest ()) + throw invalid_argument ("equal version endpoints are earliest"); + } } } diff --git a/butl/standard-version.ixx b/butl/standard-version.ixx index b01faef..332eb02 100644 --- a/butl/standard-version.ixx +++ b/butl/standard-version.ixx @@ -8,8 +8,9 @@ namespace butl standard_version ( std::uint16_t e, std::uint64_t v, const std::string& s, - std::uint16_t r) - : standard_version (v, s) + std::uint16_t r, + bool allow_earliest) + : standard_version (v, s, allow_earliest) { // Can't initialize above due to ctor delegating. // @@ -20,9 +21,10 @@ namespace butl inline std::uint16_t standard_version:: major () const noexcept { + std::uint64_t e (version % 10); std::uint64_t v (version / 10); std::uint64_t ab (v % 1000); - if (ab != 0) + if (ab != 0 || e == 1) v += 1000 - ab; return static_cast (v / 1000000000 % 1000); @@ -31,9 +33,10 @@ namespace butl inline std::uint16_t standard_version:: minor () const noexcept { + std::uint64_t e (version % 10); std::uint64_t v (version / 10); std::uint64_t ab (v % 1000); - if (ab != 0) + if (ab != 0 || e == 1) v += 1000 - ab; return static_cast (v / 1000000 % 1000); @@ -42,9 +45,10 @@ namespace butl inline std::uint16_t standard_version:: patch () const noexcept { + std::uint64_t e (version % 10); std::uint64_t v (version / 10); std::uint64_t ab (v % 1000); - if (ab != 0) + if (ab != 0 || e == 1) v += 1000 - ab; return static_cast (v / 1000 % 1000); @@ -74,6 +78,12 @@ namespace butl return abe > 5000; } + inline bool standard_version:: + earliest () const noexcept + { + return version % 10000 == 1 && !snapshot (); + } + inline int standard_version:: compare (const standard_version& v) const noexcept { -- cgit v1.1