Skip to content

Commit

Permalink
Merge pull request #751 from Edgars-Cirulis/develop
Browse files Browse the repository at this point in the history
  • Loading branch information
Scrumplex committed Feb 5, 2023
2 parents d2fd0fd + 445f9e5 commit a47bf72
Show file tree
Hide file tree
Showing 5 changed files with 336 additions and 130 deletions.
149 changes: 96 additions & 53 deletions launcher/Version.cpp
Original file line number Diff line number Diff line change
@@ -1,85 +1,128 @@
#include "Version.h"

#include <QStringList>
#include <QUrl>
#include <QDebug>
#include <QRegularExpression>
#include <QRegularExpressionMatch>
#include <QUrl>

Version::Version(const QString &str) : m_string(str)
Version::Version(QString str) : m_string(std::move(str))
{
parse();
}

bool Version::operator<(const Version &other) const
{
const int size = qMax(m_sections.size(), other.m_sections.size());
for (int i = 0; i < size; ++i)
{
const Section sec1 = (i >= m_sections.size()) ? Section("0") : m_sections.at(i);
const Section sec2 =
(i >= other.m_sections.size()) ? Section("0") : other.m_sections.at(i);
if (sec1 != sec2)
{
return sec1 < sec2;
}
#define VERSION_OPERATOR(return_on_different) \
bool exclude_our_sections = false; \
bool exclude_their_sections = false; \
\
const auto size = qMax(m_sections.size(), other.m_sections.size()); \
for (int i = 0; i < size; ++i) { \
Section sec1 = (i >= m_sections.size()) ? Section() : m_sections.at(i); \
Section sec2 = (i >= other.m_sections.size()) ? Section() : other.m_sections.at(i); \
\
{ /* Don't include appendixes in the comparison */ \
if (sec1.isAppendix()) \
exclude_our_sections = true; \
if (sec2.isAppendix()) \
exclude_their_sections = true; \
\
if (exclude_our_sections) { \
sec1 = Section(); \
if (sec2.m_isNull) \
break; \
} \
\
if (exclude_their_sections) { \
sec2 = Section(); \
if (sec1.m_isNull) \
break; \
} \
} \
\
if (sec1 != sec2) \
return return_on_different; \
}

bool Version::operator<(const Version& other) const
{
VERSION_OPERATOR(sec1 < sec2)

return false;
}
bool Version::operator<=(const Version &other) const
bool Version::operator==(const Version& other) const
{
VERSION_OPERATOR(false)

return true;
}
bool Version::operator!=(const Version& other) const
{
return !operator==(other);
}
bool Version::operator<=(const Version& other) const
{
return *this < other || *this == other;
}
bool Version::operator>(const Version &other) const
bool Version::operator>(const Version& other) const
{
const int size = qMax(m_sections.size(), other.m_sections.size());
for (int i = 0; i < size; ++i)
{
const Section sec1 = (i >= m_sections.size()) ? Section("0") : m_sections.at(i);
const Section sec2 =
(i >= other.m_sections.size()) ? Section("0") : other.m_sections.at(i);
if (sec1 != sec2)
{
return sec1 > sec2;
}
}

return false;
return !(*this <= other);
}
bool Version::operator>=(const Version &other) const
bool Version::operator>=(const Version& other) const
{
return *this > other || *this == other;
return !(*this < other);
}
bool Version::operator==(const Version &other) const

void Version::parse()
{
const int size = qMax(m_sections.size(), other.m_sections.size());
for (int i = 0; i < size; ++i)
{
const Section sec1 = (i >= m_sections.size()) ? Section("0") : m_sections.at(i);
const Section sec2 =
(i >= other.m_sections.size()) ? Section("0") : other.m_sections.at(i);
if (sec1 != sec2)
{
m_sections.clear();
QString currentSection;

if (m_string.isEmpty())
return;

auto classChange = [&](QChar lastChar, QChar currentChar) {
if (lastChar.isNull())
return false;
if (lastChar.isDigit() != currentChar.isDigit())
return true;

const QList<QChar> s_separators{ '.', '-', '+' };
if (s_separators.contains(currentChar) && currentSection.at(0) != currentChar)
return true;

return false;
};

currentSection += m_string.at(0);
for (int i = 1; i < m_string.size(); ++i) {
const auto& current_char = m_string.at(i);
if (classChange(m_string.at(i - 1), current_char)) {
if (!currentSection.isEmpty())
m_sections.append(Section(currentSection));
currentSection = "";
}

currentSection += current_char;
}

return true;
}
bool Version::operator!=(const Version &other) const
{
return !operator==(other);
if (!currentSection.isEmpty())
m_sections.append(Section(currentSection));
}

void Version::parse()
/// qDebug print support for the Version class
QDebug operator<<(QDebug debug, const Version& v)
{
m_sections.clear();
QDebugStateSaver saver(debug);

// FIXME: this is bad. versions can contain a lot more separators...
QStringList parts = m_string.split('.');
debug.nospace() << "Version{ string: " << v.toString() << ", sections: [ ";

for (const auto& part : parts)
{
m_sections.append(Section(part));
bool first = true;
for (auto s : v.m_sections) {
if (!first) debug.nospace() << ", ";
debug.nospace() << s.m_fullString;
first = false;
}

debug.nospace() << " ]" << " }";

return debug;
}
135 changes: 78 additions & 57 deletions launcher/Version.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2023 flowln <flowlnlnln@gmail.com>
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
Expand Down Expand Up @@ -35,17 +36,17 @@

#pragma once

#include <QDebug>
#include <QList>
#include <QString>
#include <QStringView>
#include <QList>

class QUrl;

class Version
{
public:
Version(const QString &str);
Version() {}
class Version {
public:
Version(QString str);
Version() = default;

bool operator<(const Version &other) const;
bool operator<=(const Version &other) const;
Expand All @@ -54,96 +55,116 @@ class Version
bool operator==(const Version &other) const;
bool operator!=(const Version &other) const;

QString toString() const
{
return m_string;
}
QString toString() const { return m_string; }

private:
QString m_string;
struct Section
{
explicit Section(const QString &fullString)
friend QDebug operator<<(QDebug debug, const Version& v);

private:
struct Section {
explicit Section(QString fullString) : m_fullString(std::move(fullString))
{
m_fullString = fullString;
int cutoff = m_fullString.size();
for(int i = 0; i < m_fullString.size(); i++)
{
if(!m_fullString[i].isDigit())
{
for (int i = 0; i < m_fullString.size(); i++) {
if (!m_fullString[i].isDigit()) {
cutoff = i;
break;
}
}

#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
auto numPart = QStringView{m_fullString}.left(cutoff);
#else
auto numPart = m_fullString.leftRef(cutoff);
#endif
if(numPart.size())
{
numValid = true;

if (!numPart.isEmpty()) {
m_isNull = false;
m_numPart = numPart.toInt();
}

#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
auto stringPart = QStringView{m_fullString}.mid(cutoff);
#else
auto stringPart = m_fullString.midRef(cutoff);
#endif
if(stringPart.size())
{

if (!stringPart.isEmpty()) {
m_isNull = false;
m_stringPart = stringPart.toString();
}
}
explicit Section() {}
bool numValid = false;

explicit Section() = default;

bool m_isNull = true;

int m_numPart = 0;
QString m_stringPart;

QString m_fullString;

inline bool operator!=(const Section &other) const
[[nodiscard]] inline bool isAppendix() const { return m_stringPart.startsWith('+'); }
[[nodiscard]] inline bool isPreRelease() const { return m_stringPart.startsWith('-') && m_stringPart.length() > 1; }

inline bool operator==(const Section& other) const
{
if(numValid && other.numValid)
{
return m_numPart != other.m_numPart || m_stringPart != other.m_stringPart;
}
else
{
return m_fullString != other.m_fullString;
if (m_isNull && !other.m_isNull)
return false;
if (!m_isNull && other.m_isNull)
return false;

if (!m_isNull && !other.m_isNull) {
return (m_numPart == other.m_numPart) && (m_stringPart == other.m_stringPart);
}

return true;
}
inline bool operator<(const Section &other) const
{
if(numValid && other.numValid)
{
if(m_numPart < other.m_numPart)

inline bool operator<(const Section& other) const
{
static auto unequal_is_less = [](Section const& non_null) -> bool {
if (non_null.m_stringPart.isEmpty())
return non_null.m_numPart == 0;
return (non_null.m_stringPart != QLatin1Char('.')) && non_null.isPreRelease();
};

if (!m_isNull && other.m_isNull)
return unequal_is_less(*this);
if (m_isNull && !other.m_isNull)
return !unequal_is_less(other);

if (!m_isNull && !other.m_isNull) {
if (m_numPart < other.m_numPart)
return true;
if(m_numPart == other.m_numPart && m_stringPart < other.m_stringPart)
if (m_numPart == other.m_numPart && m_stringPart < other.m_stringPart)
return true;

if (!m_stringPart.isEmpty() && other.m_stringPart.isEmpty())
return false;
if (m_stringPart.isEmpty() && !other.m_stringPart.isEmpty())
return true;

return false;
}
else
{
return m_fullString < other.m_fullString;
}

return m_fullString < other.m_fullString;
}

inline bool operator!=(const Section& other) const
{
return !(*this == other);
}
inline bool operator>(const Section &other) const
{
if(numValid && other.numValid)
{
if(m_numPart > other.m_numPart)
return true;
if(m_numPart == other.m_numPart && m_stringPart > other.m_stringPart)
return true;
return false;
}
else
{
return m_fullString > other.m_fullString;
}
return !(*this < other || *this == other);
}
};

private:
QString m_string;
QList<Section> m_sections;

void parse();
};


3 changes: 3 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,6 @@ ecm_add_test(Packwiz_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR

ecm_add_test(Index_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
TEST_NAME Index)

ecm_add_test(Version_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
TEST_NAME Version)

0 comments on commit a47bf72

Please sign in to comment.