// file : libbutl/standard-version.mxx -*- C++ -*- // license : MIT; see accompanying LICENSE file #ifndef __cpp_modules_ts #pragma once #endif // C includes. #ifndef __cpp_lib_modules_ts #include #include // uint*_t #include // size_t #include #endif // Other includes. #ifdef __cpp_modules_ts export module butl.standard_version; #ifdef __cpp_lib_modules_ts 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 { // The build2 "standard version" (normal, earliest, and stub): // // [+-]..[-(a|b).[.[.]]][+] // [+-]..- // 0[+] // // The normal version can be release, final pre-release, or a pre-release // snapshot (release is naturally always final). Pre-release can be alpha or // beta. // // The numeric version format is AAAAABBBBBCCCCCDDDE where: // // AAAAA - major version number // BBBBB - minor version number // CCCCC - patch version number // DDD - alpha / beta (DDD + 500) version number // E - final (0) / snapshot (1) // // When DDDE is not 0, 1 is subtracted from AAAAABBBBBCCCCC. For example: // // Version AAAAABBBBBCCCCCDDDE // // 0.1.0 0000000001000000000 // 0.1.2 0000000001000020000 // 1.2.3 0000100002000030000 // 2.2.0-a.1 0000200001999990010 // 3.0.0-b.2 0000299999999995020 // 2.2.0-a.1.z 0000200001999990011 // // Stub is represented as ~0 (but is not considered a pre-release). // struct LIBBUTL_SYMEXPORT standard_version { // Invariants: // // 1. allow_earliest // ? (E == 1) || (snapshot_sn == 0) // : (E == 0) == (snapshot_sn == 0) // // 2. version != 0 || allow_stub && epoch == 0 && snapshot_sn == 0 // // 3. snapshot_sn != latest_sn && snapshot_sn != 0 || snapshot_id.empty () // static const std::uint64_t latest_sn = std::uint64_t (~0); std::uint16_t epoch = 1; // 0 if a stub, 1 if not specified. std::uint64_t version = 0; // AAAAABBBBBCCCCCDDDE or ~0 for stub. std::uint64_t snapshot_sn = 0; // 0 if not specifed, latest_sn if 'z'. std::string snapshot_id; // Empty if not specified. std::uint16_t revision = 0; // 0 if not specified. std::uint32_t major () const noexcept; std::uint32_t minor () const noexcept; std::uint32_t patch () const noexcept; // Return the alpha/beta version number if pre-release and nullopt // otherwise. // // Can be used as a predicate and also to get the value. // optional alpha () const noexcept; optional beta () const noexcept; // Return the DDD version part if a pre-release and nullopt otherwise. // // Can be used as a predicate and also to get the value. Note that 0 is // ambiguous (-[ab].0.z, or earliest version; see below). // optional pre_release () const noexcept; // String representations. // // Note: return empty if the corresponding component is unspecified. // std::string string () const; // Package version. // Project version (no epoch). // std::string string_project (bool revision = false) const; std::string string_project_id () const; // Project version id (no snapsn). std::string string_version () const; // Version only (no snapshot). std::string string_pre_release () const; // Pre-release part only (a.1). std::string string_snapshot () const; // Snapshot part only (1234.1f23). // Predicates. See also alpha(), beta(), and pre_release() above. // // The earliest version is represented as the (otherwise illegal) DDDE // value 0001 and snapshot_sn 0. Note that the earliest version is a final // alpha pre-release. // bool empty () const noexcept {return version == 0;} bool stub () const noexcept {return version == std::uint64_t (~0);} bool earliest () const noexcept; bool release () const noexcept; bool snapshot () const noexcept {return snapshot_sn != 0;} bool latest_snapshot () const noexcept; bool final () const noexcept; // Comparison of empty or stub versions doesn't make sense. // int compare (const standard_version& v, bool ignore_revision = false) const noexcept { if (epoch != v.epoch) return epoch < v.epoch ? -1 : 1; if (version != v.version) return version < v.version ? -1 : 1; if (snapshot_sn != v.snapshot_sn) return snapshot_sn < v.snapshot_sn ? -1 : 1; if (!ignore_revision) { if (revision != v.revision) return revision < v.revision ? -1 : 1; } return 0; } // Parse the version. Throw std::invalid_argument if the format is not // recognizable or components are invalid. // enum flags { none = 0, allow_earliest = 0x01, // Allow ..- form. allow_stub = 0x02 // Allow 0[+] form. }; explicit standard_version (const std::string&, flags = none); explicit standard_version (std::uint64_t version, flags = none); standard_version (std::uint64_t version, const std::string& snapshot, flags = none); // Note that the default epoch is 1 for real versions and 0 for stubs. // standard_version (std::uint16_t epoch, std::uint64_t version, const std::string& snapshot, std::uint16_t revision, flags = none); standard_version (std::uint16_t epoch, std::uint64_t version, std::uint64_t snapshot_sn, std::string snapshot_id, std::uint16_t revision, flags = none); // Version as separate major, minor, patch, and pre-release components. // Note that the pre-release here is in the DDD form, that is, incremented // by 500 for betas. // standard_version (std::uint16_t epoch, std::uint32_t major, std::uint32_t minor, std::uint32_t patch, std::uint16_t pre_release = 0, std::uint16_t revision = 0); standard_version (std::uint16_t epoch, std::uint32_t major, std::uint32_t minor, std::uint32_t patch, std::uint16_t pre_release, std::uint64_t snapshot_sn, std::string snapshot_id, std::uint16_t revision = 0); // Create empty version. // standard_version () {} // = default; @@ MOD VC }; // Try to parse a string as a standard version returning nullopt if invalid. // LIBBUTL_SYMEXPORT optional parse_standard_version (const std::string&, standard_version::flags = standard_version::none); inline bool operator< (const standard_version& x, const standard_version& y) noexcept { return x.compare (y) < 0; } inline bool operator> (const standard_version& x, const standard_version& y) noexcept { return x.compare (y) > 0; } inline bool operator== (const standard_version& x, const standard_version& y) noexcept { return x.compare (y) == 0; } inline bool operator<= (const standard_version& x, const standard_version& y) noexcept { return x.compare (y) <= 0; } inline bool operator>= (const standard_version& x, const standard_version& y) noexcept { return x.compare (y) >= 0; } inline bool operator!= (const standard_version& x, const standard_version& y) noexcept { return !(x == y); } inline std::ostream& operator<< (std::ostream& o, const standard_version& x) { return o << x.string (); } inline standard_version::flags operator& (standard_version::flags, standard_version::flags); inline standard_version::flags operator| (standard_version::flags, standard_version::flags); inline standard_version::flags operator&= (standard_version::flags&, standard_version::flags); inline standard_version::flags operator|= (standard_version::flags&, standard_version::flags); // The build2 "standard version" constraint: // // ('==' | '>' | '<' | '>=' | '<=') // ('^' | '~') // ('(' | '[') (')' | ']') // // The version may be `$` which refers to the dependent package version. // struct LIBBUTL_SYMEXPORT standard_version_constraint { butl::optional min_version; butl::optional max_version; bool min_open; bool max_open; // Parse the version constraint. Throw std::invalid_argument on error. // explicit standard_version_constraint (const std::string&); // As above but also completes the special `$` version using the specified // dependent package version. // standard_version_constraint (const std::string&, const standard_version& dependent_version); // Throw std::invalid_argument if the specified version range is invalid. // standard_version_constraint ( butl::optional min_version, bool min_open, butl::optional max_version, bool max_open); explicit standard_version_constraint (const standard_version& v) : standard_version_constraint (v, false, v, false) {} standard_version_constraint () = default; std::string string () const; bool empty () const noexcept {return !min_version && !max_version;} bool satisfies (const standard_version&) const noexcept; }; inline bool operator== (const standard_version_constraint& x, const standard_version_constraint& y) { return x.min_version == y.min_version && x.max_version == y.max_version && x.min_open == y.min_open && x.max_open == y.max_open; } inline bool operator!= (const standard_version_constraint& x, const standard_version_constraint& y) { return !(x == y); } inline std::ostream& operator<< (std::ostream& o, const standard_version_constraint& x) { return o << x.string (); } } #include