| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- #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;
- }
- };
|