From c926e18f42aeaa665ee1461c577954bbad46786e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Sat, 9 May 2015 08:34:44 +0200 Subject: [PATCH 01/17] Use more const. --- PowerEditor/src/MISC/Common/Common.cpp | 4 ++-- PowerEditor/src/MISC/Common/Common.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/PowerEditor/src/MISC/Common/Common.cpp b/PowerEditor/src/MISC/Common/Common.cpp index 9578cf72..1580924c 100644 --- a/PowerEditor/src/MISC/Common/Common.cpp +++ b/PowerEditor/src/MISC/Common/Common.cpp @@ -718,7 +718,7 @@ generic_string stringReplace(generic_string subject, const generic_string& searc return subject; } -std::vector stringSplit(const generic_string& input, generic_string delimiter) +std::vector stringSplit(const generic_string& input, const generic_string &delimiter) { auto start = 0U; auto end = input.find(delimiter); @@ -734,7 +734,7 @@ std::vector stringSplit(const generic_string& input, generic_str return output; } -generic_string stringJoin(const std::vector &strings, generic_string separator) +generic_string stringJoin(const std::vector &strings, const generic_string &separator) { generic_string joined; size_t length = strings.size(); diff --git a/PowerEditor/src/MISC/Common/Common.h b/PowerEditor/src/MISC/Common/Common.h index 43bc0e6a..4176a2ca 100644 --- a/PowerEditor/src/MISC/Common/Common.h +++ b/PowerEditor/src/MISC/Common/Common.h @@ -188,7 +188,7 @@ generic_string PathAppend(generic_string &strDest, const generic_string & str2ap COLORREF getCtrlBgColor(HWND hWnd); 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, generic_string delimiter); -generic_string stringJoin(const std::vector &strings, generic_string separator); +std::vector stringSplit(const generic_string& input, const generic_string &delimiter); +generic_string stringJoin(const std::vector &strings, const generic_string &separator); #endif //M30_IDE_COMMUN_H From 01c1667b099113611ed16f72f5f57b65e4159299 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Sat, 9 May 2015 08:34:56 +0200 Subject: [PATCH 02/17] Use TCHAR instead of _TCHAR. --- PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp index ed0f9cc4..b93814c3 100644 --- a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp +++ b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp @@ -1703,7 +1703,7 @@ generic_string ScintillaEditView::getGenericTextAsString(int start, int end) con { assert(end > start); const int bufSize = end - start + 1; - _TCHAR *buf = new _TCHAR[bufSize]; + TCHAR *buf = new TCHAR[bufSize]; getGenericText(buf, bufSize, start, end); generic_string text = buf; delete[] buf; From 351b9b6bff1d9ce9c40d1f1792b76d0aa0eedeac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Sat, 9 May 2015 10:05:45 +0200 Subject: [PATCH 03/17] Rename quickSortLines -> sortLines. --- PowerEditor/src/NppCommands.cpp | 2 +- PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp | 2 +- PowerEditor/src/ScitillaComponent/ScintillaEditView.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/PowerEditor/src/NppCommands.cpp b/PowerEditor/src/NppCommands.cpp index f852e7fd..0dbd252c 100644 --- a/PowerEditor/src/NppCommands.cpp +++ b/PowerEditor/src/NppCommands.cpp @@ -375,7 +375,7 @@ void Notepad_plus::command(int id) } _pEditView->execute(SCI_BEGINUNDOACTION); - _pEditView->quickSortLines(fromLine, toLine, id == IDM_EDIT_SORTLINES_DESCENDING); + _pEditView->sortLines(fromLine, toLine, id == IDM_EDIT_SORTLINES_DESCENDING); _pEditView->execute(SCI_ENDUNDOACTION); if (hasSelection) // there was 1 selection, so we restore it diff --git a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp index b93814c3..a81f837c 100644 --- a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp +++ b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp @@ -2947,7 +2947,7 @@ void ScintillaEditView::insertNewLineBelowCurrentLine() execute(SCI_SETEMPTYSELECTION, execute(SCI_POSITIONFROMLINE, current_line + 1)); } -void ScintillaEditView::quickSortLines(size_t fromLine, size_t toLine, bool isDescending) +void ScintillaEditView::sortLines(size_t fromLine, size_t toLine, bool isDescending) { if (fromLine >= toLine) { diff --git a/PowerEditor/src/ScitillaComponent/ScintillaEditView.h b/PowerEditor/src/ScitillaComponent/ScintillaEditView.h index e296ba64..0dcf90ae 100644 --- a/PowerEditor/src/ScitillaComponent/ScintillaEditView.h +++ b/PowerEditor/src/ScitillaComponent/ScintillaEditView.h @@ -636,7 +636,7 @@ public: }; void scrollPosToCenter(int pos); generic_string getEOLString(); - void quickSortLines(size_t fromLine, size_t toLine, bool isDescending); + void sortLines(size_t fromLine, size_t toLine, bool isDescending); void changeTextDirection(bool isRTL); bool isTextDirectionRTL() const; From 6e84be21f4c0a3c4b214e005531c52a199d71f0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Sat, 9 May 2015 10:22:50 +0200 Subject: [PATCH 04/17] Fix newline bug when not sorting all lines. --- .../ScitillaComponent/ScintillaEditView.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp index a81f837c..e19757cf 100644 --- a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp +++ b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp @@ -2958,6 +2958,16 @@ void ScintillaEditView::sortLines(size_t fromLine, size_t toLine, bool isDescend const int endPos = execute(SCI_POSITIONFROMLINE, toLine) + execute(SCI_LINELENGTH, toLine); const generic_string text = getGenericTextAsString(startPos, endPos); std::vector splitText = stringSplit(text, getEOLString()); + const size_t lineCount = execute(SCI_GETLINECOUNT); + const bool sortAllLines = toLine == lineCount - 1; + if (!sortAllLines) + { + if (splitText.rbegin()->empty()) + { + splitText.pop_back(); + } + } + assert(toLine - fromLine + 1 == splitText.size()); std::sort(splitText.begin(), splitText.end(), [isDescending](generic_string a, generic_string b) { if (isDescending) @@ -2970,7 +2980,14 @@ void ScintillaEditView::sortLines(size_t fromLine, size_t toLine, bool isDescend } }); const generic_string joined = stringJoin(splitText, getEOLString()); - replaceTarget(joined.c_str(), startPos, endPos); + if (sortAllLines) + { + replaceTarget(joined.c_str(), startPos, endPos); + } + else + { + replaceTarget((joined + getEOLString()).c_str(), startPos, endPos); + } } bool ScintillaEditView::isTextDirectionRTL() const From eee7c4f16efbd22618fa01426f395a901788507f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Sat, 9 May 2015 11:02:58 +0200 Subject: [PATCH 05/17] Sort numerically (not lexicographically) if all lines are integers. --- PowerEditor/src/MISC/Common/Common.cpp | 12 ++++ PowerEditor/src/MISC/Common/Common.h | 1 + .../ScitillaComponent/ScintillaEditView.cpp | 58 ++++++++++++++++++- .../src/ScitillaComponent/ScintillaEditView.h | 2 + 4 files changed, 70 insertions(+), 3 deletions(-) diff --git a/PowerEditor/src/MISC/Common/Common.cpp b/PowerEditor/src/MISC/Common/Common.cpp index 1580924c..7c649486 100644 --- a/PowerEditor/src/MISC/Common/Common.cpp +++ b/PowerEditor/src/MISC/Common/Common.cpp @@ -747,4 +747,16 @@ generic_string stringJoin(const std::vector &strings, const gene } } return joined; +} + +int stoi_CountNewlinesAsMinimum(const generic_string &input, const generic_string &newLine) +{ + if (input.empty() || input == newLine) + { + return INT_MIN; + } + else + { + return std::stoi(input); + } } \ No newline at end of file diff --git a/PowerEditor/src/MISC/Common/Common.h b/PowerEditor/src/MISC/Common/Common.h index 4176a2ca..e5cc1dfb 100644 --- a/PowerEditor/src/MISC/Common/Common.h +++ b/PowerEditor/src/MISC/Common/Common.h @@ -190,5 +190,6 @@ 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_CountNewlinesAsMinimum(const generic_string &input, const generic_string &newLine); #endif //M30_IDE_COMMUN_H diff --git a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp index e19757cf..5f7de042 100644 --- a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp +++ b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp @@ -1922,6 +1922,17 @@ void ScintillaEditView::getLine(int lineNumber, TCHAR * line, int lineBufferLen) delete [] lineA; } +generic_string ScintillaEditView::getLine(int lineNumber) +{ + int lineLen = execute(SCI_LINELENGTH, lineNumber); + const int bufSize = 1 + lineLen; + _TCHAR *buf = new _TCHAR[bufSize]; + getLine(lineNumber, buf, bufSize); + generic_string text = buf; + delete[] buf; + return text; +} + void ScintillaEditView::addText(int length, const char *buf) { execute(SCI_ADDTEXT, length, (LPARAM)buf); @@ -2947,6 +2958,27 @@ void ScintillaEditView::insertNewLineBelowCurrentLine() execute(SCI_SETEMPTYSELECTION, execute(SCI_POSITIONFROMLINE, current_line + 1)); } +bool ScintillaEditView::allLinesAreNumeric(size_t fromLine, size_t toLine) +{ + const generic_string newLine = getEOLString(); + for (size_t i = fromLine; i <= toLine; ++i) + { + try + { + stoi_CountNewlinesAsMinimum(getLine(i), newLine); + } + catch (std::invalid_argument&) + { + return false; + } + catch (std::out_of_range&) + { + return false; + } + } + return true; +} + void ScintillaEditView::sortLines(size_t fromLine, size_t toLine, bool isDescending) { if (fromLine >= toLine) @@ -2968,15 +3000,35 @@ void ScintillaEditView::sortLines(size_t fromLine, size_t toLine, bool isDescend } } assert(toLine - fromLine + 1 == splitText.size()); - std::sort(splitText.begin(), splitText.end(), [isDescending](generic_string a, generic_string b) + const bool isNumericSort = allLinesAreNumeric(fromLine, toLine); + const generic_string newLine = getEOLString(); + std::sort(splitText.begin(), splitText.end(), [isDescending, isNumericSort, newLine](generic_string a, generic_string b) { if (isDescending) { - return a.compare(b) > 0; + if (isNumericSort) + { + int numA = stoi_CountNewlinesAsMinimum(a, newLine); + int numB = stoi_CountNewlinesAsMinimum(b, newLine); + return numA > numB; + } + else + { + return a.compare(b) > 0; + } } else { - return a.compare(b) < 0; + if (isNumericSort) + { + int numA = stoi_CountNewlinesAsMinimum(a, newLine); + int numB = stoi_CountNewlinesAsMinimum(b, newLine); + return numA < numB; + } + else + { + return a.compare(b) < 0; + } } }); const generic_string joined = stringJoin(splitText, getEOLString()); diff --git a/PowerEditor/src/ScitillaComponent/ScintillaEditView.h b/PowerEditor/src/ScitillaComponent/ScintillaEditView.h index 0dcf90ae..cffcc272 100644 --- a/PowerEditor/src/ScitillaComponent/ScintillaEditView.h +++ b/PowerEditor/src/ScitillaComponent/ScintillaEditView.h @@ -271,6 +271,7 @@ public: void showAutoComletion(int lenEntered, const TCHAR * list); void showCallTip(int startPos, const TCHAR * def); void getLine(int lineNumber, TCHAR * line, int lineBufferLen); + generic_string getLine(int lineNumber); void addText(int length, const char *buf); void insertNewLineAboveCurrentLine(); @@ -637,6 +638,7 @@ public: void scrollPosToCenter(int pos); generic_string getEOLString(); void sortLines(size_t fromLine, size_t toLine, bool isDescending); + bool allLinesAreNumeric(size_t fromLine, size_t toLine); void changeTextDirection(bool isRTL); bool isTextDirectionRTL() const; From 0eca4db9497bd107858679117d9615f6cae085a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Sat, 9 May 2015 11:25:07 +0200 Subject: [PATCH 06/17] Improve numeric sorting. No need to read lines from Scintilla, we already have them in a vector. --- PowerEditor/src/MISC/Common/Common.cpp | 25 ++++++++++++-- PowerEditor/src/MISC/Common/Common.h | 3 +- .../ScitillaComponent/ScintillaEditView.cpp | 34 ++++--------------- .../src/ScitillaComponent/ScintillaEditView.h | 1 - 4 files changed, 31 insertions(+), 32 deletions(-) diff --git a/PowerEditor/src/MISC/Common/Common.cpp b/PowerEditor/src/MISC/Common/Common.cpp index 7c649486..61e30b92 100644 --- a/PowerEditor/src/MISC/Common/Common.cpp +++ b/PowerEditor/src/MISC/Common/Common.cpp @@ -749,9 +749,9 @@ generic_string stringJoin(const std::vector &strings, const gene return joined; } -int stoi_CountNewlinesAsMinimum(const generic_string &input, const generic_string &newLine) +int stoi_CountEmptyLinesAsMinimum(const generic_string &input) { - if (input.empty() || input == newLine) + if (input.empty()) { return INT_MIN; } @@ -759,4 +759,25 @@ int stoi_CountNewlinesAsMinimum(const generic_string &input, const generic_strin { return std::stoi(input); } +} + +bool allLinesAreNumericOrEmpty(const std::vector &lines) +{ + const auto endit = lines.end(); + for (auto it = lines.begin(); it != endit; ++it) + { + try + { + stoi_CountEmptyLinesAsMinimum(*it); + } + catch (std::invalid_argument&) + { + return false; + } + catch (std::out_of_range&) + { + return false; + } + } + return true; } \ No newline at end of file diff --git a/PowerEditor/src/MISC/Common/Common.h b/PowerEditor/src/MISC/Common/Common.h index e5cc1dfb..ea8a9781 100644 --- a/PowerEditor/src/MISC/Common/Common.h +++ b/PowerEditor/src/MISC/Common/Common.h @@ -190,6 +190,7 @@ 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_CountNewlinesAsMinimum(const generic_string &input, const generic_string &newLine); +int stoi_CountEmptyLinesAsMinimum(const generic_string &input); +bool allLinesAreNumericOrEmpty(const std::vector &lines); #endif //M30_IDE_COMMUN_H diff --git a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp index 5f7de042..d5feb77c 100644 --- a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp +++ b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp @@ -2958,27 +2958,6 @@ void ScintillaEditView::insertNewLineBelowCurrentLine() execute(SCI_SETEMPTYSELECTION, execute(SCI_POSITIONFROMLINE, current_line + 1)); } -bool ScintillaEditView::allLinesAreNumeric(size_t fromLine, size_t toLine) -{ - const generic_string newLine = getEOLString(); - for (size_t i = fromLine; i <= toLine; ++i) - { - try - { - stoi_CountNewlinesAsMinimum(getLine(i), newLine); - } - catch (std::invalid_argument&) - { - return false; - } - catch (std::out_of_range&) - { - return false; - } - } - return true; -} - void ScintillaEditView::sortLines(size_t fromLine, size_t toLine, bool isDescending) { if (fromLine >= toLine) @@ -3000,16 +2979,15 @@ void ScintillaEditView::sortLines(size_t fromLine, size_t toLine, bool isDescend } } assert(toLine - fromLine + 1 == splitText.size()); - const bool isNumericSort = allLinesAreNumeric(fromLine, toLine); - const generic_string newLine = getEOLString(); - std::sort(splitText.begin(), splitText.end(), [isDescending, isNumericSort, newLine](generic_string a, generic_string b) + const bool isNumericSort = allLinesAreNumericOrEmpty(splitText); + std::sort(splitText.begin(), splitText.end(), [isDescending, isNumericSort](generic_string a, generic_string b) { if (isDescending) { if (isNumericSort) { - int numA = stoi_CountNewlinesAsMinimum(a, newLine); - int numB = stoi_CountNewlinesAsMinimum(b, newLine); + int numA = stoi_CountEmptyLinesAsMinimum(a); + int numB = stoi_CountEmptyLinesAsMinimum(b); return numA > numB; } else @@ -3021,8 +2999,8 @@ void ScintillaEditView::sortLines(size_t fromLine, size_t toLine, bool isDescend { if (isNumericSort) { - int numA = stoi_CountNewlinesAsMinimum(a, newLine); - int numB = stoi_CountNewlinesAsMinimum(b, newLine); + int numA = stoi_CountEmptyLinesAsMinimum(a); + int numB = stoi_CountEmptyLinesAsMinimum(b); return numA < numB; } else diff --git a/PowerEditor/src/ScitillaComponent/ScintillaEditView.h b/PowerEditor/src/ScitillaComponent/ScintillaEditView.h index cffcc272..0c774eb1 100644 --- a/PowerEditor/src/ScitillaComponent/ScintillaEditView.h +++ b/PowerEditor/src/ScitillaComponent/ScintillaEditView.h @@ -638,7 +638,6 @@ public: void scrollPosToCenter(int pos); generic_string getEOLString(); void sortLines(size_t fromLine, size_t toLine, bool isDescending); - bool allLinesAreNumeric(size_t fromLine, size_t toLine); void changeTextDirection(bool isRTL); bool isTextDirectionRTL() const; From bcbe48b13f98b1666dd85a755cabcc09a672a41d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Sat, 9 May 2015 12:49:47 +0200 Subject: [PATCH 07/17] Make stoi_CountEmptyLinesAsMinimum more restrictive. It now only accepts digits and possibly a single minus character as the first character. Ordinary std::stoi has too much special magic, e.g. it converts "1 a" to "1". --- PowerEditor/src/MISC/Common/Common.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/PowerEditor/src/MISC/Common/Common.cpp b/PowerEditor/src/MISC/Common/Common.cpp index 61e30b92..f7b8cf5c 100644 --- a/PowerEditor/src/MISC/Common/Common.cpp +++ b/PowerEditor/src/MISC/Common/Common.cpp @@ -757,6 +757,23 @@ int stoi_CountEmptyLinesAsMinimum(const generic_string &input) } else { + // Check minus characters. + const int minuses = std::count(input.begin(), input.end(), TEXT('-')); + if (minuses > 1) + { + throw std::invalid_argument("More than one minus sign."); + } + else if (minuses == 1 && input[0] != TEXT('-')) + { + throw std::invalid_argument("Minus sign must be first."); + } + + // Check for other characters which are not allowed. + if (input.find_first_not_of(TEXT("-0123456789")) != std::string::npos) + { + throw new std::invalid_argument("Invalid character found."); + } + return std::stoi(input); } } 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 08/17] 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 f7b8cf5c..281677f2 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 ea8a9781..e8c52884 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 d5feb77c..6d40acfa 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); From 6f004d86a459e1f5728182727f2f8c9b09b69782 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Sat, 9 May 2015 13:21:35 +0200 Subject: [PATCH 09/17] Rename sortAllLines -> sortEntireDocument. --- PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp index 6d40acfa..86a9cf62 100644 --- a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp +++ b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp @@ -2970,8 +2970,8 @@ void ScintillaEditView::sortLines(size_t fromLine, size_t toLine, bool isDescend const generic_string text = getGenericTextAsString(startPos, endPos); std::vector splitText = stringSplit(text, getEOLString()); const size_t lineCount = execute(SCI_GETLINECOUNT); - const bool sortAllLines = toLine == lineCount - 1; - if (!sortAllLines) + const bool sortEntireDocument = toLine == lineCount - 1; + if (!sortEntireDocument) { if (splitText.rbegin()->empty()) { @@ -2990,7 +2990,7 @@ void ScintillaEditView::sortLines(size_t fromLine, size_t toLine, bool isDescend sortedText = lexicographicSort(splitText, isDescending); } const generic_string joined = stringJoin(sortedText, getEOLString()); - if (sortAllLines) + if (sortEntireDocument) { replaceTarget(joined.c_str(), startPos, endPos); } From 4b3fbdd5706d662b040a4492974e62ef5f513ad7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Sat, 9 May 2015 13:25:36 +0200 Subject: [PATCH 10/17] Don't throw pointers (MFC habit). --- PowerEditor/src/MISC/Common/Common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PowerEditor/src/MISC/Common/Common.cpp b/PowerEditor/src/MISC/Common/Common.cpp index 281677f2..0791305e 100644 --- a/PowerEditor/src/MISC/Common/Common.cpp +++ b/PowerEditor/src/MISC/Common/Common.cpp @@ -771,7 +771,7 @@ int stoiStrict(const generic_string &input) // Check for other characters which are not allowed. if (input.find_first_not_of(TEXT("-0123456789")) != std::string::npos) { - throw new std::invalid_argument("Invalid character found."); + throw std::invalid_argument("Invalid character found."); } return std::stoi(input); From 83c16755aba6961a169b607cd5157b2e3237415b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Sat, 9 May 2015 21:23:40 +0200 Subject: [PATCH 11/17] Don't cache int->string conversion, it doesn't speed up anything. --- PowerEditor/src/MISC/Common/Common.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/PowerEditor/src/MISC/Common/Common.cpp b/PowerEditor/src/MISC/Common/Common.cpp index 0791305e..1f2223d1 100644 --- a/PowerEditor/src/MISC/Common/Common.cpp +++ b/PowerEditor/src/MISC/Common/Common.cpp @@ -819,12 +819,9 @@ std::vector numericSort(std::vector input, bool { // 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; + inputAsInts.push_back(stoiStrict(*it)); } std::sort(inputAsInts.begin(), inputAsInts.end(), [isDescending](int a, int b) { @@ -840,7 +837,7 @@ std::vector numericSort(std::vector input, bool std::vector output; for (auto it = inputAsInts.begin(); it != inputAsInts.end(); ++it) { - output.push_back(intToString[*it]); + output.push_back(std::to_wstring(*it)); } return output; } \ No newline at end of file From 501ce1d689026d94078d888a7e098a86cbc9087f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Sun, 10 May 2015 10:25:56 +0200 Subject: [PATCH 12/17] Make reference signs consistent. --- PowerEditor/src/MISC/Common/Common.cpp | 8 ++++---- PowerEditor/src/MISC/Common/Common.h | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/PowerEditor/src/MISC/Common/Common.cpp b/PowerEditor/src/MISC/Common/Common.cpp index 1f2223d1..873ae4a5 100644 --- a/PowerEditor/src/MISC/Common/Common.cpp +++ b/PowerEditor/src/MISC/Common/Common.cpp @@ -718,7 +718,7 @@ generic_string stringReplace(generic_string subject, const generic_string& searc return subject; } -std::vector stringSplit(const generic_string& input, const generic_string &delimiter) +std::vector stringSplit(const generic_string& input, const generic_string& delimiter) { auto start = 0U; auto end = input.find(delimiter); @@ -734,7 +734,7 @@ std::vector stringSplit(const generic_string& input, const gener return output; } -generic_string stringJoin(const std::vector &strings, const generic_string &separator) +generic_string stringJoin(const std::vector& strings, const generic_string& separator) { generic_string joined; size_t length = strings.size(); @@ -749,7 +749,7 @@ generic_string stringJoin(const std::vector &strings, const gene return joined; } -int stoiStrict(const generic_string &input) +int stoiStrict(const generic_string& input) { if (input.empty()) { @@ -778,7 +778,7 @@ int stoiStrict(const generic_string &input) } } -bool allLinesAreNumeric(const std::vector &lines) +bool allLinesAreNumeric(const std::vector& lines) { const auto endit = lines.end(); for (auto it = lines.begin(); it != endit; ++it) diff --git a/PowerEditor/src/MISC/Common/Common.h b/PowerEditor/src/MISC/Common/Common.h index e8c52884..a8dc3143 100644 --- a/PowerEditor/src/MISC/Common/Common.h +++ b/PowerEditor/src/MISC/Common/Common.h @@ -188,10 +188,10 @@ generic_string PathAppend(generic_string &strDest, const generic_string & str2ap COLORREF getCtrlBgColor(HWND hWnd); 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 stoiStrict(const generic_string &input); -bool allLinesAreNumeric(const std::vector &lines); +std::vector stringSplit(const generic_string& input, const generic_string& delimiter); +generic_string stringJoin(const std::vector& strings, const generic_string& separator); +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); From dd846658e6599ba2878a0fbed3c0c2e8891abbe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Sun, 10 May 2015 10:27:36 +0200 Subject: [PATCH 13/17] Use new kind of loop. --- PowerEditor/src/MISC/Common/Common.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/PowerEditor/src/MISC/Common/Common.cpp b/PowerEditor/src/MISC/Common/Common.cpp index 873ae4a5..98be1332 100644 --- a/PowerEditor/src/MISC/Common/Common.cpp +++ b/PowerEditor/src/MISC/Common/Common.cpp @@ -780,12 +780,11 @@ int stoiStrict(const generic_string& input) bool allLinesAreNumeric(const std::vector& lines) { - const auto endit = lines.end(); - for (auto it = lines.begin(); it != endit; ++it) + for (const generic_string& line : lines) { try { - stoiStrict(*it); + stoiStrict(line); } catch (std::invalid_argument&) { @@ -819,9 +818,9 @@ std::vector numericSort(std::vector input, bool { // Pre-condition: all strings in "input" are convertible to int with stoiStrict. std::vector inputAsInts; - for (auto it = input.begin(); it != input.end(); ++it) + for (const generic_string& line : input) { - inputAsInts.push_back(stoiStrict(*it)); + inputAsInts.push_back(stoiStrict(line)); } std::sort(inputAsInts.begin(), inputAsInts.end(), [isDescending](int a, int b) { @@ -835,9 +834,9 @@ std::vector numericSort(std::vector input, bool } }); std::vector output; - for (auto it = inputAsInts.begin(); it != inputAsInts.end(); ++it) + for (const int& sortedInt : inputAsInts) { - output.push_back(std::to_wstring(*it)); + output.push_back(std::to_wstring(sortedInt)); } return output; } \ No newline at end of file From 60505765ccd6687586c23ee2f3791426b3d252ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Sun, 10 May 2015 10:29:21 +0200 Subject: [PATCH 14/17] Remove ScintillaEditView::getLine, no longer used. --- .../src/ScitillaComponent/ScintillaEditView.cpp | 11 ----------- PowerEditor/src/ScitillaComponent/ScintillaEditView.h | 1 - 2 files changed, 12 deletions(-) diff --git a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp index 86a9cf62..dcfe800f 100644 --- a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp +++ b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp @@ -1922,17 +1922,6 @@ void ScintillaEditView::getLine(int lineNumber, TCHAR * line, int lineBufferLen) delete [] lineA; } -generic_string ScintillaEditView::getLine(int lineNumber) -{ - int lineLen = execute(SCI_LINELENGTH, lineNumber); - const int bufSize = 1 + lineLen; - _TCHAR *buf = new _TCHAR[bufSize]; - getLine(lineNumber, buf, bufSize); - generic_string text = buf; - delete[] buf; - return text; -} - void ScintillaEditView::addText(int length, const char *buf) { execute(SCI_ADDTEXT, length, (LPARAM)buf); diff --git a/PowerEditor/src/ScitillaComponent/ScintillaEditView.h b/PowerEditor/src/ScitillaComponent/ScintillaEditView.h index 0c774eb1..0dcf90ae 100644 --- a/PowerEditor/src/ScitillaComponent/ScintillaEditView.h +++ b/PowerEditor/src/ScitillaComponent/ScintillaEditView.h @@ -271,7 +271,6 @@ public: void showAutoComletion(int lenEntered, const TCHAR * list); void showCallTip(int startPos, const TCHAR * def); void getLine(int lineNumber, TCHAR * line, int lineBufferLen); - generic_string getLine(int lineNumber); void addText(int length, const char *buf); void insertNewLineAboveCurrentLine(); From 936d9c56fc2f929a603f7485f38595e3d3a85c31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Sun, 10 May 2015 10:30:17 +0200 Subject: [PATCH 15/17] When sorting, reserve enough space for work + output. --- PowerEditor/src/MISC/Common/Common.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/PowerEditor/src/MISC/Common/Common.cpp b/PowerEditor/src/MISC/Common/Common.cpp index 98be1332..3a6a454c 100644 --- a/PowerEditor/src/MISC/Common/Common.cpp +++ b/PowerEditor/src/MISC/Common/Common.cpp @@ -818,6 +818,7 @@ std::vector numericSort(std::vector input, bool { // Pre-condition: all strings in "input" are convertible to int with stoiStrict. std::vector inputAsInts; + inputAsInts.reserve(input.size()); for (const generic_string& line : input) { inputAsInts.push_back(stoiStrict(line)); @@ -834,6 +835,7 @@ std::vector numericSort(std::vector input, bool } }); std::vector output; + output.reserve(input.size()); for (const int& sortedInt : inputAsInts) { output.push_back(std::to_wstring(sortedInt)); From ee225f5cad3324784d61df33d557ee93dfd39abe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Sun, 10 May 2015 11:00:58 +0200 Subject: [PATCH 16/17] Handle empty lines properly in numeric sort. --- PowerEditor/src/MISC/Common/Common.cpp | 51 ++++++++++++++++--- PowerEditor/src/MISC/Common/Common.h | 3 +- .../ScitillaComponent/ScintillaEditView.cpp | 2 +- 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/PowerEditor/src/MISC/Common/Common.cpp b/PowerEditor/src/MISC/Common/Common.cpp index 3a6a454c..e1e7c663 100644 --- a/PowerEditor/src/MISC/Common/Common.cpp +++ b/PowerEditor/src/MISC/Common/Common.cpp @@ -778,13 +778,16 @@ int stoiStrict(const generic_string& input) } } -bool allLinesAreNumeric(const std::vector& lines) +bool allLinesAreNumericOrEmpty(const std::vector& lines) { for (const generic_string& line : lines) { try { - stoiStrict(line); + if (!line.empty()) + { + stoiStrict(line); + } } catch (std::invalid_argument&) { @@ -798,6 +801,18 @@ bool allLinesAreNumeric(const std::vector& lines) return true; } +std::vector repeatString(const generic_string& text, const size_t count) +{ + std::vector output; + output.reserve(count); + for (size_t i = 0; i < count; ++i) + { + output.push_back(text); + } + assert(output.size() == count); + return output; +} + std::vector lexicographicSort(std::vector input, bool isDescending) { std::sort(input.begin(), input.end(), [isDescending](generic_string a, generic_string b) @@ -816,14 +831,24 @@ std::vector lexicographicSort(std::vector input, std::vector numericSort(std::vector input, bool isDescending) { - // Pre-condition: all strings in "input" are convertible to int with stoiStrict. - std::vector inputAsInts; - inputAsInts.reserve(input.size()); + // Pre-condition: all strings in "input" are either empty or convertible to int with stoiStrict. + // Note that empty lines are filtered out and added back manually to the output at the end. + std::vector nonEmptyinputAsInts; + size_t nofEmptyLines = 0; + nonEmptyinputAsInts.reserve(input.size()); for (const generic_string& line : input) { - inputAsInts.push_back(stoiStrict(line)); + if (line.empty()) + { + ++nofEmptyLines; + } + else + { + nonEmptyinputAsInts.push_back(stoiStrict(line)); + } } - std::sort(inputAsInts.begin(), inputAsInts.end(), [isDescending](int a, int b) + assert(nonEmptyinputAsInts.size() + nofEmptyLines == input.size()); + std::sort(nonEmptyinputAsInts.begin(), nonEmptyinputAsInts.end(), [isDescending](int a, int b) { if (isDescending) { @@ -836,9 +861,19 @@ std::vector numericSort(std::vector input, bool }); std::vector output; output.reserve(input.size()); - for (const int& sortedInt : inputAsInts) + const std::vector empties = repeatString(TEXT(""), nofEmptyLines); + if (!isDescending) + { + output.insert(output.end(), empties.begin(), empties.end()); + } + for (const int& sortedInt : nonEmptyinputAsInts) { output.push_back(std::to_wstring(sortedInt)); } + if (isDescending) + { + output.insert(output.end(), empties.begin(), empties.end()); + } + assert(output.size() == input.size()); 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 a8dc3143..a86e6329 100644 --- a/PowerEditor/src/MISC/Common/Common.h +++ b/PowerEditor/src/MISC/Common/Common.h @@ -191,7 +191,8 @@ generic_string stringReplace(generic_string subject, const generic_string& searc std::vector stringSplit(const generic_string& input, const generic_string& delimiter); generic_string stringJoin(const std::vector& strings, const generic_string& separator); int stoiStrict(const generic_string& input); -bool allLinesAreNumeric(const std::vector& lines); +bool allLinesAreNumericOrEmpty(const std::vector& lines); +std::vector repeatString(const generic_string& text, const size_t count); std::vector numericSort(std::vector input, bool isDescending); std::vector lexicographicSort(std::vector input, bool isDescending); diff --git a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp index dcfe800f..91cad99a 100644 --- a/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp +++ b/PowerEditor/src/ScitillaComponent/ScintillaEditView.cpp @@ -2968,7 +2968,7 @@ void ScintillaEditView::sortLines(size_t fromLine, size_t toLine, bool isDescend } } assert(toLine - fromLine + 1 == splitText.size()); - const bool isNumericSort = allLinesAreNumeric(splitText); + const bool isNumericSort = allLinesAreNumericOrEmpty(splitText); std::vector sortedText; if (isNumericSort) { From 83de4a9da26229872dc2fff4eb75ed11e30e6e52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20J=C3=B6nsson?= Date: Mon, 11 May 2015 09:26:31 +0200 Subject: [PATCH 17/17] Use long long in numeric sort (ie 64 bit numbers). --- PowerEditor/src/MISC/Common/Common.cpp | 18 +++++++++--------- PowerEditor/src/MISC/Common/Common.h | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/PowerEditor/src/MISC/Common/Common.cpp b/PowerEditor/src/MISC/Common/Common.cpp index e1e7c663..96d97eb2 100644 --- a/PowerEditor/src/MISC/Common/Common.cpp +++ b/PowerEditor/src/MISC/Common/Common.cpp @@ -749,7 +749,7 @@ generic_string stringJoin(const std::vector& strings, const gene return joined; } -int stoiStrict(const generic_string& input) +long long stollStrict(const generic_string& input) { if (input.empty()) { @@ -774,7 +774,7 @@ int stoiStrict(const generic_string& input) throw std::invalid_argument("Invalid character found."); } - return std::stoi(input); + return std::stoll(input); } } @@ -786,7 +786,7 @@ bool allLinesAreNumericOrEmpty(const std::vector& lines) { if (!line.empty()) { - stoiStrict(line); + stollStrict(line); } } catch (std::invalid_argument&) @@ -833,9 +833,9 @@ std::vector numericSort(std::vector input, bool { // Pre-condition: all strings in "input" are either empty or convertible to int with stoiStrict. // Note that empty lines are filtered out and added back manually to the output at the end. - std::vector nonEmptyinputAsInts; + std::vector nonEmptyInputAsNumbers; size_t nofEmptyLines = 0; - nonEmptyinputAsInts.reserve(input.size()); + nonEmptyInputAsNumbers.reserve(input.size()); for (const generic_string& line : input) { if (line.empty()) @@ -844,11 +844,11 @@ std::vector numericSort(std::vector input, bool } else { - nonEmptyinputAsInts.push_back(stoiStrict(line)); + nonEmptyInputAsNumbers.push_back(stollStrict(line)); } } assert(nonEmptyinputAsInts.size() + nofEmptyLines == input.size()); - std::sort(nonEmptyinputAsInts.begin(), nonEmptyinputAsInts.end(), [isDescending](int a, int b) + std::sort(nonEmptyInputAsNumbers.begin(), nonEmptyInputAsNumbers.end(), [isDescending](long long a, long long b) { if (isDescending) { @@ -866,9 +866,9 @@ std::vector numericSort(std::vector input, bool { output.insert(output.end(), empties.begin(), empties.end()); } - for (const int& sortedInt : nonEmptyinputAsInts) + for (const long long& sortedNumber : nonEmptyInputAsNumbers) { - output.push_back(std::to_wstring(sortedInt)); + output.push_back(std::to_wstring(sortedNumber)); } if (isDescending) { diff --git a/PowerEditor/src/MISC/Common/Common.h b/PowerEditor/src/MISC/Common/Common.h index a86e6329..2e90fea6 100644 --- a/PowerEditor/src/MISC/Common/Common.h +++ b/PowerEditor/src/MISC/Common/Common.h @@ -190,7 +190,7 @@ 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 stoiStrict(const generic_string& input); +long long stollStrict(const generic_string& input); bool allLinesAreNumericOrEmpty(const std::vector& lines); std::vector repeatString(const generic_string& text, const size_t count);