mirror of
https://github.com/MarlinFirmware/Marlin.git
synced 2025-12-28 18:30:36 -07:00
parent
788e86ccc6
commit
3a77a7eefd
2 changed files with 168 additions and 174 deletions
|
|
@ -1328,171 +1328,6 @@ void CardReader::cdroot() {
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if ENABLED(SDSORT_QUICK)
|
||||
|
||||
// Quick Sort
|
||||
bool CardReader::sort_cmp_files(const int16_t o1, const int16_t o2) {
|
||||
auto _sort_cmp_file = [](const char *const n1, const char *const n2) -> bool {
|
||||
const bool sort = strcasecmp(n1, n2) < 0;
|
||||
return (TERN(SDSORT_GCODE, sort_alpha == AS_REV, ENABLED(SDSORT_REVERSE))) ? !sort : sort;
|
||||
};
|
||||
|
||||
#if ENABLED(SDSORT_USES_RAM)
|
||||
const bool dir1 = IS_DIR(o1), dir2 = IS_DIR(o2);
|
||||
const char *name1 = card.sortnames[o1], *name2 = card.sortnames[o2];
|
||||
#else
|
||||
card.selectFileByIndex(o1);
|
||||
char name1_buffer[LONG_FILENAME_LENGTH];
|
||||
strcpy(name1_buffer, card.longest_filename());
|
||||
const char *name1 = name1_buffer;
|
||||
const bool dir1 = card.flag.filenameIsDir;
|
||||
|
||||
card.selectFileByIndex(o2);
|
||||
const char *name2 = card.longest_filename();
|
||||
const bool dir2 = card.flag.filenameIsDir;
|
||||
#endif
|
||||
|
||||
#if HAS_FOLDER_SORTING
|
||||
#if ENABLED(SDSORT_GCODE)
|
||||
if (card.sort_folders && dir1 != dir2)
|
||||
return (card.sort_folders > 0) ? dir1 : !dir1;
|
||||
#else
|
||||
if (dir1 != dir2)
|
||||
return (SDSORT_FOLDERS > 0) ? dir1 : !dir1;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return _sort_cmp_file(name1, name2);
|
||||
}
|
||||
|
||||
int16_t CardReader::partition(uint8_t* arr, int16_t low, int16_t high) {
|
||||
int16_t pivotIndex = arr[high];
|
||||
int16_t i = (low - 1);
|
||||
|
||||
for (int16_t j = low; j < high; j++) {
|
||||
if (sort_cmp_files(arr[j], pivotIndex)) {
|
||||
i++;
|
||||
uint8_t temp = arr[i];
|
||||
arr[i] = arr[j];
|
||||
arr[j] = temp;
|
||||
}
|
||||
}
|
||||
// Manual swap
|
||||
uint8_t temp = arr[i + 1];
|
||||
arr[i + 1] = arr[high];
|
||||
arr[high] = temp;
|
||||
return (i + 1);
|
||||
}
|
||||
|
||||
void CardReader::quicksort(uint8_t* arr, int16_t low, int16_t high) {
|
||||
int16_t stack[SDSORT_LIMIT + 1];
|
||||
int16_t top = -1; // Initialize top of stack
|
||||
|
||||
// Push initial values to the stack
|
||||
stack[++top] = low;
|
||||
stack[++top] = high;
|
||||
|
||||
// Pop from stack while not empty
|
||||
while (top >= 0) {
|
||||
high = stack[top--];
|
||||
low = stack[top--];
|
||||
|
||||
// Set pivot element at correct position
|
||||
const int16_t pivot = partition(arr, low, high);
|
||||
// If elements are on left side, push to stack
|
||||
if (pivot - 1 > low) {
|
||||
stack[++top] = low;
|
||||
stack[++top] = pivot - 1;
|
||||
}
|
||||
// If elements are on right side, push to stack
|
||||
if (pivot + 1 < high) {
|
||||
stack[++top] = pivot + 1;
|
||||
stack[++top] = high;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else // !SDSORT_QUICK
|
||||
|
||||
// Bubble Sort
|
||||
void CardReader::bubblesort(uint8_t* arr, int16_t fileCnt) {
|
||||
for (int16_t i = fileCnt; --i;) {
|
||||
bool didSwap = false;
|
||||
int16_t o1 = arr[0];
|
||||
#if DISABLED(SDSORT_USES_RAM)
|
||||
// By default re-read the names from SD for every compare
|
||||
// retaining only two filenames at a time. This is very
|
||||
// slow but is safest and uses minimal RAM.
|
||||
char name1[LONG_FILENAME_LENGTH];
|
||||
selectFileByIndex(o1); // Pre-fetch the first entry and save it
|
||||
strcpy(name1, longest_filename()); // so the loop only needs one fetch
|
||||
#if HAS_FOLDER_SORTING
|
||||
bool dir1 = flag.filenameIsDir;
|
||||
#endif
|
||||
if ((i & 0x7) == 7) hal.watchdog_refresh();
|
||||
#endif
|
||||
|
||||
for (int16_t j = 0; j < i; ++j) {
|
||||
const int16_t o2 = arr[j + 1];
|
||||
|
||||
// Compare names from the array or just the two buffered names
|
||||
auto _sort_cmp_file = [](char * const n1, char * const n2) -> bool {
|
||||
const bool sort = strcasecmp(n1, n2) > 0;
|
||||
return (TERN(SDSORT_GCODE, sort_alpha == AS_REV, ENABLED(SDSORT_REVERSE))) ? !sort : sort;
|
||||
};
|
||||
#define _SORT_CMP_FILE() _sort_cmp_file(TERN(SDSORT_USES_RAM, sortnames[o1], name1), TERN(SDSORT_USES_RAM, sortnames[o2], name2))
|
||||
|
||||
#if HAS_FOLDER_SORTING
|
||||
#if ENABLED(SDSORT_USES_RAM)
|
||||
// Folder sorting needs an index and bit to test for folder-ness.
|
||||
#define _SORT_CMP_DIR(fs) (IS_DIR(o1) == IS_DIR(o2) ? _SORT_CMP_FILE() : IS_DIR(fs > 0 ? o1 : o2))
|
||||
#else
|
||||
#define _SORT_CMP_DIR(fs) ((dir1 == flag.filenameIsDir) ? _SORT_CMP_FILE() : (fs > 0 ? dir1 : !dir1))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// The most economical method reads names as-needed
|
||||
// throughout the loop. Slow if there are many.
|
||||
#if DISABLED(SDSORT_USES_RAM)
|
||||
selectFileByIndex(o2);
|
||||
const bool dir2 = flag.filenameIsDir;
|
||||
char * const name2 = longest_filename(); // Use the string in-place
|
||||
if ((i & 0x7) == 7) hal.watchdog_refresh();
|
||||
#endif
|
||||
|
||||
// Sort the current pair according to settings.
|
||||
if (
|
||||
#if HAS_FOLDER_SORTING
|
||||
#if ENABLED(SDSORT_GCODE)
|
||||
sort_folders ? _SORT_CMP_DIR(sort_folders) : _SORT_CMP_FILE()
|
||||
#else
|
||||
_SORT_CMP_DIR(SDSORT_FOLDERS)
|
||||
#endif
|
||||
#else
|
||||
_SORT_CMP_FILE()
|
||||
#endif
|
||||
) {
|
||||
// Reorder the index, indicate that sorting happened
|
||||
// Note that the next o1 will be the current o1. No new fetch needed.
|
||||
arr[j] = o2;
|
||||
arr[j + 1] = o1;
|
||||
didSwap = true;
|
||||
}
|
||||
else {
|
||||
// The next o1 is the current o2. No new fetch needed.
|
||||
o1 = o2;
|
||||
#if DISABLED(SDSORT_USES_RAM)
|
||||
TERN_(HAS_FOLDER_SORTING, dir1 = dir2);
|
||||
strcpy(name1, name2);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (!didSwap) break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !SDSORT_QUICK
|
||||
|
||||
/**
|
||||
* Read all the files and produce a sort key
|
||||
*
|
||||
|
|
@ -1543,6 +1378,13 @@ void CardReader::cdroot() {
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#else // !SDSORT_USES_RAM
|
||||
|
||||
// By default re-read the names from SD for every compare
|
||||
// retaining only two filenames at a time. This is very
|
||||
// slow but is safest and uses minimal RAM.
|
||||
char name1[LONG_FILENAME_LENGTH];
|
||||
|
||||
#endif
|
||||
|
||||
if (fileCnt > 1) {
|
||||
|
|
@ -1564,15 +1406,171 @@ void CardReader::cdroot() {
|
|||
if (flag.filenameIsDir) SBI(isDir[ind], bit);
|
||||
#endif
|
||||
#endif
|
||||
if ((i & 0x7) == 7) hal.watchdog_refresh();
|
||||
}
|
||||
|
||||
// Sorting Algorithm
|
||||
#if ENABLED(SDSORT_QUICK)
|
||||
quicksort(sort_order, 0, fileCnt - 1);
|
||||
{
|
||||
auto sort_cmp_files = [&](const int16_t o1, const int16_t o2) -> bool {
|
||||
#if DISABLED(SDSORT_USES_RAM)
|
||||
char name1[LONG_FILENAME_LENGTH];
|
||||
selectFileByIndex(o1);
|
||||
strcpy(name1, longest_filename());
|
||||
#if HAS_FOLDER_SORTING
|
||||
const bool dir1 = flag.filenameIsDir;
|
||||
#endif
|
||||
selectFileByIndex(o2);
|
||||
const char *name2 = longest_filename();
|
||||
#if HAS_FOLDER_SORTING
|
||||
const bool dir2 = flag.filenameIsDir;
|
||||
#endif
|
||||
#else
|
||||
#if HAS_FOLDER_SORTING
|
||||
const bool dir1 = IS_DIR(o1), dir2 = IS_DIR(o2);
|
||||
#endif
|
||||
const char *name1 = sortnames[o1], *name2 = sortnames[o2];
|
||||
#endif
|
||||
|
||||
#if HAS_FOLDER_SORTING
|
||||
#if ENABLED(SDSORT_GCODE)
|
||||
if (sort_folders && dir1 != dir2)
|
||||
return (sort_folders > 0) ? dir1 : !dir1;
|
||||
#else
|
||||
if (dir1 != dir2)
|
||||
return (SDSORT_FOLDERS > 0) ? dir1 : !dir1;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
const bool sort = strcasecmp(name1, name2) < 0;
|
||||
return (TERN(SDSORT_GCODE, sort_alpha == AS_REV, ENABLED(SDSORT_REVERSE))) ? !sort : sort;
|
||||
};
|
||||
|
||||
auto partition = [&](uint8_t* arr, int16_t low, int16_t high) -> int16_t {
|
||||
int16_t pivotIndex = arr[high];
|
||||
int16_t i = (low - 1);
|
||||
|
||||
for (int16_t j = low; j < high; j++) {
|
||||
if (sort_cmp_files(arr[j], pivotIndex)) {
|
||||
i++;
|
||||
uint8_t temp = arr[i];
|
||||
arr[i] = arr[j];
|
||||
arr[j] = temp;
|
||||
}
|
||||
}
|
||||
// Manual swap
|
||||
uint8_t temp = arr[i + 1];
|
||||
arr[i + 1] = arr[high];
|
||||
arr[high] = temp;
|
||||
return (i + 1);
|
||||
};
|
||||
|
||||
// Quick Sort
|
||||
int16_t stack[SDSORT_LIMIT + 1];
|
||||
int16_t top = -1; // Initialize top of stack
|
||||
|
||||
int16_t low = 0, high = fileCnt - 1;
|
||||
|
||||
// Push initial values to the stack
|
||||
stack[++top] = low;
|
||||
stack[++top] = high;
|
||||
|
||||
// Pop from stack while not empty
|
||||
while (top >= 0) {
|
||||
high = stack[top--];
|
||||
low = stack[top--];
|
||||
|
||||
// Set pivot element at correct position
|
||||
const int16_t pivot = partition(sort_order, low, high);
|
||||
|
||||
// If elements are on left side, push to stack
|
||||
if (pivot - 1 > low) {
|
||||
stack[++top] = low;
|
||||
stack[++top] = pivot - 1;
|
||||
}
|
||||
// If elements are on right side, push to stack
|
||||
if (pivot + 1 < high) {
|
||||
stack[++top] = pivot + 1;
|
||||
stack[++top] = high;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#else
|
||||
bubblesort(sort_order, fileCnt);
|
||||
#endif
|
||||
{
|
||||
// Bubble Sort
|
||||
for (int16_t i = fileCnt; --i;) {
|
||||
bool didSwap = false;
|
||||
int16_t o1 = sort_order[0];
|
||||
#if DISABLED(SDSORT_USES_RAM)
|
||||
// By default re-read the names from SD for every compare
|
||||
// retaining only two filenames at a time. This is very
|
||||
// slow but is safest and uses minimal RAM.
|
||||
selectFileByIndex(o1); // Pre-fetch the first entry and save it
|
||||
strcpy(name1, longest_filename()); // so the loop only needs one fetch
|
||||
#if HAS_FOLDER_SORTING
|
||||
bool dir1 = flag.filenameIsDir;
|
||||
#endif
|
||||
if ((i & 0x7) == 7) hal.watchdog_refresh();
|
||||
#endif
|
||||
|
||||
for (int16_t j = 0; j < i; ++j) {
|
||||
const int16_t o2 = sort_order[j + 1];
|
||||
|
||||
// Compare names from the array or just the two buffered names
|
||||
auto _sort_cmp_file = [](char * const n1, char * const n2) -> bool {
|
||||
const bool sort = strcasecmp(n1, n2) > 0;
|
||||
return (TERN(SDSORT_GCODE, sort_alpha == AS_REV, ENABLED(SDSORT_REVERSE))) ? !sort : sort;
|
||||
};
|
||||
#define _SORT_CMP_FILE() _sort_cmp_file(TERN(SDSORT_USES_RAM, sortnames[o1], name1), TERN(SDSORT_USES_RAM, sortnames[o2], name2))
|
||||
|
||||
#if HAS_FOLDER_SORTING
|
||||
#if ENABLED(SDSORT_USES_RAM)
|
||||
// Folder sorting needs an index and bit to test for folder-ness.
|
||||
#define _SORT_CMP_DIR(fs) (IS_DIR(o1) == IS_DIR(o2) ? _SORT_CMP_FILE() : IS_DIR(fs > 0 ? o1 : o2))
|
||||
#else
|
||||
#define _SORT_CMP_DIR(fs) ((dir1 == flag.filenameIsDir) ? _SORT_CMP_FILE() : (fs > 0 ? dir1 : !dir1))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// The most economical method reads names as-needed
|
||||
// throughout the loop. Slow if there are many.
|
||||
#if DISABLED(SDSORT_USES_RAM)
|
||||
selectFileByIndex(o2);
|
||||
const bool dir2 = flag.filenameIsDir;
|
||||
char * const name2 = longest_filename(); // Use the string in-place
|
||||
if ((i & 0x7) == 7) hal.watchdog_refresh();
|
||||
#endif
|
||||
|
||||
// Sort the current pair according to settings.
|
||||
if (
|
||||
#if HAS_FOLDER_SORTING
|
||||
#if ENABLED(SDSORT_GCODE)
|
||||
sort_folders ? _SORT_CMP_DIR(sort_folders) : _SORT_CMP_FILE()
|
||||
#else
|
||||
_SORT_CMP_DIR(SDSORT_FOLDERS)
|
||||
#endif
|
||||
#else
|
||||
_SORT_CMP_FILE()
|
||||
#endif
|
||||
) {
|
||||
// Reorder the index, indicate that sorting happened
|
||||
// Note that the next o1 will be the current o1. No new fetch needed.
|
||||
sort_order[j] = o2;
|
||||
sort_order[j + 1] = o1;
|
||||
didSwap = true;
|
||||
}
|
||||
else {
|
||||
// The next o1 is the current o2. No new fetch needed.
|
||||
o1 = o2;
|
||||
#if DISABLED(SDSORT_USES_RAM)
|
||||
TERN_(HAS_FOLDER_SORTING, dir1 = dir2);
|
||||
strcpy(name1, name2);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (!didSwap) break;
|
||||
}
|
||||
}
|
||||
#endif // Bubble Sort
|
||||
|
||||
// Using RAM but not keeping names around
|
||||
#if ENABLED(SDSORT_USES_RAM) && DISABLED(SDSORT_CACHE_NAMES)
|
||||
|
|
|
|||
|
|
@ -403,10 +403,6 @@ private:
|
|||
#endif // SDSORT_USES_RAM
|
||||
|
||||
static void flush_presort();
|
||||
static bool sort_cmp_files(const int16_t o1, const int16_t o2);
|
||||
static int16_t partition(uint8_t* arr, int16_t low, int16_t high);
|
||||
static void quicksort(uint8_t* arr, int16_t low, int16_t high);
|
||||
static void bubblesort(uint8_t* arr, int16_t fileCnt);
|
||||
#endif // SDCARD_SORT_ALPHA
|
||||
|
||||
//
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue