diff --git a/include/semver200.h b/include/semver200.h new file mode 100644 index 0000000..e889cc3 --- /dev/null +++ b/include/semver200.h @@ -0,0 +1,48 @@ +/* +The MIT License (MIT) + +Copyright (c) 2015 Marko Zivanovic + +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. +*/ + +#pragma once + +#include "version.h" + +namespace version { + + /// Parse string into Version_data structure according to semantic versioning 2.0.0 rules. + struct Semver200_parser { + Version_data parse(const std::string&) const; + }; + + /// Compare Version_data to another using semantic versioning 2.0.0 rules. + struct Semver200_comparator { + int compare(const Version_data&, const Version_data&) const; + }; + + /// Concrete version class that binds all semver 2.0.0 functionality together. + class Semver200_version : public Basic_version { + public: + Semver200_version(const std::string& v) + : Basic_version{ v, Semver200_parser(), Semver200_comparator() } {} + }; + +} \ No newline at end of file diff --git a/include/version.h b/include/version.h index 3f6d66c..170c0f5 100644 --- a/include/version.h +++ b/include/version.h @@ -75,46 +75,45 @@ namespace version { Build_identifiers build_ids; }; + /// Forward declaration required for operators' template declarations. + template + class Basic_version; + + /// Compare if left version object is less than the right. + template + bool operator<(const Basic_version&, const Basic_version&); + + /// Compare if two version objects are equal. + template + bool operator==(const Basic_version& l, const Basic_version& r); + + /// Output version object to stream using standard semver format (X.Y.Z-PR+B). + template + std::ostream& operator<<(std::ostream& os, const Basic_version& v); + + /// Generic version description and comparison class. /** Basic_version class describes general version object without prescribing parsing, - validation and comparison rules. These rules are implemented by supplied Parser and - Comparator parameters. + validation and comparison rules. These rules are implemented by supplied P and + C parameters. */ template class Basic_version { public: - /// Construct Basic_version object using Parser to parse version string and Comparator for comparison. + /// Construct Basic_version object using P to parse version string and C for comparison. Basic_version(const std::string& v, Parser p, Comparator c) : parser_(p), comparator_(c), ver_(parser_.parse(v)) {}; - /// Compare if left version object is less than the right. - friend bool operator<(const Basic_version& l, const Basic_version& r) { - return l.comparator_.compare(l.ver_, r.ver_) == -1; - } - /// Compare if two version objects are equal. - friend bool operator==(const Basic_version& l, const Basic_version& r) { - return l.comparator_.compare(l.ver_, r.ver_) == 0; - } - /// Output version object to stream using standard semver format (X.Y.Z-PR+B). - friend std::ostream& operator<<(std::ostream& os, const Basic_version& v) { - os << v.ver_.major << "." << v.ver_.minor << "." << v.ver_.patch; - if (!v.ver_.prerelease_ids.empty()) { - os << "-"; - for (auto it = v.ver_.prerelease_ids.cbegin(); it < v.ver_.prerelease_ids.cend() - 1; ++it) { - os << it->first << "."; - } - os << v.ver_.prerelease_ids.crbegin()->first; - } - if (!v.ver_.build_ids.empty()) { - os << "+"; - for (auto it = v.ver_.build_ids.cbegin(); it < v.ver_.build_ids.cend() - 1; ++it) { - os << *it << "."; - } - os << *v.ver_.build_ids.crbegin(); - } - return os; - } + const int major() const; + const int minor() const; + const int patch() const; + const std::string prerelease() const; + const std::string build() const; + + friend bool operator< <>(const Basic_version& l, const Basic_version& r); + friend bool operator== <>(const Basic_version& l, const Basic_version& r); + friend std::ostream& operator<< <>(std::ostream& os, const Basic_version& v); private: Parser parser_; @@ -122,45 +121,22 @@ namespace version { const Version_data ver_; }; - /// Parse string into Version_data structure according to semantic versioning 2.0.0 rules. - struct Semver200_parser { - Version_data parse(const std::string&) const; - }; - - /// Compare Version_data to another using semantic versioning 2.0.0 rules. - struct Semver200_comparator { - int compare(const Version_data&, const Version_data&) const; - }; - - /// Concrete version class that binds all semver 2.0.0 functionality together. - class Semver200_version : public Basic_version { - public: - Semver200_version(const std::string& v) - : Basic_version{ v, Semver200_parser(), Semver200_comparator() } {} - }; - /// Compare if two version objects are different. - template - inline bool operator!=(const Basic_version& l, const Basic_version& r) { - return !(l == r); - } + template + bool operator!=(const version::Basic_version& l, const version::Basic_version& r); /// Compare if left version object is greater than the right. - template - inline bool operator>(const Basic_version& l, const Basic_version& r) { - return r < l; - } + template + bool operator>(const version::Basic_version& l, const version::Basic_version& r); /// Compare if left version object is greater than or equal the right. - template - inline bool operator>=(const Basic_version& l, const Basic_version& r) { - return !(l < r); - } + template + bool operator>=(const version::Basic_version& l, const version::Basic_version& r); /// Compare if left version object is less than or equal the right. - template - inline bool operator<=(const Basic_version& l, const Basic_version& r) { - return !(l > r); - } + template + bool operator<=(const version::Basic_version& l, const version::Basic_version& r); } + +#include "version.inl" diff --git a/include/version.inl b/include/version.inl new file mode 100644 index 0000000..7e73d05 --- /dev/null +++ b/include/version.inl @@ -0,0 +1,122 @@ +/* +The MIT License (MIT) + +Copyright (c) 2015 Marko Zivanovic + +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. +*/ + +#pragma once + +#include "version.h" + +namespace version { + + namespace { + + /// Utility function to splice all vector elements to output stream, using designated separator and + /// function object for getting value from vector element. + template + std::ostream& splice(std::ostream& os, const std::vector& v, const std::string& sep, F read) { + for (auto it = v.cbegin(); it < v.cend() - 1; ++it) { + os << read(*it) << sep; + } + os << read(*v.crbegin()); + return os; + } + } + + template + const int Basic_version::major() const { + return ver_.major; + } + + template + const int Basic_version::minor() const { + return ver_.minor; + } + + template + const int Basic_version::patch() const { + return ver_.patch; + } + + template + const std::string Basic_version::prerelease() const { + std::stringstream ss; + splice(ss, ver_.prerelease_ids, ".", [](const auto& id) { return id.first;}); + return ss.str(); + } + + template + const std::string Basic_version::build() const { + std::stringstream ss; + splice(ss, ver_.build_ids, ".", [](const auto& id) { return id;}); + return ss.str(); + } + + + template + bool operator<(const Basic_version& l, const Basic_version& r) { + return l.comparator_.compare(l.ver_, r.ver_) == -1; + } + + template + bool operator==(const version::Basic_version& l, const version::Basic_version& r) { + return l.comparator_.compare(l.ver_, r.ver_) == 0; + } + + template + std::ostream& operator<<(std::ostream& os, const version::Basic_version& v) { + os << v.ver_.major << "." << v.ver_.minor << "." << v.ver_.patch; + if (!v.ver_.prerelease_ids.empty()) { + os << "-"; + splice(os, v.ver_.prerelease_ids, ".", [](const auto& id) { return id.first;}); + } + if (!v.ver_.build_ids.empty()) { + os << "+"; + splice(os, v.ver_.build_ids, ".", [](const auto& id) { return id;}); + } + return os; + } + + /// Compare if two version objects are different. + template + inline bool operator!=(const version::Basic_version& l, const version::Basic_version& r) { + return !(l == r); + } + + /// Compare if left version object is greater than the right. + template + inline bool operator>(const version::Basic_version& l, const version::Basic_version& r) { + return r < l; + } + + /// Compare if left version object is greater than or equal the right. + template + inline bool operator>=(const version::Basic_version& l, const version::Basic_version& r) { + return !(l < r); + } + + /// Compare if left version object is less than or equal the right. + template + inline bool operator<=(const version::Basic_version& l, const version::Basic_version& r) { + return !(l > r); + } +} \ No newline at end of file diff --git a/src/Semver200_comparator.cpp b/src/Semver200_comparator.cpp index 6e0437a..2a980ef 100644 --- a/src/Semver200_comparator.cpp +++ b/src/Semver200_comparator.cpp @@ -25,7 +25,7 @@ SOFTWARE. #include #include #include -#include "version.h" +#include "semver200.h" using namespace std; diff --git a/src/Semver200_parser.cpp b/src/Semver200_parser.cpp index de8c531..2426e56 100644 --- a/src/Semver200_parser.cpp +++ b/src/Semver200_parser.cpp @@ -24,7 +24,7 @@ SOFTWARE. #include #include -#include "version.h" +#include "semver200.h" using namespace std; diff --git a/test/semver200_comparator_tests.cpp b/test/semver200_comparator_tests.cpp index 399d731..50ce8b2 100644 --- a/test/semver200_comparator_tests.cpp +++ b/test/semver200_comparator_tests.cpp @@ -25,7 +25,7 @@ SOFTWARE. #define BOOST_TEST_MODULE semver200_comparator_tests #include -#include "version.h" +#include "semver200.h" using namespace version; diff --git a/test/semver200_parser_util.h b/test/semver200_parser_util.h index c32e612..fbb13b6 100644 --- a/test/semver200_parser_util.h +++ b/test/semver200_parser_util.h @@ -26,7 +26,7 @@ SOFTWARE. #include #include -#include "version.h" +#include "semver200.h" version::Semver200_parser p; const version::Prerelease_identifiers no_rel_ids; diff --git a/test/semver200_version_tests.cpp b/test/semver200_version_tests.cpp index 0bea638..a331c47 100644 --- a/test/semver200_version_tests.cpp +++ b/test/semver200_version_tests.cpp @@ -25,7 +25,7 @@ SOFTWARE. #define BOOST_TEST_MODULE semver200_version_tests #include -#include "version.h" +#include "semver200.h" using namespace version; @@ -54,6 +54,8 @@ BOOST_AUTO_TEST_CASE(test_relational_operators) { BOOST_CHECK(v("1.0.0") >= v("1.0.0")); BOOST_CHECK(v("1.0.0") >= v("0.0.9")); + + BOOST_CHECK(v("2.0.0") > v("1.9.9")); } BOOST_AUTO_TEST_CASE(test_ostream_output) { @@ -64,4 +66,13 @@ BOOST_AUTO_TEST_CASE(test_ostream_output) { CHECK_RT("1.2.3-alpha+build.314"); CHECK_RT("1.2.3-alpha.1+build.314"); CHECK_RT("1.2.3-alpha.1.2.3+build.314"); +} + +BOOST_AUTO_TEST_CASE(test_accessors) { + auto p = v("1.2.3-pre.rel.1+test.build.321"); + BOOST_CHECK_EQUAL(p.major(), 1); + BOOST_CHECK_EQUAL(p.minor(), 2); + BOOST_CHECK_EQUAL(p.patch(), 3); + BOOST_CHECK_EQUAL(p.prerelease(), "pre.rel.1"); + BOOST_CHECK_EQUAL(p.build(), "test.build.321"); } \ No newline at end of file