From e258bcb3a742b25ee5e25d78666dfea9910863ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Sat, 9 May 2015 13:20:37 +0200 Subject: [PATCH] Speed up numeric sorting by 10x. Convert strings to int, sort, then convert back to strings. --- PowerEditor/src/MISC/Common/Common.cpp | 54 +++++++++++++++++-- PowerEditor/src/MISC/Common/Common.h | 7 ++- .../ScitillaComponent/ScintillaEditView.cpp | 40 ++++---------- 3 files changed, 65 insertions(+), 36 deletions(-) diff --git a/PowerEditor/src/MISC/Common/Common.cpp b/PowerEditor/src/MISC/Common/Common.cpp index f7b8cf5c2..281677f28 100644 --- a/PowerEditor/src/MISC/Common/Common.cpp +++ b/PowerEditor/src/MISC/Common/Common.cpp @@ -749,11 +749,11 @@ generic_string stringJoin(const std::vector &strings, const gene return joined; } -int stoi_CountEmptyLinesAsMinimum(const generic_string &input) +int stoiStrict(const generic_string &input) { if (input.empty()) { - return INT_MIN; + throw std::invalid_argument("Empty input."); } else { @@ -778,14 +778,14 @@ int stoi_CountEmptyLinesAsMinimum(const generic_string &input) } } -bool allLinesAreNumericOrEmpty(const std::vector &lines) +bool allLinesAreNumeric(const std::vector &lines) { const auto endit = lines.end(); for (auto it = lines.begin(); it != endit; ++it) { try { - stoi_CountEmptyLinesAsMinimum(*it); + stoiStrict(*it); } catch (std::invalid_argument&) { @@ -797,4 +797,50 @@ bool allLinesAreNumericOrEmpty(const std::vector &lines) } } return true; +} + +std::vector lexicographicSort(std::vector input, bool isDescending) +{ + std::sort(input.begin(), input.end(), [isDescending](generic_string a, generic_string b) + { + if (isDescending) + { + return a.compare(b) > 0; + } + else + { + return a.compare(b) < 0; + } + }); + return input; +} + +std::vector numericSort(std::vector input, bool isDescending) +{ + // Pre-condition: all strings in "input" are convertible to int with stoiStrict. + std::vector inputAsInts; + std::map intToString; // Cache for ints converted to strings. + for (auto it = input.begin(); it != input.end(); ++it) + { + int converted = stoiStrict(*it); + inputAsInts.push_back(converted); + intToString[converted] = *it; + } + std::sort(inputAsInts.begin(), inputAsInts.end(), [isDescending](int a, int b) + { + if (isDescending) + { + return a > b; + } + else + { + return a < b; + } + }); + std::vector output; + for (auto it = inputAsInts.begin(); it != inputAsInts.end(); ++it) + { + output.push_back(intToString[*it]); + } + return output; } \ No newline at end of file diff --git a/PowerEditor/src/MISC/Common/Common.h b/PowerEditor/src/MISC/Common/Common.h index ea8a97815..e8c528848 100644 --- a/PowerEditor/src/MISC/Common/Common.h +++ b/PowerEditor/src/MISC/Common/Common.h @@ -190,7 +190,10 @@ generic_string stringToUpper(generic_string strToConvert); generic_string stringReplace(generic_string subject, const generic_string& search, const generic_string& replace); std::vector stringSplit(const generic_string& input, const generic_string &delimiter); generic_string stringJoin(const std::vector &strings, const generic_string &separator); -int stoi_CountEmptyLinesAsMinimum(const generic_string &input); -bool allLinesAreNumericOrEmpty(const std::vector &lines); +int stoiStrict(const generic_string &input); +bool allLinesAreNumeric(const std::vector &lines); + +std::vector numericSort(std::vector input, bool isDescending); +std::vector lexicographicSort(std::vector input, bool isDescending); #endif //M30_IDE_COMMUN_H diff --git a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp index d5feb77ca..6d40acfa9 100644 --- a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp +++ b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp @@ -2979,37 +2979,17 @@ void ScintillaEditView::sortLines(size_t fromLine, size_t toLine, bool isDescend } } assert(toLine - fromLine + 1 == splitText.size()); - const bool isNumericSort = allLinesAreNumericOrEmpty(splitText); - std::sort(splitText.begin(), splitText.end(), [isDescending, isNumericSort](generic_string a, generic_string b) + const bool isNumericSort = allLinesAreNumeric(splitText); + std::vector sortedText; + if (isNumericSort) { - if (isDescending) - { - if (isNumericSort) - { - int numA = stoi_CountEmptyLinesAsMinimum(a); - int numB = stoi_CountEmptyLinesAsMinimum(b); - return numA > numB; - } - else - { - return a.compare(b) > 0; - } - } - else - { - if (isNumericSort) - { - int numA = stoi_CountEmptyLinesAsMinimum(a); - int numB = stoi_CountEmptyLinesAsMinimum(b); - return numA < numB; - } - else - { - return a.compare(b) < 0; - } - } - }); - const generic_string joined = stringJoin(splitText, getEOLString()); + sortedText = numericSort(splitText, isDescending); + } + else + { + sortedText = lexicographicSort(splitText, isDescending); + } + const generic_string joined = stringJoin(sortedText, getEOLString()); if (sortAllLines) { replaceTarget(joined.c_str(), startPos, endPos);