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_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_POINTERS false //stores adresses of filenames on stack
#define SDSORT_POINTERS false //stores adresses of filenames on stack
#define QUICKSORT
#endif
#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) {
int16_t n;
// 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 (longFilename != NULL)
{
// SERIAL_ECHOPGM("; reseting long filename; ");
longFilename[0] = '\0';
}
//int i_pom = 0;
while (1) {
n = read(dir, sizeof(dir_t));
/*SERIAL_ECHOPGM("Jsem uvnitr: ");
MYSERIAL.print(n);
uint32_t pom = curPosition();
SERIAL_ECHOPGM(": ");
MYSERIAL.println(pom, 10);*/
//SERIAL_ECHOPGM("i: ");
//MYSERIAL.println(i_pom++);
if (n != sizeof(dir_t)) return n == 0 ? 0 : -1;
// 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 ..
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,
// long filename entries are stored before the actual filename.
if (DIR_IS_LONG_NAME(dir) && longFilename != NULL)
{
//SERIAL_ECHOLNPGM("We have long filename entry");
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
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.
n = ((VFAT->sequenceNumber & 0x1F) - 1) * 13;
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+12] = VFAT->name3[1];
//If this VFAT entry is the last one, add a NUL terminator at the end of the string
if (VFAT->sequenceNumber & 0x40)
longFilename[n+13] = '\0';
if (VFAT->sequenceNumber & 0x40) {
longFilename[n + 13] = '\0';
//SERIAL_ECHOPGM("LOng F");
//MYSERIAL.println(longFilename);
}
}
}
// 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 =
// 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);
//SERIAL_ECHOPGM("Cur pos.: ");
//pom = parent.curPosition();
//MYSERIAL.println(pom, 10);
uint8_t pn0 = p.name[0];
@ -103,9 +108,9 @@ void CardReader::lsDive(const char *prepend, SdFile parent, const char * const m
//SERIAL_ECHOPGM(": ");
//MYSERIAL.print(pom, 10);
//SERIAL_ECHOPGM("; ");
/*SERIAL_ECHOPGM("Cur pos.: ");
uint32_t pom = parent.curPosition();
MYSERIAL.println(pom, 10);*/
//SERIAL_ECHOPGM("Cur pos.: ");
//uint32_t pom = parent.curPosition();
//MYSERIAL.println(pom, 10);
// If the entry is a directory and the action is LS_SerialPrint
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:
//SERIAL_ECHOPGM("File: ");
createFilename(filename, p);
//MYSERIAL.println(p.name);
/*MYSERIAL.println(filename);
SERIAL_ECHOPGM("Write date: ");
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*/)
{
//SERIAL_ECHOPGM("FILE NR:");
//MYSERIAL.println(position);
curDir = &workDir;
//curDir = curDir + nr * 32 * 8; //32 bytes per entry
lsAction = LS_GetFilename;
//nrFiles = nr;
nrFiles = 0;
//curDir->rewind();
curDir->seekSet(position);
//curDir->setpos(32*nr);
lsDive_pointer("", *curDir, match);
/*SERIAL_ECHOPGM("; Position:");
uint32_t pom = curDir->curPosition();
MYSERIAL.print(pom, 10);
SERIAL_ECHOPGM("; Cluster:");
MYSERIAL.println(curDir->curCluster());*/
lsDive("", *curDir, match);
}
@ -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
*
@ -842,6 +886,7 @@ void CardReader::presort() {
#else // !SDSORT_USES_RAM
// uint32_t clusters [fileCnt];
uint32_t positions [fileCnt];
// char *names[fileCnt];
// By default re-read the names from SD for every compare
@ -852,16 +897,32 @@ void CardReader::presort() {
uint16_t creation_date_bckp;
#endif
position = 0;
if (fileCnt > 1) {
// Init sort order.
for (uint16_t i = 0; i < fileCnt; 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;
positions[i] = position-96;
//if (longFilename[0]) SERIAL_ECHOPGM("; Long; ");
//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 SDSORT_USES_RAM
getfilename(i);
@ -892,9 +953,12 @@ void CardReader::presort() {
#endif
#endif
}
SERIAL_ECHOPGM("Mezicas:");
MYSERIAL.println(millis() - start_time);
// Bubble Sort
/*SERIAL_ECHOPGM("Mezicas:");
MYSERIAL.println(millis() - start_time);*/
#ifdef QUICKSORT
quicksort(sort_order, 0, fileCnt - 1, positions);
#else //Qicksort not defined, use Bubble Sort
uint16_t counter = 0;
for (uint16_t i = fileCnt; --i;) {
bool didSwap = false;
@ -982,7 +1046,7 @@ void CardReader::presort() {
}
if (!didSwap) break;
} //end of bubble sort loop
#endif
// Using RAM but not keeping names around
#if (SDSORT_USES_RAM && !SDSORT_CACHE_NAMES)
#if SDSORT_DYNAMIC_RAM

View File

@ -45,6 +45,8 @@ public:
#ifdef SDCARD_SORT_ALPHA
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);
#if SDSORT_GCODE
FORCE_INLINE void setSortOn(bool b) { sort_alpha = b; presort(); }