mirror of
https://github.com/textmate/textmate.git
synced 2026-04-28 03:00:34 -04:00
Add code for comparing complex version strings
This commit is contained in:
74
Frameworks/SoftwareUpdate/src/version_compare.cc
Normal file
74
Frameworks/SoftwareUpdate/src/version_compare.cc
Normal file
@@ -0,0 +1,74 @@
|
||||
#include "version_compare.h"
|
||||
|
||||
static bool is_numeric (std::string const& str)
|
||||
{
|
||||
return str.find_first_not_of("0123456789") == std::string::npos;
|
||||
}
|
||||
|
||||
static std::vector<std::string> components (std::string const& str)
|
||||
{
|
||||
std::vector<std::string> res;
|
||||
|
||||
for(size_t from = 0; from < str.size(); )
|
||||
{
|
||||
size_t to = str.find_first_of(".-+", from);
|
||||
if(to != std::string::npos)
|
||||
{
|
||||
res.push_back(str.substr(from, to - from));
|
||||
res.push_back(str.substr(to, 1));
|
||||
from = to + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
res.push_back(str.substr(from));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static std::vector<std::string> strip_trailing_zeroes (std::vector<std::string> const& src)
|
||||
{
|
||||
auto last = std::find_if_not(src.begin(), src.end(), [](std::string const& str){ return is_numeric(str) || str == "."; });
|
||||
auto from = last;
|
||||
|
||||
while(last != src.begin() && is_numeric(*(last-1)) && std::stol(*(last-1)) == 0 && --last != src.begin())
|
||||
--last;
|
||||
|
||||
std::vector<std::string> res;
|
||||
res.insert(res.end(), src.begin(), last);
|
||||
res.insert(res.end(), from, src.end());
|
||||
return res;
|
||||
}
|
||||
|
||||
bool version_less (std::string const& lhs, std::string const& rhs)
|
||||
{
|
||||
auto lhsV = strip_trailing_zeroes(components(lhs));
|
||||
auto rhsV = strip_trailing_zeroes(components(rhs));
|
||||
|
||||
auto lhsIt = lhsV.begin();
|
||||
auto rhsIt = rhsV.begin();
|
||||
|
||||
while(lhsIt != lhsV.end() && rhsIt != rhsV.end())
|
||||
{
|
||||
bool numberCompare = is_numeric(*lhsIt) && is_numeric(*rhsIt);
|
||||
if(*lhsIt != *rhsIt && (!numberCompare || std::stol(*lhsIt) != std::stol(*rhsIt)))
|
||||
{
|
||||
if(numberCompare)
|
||||
return std::stol(*lhsIt) < std::stol(*rhsIt);
|
||||
else if(lhsIt->find_first_not_of(".-+") == std::string::npos)
|
||||
return *lhsIt == "-" || (*lhsIt == "+" && *rhsIt == ".");
|
||||
return *lhsIt < *rhsIt;
|
||||
}
|
||||
else if(*lhsIt == "+")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
++lhsIt;
|
||||
++rhsIt;
|
||||
}
|
||||
|
||||
return lhsIt != lhsV.end() ? *lhsIt == "-" : (rhsIt != rhsV.end() && *rhsIt == ".");
|
||||
}
|
||||
11
Frameworks/SoftwareUpdate/src/version_compare.h
Normal file
11
Frameworks/SoftwareUpdate/src/version_compare.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef VERSION_COMPARE_H_FY5OTOGA
|
||||
#define VERSION_COMPARE_H_FY5OTOGA
|
||||
|
||||
bool version_less (std::string const& rhs, std::string const& lhs);
|
||||
|
||||
inline bool version_equal (std::string const& rhs, std::string const& lhs)
|
||||
{
|
||||
return !version_less(lhs, rhs) && !version_less(rhs, lhs);
|
||||
}
|
||||
|
||||
#endif /* end of include guard: VERSION_COMPARE_H_FY5OTOGA */
|
||||
63
Frameworks/SoftwareUpdate/tests/t_version_compare.cc
Normal file
63
Frameworks/SoftwareUpdate/tests/t_version_compare.cc
Normal file
@@ -0,0 +1,63 @@
|
||||
#include "../src/version_compare.h"
|
||||
|
||||
static bool less (std::string const& lhs, std::string const& rhs)
|
||||
{
|
||||
return version_less(lhs, rhs) && !version_less(rhs, lhs);
|
||||
}
|
||||
|
||||
static bool equal (std::string const& lhs, std::string const& rhs)
|
||||
{
|
||||
return version_equal(lhs, rhs);
|
||||
}
|
||||
|
||||
static bool greator (std::string const& lhs, std::string const& rhs)
|
||||
{
|
||||
return !less(lhs, rhs);
|
||||
}
|
||||
|
||||
void test_trailing_zero ()
|
||||
{
|
||||
OAK_ASSERT( less("2-beta", "2.0"));
|
||||
OAK_ASSERT( less("2.0-beta", "2.0"));
|
||||
OAK_ASSERT( less("2.0.0-beta", "2.0"));
|
||||
OAK_ASSERT( equal("2", "2.0"));
|
||||
OAK_ASSERT( equal("2", "2.0+git.hash"));
|
||||
OAK_ASSERT( equal("2+git.hash", "2.0"));
|
||||
OAK_ASSERT(greator("2.0.1-beta", "2.0"));
|
||||
OAK_ASSERT(greator("2.1-beta", "2.0"));
|
||||
}
|
||||
|
||||
void test_exhaustive ()
|
||||
{
|
||||
std::string const numbers[] = { "1", "1.01", "1.1.1", "1.1.2", "1.2", "1.2.1", "1.10", "2", "2.1", "2.1.1", "2.2" };
|
||||
std::vector<std::string> versions;
|
||||
|
||||
for(auto number : numbers)
|
||||
{
|
||||
versions.push_back(number + "-alpha");
|
||||
versions.push_back(number + "-alpha.1");
|
||||
versions.push_back(number + "-alpha.2");
|
||||
versions.push_back(number + "-beta");
|
||||
versions.push_back(number + "-beta.1");
|
||||
versions.push_back(number + "-beta.2");
|
||||
versions.push_back(number + "-rc.1");
|
||||
versions.push_back(number);
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < versions.size(); ++i)
|
||||
{
|
||||
for(size_t j = i; j < versions.size(); ++j)
|
||||
{
|
||||
for(auto lhs : { versions[i], versions[i] + "+git.c0de" })
|
||||
{
|
||||
for(auto rhs : { versions[j], versions[j] + "+git.b337" })
|
||||
{
|
||||
auto msg = text::format("%s %c %s", lhs.c_str(), i < j ? '<' : (i == j ? '=' : '>'), rhs.c_str());
|
||||
if(i < j) { OAK_MASSERT(msg, less(lhs, rhs)); }
|
||||
if(i == j) { OAK_MASSERT(msg, equal(lhs, rhs)); }
|
||||
if(i > j) { OAK_MASSERT(msg, greator(lhs, rhs)); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user