Merge pull request #3054 from espr14/insert_sort

File: use insert sort
This commit is contained in:
Alex Voinea 2022-07-15 15:44:04 +03:00 committed by GitHub
commit 2059e40596
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 118 additions and 154 deletions

View file

@ -229,8 +229,9 @@
#define SD_SORT_TIME 0
#define SD_SORT_ALPHA 1
#define SD_SORT_NONE 2
// #define SHELLSORT
#define INSERTSORT
// #define SORTING_DUMP
// #define SORTING_SPEEDTEST
#define SDSORT_LIMIT 100 // Maximum number of sorted items (10-256).
#define FOLDER_SORTING -1 // -1=above 0=none 1=below

View file

@ -64,5 +64,18 @@ bool Timer<T>::expired(T msPeriod)
return expired;
}
/**
* @brief Ticks since the timer was started
*
* This function returns 0 if the timer is not started. Otherwise, it returns
* the time in milliseconds since the timer was started.
* This function is expected to handle wrap around of time register well.
* The maximum elapsed time is dictated by the template type
*/
template<typename T>
T Timer<T>::elapsed() {
return m_isRunning ? (_millis() - m_started) : 0;
}
template class Timer<unsigned long>;
template class Timer<unsigned short>;

View file

@ -22,6 +22,7 @@ public:
void stop(){m_isRunning = false;}
bool running()const {return m_isRunning;}
bool expired(T msPeriod);
T elapsed();
protected:
T started()const {return m_started;}
private:

View file

@ -791,136 +791,119 @@ void CardReader::getfilename_sorted(const uint16_t nr, uint8_t sdSort) {
* - Most RAM: Buffer the directory and return filenames from RAM
*/
void CardReader::presort() {
// Throw away old sort index
flush_presort();
if (farm_mode || IS_SD_INSERTED == false) return; //sorting is not used in farm mode
uint8_t sdSort = eeprom_read_byte((uint8_t*)EEPROM_SD_SORT);
if (sdSort == SD_SORT_NONE) return; //sd sort is turned off
KEEPALIVE_STATE(IN_HANDLER);
// Throw away old sort index
flush_presort();
// If there are files, sort up to the limit
uint16_t fileCnt = getnrfilenames();
if (fileCnt > 0) {
// Never sort more than the max allowed
// If you use folders to organize, 20 may be enough
if (fileCnt > SDSORT_LIMIT) {
lcd_show_fullscreen_message_and_wait_P(_i("Some files will not be sorted. Max. No. of files in 1 folder for sorting is 100."));////MSG_FILE_CNT c=20 r=6
if (sdSort != SD_SORT_NONE) {
lcd_show_fullscreen_message_and_wait_P(_i("Some files will not be sorted. Max. No. of files in 1 folder for sorting is 100."));////MSG_FILE_CNT c=20 r=6
}
fileCnt = SDSORT_LIMIT;
}
// 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];
uint16_t crmod_time_bckp;
uint16_t crmod_date_bckp;
sort_count = fileCnt;
// Init sort order.
for (uint16_t i = 0; i < fileCnt; i++) {
if (!IS_SD_INSERTED) return;
manage_heater();
if (i == 0)
getfilename(0);
else
getfilename_next(position);
sort_entries[i] = position >> 5;
}
#if HAS_FOLDER_SORTING
uint16_t dirCnt = 0;
#endif
if ((fileCnt > 1) && (sdSort != SD_SORT_NONE)) {
if (fileCnt > 1) {
// Init sort order.
uint8_t sort_order[fileCnt];
for (uint16_t i = 0; i < fileCnt; i++) {
if (!IS_SD_INSERTED) return;
manage_heater();
if (i == 0)
getfilename(0);
else
getfilename_next(position);
sort_order[i] = i;
sort_entries[i] = position >> 5;
#if HAS_FOLDER_SORTING
if (filenameIsDir) dirCnt++;
#endif
}
#ifdef SORTING_SPEEDTEST
LongTimer sortingSpeedtestTimer;
sortingSpeedtestTimer.start();
#endif //SORTING_SPEEDTEST
#ifdef QUICKSORT
quicksort(0, fileCnt - 1);
#elif defined(SHELLSORT)
// 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];
uint16_t crmod_time_bckp;
uint16_t crmod_date_bckp;
#ifdef INSERTSORT
#define _SORT_CMP_NODIR() (strcasecmp(name1, name2) < 0) //true if lowercase(name1) < lowercase(name2)
#define _SORT_CMP_TIME_NODIR() (((crmod_date_bckp == crmodDate) && (crmod_time_bckp < crmodTime)) || (crmod_date_bckp < crmodDate))
#define _SORT_CMP_TIME_NODIR() (((crmod_date_bckp == crmodDate) && (crmod_time_bckp > crmodTime)) || (crmod_date_bckp > crmodDate))
#if HAS_FOLDER_SORTING
#define _SORT_CMP_DIR(fs) ((dir1 == filenameIsDir) ? _SORT_CMP_NODIR() : (fs < 0 ? dir1 : !dir1))
#define _SORT_CMP_TIME_DIR(fs) ((dir1 == filenameIsDir) ? _SORT_CMP_TIME_NODIR() : (fs < 0 ? dir1 : !dir1))
#endif
for (uint8_t runs = 0; runs < 2; runs++)
{
//run=0: sorts all files and moves folders to the beginning
//run=1: assumes all folders are at the beginning of the list and sorts them
uint16_t sortCountFiles = 0;
if (runs == 0)
{
sortCountFiles = fileCnt;
}
#if HAS_FOLDER_SORTING
else
{
sortCountFiles = dirCnt;
}
#endif
uint16_t counter = 0;
uint16_t total = 0;
for (uint16_t i = sortCountFiles/2; i > 0; i /= 2) total += sortCountFiles - i; //total runs for progress bar
menu_progressbar_init(
total, (runs == 0)
? _i("Sorting files") ////MSG_SORTING_FILES c=20
: _i("Sorting folders")); ////MSG_SORTING_FOLDERS c=20
for (uint16_t gap = sortCountFiles/2; gap > 0; gap /= 2)
{
for (uint16_t i = gap; i < sortCountFiles; i++)
{
if (!IS_SD_INSERTED) return;
menu_progressbar_update(counter);
counter++;
manage_heater();
uint8_t orderBckp = sort_order[i];
getfilename_simple(sort_entries[orderBckp]);
strcpy(name1, LONGEST_FILENAME); // save (or getfilename below will trounce it)
crmod_date_bckp = crmodDate;
crmod_time_bckp = crmodTime;
#if HAS_FOLDER_SORTING
bool dir1 = filenameIsDir;
#endif
uint16_t j = i;
getfilename_simple(sort_entries[sort_order[j - gap]]);
char *name2 = LONGEST_FILENAME; // use the string in-place
#if HAS_FOLDER_SORTING
while (j >= gap && ((sdSort == SD_SORT_TIME)?_SORT_CMP_TIME_DIR(FOLDER_SORTING):_SORT_CMP_DIR(FOLDER_SORTING)))
#else
while (j >= gap && ((sdSort == SD_SORT_TIME)?_SORT_CMP_TIME_NODIR():_SORT_CMP_NODIR()))
#endif
{
sort_order[j] = sort_order[j - gap];
j -= gap;
#ifdef SORTING_DUMP
for (uint16_t z = 0; z < sortCountFiles; z++)
{
printf_P(PSTR("%2u "), sort_order[z]);
}
printf_P(PSTR("i%2d j%2d gap%2d orderBckp%2d\n"), i, j, gap, orderBckp);
#endif
if (j < gap) break;
getfilename_simple(sort_entries[sort_order[j - gap]]);
name2 = LONGEST_FILENAME; // use the string in-place
}
sort_order[j] = orderBckp;
}
}
}
uint16_t counter = 0;
menu_progressbar_init(fileCnt * fileCnt / 2, _i("Sorting files"));
for (uint16_t i = 1; i < fileCnt; ++i){
// if (!IS_SD_INSERTED) return;
menu_progressbar_update(counter);
counter += i;
/// pop the position
const uint16_t o1 = sort_entries[i];
getfilename_simple(o1);
strcpy(name1, LONGEST_FILENAME); // save (or getfilename below will trounce it)
crmod_date_bckp = crmodDate;
crmod_time_bckp = crmodTime;
#if HAS_FOLDER_SORTING
bool dir1 = filenameIsDir;
#endif
/// find proper place
uint16_t j = i;
for (; j > 0; --j){
if (!IS_SD_INSERTED) return;
#ifdef SORTING_DUMP
for (uint16_t z = 0; z < fileCnt; z++){
printf_P(PSTR("%2u "), sort_entries[z]);
}
MYSERIAL.println();
#endif
manage_heater();
const uint16_t o2 = sort_entries[j - 1];
getfilename_simple(o2);
char *name2 = LONGEST_FILENAME; // use the string in-place
// Sort the current pair according to settings.
if (
#if HAS_FOLDER_SORTING
(sdSort == SD_SORT_TIME && _SORT_CMP_TIME_DIR(FOLDER_SORTING)) || (sdSort == SD_SORT_ALPHA && !_SORT_CMP_DIR(FOLDER_SORTING))
#else
(sdSort == SD_SORT_TIME && _SORT_CMP_TIME_NODIR()) || (sdSort == SD_SORT_ALPHA && !_SORT_CMP_NODIR())
#endif
)
{
break;
} else {
#ifdef SORTING_DUMP
puts_P(PSTR("shift"));
#endif
sort_entries[j] = o2;
}
}
/// place the position
sort_entries[j] = o1;
}
#else //Bubble Sort
@ -947,22 +930,22 @@ void CardReader::presort() {
#ifdef SORTING_DUMP
for (uint16_t z = 0; z < fileCnt; z++)
{
printf_P(PSTR("%2u "), sort_order[z]);
printf_P(PSTR("%2u "), sort_entries[z]);
}
MYSERIAL.println();
#endif
manage_heater();
const uint16_t o1 = sort_order[j], o2 = sort_order[j + 1];
const uint16_t o1 = sort_entries[j], o2 = sort_entries[j + 1];
counter++;
getfilename_simple(sort_entries[o1]);
getfilename_simple(o1);
strcpy(name1, LONGEST_FILENAME); // save (or getfilename below will trounce it)
crmod_date_bckp = crmodDate;
crmod_time_bckp = crmodTime;
#if HAS_FOLDER_SORTING
bool dir1 = filenameIsDir;
#endif
getfilename_simple(sort_entries[o2]);
getfilename_simple(o2);
char *name2 = LONGEST_FILENAME; // use the string in-place
// Sort the current pair according to settings.
@ -978,51 +961,27 @@ void CardReader::presort() {
puts_P(PSTR("swap"));
#endif
sort_order[j] = o2;
sort_order[j + 1] = o1;
sort_entries[j] = o2;
sort_entries[j + 1] = o1;
didSwap = true;
}
}
if (!didSwap) break;
} //end of bubble sort loop
#endif
#ifdef SORTING_SPEEDTEST
printf_P(PSTR("sortingSpeedtestTimer:%lu\n"), sortingSpeedtestTimer.elapsed());
#endif //SORTING_SPEEDTEST
#ifdef SORTING_DUMP
for (uint16_t z = 0; z < fileCnt; z++)
printf_P(PSTR("%2u "), sort_order[z]);
printf_P(PSTR("%2u "), sort_entries[z]);
SERIAL_PROTOCOLLN();
#endif
uint8_t sort_order_reverse_index[fileCnt];
for (uint8_t i = 0; i < fileCnt; i++)
sort_order_reverse_index[sort_order[i]] = i;
for (uint8_t i = 0; i < fileCnt; i++)
{
if (sort_order_reverse_index[i] != i)
{
uint32_t el = sort_entries[i];
uint8_t idx = sort_order_reverse_index[i];
while (idx != i)
{
uint32_t el1 = sort_entries[idx];
uint8_t idx1 = sort_order_reverse_index[idx];
sort_order_reverse_index[idx] = idx;
sort_entries[idx] = el;
idx = idx1;
el = el1;
}
sort_order_reverse_index[idx] = idx;
sort_entries[idx] = el;
}
}
menu_progressbar_finish();
}
else {
getfilename(0);
sort_entries[0] = position >> 5;
}
sort_count = fileCnt;
}
lcd_update(2);

View file

@ -63,10 +63,6 @@ public:
#ifdef SDCARD_SORT_ALPHA
void presort();
#ifdef SDSORT_QUICKSORT
void swap(uint8_t left, uint8_t right);
void quicksort(uint8_t left, uint8_t right);
#endif //SDSORT_QUICKSORT
void getfilename_sorted(const uint16_t nr, uint8_t sdSort);
#endif

View file

@ -6440,10 +6440,7 @@ void lcd_sdcard_menu()
{
//load filename to memory.
#ifdef SDCARD_SORT_ALPHA
if (_md->sdSort == SD_SORT_NONE)
card.getfilename(i);
else
card.getfilename_sorted(i, _md->sdSort);
card.getfilename_sorted(i, _md->sdSort);
#else
card.getfilename(i);
#endif
@ -6471,10 +6468,7 @@ void lcd_sdcard_menu()
{
//load filename to memory.
#ifdef SDCARD_SORT_ALPHA
if (_md->sdSort == SD_SORT_NONE)
card.getfilename(_md->selectedFileID);
else
card.getfilename_sorted(_md->selectedFileID, _md->sdSort);
card.getfilename_sorted(_md->selectedFileID, _md->sdSort);
#else
card.getfilename(_md->selectedFileID);
#endif