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_TIME 0
#define SD_SORT_ALPHA 1 #define SD_SORT_ALPHA 1
#define SD_SORT_NONE 2 #define SD_SORT_NONE 2
// #define SHELLSORT #define INSERTSORT
// #define SORTING_DUMP // #define SORTING_DUMP
// #define SORTING_SPEEDTEST
#define SDSORT_LIMIT 100 // Maximum number of sorted items (10-256). #define SDSORT_LIMIT 100 // Maximum number of sorted items (10-256).
#define FOLDER_SORTING -1 // -1=above 0=none 1=below #define FOLDER_SORTING -1 // -1=above 0=none 1=below

View File

@ -64,5 +64,18 @@ bool Timer<T>::expired(T msPeriod)
return expired; 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 long>;
template class Timer<unsigned short>; template class Timer<unsigned short>;

View File

@ -22,6 +22,7 @@ public:
void stop(){m_isRunning = false;} void stop(){m_isRunning = false;}
bool running()const {return m_isRunning;} bool running()const {return m_isRunning;}
bool expired(T msPeriod); bool expired(T msPeriod);
T elapsed();
protected: protected:
T started()const {return m_started;} T started()const {return m_started;}
private: 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 * - Most RAM: Buffer the directory and return filenames from RAM
*/ */
void CardReader::presort() { 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 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); 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); KEEPALIVE_STATE(IN_HANDLER);
// Throw away old sort index
flush_presort();
// If there are files, sort up to the limit // If there are files, sort up to the limit
uint16_t fileCnt = getnrfilenames(); uint16_t fileCnt = getnrfilenames();
if (fileCnt > 0) { if (fileCnt > 0) {
// Never sort more than the max allowed // Never sort more than the max allowed
// If you use folders to organize, 20 may be enough // If you use folders to organize, 20 may be enough
if (fileCnt > SDSORT_LIMIT) { 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; fileCnt = SDSORT_LIMIT;
} }
// By default re-read the names from SD for every compare sort_count = fileCnt;
// retaining only two filenames at a time. This is very
// slow but is safest and uses minimal RAM. // Init sort order.
char name1[LONG_FILENAME_LENGTH]; for (uint16_t i = 0; i < fileCnt; i++) {
uint16_t crmod_time_bckp; if (!IS_SD_INSERTED) return;
uint16_t crmod_date_bckp; manage_heater();
if (i == 0)
getfilename(0);
else
getfilename_next(position);
sort_entries[i] = position >> 5;
}
#if HAS_FOLDER_SORTING if ((fileCnt > 1) && (sdSort != SD_SORT_NONE)) {
uint16_t dirCnt = 0;
#endif
if (fileCnt > 1) { #ifdef SORTING_SPEEDTEST
// Init sort order. LongTimer sortingSpeedtestTimer;
uint8_t sort_order[fileCnt]; sortingSpeedtestTimer.start();
for (uint16_t i = 0; i < fileCnt; i++) { #endif //SORTING_SPEEDTEST
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 QUICKSORT // By default re-read the names from SD for every compare
quicksort(0, fileCnt - 1); // retaining only two filenames at a time. This is very
#elif defined(SHELLSORT) // 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_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 #if HAS_FOLDER_SORTING
#define _SORT_CMP_DIR(fs) ((dir1 == filenameIsDir) ? _SORT_CMP_NODIR() : (fs < 0 ? dir1 : !dir1)) #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)) #define _SORT_CMP_TIME_DIR(fs) ((dir1 == filenameIsDir) ? _SORT_CMP_TIME_NODIR() : (fs < 0 ? dir1 : !dir1))
#endif #endif
for (uint8_t runs = 0; runs < 2; runs++) uint16_t counter = 0;
{ menu_progressbar_init(fileCnt * fileCnt / 2, _i("Sorting files"));
//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 for (uint16_t i = 1; i < fileCnt; ++i){
uint16_t sortCountFiles = 0; // if (!IS_SD_INSERTED) return;
if (runs == 0) menu_progressbar_update(counter);
{ counter += i;
sortCountFiles = fileCnt;
} /// pop the position
#if HAS_FOLDER_SORTING const uint16_t o1 = sort_entries[i];
else getfilename_simple(o1);
{ strcpy(name1, LONGEST_FILENAME); // save (or getfilename below will trounce it)
sortCountFiles = dirCnt; crmod_date_bckp = crmodDate;
} crmod_time_bckp = crmodTime;
#endif #if HAS_FOLDER_SORTING
bool dir1 = filenameIsDir;
uint16_t counter = 0; #endif
uint16_t total = 0;
for (uint16_t i = sortCountFiles/2; i > 0; i /= 2) total += sortCountFiles - i; //total runs for progress bar /// find proper place
menu_progressbar_init( uint16_t j = i;
total, (runs == 0) for (; j > 0; --j){
? _i("Sorting files") ////MSG_SORTING_FILES c=20 if (!IS_SD_INSERTED) return;
: _i("Sorting folders")); ////MSG_SORTING_FOLDERS c=20
#ifdef SORTING_DUMP
for (uint16_t gap = sortCountFiles/2; gap > 0; gap /= 2) for (uint16_t z = 0; z < fileCnt; z++){
{ printf_P(PSTR("%2u "), sort_entries[z]);
for (uint16_t i = gap; i < sortCountFiles; i++) }
{ MYSERIAL.println();
if (!IS_SD_INSERTED) return; #endif
menu_progressbar_update(counter); manage_heater();
counter++; const uint16_t o2 = sort_entries[j - 1];
manage_heater(); getfilename_simple(o2);
uint8_t orderBckp = sort_order[i]; char *name2 = LONGEST_FILENAME; // use the string in-place
getfilename_simple(sort_entries[orderBckp]);
strcpy(name1, LONGEST_FILENAME); // save (or getfilename below will trounce it) // Sort the current pair according to settings.
crmod_date_bckp = crmodDate; if (
crmod_time_bckp = crmodTime; #if HAS_FOLDER_SORTING
#if HAS_FOLDER_SORTING (sdSort == SD_SORT_TIME && _SORT_CMP_TIME_DIR(FOLDER_SORTING)) || (sdSort == SD_SORT_ALPHA && !_SORT_CMP_DIR(FOLDER_SORTING))
bool dir1 = filenameIsDir; #else
#endif (sdSort == SD_SORT_TIME && _SORT_CMP_TIME_NODIR()) || (sdSort == SD_SORT_ALPHA && !_SORT_CMP_NODIR())
#endif
uint16_t j = i; )
getfilename_simple(sort_entries[sort_order[j - gap]]); {
char *name2 = LONGEST_FILENAME; // use the string in-place break;
#if HAS_FOLDER_SORTING } else {
while (j >= gap && ((sdSort == SD_SORT_TIME)?_SORT_CMP_TIME_DIR(FOLDER_SORTING):_SORT_CMP_DIR(FOLDER_SORTING))) #ifdef SORTING_DUMP
#else puts_P(PSTR("shift"));
while (j >= gap && ((sdSort == SD_SORT_TIME)?_SORT_CMP_TIME_NODIR():_SORT_CMP_NODIR())) #endif
#endif sort_entries[j] = o2;
{ }
sort_order[j] = sort_order[j - gap]; }
j -= gap; /// place the position
#ifdef SORTING_DUMP sort_entries[j] = o1;
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;
}
}
}
#else //Bubble Sort #else //Bubble Sort
@ -947,22 +930,22 @@ void CardReader::presort() {
#ifdef SORTING_DUMP #ifdef SORTING_DUMP
for (uint16_t z = 0; z < fileCnt; z++) for (uint16_t z = 0; z < fileCnt; z++)
{ {
printf_P(PSTR("%2u "), sort_order[z]); printf_P(PSTR("%2u "), sort_entries[z]);
} }
MYSERIAL.println(); MYSERIAL.println();
#endif #endif
manage_heater(); 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++; counter++;
getfilename_simple(sort_entries[o1]); getfilename_simple(o1);
strcpy(name1, LONGEST_FILENAME); // save (or getfilename below will trounce it) strcpy(name1, LONGEST_FILENAME); // save (or getfilename below will trounce it)
crmod_date_bckp = crmodDate; crmod_date_bckp = crmodDate;
crmod_time_bckp = crmodTime; crmod_time_bckp = crmodTime;
#if HAS_FOLDER_SORTING #if HAS_FOLDER_SORTING
bool dir1 = filenameIsDir; bool dir1 = filenameIsDir;
#endif #endif
getfilename_simple(sort_entries[o2]); getfilename_simple(o2);
char *name2 = LONGEST_FILENAME; // use the string in-place char *name2 = LONGEST_FILENAME; // use the string in-place
// Sort the current pair according to settings. // Sort the current pair according to settings.
@ -978,51 +961,27 @@ void CardReader::presort() {
puts_P(PSTR("swap")); puts_P(PSTR("swap"));
#endif #endif
sort_order[j] = o2; sort_entries[j] = o2;
sort_order[j + 1] = o1; sort_entries[j + 1] = o1;
didSwap = true; didSwap = true;
} }
} }
if (!didSwap) break; if (!didSwap) break;
} //end of bubble sort loop } //end of bubble sort loop
#endif #endif
#ifdef SORTING_SPEEDTEST
printf_P(PSTR("sortingSpeedtestTimer:%lu\n"), sortingSpeedtestTimer.elapsed());
#endif //SORTING_SPEEDTEST
#ifdef SORTING_DUMP #ifdef SORTING_DUMP
for (uint16_t z = 0; z < fileCnt; z++) for (uint16_t z = 0; z < fileCnt; z++)
printf_P(PSTR("%2u "), sort_order[z]); printf_P(PSTR("%2u "), sort_entries[z]);
SERIAL_PROTOCOLLN(); SERIAL_PROTOCOLLN();
#endif #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(); menu_progressbar_finish();
} }
else {
getfilename(0);
sort_entries[0] = position >> 5;
}
sort_count = fileCnt;
} }
lcd_update(2); lcd_update(2);

View File

@ -63,10 +63,6 @@ public:
#ifdef SDCARD_SORT_ALPHA #ifdef SDCARD_SORT_ALPHA
void presort(); 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); void getfilename_sorted(const uint16_t nr, uint8_t sdSort);
#endif #endif

View File

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