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;
|
||||
}
|
||||
|
||||
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 end = input.find(delimiter);
|
||||
@ -734,7 +734,7 @@ std::vector<generic_string> stringSplit(const generic_string& input, generic_str
|
||||
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;
|
||||
size_t length = strings.size();
|
||||
@ -747,4 +747,133 @@ generic_string stringJoin(const std::vector<generic_string> &strings, generic_st
|
||||
}
|
||||
}
|
||||
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);
|
||||
generic_string stringToUpper(generic_string strToConvert);
|
||||
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);
|
||||
generic_string stringJoin(const std::vector<generic_string> &strings, generic_string separator);
|
||||
std::vector<generic_string> stringSplit(const generic_string& input, const generic_string& delimiter);
|
||||
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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
@ -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)
|
||||
{
|
||||
@ -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 generic_string text = getGenericTextAsString(startPos, endPos);
|
||||
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();
|
||||
}
|
||||
else
|
||||
{
|
||||
return a.compare(b) < 0;
|
||||
}
|
||||
});
|
||||
const generic_string joined = stringJoin(splitText, getEOLString());
|
||||
replaceTarget(joined.c_str(), startPos, endPos);
|
||||
}
|
||||
assert(toLine - fromLine + 1 == splitText.size());
|
||||
const bool isNumericSort = allLinesAreNumericOrEmpty(splitText);
|
||||
std::vector<generic_string> sortedText;
|
||||
if (isNumericSort)
|
||||
{
|
||||
sortedText = numericSort(splitText, isDescending);
|
||||
}
|
||||
else
|
||||
{
|
||||
sortedText = lexicographicSort(splitText, isDescending);
|
||||
}
|
||||
const generic_string joined = stringJoin(sortedText, getEOLString());
|
||||
if (sortEntireDocument)
|
||||
{
|
||||
replaceTarget(joined.c_str(), startPos, endPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
replaceTarget((joined + getEOLString()).c_str(), startPos, endPos);
|
||||
}
|
||||
}
|
||||
|
||||
bool ScintillaEditView::isTextDirectionRTL() const
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user