mirror of
https://github.com/notepad-plus-plus/notepad-plus-plus.git
synced 2025-07-23 13:54:54 +02:00
Merge pull request #44 from andreas-jonsson/more_optimize_sort
[BUG_FIXED] Fix issues related to sort optimization.
This commit is contained in:
commit
72c8f0b4ae
@ -718,7 +718,7 @@ generic_string stringReplace(generic_string subject, const generic_string& searc
|
|||||||
return subject;
|
return subject;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<generic_string> stringSplit(const generic_string& input, generic_string delimiter)
|
std::vector<generic_string> stringSplit(const generic_string& input, const generic_string& delimiter)
|
||||||
{
|
{
|
||||||
auto start = 0U;
|
auto start = 0U;
|
||||||
auto end = input.find(delimiter);
|
auto end = input.find(delimiter);
|
||||||
@ -734,7 +734,7 @@ std::vector<generic_string> stringSplit(const generic_string& input, generic_str
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
generic_string stringJoin(const std::vector<generic_string> &strings, generic_string separator)
|
generic_string stringJoin(const std::vector<generic_string>& strings, const generic_string& separator)
|
||||||
{
|
{
|
||||||
generic_string joined;
|
generic_string joined;
|
||||||
size_t length = strings.size();
|
size_t length = strings.size();
|
||||||
@ -748,3 +748,132 @@ generic_string stringJoin(const std::vector<generic_string> &strings, generic_st
|
|||||||
}
|
}
|
||||||
return joined;
|
return joined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long long stollStrict(const generic_string& input)
|
||||||
|
{
|
||||||
|
if (input.empty())
|
||||||
|
{
|
||||||
|
throw std::invalid_argument("Empty 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 std::invalid_argument("Invalid character found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::stoll(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool allLinesAreNumericOrEmpty(const std::vector<generic_string>& lines)
|
||||||
|
{
|
||||||
|
for (const generic_string& line : lines)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!line.empty())
|
||||||
|
{
|
||||||
|
stollStrict(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::invalid_argument&)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (std::out_of_range&)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<generic_string> repeatString(const generic_string& text, const size_t count)
|
||||||
|
{
|
||||||
|
std::vector<generic_string> output;
|
||||||
|
output.reserve(count);
|
||||||
|
for (size_t i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
output.push_back(text);
|
||||||
|
}
|
||||||
|
assert(output.size() == count);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<generic_string> lexicographicSort(std::vector<generic_string> 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<generic_string> numericSort(std::vector<generic_string> input, bool isDescending)
|
||||||
|
{
|
||||||
|
// 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<long long> nonEmptyInputAsNumbers;
|
||||||
|
size_t nofEmptyLines = 0;
|
||||||
|
nonEmptyInputAsNumbers.reserve(input.size());
|
||||||
|
for (const generic_string& line : input)
|
||||||
|
{
|
||||||
|
if (line.empty())
|
||||||
|
{
|
||||||
|
++nofEmptyLines;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nonEmptyInputAsNumbers.push_back(stollStrict(line));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(nonEmptyinputAsInts.size() + nofEmptyLines == input.size());
|
||||||
|
std::sort(nonEmptyInputAsNumbers.begin(), nonEmptyInputAsNumbers.end(), [isDescending](long long a, long long b)
|
||||||
|
{
|
||||||
|
if (isDescending)
|
||||||
|
{
|
||||||
|
return a > b;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return a < b;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
std::vector<generic_string> output;
|
||||||
|
output.reserve(input.size());
|
||||||
|
const std::vector<generic_string> empties = repeatString(TEXT(""), nofEmptyLines);
|
||||||
|
if (!isDescending)
|
||||||
|
{
|
||||||
|
output.insert(output.end(), empties.begin(), empties.end());
|
||||||
|
}
|
||||||
|
for (const long long& sortedNumber : nonEmptyInputAsNumbers)
|
||||||
|
{
|
||||||
|
output.push_back(std::to_wstring(sortedNumber));
|
||||||
|
}
|
||||||
|
if (isDescending)
|
||||||
|
{
|
||||||
|
output.insert(output.end(), empties.begin(), empties.end());
|
||||||
|
}
|
||||||
|
assert(output.size() == input.size());
|
||||||
|
return output;
|
||||||
|
}
|
@ -188,7 +188,13 @@ generic_string PathAppend(generic_string &strDest, const generic_string & str2ap
|
|||||||
COLORREF getCtrlBgColor(HWND hWnd);
|
COLORREF getCtrlBgColor(HWND hWnd);
|
||||||
generic_string stringToUpper(generic_string strToConvert);
|
generic_string stringToUpper(generic_string strToConvert);
|
||||||
generic_string stringReplace(generic_string subject, const generic_string& search, const generic_string& replace);
|
generic_string stringReplace(generic_string subject, const generic_string& search, const generic_string& replace);
|
||||||
std::vector<generic_string> stringSplit(const generic_string& input, generic_string delimiter);
|
std::vector<generic_string> stringSplit(const generic_string& input, const generic_string& delimiter);
|
||||||
generic_string stringJoin(const std::vector<generic_string> &strings, generic_string separator);
|
generic_string stringJoin(const std::vector<generic_string>& strings, const generic_string& separator);
|
||||||
|
long long stollStrict(const generic_string& input);
|
||||||
|
bool allLinesAreNumericOrEmpty(const std::vector<generic_string>& lines);
|
||||||
|
std::vector<generic_string> repeatString(const generic_string& text, const size_t count);
|
||||||
|
|
||||||
|
std::vector<generic_string> numericSort(std::vector<generic_string> input, bool isDescending);
|
||||||
|
std::vector<generic_string> lexicographicSort(std::vector<generic_string> input, bool isDescending);
|
||||||
|
|
||||||
#endif //M30_IDE_COMMUN_H
|
#endif //M30_IDE_COMMUN_H
|
||||||
|
@ -375,7 +375,7 @@ void Notepad_plus::command(int id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
_pEditView->execute(SCI_BEGINUNDOACTION);
|
_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);
|
_pEditView->execute(SCI_ENDUNDOACTION);
|
||||||
|
|
||||||
if (hasSelection) // there was 1 selection, so we restore it
|
if (hasSelection) // there was 1 selection, so we restore it
|
||||||
|
@ -1703,7 +1703,7 @@ generic_string ScintillaEditView::getGenericTextAsString(int start, int end) con
|
|||||||
{
|
{
|
||||||
assert(end > start);
|
assert(end > start);
|
||||||
const int bufSize = end - start + 1;
|
const int bufSize = end - start + 1;
|
||||||
_TCHAR *buf = new _TCHAR[bufSize];
|
TCHAR *buf = new TCHAR[bufSize];
|
||||||
getGenericText(buf, bufSize, start, end);
|
getGenericText(buf, bufSize, start, end);
|
||||||
generic_string text = buf;
|
generic_string text = buf;
|
||||||
delete[] buf;
|
delete[] buf;
|
||||||
@ -2947,7 +2947,7 @@ void ScintillaEditView::insertNewLineBelowCurrentLine()
|
|||||||
execute(SCI_SETEMPTYSELECTION, execute(SCI_POSITIONFROMLINE, current_line + 1));
|
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)
|
if (fromLine >= toLine)
|
||||||
{
|
{
|
||||||
@ -2958,19 +2958,35 @@ void ScintillaEditView::quickSortLines(size_t fromLine, size_t toLine, bool isDe
|
|||||||
const int endPos = execute(SCI_POSITIONFROMLINE, toLine) + execute(SCI_LINELENGTH, toLine);
|
const int endPos = execute(SCI_POSITIONFROMLINE, toLine) + execute(SCI_LINELENGTH, toLine);
|
||||||
const generic_string text = getGenericTextAsString(startPos, endPos);
|
const generic_string text = getGenericTextAsString(startPos, endPos);
|
||||||
std::vector<generic_string> splitText = stringSplit(text, getEOLString());
|
std::vector<generic_string> splitText = stringSplit(text, getEOLString());
|
||||||
std::sort(splitText.begin(), splitText.end(), [isDescending](generic_string a, generic_string b)
|
const size_t lineCount = execute(SCI_GETLINECOUNT);
|
||||||
|
const bool sortEntireDocument = toLine == lineCount - 1;
|
||||||
|
if (!sortEntireDocument)
|
||||||
{
|
{
|
||||||
if (isDescending)
|
if (splitText.rbegin()->empty())
|
||||||
{
|
{
|
||||||
return a.compare(b) > 0;
|
splitText.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(toLine - fromLine + 1 == splitText.size());
|
||||||
|
const bool isNumericSort = allLinesAreNumericOrEmpty(splitText);
|
||||||
|
std::vector<generic_string> sortedText;
|
||||||
|
if (isNumericSort)
|
||||||
|
{
|
||||||
|
sortedText = numericSort(splitText, isDescending);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return a.compare(b) < 0;
|
sortedText = lexicographicSort(splitText, isDescending);
|
||||||
}
|
}
|
||||||
});
|
const generic_string joined = stringJoin(sortedText, getEOLString());
|
||||||
const generic_string joined = stringJoin(splitText, getEOLString());
|
if (sortEntireDocument)
|
||||||
|
{
|
||||||
replaceTarget(joined.c_str(), startPos, endPos);
|
replaceTarget(joined.c_str(), startPos, endPos);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
replaceTarget((joined + getEOLString()).c_str(), startPos, endPos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScintillaEditView::isTextDirectionRTL() const
|
bool ScintillaEditView::isTextDirectionRTL() const
|
||||||
|
@ -636,7 +636,7 @@ public:
|
|||||||
};
|
};
|
||||||
void scrollPosToCenter(int pos);
|
void scrollPosToCenter(int pos);
|
||||||
generic_string getEOLString();
|
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);
|
void changeTextDirection(bool isRTL);
|
||||||
bool isTextDirectionRTL() const;
|
bool isTextDirectionRTL() const;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user