quicksort

This commit is contained in:
PavelSindler 2017-10-02 03:59:41 +02:00
parent b2552b8e0e
commit 5a35212231
4 changed files with 120 additions and 33 deletions

View File

@ -268,7 +268,8 @@
#define SDSORT_USES_STACK false // Prefer the stack for pre-sorting to give back some SRAM. (Negated by next 2 options.) #define SDSORT_USES_STACK false // Prefer the stack for pre-sorting to give back some SRAM. (Negated by next 2 options.)
#define SDSORT_CACHE_NAMES false // Keep sorted items in RAM longer for speedy performance. Most expensive option. #define SDSORT_CACHE_NAMES false // Keep sorted items in RAM longer for speedy performance. Most expensive option.
#define SDSORT_DYNAMIC_RAM false // Use dynamic allocation (within SD menus). Least expensive option. Set SDSORT_LIMIT before use! #define SDSORT_DYNAMIC_RAM false // Use dynamic allocation (within SD menus). Least expensive option. Set SDSORT_LIMIT before use!
#define SDSORT_POINTERS false //stores adresses of filenames on stack #define SDSORT_POINTERS false //stores adresses of filenames on stack
#define QUICKSORT
#endif #endif
#if defined(SDCARD_SORT_ALPHA) #if defined(SDCARD_SORT_ALPHA)

View File

@ -1113,34 +1113,51 @@ int16_t SdBaseFile::read(void* buf, uint16_t nbyte) {
int8_t SdBaseFile::readDir(dir_t* dir, char* longFilename) { int8_t SdBaseFile::readDir(dir_t* dir, char* longFilename) {
int16_t n; int16_t n;
// if not a directory file or miss-positioned return an error // if not a directory file or miss-positioned return an error
if (!isDir() || (0X1F & curPosition_)) return -1; if (!isDir() || (0X1F & curPosition_)) {
SERIAL_ECHOLNPGM("return -1");
return -1;
}
//If we have a longFilename buffer, mark it as invalid. If we find a long filename it will be filled automaticly. //If we have a longFilename buffer, mark it as invalid. If we find a long filename it will be filled automaticly.
if (longFilename != NULL) if (longFilename != NULL)
{ {
// SERIAL_ECHOPGM("; reseting long filename; ");
longFilename[0] = '\0'; longFilename[0] = '\0';
} }
//int i_pom = 0;
while (1) { while (1) {
n = read(dir, sizeof(dir_t)); n = read(dir, sizeof(dir_t));
/*SERIAL_ECHOPGM("Jsem uvnitr: "); /*SERIAL_ECHOPGM("Jsem uvnitr: ");
MYSERIAL.print(n); MYSERIAL.print(n);
uint32_t pom = curPosition(); uint32_t pom = curPosition();
SERIAL_ECHOPGM(": "); SERIAL_ECHOPGM(": ");
MYSERIAL.println(pom, 10);*/ MYSERIAL.println(pom, 10);*/
//SERIAL_ECHOPGM("i: ");
//MYSERIAL.println(i_pom++);
if (n != sizeof(dir_t)) return n == 0 ? 0 : -1; if (n != sizeof(dir_t)) return n == 0 ? 0 : -1;
// last entry if DIR_NAME_FREE // last entry if DIR_NAME_FREE
if (dir->name[0] == DIR_NAME_FREE) return 0; if (dir->name[0] == DIR_NAME_FREE) {
return 0;
SERIAL_ECHOLNPGM("DIR_NAME_FREE");
}
// skip empty entries and entry for . and .. // skip empty entries and entry for . and ..
if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') continue; if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') {
//SERIAL_ECHOLNPGM("Empty entry, . or ..");
continue;
}
//Fill the long filename if we have a long filename entry, //Fill the long filename if we have a long filename entry,
// long filename entries are stored before the actual filename. // long filename entries are stored before the actual filename.
if (DIR_IS_LONG_NAME(dir) && longFilename != NULL) if (DIR_IS_LONG_NAME(dir) && longFilename != NULL)
{ {
//SERIAL_ECHOLNPGM("We have long filename entry");
vfat_t *VFAT = (vfat_t*)dir; vfat_t *VFAT = (vfat_t*)dir;
//Sanity check the VFAT entry. The first cluster is always set to zero. And th esequence number should be higher then 0 //Sanity check the VFAT entry. The first cluster is always set to zero. And th esequence number should be higher then 0
if (VFAT->firstClusterLow == 0 && (VFAT->sequenceNumber & 0x1F) > 0 && (VFAT->sequenceNumber & 0x1F) <= MAX_VFAT_ENTRIES) if (VFAT->firstClusterLow == 0 && (VFAT->sequenceNumber & 0x1F) > 0 && (VFAT->sequenceNumber & 0x1F) <= MAX_VFAT_ENTRIES)
{ {
//SERIAL_ECHOPGM("VFAT Entries no:");
//MYSERIAL.println(VFAT->sequenceNumber & 0x1F);
//TODO: Store the filename checksum to verify if a none-long filename aware system modified the file table. //TODO: Store the filename checksum to verify if a none-long filename aware system modified the file table.
n = ((VFAT->sequenceNumber & 0x1F) - 1) * 13; n = ((VFAT->sequenceNumber & 0x1F) - 1) * 13;
longFilename[n+0] = VFAT->name1[0]; longFilename[n+0] = VFAT->name1[0];
@ -1157,8 +1174,11 @@ int8_t SdBaseFile::readDir(dir_t* dir, char* longFilename) {
longFilename[n+11] = VFAT->name3[0]; longFilename[n+11] = VFAT->name3[0];
longFilename[n+12] = VFAT->name3[1]; longFilename[n+12] = VFAT->name3[1];
//If this VFAT entry is the last one, add a NUL terminator at the end of the string //If this VFAT entry is the last one, add a NUL terminator at the end of the string
if (VFAT->sequenceNumber & 0x40) if (VFAT->sequenceNumber & 0x40) {
longFilename[n+13] = '\0'; longFilename[n + 13] = '\0';
//SERIAL_ECHOPGM("LOng F");
//MYSERIAL.println(longFilename);
}
} }
} }
// return if normal file or subdirectory // return if normal file or subdirectory

View File

@ -65,8 +65,13 @@ void CardReader::lsDive_pointer(const char *prepend, SdFile parent, const char *
//parent.seekSet = //parent.seekSet =
// Read the next entry from a directory // Read the next entry from a directory
//SERIAL_ECHOPGM("Cur pos before.: ");
//uint32_t pom = parent.curPosition();
//MYSERIAL.println(pom, 10);
parent.readDir(p, longFilename); parent.readDir(p, longFilename);
//SERIAL_ECHOPGM("Cur pos.: ");
//pom = parent.curPosition();
//MYSERIAL.println(pom, 10);
uint8_t pn0 = p.name[0]; uint8_t pn0 = p.name[0];
@ -103,9 +108,9 @@ void CardReader::lsDive(const char *prepend, SdFile parent, const char * const m
//SERIAL_ECHOPGM(": "); //SERIAL_ECHOPGM(": ");
//MYSERIAL.print(pom, 10); //MYSERIAL.print(pom, 10);
//SERIAL_ECHOPGM("; "); //SERIAL_ECHOPGM("; ");
/*SERIAL_ECHOPGM("Cur pos.: "); //SERIAL_ECHOPGM("Cur pos.: ");
uint32_t pom = parent.curPosition(); //uint32_t pom = parent.curPosition();
MYSERIAL.println(pom, 10);*/ //MYSERIAL.println(pom, 10);
// If the entry is a directory and the action is LS_SerialPrint // If the entry is a directory and the action is LS_SerialPrint
if (DIR_IS_SUBDIR(&p) && lsAction != LS_Count && lsAction != LS_GetFilename) { if (DIR_IS_SUBDIR(&p) && lsAction != LS_Count && lsAction != LS_GetFilename) {
@ -168,6 +173,7 @@ void CardReader::lsDive(const char *prepend, SdFile parent, const char * const m
case LS_GetFilename: case LS_GetFilename:
//SERIAL_ECHOPGM("File: "); //SERIAL_ECHOPGM("File: ");
createFilename(filename, p); createFilename(filename, p);
//MYSERIAL.println(p.name);
/*MYSERIAL.println(filename); /*MYSERIAL.println(filename);
SERIAL_ECHOPGM("Write date: "); SERIAL_ECHOPGM("Write date: ");
writeDate = p.lastWriteDate; writeDate = p.lastWriteDate;
@ -688,24 +694,12 @@ void CardReader::getfilename(uint16_t nr, const char * const match/*=NULL*/)
void CardReader::getfilename_simple(uint32_t position, const char * const match/*=NULL*/) void CardReader::getfilename_simple(uint32_t position, const char * const match/*=NULL*/)
{ {
//SERIAL_ECHOPGM("FILE NR:");
//MYSERIAL.println(position);
curDir = &workDir; curDir = &workDir;
//curDir = curDir + nr * 32 * 8; //32 bytes per entry
lsAction = LS_GetFilename; lsAction = LS_GetFilename;
//nrFiles = nr; nrFiles = 0;
//curDir->rewind(); //curDir->rewind();
curDir->seekSet(position); curDir->seekSet(position);
//curDir->setpos(32*nr); lsDive("", *curDir, match);
lsDive_pointer("", *curDir, match);
/*SERIAL_ECHOPGM("; Position:");
uint32_t pom = curDir->curPosition();
MYSERIAL.print(pom, 10);
SERIAL_ECHOPGM("; Cluster:");
MYSERIAL.println(curDir->curCluster());*/
} }
@ -771,6 +765,56 @@ void CardReader::getfilename_sorted(const uint16_t nr) {
); );
} }
void CardReader::swap(uint8_t array[], uint8_t left, uint8_t right) {
uint8_t tmp = array[right];
array[right] = array[left];
array[left] = tmp;
//SERIAL_ECHOLNPGM("Did swap");
}
void CardReader::quicksort(uint8_t array[], uint8_t left, uint8_t right, uint32_t positions[]) {
if (left < right) {
char name_left[LONG_FILENAME_LENGTH + 1];
char name_i[LONG_FILENAME_LENGTH + 1];
uint16_t creation_time_left;
uint16_t creation_date_left;
uint8_t boundary = left;
for (uint8_t i = left+1; i < right; i++) {
uint8_t o_left = array[left];
uint8_t o_i = array[i];
getfilename_simple(positions[o_left]);
strcpy(name_left, LONGEST_FILENAME); // save (or getfilename below will trounce it)
creation_date_left = creationDate;
creation_time_left = creationTime;
getfilename_simple(positions[o_i]);
/*SERIAL_ECHOLNPGM(" ");
MYSERIAL.print(int(o_left));
SERIAL_ECHOPGM(": ");
MYSERIAL.print(positions[o_left]);
SERIAL_ECHOPGM(": ");
MYSERIAL.println(name_left);
MYSERIAL.print(int(o_i));
SERIAL_ECHOPGM(": ");
MYSERIAL.print(positions[o_i]);
SERIAL_ECHOPGM(": ");
MYSERIAL.println(LONGEST_FILENAME);*/
strcpy(name_i, LONGEST_FILENAME);
if (strcasecmp(name_left, name_i) > 0) {
swap(array, i, ++boundary);
}
}
swap(array, left, boundary);
quicksort(array, left, boundary, positions);
quicksort(array, boundary + 1, right, positions);
}
}
/** /**
* Read all the files and produce a sort key * Read all the files and produce a sort key
* *
@ -842,6 +886,7 @@ void CardReader::presort() {
#else // !SDSORT_USES_RAM #else // !SDSORT_USES_RAM
// uint32_t clusters [fileCnt]; // uint32_t clusters [fileCnt];
uint32_t positions [fileCnt]; uint32_t positions [fileCnt];
// char *names[fileCnt];
// By default re-read the names from SD for every compare // By default re-read the names from SD for every compare
@ -852,16 +897,32 @@ void CardReader::presort() {
uint16_t creation_date_bckp; uint16_t creation_date_bckp;
#endif #endif
position = 0;
if (fileCnt > 1) { if (fileCnt > 1) {
// Init sort order. // Init sort order.
for (uint16_t i = 0; i < fileCnt; i++) { for (uint16_t i = 0; i < fileCnt; i++) {
sort_order[i] = i; sort_order[i] = i;
getfilename(i); /*MYSERIAL.print(i);
SERIAL_ECHOPGM(": ");
MYSERIAL.print(position);
SERIAL_ECHOPGM("; ");
MYSERIAL.print(cluster);
SERIAL_ECHOPGM(" ");*/
positions[i] = position;
getfilename(i);
//MYSERIAL.print(LONGEST_FILENAME);
//names[i] =
//clusters[i] = cluster; //clusters[i] = cluster;
positions[i] = position-96; //if (longFilename[0]) SERIAL_ECHOPGM("; Long; ");
//MYSERIAL.println(i); //MYSERIAL.println(i);
//MYSERIAL.println(position); /*SERIAL_ECHOPGM("; ");
MYSERIAL.print(position);
SERIAL_ECHOPGM("; ");
MYSERIAL.print(positions[i]);
SERIAL_ECHOPGM("; ");
MYSERIAL.println(cluster);*/
// If using RAM then read all filenames now. // If using RAM then read all filenames now.
#if SDSORT_USES_RAM #if SDSORT_USES_RAM
getfilename(i); getfilename(i);
@ -892,9 +953,12 @@ void CardReader::presort() {
#endif #endif
#endif #endif
} }
SERIAL_ECHOPGM("Mezicas:"); /*SERIAL_ECHOPGM("Mezicas:");
MYSERIAL.println(millis() - start_time); MYSERIAL.println(millis() - start_time);*/
// Bubble Sort
#ifdef QUICKSORT
quicksort(sort_order, 0, fileCnt - 1, positions);
#else //Qicksort not defined, use Bubble Sort
uint16_t counter = 0; uint16_t counter = 0;
for (uint16_t i = fileCnt; --i;) { for (uint16_t i = fileCnt; --i;) {
bool didSwap = false; bool didSwap = false;
@ -982,7 +1046,7 @@ void CardReader::presort() {
} }
if (!didSwap) break; if (!didSwap) break;
} //end of bubble sort loop } //end of bubble sort loop
#endif
// Using RAM but not keeping names around // Using RAM but not keeping names around
#if (SDSORT_USES_RAM && !SDSORT_CACHE_NAMES) #if (SDSORT_USES_RAM && !SDSORT_CACHE_NAMES)
#if SDSORT_DYNAMIC_RAM #if SDSORT_DYNAMIC_RAM

View File

@ -45,6 +45,8 @@ public:
#ifdef SDCARD_SORT_ALPHA #ifdef SDCARD_SORT_ALPHA
void presort(); void presort();
void swap(uint8_t array[], uint8_t left, uint8_t right);
void quicksort(uint8_t array[], uint8_t left, uint8_t right, uint32_t positions[]);
void getfilename_sorted(const uint16_t nr); void getfilename_sorted(const uint16_t nr);
#if SDSORT_GCODE #if SDSORT_GCODE
FORCE_INLINE void setSortOn(bool b) { sort_alpha = b; presort(); } FORCE_INLINE void setSortOn(bool b) { sort_alpha = b; presort(); }