Sorters.h 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. #pragma once
  2. #include <algorithm>
  3. #include <utility>
  4. #include <random>
  5. #include <QString>
  6. // Base interface for line sorting.
  7. class ISorter
  8. {
  9. private:
  10. bool _isDescending = true;
  11. size_t _fromColumn = 0;
  12. size_t _toColumn = 0;
  13. protected:
  14. bool isDescending() const
  15. {
  16. return _isDescending;
  17. }
  18. QString getSortKey(const QString& input)
  19. {
  20. if (isSortingSpecificColumns())
  21. {
  22. if (input.length() < _fromColumn)
  23. {
  24. // prevent an std::out_of_range exception
  25. return QString("");
  26. }
  27. else if (_fromColumn == _toColumn)
  28. {
  29. // get characters from the indicated column to the end of the line
  30. return input.mid(_fromColumn);
  31. }
  32. else
  33. {
  34. // get characters between the indicated columns, inclusive
  35. return input.mid(_fromColumn, _toColumn - _fromColumn);
  36. }
  37. }
  38. else
  39. {
  40. return input;
  41. }
  42. }
  43. bool isSortingSpecificColumns()
  44. {
  45. return _toColumn != 0;
  46. }
  47. public:
  48. ISorter(bool isDescending, size_t fromColumn, size_t toColumn) : _isDescending(isDescending), _fromColumn(fromColumn), _toColumn(toColumn)
  49. {
  50. assert(_fromColumn <= _toColumn);
  51. };
  52. virtual ~ISorter() { };
  53. virtual QList<QString> sort(QList<QString> lines) = 0;
  54. };
  55. // Implementation of lexicographic sorting of lines.
  56. class LexicographicSorter : public ISorter
  57. {
  58. public:
  59. LexicographicSorter(bool isDescending, size_t fromColumn, size_t toColumn) : ISorter(isDescending, fromColumn, toColumn) { };
  60. QList<QString> sort(QList<QString> lines) override
  61. {
  62. // Note that both branches here are equivalent in the sense that they always give the same answer.
  63. // However, if we are *not* sorting specific columns, then we get a 40% speed improvement by not calling
  64. // getSortKey() so many times.
  65. if (isSortingSpecificColumns())
  66. {
  67. std::sort(lines.begin(), lines.end(), [this](QString a, QString b)
  68. {
  69. if (isDescending())
  70. {
  71. return getSortKey(a).compare(getSortKey(b)) > 0;
  72. }
  73. else
  74. {
  75. return getSortKey(a).compare(getSortKey(b)) < 0;
  76. }
  77. });
  78. }
  79. else
  80. {
  81. std::sort(lines.begin(), lines.end(), [this](QString a, QString b)
  82. {
  83. if (isDescending())
  84. {
  85. return a.compare(b) > 0;
  86. }
  87. else
  88. {
  89. return a.compare(b) < 0;
  90. }
  91. });
  92. }
  93. return lines;
  94. }
  95. };
  96. // Implementation of lexicographic sorting of lines, ignoring character casing
  97. class LexicographicCaseInsensitiveSorter : public ISorter
  98. {
  99. public:
  100. LexicographicCaseInsensitiveSorter(bool isDescending, size_t fromColumn, size_t toColumn) : ISorter(isDescending, fromColumn, toColumn) { };
  101. QList<QString> sort(QList<QString> lines) override
  102. {
  103. // Note that both branches here are equivalent in the sense that they always give the same answer.
  104. // However, if we are *not* sorting specific columns, then we get a 40% speed improvement by not calling
  105. // getSortKey() so many times.
  106. if (isSortingSpecificColumns())
  107. {
  108. std::sort(lines.begin(), lines.end(), [this](QString a, QString b)
  109. {
  110. if (isDescending())
  111. {
  112. return getSortKey(a).compare(getSortKey(b), Qt::CaseInsensitive) > 0;
  113. }
  114. else
  115. {
  116. return getSortKey(a).compare(getSortKey(b), Qt::CaseInsensitive) < 0;
  117. }
  118. });
  119. }
  120. else
  121. {
  122. std::sort(lines.begin(), lines.end(), [this](QString a, QString b)
  123. {
  124. if (isDescending())
  125. {
  126. return QString::compare(a, b, Qt::CaseInsensitive) > 0;
  127. }
  128. else
  129. {
  130. return QString::compare(a, b, Qt::CaseInsensitive) < 0;
  131. }
  132. });
  133. }
  134. return lines;
  135. }
  136. };
  137. class ReverseSorter : public ISorter
  138. {
  139. public:
  140. ReverseSorter(bool isDescending, size_t fromColumn, size_t toColumn) : ISorter(isDescending, fromColumn, toColumn) { };
  141. QList<QString> sort(QList<QString> lines) override
  142. {
  143. std::reverse(lines.begin(), lines.end());
  144. return lines;
  145. }
  146. };