mirror of https://gitee.com/cxasm/notepad--.git
160 lines
3.7 KiB
C++
Executable File
160 lines
3.7 KiB
C++
Executable File
#pragma once
|
|
#include <algorithm>
|
|
#include <utility>
|
|
#include <random>
|
|
#include <QString>
|
|
|
|
// Base interface for line sorting.
|
|
class ISorter
|
|
{
|
|
private:
|
|
bool _isDescending = true;
|
|
size_t _fromColumn = 0;
|
|
size_t _toColumn = 0;
|
|
|
|
protected:
|
|
bool isDescending() const
|
|
{
|
|
return _isDescending;
|
|
}
|
|
|
|
QString getSortKey(const QString& input)
|
|
{
|
|
if (isSortingSpecificColumns())
|
|
{
|
|
if (input.length() < _fromColumn)
|
|
{
|
|
// prevent an std::out_of_range exception
|
|
return QString("");
|
|
}
|
|
else if (_fromColumn == _toColumn)
|
|
{
|
|
// get characters from the indicated column to the end of the line
|
|
return input.mid(_fromColumn);
|
|
}
|
|
else
|
|
{
|
|
// get characters between the indicated columns, inclusive
|
|
return input.mid(_fromColumn, _toColumn - _fromColumn);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return input;
|
|
}
|
|
}
|
|
|
|
bool isSortingSpecificColumns()
|
|
{
|
|
return _toColumn != 0;
|
|
}
|
|
|
|
public:
|
|
ISorter(bool isDescending, size_t fromColumn, size_t toColumn) : _isDescending(isDescending), _fromColumn(fromColumn), _toColumn(toColumn)
|
|
{
|
|
assert(_fromColumn <= _toColumn);
|
|
};
|
|
virtual ~ISorter() { };
|
|
virtual QList<QString> sort(QList<QString> lines) = 0;
|
|
};
|
|
|
|
// Implementation of lexicographic sorting of lines.
|
|
class LexicographicSorter : public ISorter
|
|
{
|
|
public:
|
|
LexicographicSorter(bool isDescending, size_t fromColumn, size_t toColumn) : ISorter(isDescending, fromColumn, toColumn) { };
|
|
|
|
QList<QString> sort(QList<QString> lines) override
|
|
{
|
|
// Note that both branches here are equivalent in the sense that they always give the same answer.
|
|
// However, if we are *not* sorting specific columns, then we get a 40% speed improvement by not calling
|
|
// getSortKey() so many times.
|
|
if (isSortingSpecificColumns())
|
|
{
|
|
std::sort(lines.begin(), lines.end(), [this](QString a, QString b)
|
|
{
|
|
if (isDescending())
|
|
{
|
|
return getSortKey(a).compare(getSortKey(b)) > 0;
|
|
|
|
}
|
|
else
|
|
{
|
|
return getSortKey(a).compare(getSortKey(b)) < 0;
|
|
}
|
|
});
|
|
}
|
|
else
|
|
{
|
|
std::sort(lines.begin(), lines.end(), [this](QString a, QString b)
|
|
{
|
|
if (isDescending())
|
|
{
|
|
return a.compare(b) > 0;
|
|
}
|
|
else
|
|
{
|
|
return a.compare(b) < 0;
|
|
}
|
|
});
|
|
}
|
|
return lines;
|
|
}
|
|
};
|
|
|
|
|
|
// Implementation of lexicographic sorting of lines, ignoring character casing
|
|
class LexicographicCaseInsensitiveSorter : public ISorter
|
|
{
|
|
public:
|
|
LexicographicCaseInsensitiveSorter(bool isDescending, size_t fromColumn, size_t toColumn) : ISorter(isDescending, fromColumn, toColumn) { };
|
|
|
|
QList<QString> sort(QList<QString> lines) override
|
|
{
|
|
// Note that both branches here are equivalent in the sense that they always give the same answer.
|
|
// However, if we are *not* sorting specific columns, then we get a 40% speed improvement by not calling
|
|
// getSortKey() so many times.
|
|
if (isSortingSpecificColumns())
|
|
{
|
|
std::sort(lines.begin(), lines.end(), [this](QString a, QString b)
|
|
{
|
|
if (isDescending())
|
|
{
|
|
return getSortKey(a).compare(getSortKey(b), Qt::CaseInsensitive) > 0;
|
|
}
|
|
else
|
|
{
|
|
return getSortKey(a).compare(getSortKey(b), Qt::CaseInsensitive) < 0;
|
|
}
|
|
});
|
|
}
|
|
else
|
|
{
|
|
std::sort(lines.begin(), lines.end(), [this](QString a, QString b)
|
|
{
|
|
if (isDescending())
|
|
{
|
|
return QString::compare(a, b, Qt::CaseInsensitive) > 0;
|
|
}
|
|
else
|
|
{
|
|
return QString::compare(a, b, Qt::CaseInsensitive) < 0;
|
|
}
|
|
});
|
|
}
|
|
return lines;
|
|
}
|
|
};
|
|
|
|
|
|
class ReverseSorter : public ISorter
|
|
{
|
|
public:
|
|
ReverseSorter(bool isDescending, size_t fromColumn, size_t toColumn) : ISorter(isDescending, fromColumn, toColumn) { };
|
|
|
|
QList<QString> sort(QList<QString> lines) override
|
|
{
|
|
std::reverse(lines.begin(), lines.end());
|
|
return lines;
|
|
}
|
|
}; |