Optimize sort.
Remove custom, recursive implementation of quicksort which becomes too slow to use after a couple of hundred lines.
This commit is contained in:
parent
4e065b2d3f
commit
1f4a1fb2e7
@ -716,4 +716,35 @@ generic_string stringReplace(generic_string subject, const generic_string& searc
|
||||
pos += replace.length();
|
||||
}
|
||||
return subject;
|
||||
}
|
||||
|
||||
std::vector<generic_string> stringSplit(const generic_string& input, generic_string delimiter)
|
||||
{
|
||||
auto start = 0U;
|
||||
auto end = input.find(delimiter);
|
||||
std::vector<generic_string> output;
|
||||
const size_t delimiterLength = delimiter.length();
|
||||
while (end != std::string::npos)
|
||||
{
|
||||
output.push_back(input.substr(start, end - start));
|
||||
start = end + delimiterLength;
|
||||
end = input.find(delimiter, start);
|
||||
}
|
||||
output.push_back(input.substr(start, end));
|
||||
return output;
|
||||
}
|
||||
|
||||
generic_string stringJoin(const std::vector<generic_string> &strings, generic_string separator)
|
||||
{
|
||||
generic_string joined;
|
||||
size_t length = strings.size();
|
||||
for (size_t i = 0; i < length; ++i)
|
||||
{
|
||||
joined += strings.at(i);
|
||||
if (i != length - 1)
|
||||
{
|
||||
joined += separator;
|
||||
}
|
||||
}
|
||||
return joined;
|
||||
}
|
@ -188,5 +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<generic_string> stringSplit(const generic_string& input, generic_string delimiter);
|
||||
generic_string stringJoin(const std::vector<generic_string> &strings, generic_string separator);
|
||||
|
||||
#endif //M30_IDE_COMMUN_H
|
||||
|
@ -274,8 +274,8 @@ BEGIN
|
||||
MENUITEM "Duplicate Current Line", IDM_EDIT_DUP_LINE
|
||||
MENUITEM "Split Lines", IDM_EDIT_SPLIT_LINES
|
||||
MENUITEM "Join Lines", IDM_EDIT_JOIN_LINES
|
||||
MENUITEM "Sort Lines in Ascending Order", IDM_EDIT_SORTLINES
|
||||
MENUITEM "Sort Lines in Descending Order", IDM_EDIT_SORTLINESREVERSE
|
||||
MENUITEM "Sort Lines in Ascending Order", IDM_EDIT_SORTLINES_ASCENDING
|
||||
MENUITEM "Sort Lines in Descending Order", IDM_EDIT_SORTLINES_DESCENDING
|
||||
MENUITEM "Move Up Current Line", IDM_EDIT_LINE_UP
|
||||
MENUITEM "Move Down Current Line", IDM_EDIT_LINE_DOWN
|
||||
MENUITEM "Remove Empty Lines", IDM_EDIT_REMOVEEMPTYLINES
|
||||
|
@ -344,8 +344,8 @@ void Notepad_plus::command(int id)
|
||||
}
|
||||
break;
|
||||
|
||||
case IDM_EDIT_SORTLINES:
|
||||
case IDM_EDIT_SORTLINESREVERSE:
|
||||
case IDM_EDIT_SORTLINES_ASCENDING:
|
||||
case IDM_EDIT_SORTLINES_DESCENDING:
|
||||
{
|
||||
// default: no selection
|
||||
size_t fromLine = 0;
|
||||
@ -375,7 +375,7 @@ void Notepad_plus::command(int id)
|
||||
}
|
||||
|
||||
_pEditView->execute(SCI_BEGINUNDOACTION);
|
||||
_pEditView->quickSortLines(fromLine, toLine, id == IDM_EDIT_SORTLINESREVERSE);
|
||||
_pEditView->quickSortLines(fromLine, toLine, id == IDM_EDIT_SORTLINES_DESCENDING);
|
||||
_pEditView->execute(SCI_ENDUNDOACTION);
|
||||
|
||||
if (hasSelection) // there was 1 selection, so we restore it
|
||||
@ -2598,8 +2598,8 @@ void Notepad_plus::command(int id)
|
||||
case IDM_EDIT_RTL :
|
||||
case IDM_EDIT_LTR :
|
||||
case IDM_EDIT_BEGINENDSELECT:
|
||||
case IDM_EDIT_SORTLINES:
|
||||
case IDM_EDIT_SORTLINESREVERSE:
|
||||
case IDM_EDIT_SORTLINES_ASCENDING:
|
||||
case IDM_EDIT_SORTLINES_DESCENDING:
|
||||
case IDM_EDIT_BLANKLINEABOVECURRENT:
|
||||
case IDM_EDIT_BLANKLINEBELOWCURRENT:
|
||||
case IDM_VIEW_FULLSCREENTOGGLE :
|
||||
|
@ -127,8 +127,8 @@ WinMenuKeyDefinition winKeyDefs[] = {
|
||||
{VK_SPACE, IDM_EDIT_FUNCCALLTIP, true, false, true, NULL},
|
||||
{VK_R, IDM_EDIT_RTL, true, true, false, NULL},
|
||||
{VK_L, IDM_EDIT_LTR, true, true, false, NULL},
|
||||
{VK_NULL, IDM_EDIT_SORTLINES, false, false, false, NULL},
|
||||
{VK_NULL, IDM_EDIT_SORTLINESREVERSE, false, false, false, NULL},
|
||||
{VK_NULL, IDM_EDIT_SORTLINES_ASCENDING, false, false, false, NULL},
|
||||
{VK_NULL, IDM_EDIT_SORTLINES_DESCENDING, false, false, false, NULL},
|
||||
{VK_RETURN, IDM_EDIT_BLANKLINEABOVECURRENT, true, true, false, NULL},
|
||||
{VK_RETURN, IDM_EDIT_BLANKLINEBELOWCURRENT, true, true, true, NULL},
|
||||
{VK_F, IDM_SEARCH_FIND, true, false, false, NULL},
|
||||
|
@ -1699,6 +1699,17 @@ void ScintillaEditView::getText(char *dest, int start, int end) const
|
||||
execute(SCI_GETTEXTRANGE, 0, reinterpret_cast<LPARAM>(&tr));
|
||||
}
|
||||
|
||||
generic_string ScintillaEditView::getGenericTextAsString(int start, int end) const
|
||||
{
|
||||
assert(end > start);
|
||||
const int bufSize = end - start + 1;
|
||||
_TCHAR *buf = new _TCHAR[bufSize];
|
||||
getGenericText(buf, bufSize, start, end);
|
||||
generic_string text = buf;
|
||||
delete[] buf;
|
||||
return text;
|
||||
}
|
||||
|
||||
void ScintillaEditView::getGenericText(TCHAR *dest, size_t destlen, int start, int end) const
|
||||
{
|
||||
WcharMbcsConvertor *wmc = WcharMbcsConvertor::getInstance();
|
||||
@ -2900,16 +2911,7 @@ void ScintillaEditView::setTabSettings(Lang *lang)
|
||||
|
||||
void ScintillaEditView::insertNewLineAboveCurrentLine()
|
||||
{
|
||||
const int eol_mode = int(execute(SCI_GETEOLMODE));
|
||||
|
||||
generic_string newline;
|
||||
if(eol_mode == SC_EOL_CRLF)
|
||||
newline = TEXT("\r\n");
|
||||
else if(eol_mode == SC_EOL_LF)
|
||||
newline = TEXT("\n");
|
||||
else
|
||||
newline = TEXT("\r");
|
||||
|
||||
generic_string newline = getEOLString();
|
||||
const int current_line = getCurrentLineNumber();
|
||||
if(current_line == 0)
|
||||
{
|
||||
@ -2918,7 +2920,7 @@ void ScintillaEditView::insertNewLineAboveCurrentLine()
|
||||
}
|
||||
else
|
||||
{
|
||||
const int eol_length = eol_mode == SC_EOL_CRLF ? 2 : 1;
|
||||
const int eol_length = newline.length();
|
||||
const long position = execute(SCI_POSITIONFROMLINE, current_line) - eol_length;
|
||||
insertGenericTextFrom(position, newline.c_str());
|
||||
}
|
||||
@ -2928,16 +2930,7 @@ void ScintillaEditView::insertNewLineAboveCurrentLine()
|
||||
|
||||
void ScintillaEditView::insertNewLineBelowCurrentLine()
|
||||
{
|
||||
const int eol_mode = int(execute(SCI_GETEOLMODE));
|
||||
|
||||
generic_string newline;
|
||||
if(eol_mode == SC_EOL_CRLF)
|
||||
newline = TEXT("\r\n");
|
||||
else if(eol_mode == SC_EOL_LF)
|
||||
newline = TEXT("\n");
|
||||
else
|
||||
newline = TEXT("\r");
|
||||
|
||||
generic_string newline = getEOLString();
|
||||
const int line_count = execute(SCI_GETLINECOUNT);
|
||||
const int current_line = getCurrentLineNumber();
|
||||
if(current_line == line_count - 1)
|
||||
@ -2947,146 +2940,38 @@ void ScintillaEditView::insertNewLineBelowCurrentLine()
|
||||
}
|
||||
else
|
||||
{
|
||||
const int eol_length = eol_mode == SC_EOL_CRLF ? 2 : 1;
|
||||
const int eol_length = newline.length();
|
||||
const long position = eol_length + execute(SCI_GETLINEENDPOSITION, current_line);
|
||||
insertGenericTextFrom(position, newline.c_str());
|
||||
}
|
||||
execute(SCI_SETEMPTYSELECTION, execute(SCI_POSITIONFROMLINE, current_line + 1));
|
||||
}
|
||||
|
||||
// Get the first left index, in which the value greater/equal or smaller/equal than pivot's one
|
||||
// If not found, then pivot's index will be returned
|
||||
size_t ScintillaEditView::getLeftLineIndex(size_t leftIndex, size_t pivotIndex, bool isReverse)
|
||||
{
|
||||
size_t i = leftIndex;
|
||||
while (i < pivotIndex)
|
||||
{
|
||||
if (!isReverse)
|
||||
{
|
||||
size_t iLine = getGreaterLineBetween(i, pivotIndex);
|
||||
if (iLine == pivotIndex) // pivotIndex > i
|
||||
++i;
|
||||
else
|
||||
break; // Bingo!
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t iLine = getGreaterLineBetween(i, pivotIndex);
|
||||
if (iLine == pivotIndex) // pivotIndex < i
|
||||
break; // Bingo!
|
||||
else
|
||||
++i;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
// Get the first right index, in which the value smaller/equal or greater/equal than pivot's one
|
||||
// If not found, then pivot's index will be returned
|
||||
size_t ScintillaEditView::getRightLineIndex(size_t rightIndex, size_t pivotIndex, bool isReverse)
|
||||
{
|
||||
size_t i = rightIndex;
|
||||
while (i > pivotIndex)
|
||||
{
|
||||
if (!isReverse)
|
||||
{
|
||||
size_t iLine = getGreaterLineBetween(i, pivotIndex);
|
||||
if (iLine == i) // pivotIndex > i
|
||||
i--;
|
||||
else
|
||||
break; // Bingo!
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t iLine = getGreaterLineBetween(i, pivotIndex);
|
||||
if (iLine == i) // pivotIndex < i
|
||||
break; // Bingo!
|
||||
else
|
||||
i--;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
size_t ScintillaEditView::getGreaterLineBetween(size_t l1, size_t l2)
|
||||
{
|
||||
int line1Len = execute(SCI_LINELENGTH, l1);
|
||||
int line2Len = execute(SCI_LINELENGTH, l2);
|
||||
|
||||
char *line1text = new char[line1Len + 1];
|
||||
char *line2text = new char[line2Len + 1];
|
||||
execute(SCI_GETLINE, l1, (LPARAM)line1text);
|
||||
line1text[line1Len] = '\0';
|
||||
execute(SCI_GETLINE, l2, (LPARAM)line2text);
|
||||
line2text[line2Len] = '\0';
|
||||
|
||||
string s1 = line1text;
|
||||
string s2 = line2text;
|
||||
|
||||
size_t res;
|
||||
if (s1.compare(s2) > 0)
|
||||
res = l1;
|
||||
else
|
||||
res = l2;
|
||||
|
||||
delete[] line1text;
|
||||
delete[] line2text;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t ScintillaEditView::getRandomPivot(size_t fromLine, size_t toLine)
|
||||
{
|
||||
srand((unsigned int)time(NULL));
|
||||
return rand() % (toLine - fromLine) + fromLine;
|
||||
}
|
||||
|
||||
|
||||
void ScintillaEditView::quickSortLines(size_t fromLine, size_t toLine, bool isReverse)
|
||||
void ScintillaEditView::quickSortLines(size_t fromLine, size_t toLine, bool isDescending)
|
||||
{
|
||||
if (fromLine >= toLine)
|
||||
return;
|
||||
|
||||
// choose the pivot
|
||||
size_t pivotIndex = getRandomPivot(fromLine, toLine);
|
||||
|
||||
// comparing right with left
|
||||
size_t leftIndex = fromLine;
|
||||
size_t rightIndex = toLine;
|
||||
|
||||
while (rightIndex > leftIndex)
|
||||
{
|
||||
leftIndex = getLeftLineIndex(leftIndex, pivotIndex, isReverse); // get the first left index, in which the value greater or equal than pivot's one
|
||||
rightIndex = getRightLineIndex(rightIndex, pivotIndex, isReverse); // get the first right index, in which the value smaller or equal than pivot's one
|
||||
|
||||
if ((leftIndex != rightIndex) && swapLines(leftIndex, rightIndex))
|
||||
{
|
||||
if (leftIndex == pivotIndex)
|
||||
{
|
||||
pivotIndex = rightIndex;
|
||||
++leftIndex;
|
||||
}
|
||||
else if (rightIndex == pivotIndex)
|
||||
{
|
||||
pivotIndex = leftIndex;
|
||||
--rightIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
++leftIndex;
|
||||
--rightIndex;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// check the left side recursively
|
||||
if (pivotIndex != fromLine)
|
||||
quickSortLines(fromLine, pivotIndex - 1, isReverse);
|
||||
const int startPos = execute(SCI_POSITIONFROMLINE, fromLine);
|
||||
const int endPos = execute(SCI_POSITIONFROMLINE, toLine) + execute(SCI_LINELENGTH, toLine);
|
||||
|
||||
// check the right side recursively
|
||||
if (pivotIndex != toLine)
|
||||
quickSortLines(pivotIndex + 1, toLine, isReverse);
|
||||
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)
|
||||
{
|
||||
if (isDescending)
|
||||
{
|
||||
return a.compare(b) > 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return a.compare(b) < 0;
|
||||
}
|
||||
});
|
||||
generic_string joined = stringJoin(splitText, getEOLString());
|
||||
replaceTarget(joined.c_str(), startPos, endPos);
|
||||
}
|
||||
|
||||
bool ScintillaEditView::isTextDirectionRTL() const
|
||||
@ -3102,88 +2987,20 @@ void ScintillaEditView::changeTextDirection(bool isRTL)
|
||||
::SetWindowLongPtr(_hSelf, GWL_EXSTYLE, exStyle);
|
||||
}
|
||||
|
||||
bool ScintillaEditView::swapLines(size_t line1, size_t line2)
|
||||
generic_string ScintillaEditView::getEOLString()
|
||||
{
|
||||
size_t lowerLine = line1;
|
||||
size_t higherLine = line2;
|
||||
|
||||
if (lowerLine == higherLine)
|
||||
return false;
|
||||
|
||||
if (line1 > line2)
|
||||
const int eol_mode = int(execute(SCI_GETEOLMODE));
|
||||
string newline;
|
||||
if (eol_mode == SC_EOL_CRLF)
|
||||
{
|
||||
lowerLine = line2;
|
||||
higherLine = line1;
|
||||
return TEXT("\r\n");
|
||||
}
|
||||
|
||||
size_t nbLine = execute(SCI_GETLINECOUNT);
|
||||
if (higherLine + 1 > nbLine)
|
||||
return false;
|
||||
|
||||
bool isLastLine = false;
|
||||
int eol_mode = SC_EOL_CRLF;
|
||||
size_t extraEOLLength = 0;
|
||||
if (higherLine + 1 == nbLine)
|
||||
else if (eol_mode == SC_EOL_LF)
|
||||
{
|
||||
isLastLine = true;
|
||||
|
||||
eol_mode = int(execute(SCI_GETEOLMODE));
|
||||
|
||||
if(eol_mode == SC_EOL_CRLF)
|
||||
extraEOLLength = 2;
|
||||
else if(eol_mode == SC_EOL_LF)
|
||||
extraEOLLength = 1;
|
||||
else // SC_EOL_CR
|
||||
extraEOLLength = 1;
|
||||
}
|
||||
|
||||
int line1Len = execute(SCI_LINELENGTH, lowerLine);
|
||||
int line2Len = execute(SCI_LINELENGTH, higherLine);
|
||||
|
||||
char *line1text = new char[line1Len + 1 ];
|
||||
char *line2text = new char[line2Len + 1 + extraEOLLength];
|
||||
execute(SCI_GETLINE, lowerLine, (LPARAM)line1text);
|
||||
line1text[line1Len - extraEOLLength] = '\0';
|
||||
execute(SCI_GETLINE, higherLine, (LPARAM)line2text);
|
||||
if (isLastLine)
|
||||
{
|
||||
if (eol_mode == SC_EOL_CRLF)
|
||||
{
|
||||
line2text[line2Len] = '\r';
|
||||
line2text[line2Len + 1] = '\n';
|
||||
line2text[line2Len + 2] = '\0';
|
||||
}
|
||||
else if (eol_mode == SC_EOL_LF)
|
||||
{
|
||||
line2text[line2Len] = '\n';
|
||||
line2text[line2Len + 1] = '\0';
|
||||
}
|
||||
else // SC_EOL_CR
|
||||
{
|
||||
line2text[line2Len] = '\r';
|
||||
line2text[line2Len + 1] = '\0';
|
||||
}
|
||||
|
||||
return TEXT("\n");
|
||||
}
|
||||
else
|
||||
line2text[line2Len] = '\0';
|
||||
|
||||
size_t posFrom1, posTo1, posFrom2, posTo2;
|
||||
posFrom1 = execute(SCI_POSITIONFROMLINE, lowerLine);
|
||||
posFrom2 = execute(SCI_POSITIONFROMLINE, higherLine);
|
||||
posTo1 = posFrom1 + line1Len;
|
||||
posTo2 = posFrom2 + line2Len;
|
||||
|
||||
execute(SCI_SETTARGETSTART, posFrom2);
|
||||
execute(SCI_SETTARGETEND, posTo2);
|
||||
execute(SCI_REPLACETARGET, (WPARAM)-1, (LPARAM)line1text);
|
||||
|
||||
execute(SCI_SETTARGETSTART, posFrom1);
|
||||
execute(SCI_SETTARGETEND, posTo1);
|
||||
execute(SCI_REPLACETARGET, (WPARAM)-1, (LPARAM)line2text);
|
||||
|
||||
delete[] line1text;
|
||||
delete[] line2text;
|
||||
|
||||
return true;
|
||||
{
|
||||
return TEXT("\r");
|
||||
}
|
||||
}
|
@ -247,6 +247,7 @@ public:
|
||||
void getText(char *dest, int start, int end) const;
|
||||
void getGenericText(TCHAR *dest, size_t destlen, int start, int end) const;
|
||||
void getGenericText(TCHAR *dest, size_t deslen, int start, int end, int *mstart, int *mend) const;
|
||||
generic_string getGenericTextAsString(int start, int end) const;
|
||||
void insertGenericTextFrom(int position, const TCHAR *text2insert) const;
|
||||
void replaceSelWith(const char * replaceText);
|
||||
|
||||
@ -634,8 +635,8 @@ public:
|
||||
(_codepage == CP_JAPANESE) || (_codepage == CP_KOREAN));
|
||||
};
|
||||
void scrollPosToCenter(int pos);
|
||||
bool swapLines(size_t line1, size_t line2);
|
||||
void quickSortLines(size_t fromLine, size_t toLine, bool isReverse = false);
|
||||
generic_string getEOLString();
|
||||
void quickSortLines(size_t fromLine, size_t toLine, bool isDescending);
|
||||
void changeTextDirection(bool isRTL);
|
||||
bool isTextDirectionRTL() const;
|
||||
|
||||
@ -911,12 +912,6 @@ protected:
|
||||
|
||||
pair<int, int> getWordRange();
|
||||
bool expandWordSelection();
|
||||
|
||||
// For the quicksort on lines
|
||||
size_t getLeftLineIndex(size_t leftIndex, size_t pivotIndex, bool isReverse);
|
||||
size_t getRightLineIndex(size_t rightIndex, size_t pivotIndex, bool isReverse);
|
||||
size_t getGreaterLineBetween(size_t l1, size_t l2);
|
||||
size_t getRandomPivot(size_t fromLine, size_t toLine);
|
||||
};
|
||||
|
||||
#endif //SCINTILLA_EDIT_VIEW_H
|
||||
|
@ -112,8 +112,8 @@
|
||||
#define IDM_EDIT_REMOVEEMPTYLINESWITHBLANK (IDM_EDIT + 56)
|
||||
#define IDM_EDIT_BLANKLINEABOVECURRENT (IDM_EDIT + 57)
|
||||
#define IDM_EDIT_BLANKLINEBELOWCURRENT (IDM_EDIT + 58)
|
||||
#define IDM_EDIT_SORTLINES (IDM_EDIT + 59)
|
||||
#define IDM_EDIT_SORTLINESREVERSE (IDM_EDIT + 60)
|
||||
#define IDM_EDIT_SORTLINES_ASCENDING (IDM_EDIT + 59)
|
||||
#define IDM_EDIT_SORTLINES_DESCENDING (IDM_EDIT + 60)
|
||||
|
||||
// Menu macro
|
||||
#define IDM_MACRO_STARTRECORDINGMACRO (IDM_EDIT + 18)
|
||||
|
Loading…
Reference in New Issue
Block a user