Browse Source

Merge pull request #3054 from espr14/insert_sort

File: use insert sort
Alex Voinea 2 years ago
parent
commit
2059e40596
6 changed files with 120 additions and 156 deletions
  1. 2 1
      Firmware/Configuration_adv.h
  2. 13 0
      Firmware/Timer.cpp
  3. 1 0
      Firmware/Timer.h
  4. 102 143
      Firmware/cardreader.cpp
  5. 0 4
      Firmware/cardreader.h
  6. 2 8
      Firmware/ultralcd.cpp

+ 2 - 1
Firmware/Configuration_adv.h

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

+ 13 - 0
Firmware/Timer.cpp

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

+ 1 - 0
Firmware/Timer.h

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

+ 102 - 143
Firmware/cardreader.cpp

@@ -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;
-
-		#if HAS_FOLDER_SORTING
-		uint16_t dirCnt = 0;
-		#endif
-
-		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
-			}
+		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 ((fileCnt > 1) && (sdSort != SD_SORT_NONE)) {
 
-#ifdef QUICKSORT
-			quicksort(0, fileCnt - 1);
-#elif defined(SHELLSORT)
+#ifdef SORTING_SPEEDTEST
+			LongTimer sortingSpeedtestTimer;
+			sortingSpeedtestTimer.start();
+#endif //SORTING_SPEEDTEST
+
+			// 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);

+ 0 - 4
Firmware/cardreader.h

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

+ 2 - 8
Firmware/ultralcd.cpp

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