// file : libbutl/semantic-version.hxx -*- C++ -*- // license : MIT; see accompanying LICENSE file #pragma once #include #include // size_t #include // uint*_t #include // move() #include #include #include // FreeBSD defines these macros in its . // #ifdef major # undef major #endif #ifdef minor # undef minor #endif namespace butl { // Semantic or semantic-like version. // // [.[.]][] // // If the minor and patch components are absent, then they default to 0. // // 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 = ""); // If the allow_build flag is specified, then build_separators argument // can be a string of characters to allow as separators, empty (any build // component allowed), or NULL (defaults to "-+"). // // Note: allow_omit_minor implies allow_omit_patch. // enum flags { none = 0, // Exact .. form. allow_omit_minor = 0x01, // Allow form. allow_omit_patch = 0x02, // Allow . form. allow_build = 0x04, // Allow ..- form. }; explicit semantic_version (const std::string&, flags = none, const char* build_separators = nullptr); // As above but parse from the specified position until the end of the // string. // semantic_version (const std::string&, std::size_t pos, flags = none, const char* = nullptr); // @@ We may also want to pass allow_* flags not to print 0 minor/patch or // maybe invent ignore_* flags. // std::string string (bool ignore_build = false) const; // Numeric representation in the AAAAABBBBBCCCCC0000 form, where: // // AAAAA - major version number // BBBBB - minor version number // CCCCC - 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 99999, 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& v, bool ignore_build = false) const { return (major != v.major ? (major < v.major ? -1 : 1) : minor != v.minor ? (minor < v.minor ? -1 : 1) : patch != v.patch ? (patch < v.patch ? -1 : 1) : ignore_build ? 0 : build.compare (v.build)); } }; // Try to parse a string as a semantic version returning nullopt if invalid. // optional parse_semantic_version (const std::string&, semantic_version::flags = semantic_version::none, const char* build_separators = nullptr); optional parse_semantic_version (const std::string&, std::size_t pos, semantic_version::flags = semantic_version::none, const char* = nullptr); // NOTE: comparison operators take the build component into account. // inline bool operator< (const semantic_version& x, const semantic_version& y) { return x.compare (y) < 0; } inline bool operator> (const semantic_version& x, const semantic_version& y) { return x.compare (y) > 0; } inline bool operator== (const semantic_version& x, const semantic_version& y) { return x.compare (y) == 0; } inline bool operator<= (const semantic_version& x, const semantic_version& y) { return x.compare (y) <= 0; } inline bool operator>= (const semantic_version& x, const semantic_version& y) { return x.compare (y) >= 0; } inline bool operator!= (const semantic_version& x, const semantic_version& y) { return !(x == y); } inline std::ostream& operator<< (std::ostream& o, const semantic_version& x) { return o << x.string (); } semantic_version::flags operator& (semantic_version::flags, semantic_version::flags); semantic_version::flags operator| (semantic_version::flags, semantic_version::flags); semantic_version::flags operator&= (semantic_version::flags&, semantic_version::flags); semantic_version::flags operator|= (semantic_version::flags&, semantic_version::flags); } #include