Merge pull request #44 from andreas-jonsson/more_optimize_sort

[BUG_FIXED] Fix issues related to sort optimization.
This commit is contained in:
Don HO 2015-05-15 03:32:15 +02:00
commit 72c8f0b4ae
5 changed files with 169 additions and 18 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;