summaryrefslogtreecommitdiff
path: root/library/sorting.h
diff options
context:
space:
mode:
Diffstat (limited to 'library/sorting.h')
-rw-r--r--library/sorting.h274
1 files changed, 274 insertions, 0 deletions
diff --git a/library/sorting.h b/library/sorting.h
new file mode 100644
index 00000000..0faa1bfd
--- /dev/null
+++ b/library/sorting.h
@@ -0,0 +1,274 @@
+#ifndef SORTING_H_INCLUDED
+#define SORTING_H_INCLUDED
+
+#include "../FreeFileSync.h"
+#include "resources.h"
+
+
+enum SideToSort
+{
+ SORT_ON_LEFT,
+ SORT_ON_RIGHT,
+};
+
+
+template <bool sortAscending>
+inline
+bool cmpString(const wxString& a, const wxString& b)
+{
+ if (a.IsEmpty())
+ return false; //if a and b are empty: false, if a empty, b not empty: also false, since empty rows should appear at the end
+ else if (b.IsEmpty())
+ return true; //empty rows after filled rows: return true
+
+ //if a and b not empty:
+ if (sortAscending)
+ return (a < b);
+ else
+ return (a > b);
+}
+
+
+template <bool sortAscending>
+inline
+bool cmpLargeInt(const wxULongLong& a, const wxULongLong& b)
+{
+ if (sortAscending)
+ return (a < b);
+ else
+ return (a > b);
+}
+
+
+template <SideToSort side>
+inline
+void getDescrLine(const FileCompareLine& a, const FileCompareLine& b, const FileDescrLine*& descrLineA, const FileDescrLine*& descrLineB)
+{
+ if (side == SORT_ON_LEFT)
+ {
+ descrLineA = &a.fileDescrLeft;
+ descrLineB = &b.fileDescrLeft;
+ }
+ else if (side == SORT_ON_RIGHT)
+ {
+ descrLineA = &a.fileDescrRight;
+ descrLineB = &b.fileDescrRight;
+ }
+ else assert(false);
+}
+
+
+inline
+wxChar formatChar(const wxChar& c)
+{
+ return c;
+ //return wxTolower(c); <- this is slow as hell! sorting slower by factor 10
+}
+
+
+inline
+int compareString(const wxChar* stringA, const wxChar* stringB, const int lengthA, const int lengthB)
+{
+ int i = 0;
+ if (lengthA == lengthB)
+ {
+ for (i = 0; i < lengthA; ++i)
+ {
+ if (formatChar(stringA[i]) != formatChar(stringB[i]))
+ break;
+ }
+ return i == lengthA ? 0 : formatChar(stringA[i]) < formatChar(stringB[i]) ? -1 : 1;
+ }
+ else if (lengthA < lengthB)
+ {
+ for (i = 0; i < lengthA; ++i)
+ {
+ if (formatChar(stringA[i]) != formatChar(stringB[i]))
+ break;
+ }
+ return i == lengthA ? -1 : formatChar(stringA[i]) < formatChar(stringB[i]) ? -1 : 1;
+ }
+ else
+ {
+ for (i = 0; i < lengthB; ++i)
+ {
+ if (formatChar(stringA[i]) != formatChar(stringB[i]))
+ break;
+ }
+ return i == lengthB ? 1 : formatChar(stringA[i]) < formatChar(stringB[i]) ? -1 : 1;
+ }
+}
+
+
+template <bool sortAscending, SideToSort side>
+inline
+bool sortByFileName(const FileCompareLine& a, const FileCompareLine& b)
+{
+ const FileDescrLine* descrLineA;
+ const FileDescrLine* descrLineB;
+ getDescrLine<side>(a, b, descrLineA, descrLineB);
+
+ //presort types: first files, then directories then empty rows
+ if (descrLineA->objType == FileDescrLine::TYPE_NOTHING)
+ return false; //empty rows always last
+ else if (descrLineB->objType == FileDescrLine::TYPE_NOTHING)
+ return true; //empty rows always last
+ else if (descrLineA->objType == FileDescrLine::TYPE_DIRECTORY)
+ return false;
+ else if (descrLineB->objType == FileDescrLine::TYPE_DIRECTORY)
+ return true;
+ else
+ {
+ const wxChar* stringA = NULL;
+ const wxChar* stringB = NULL;
+ int lenghtA = 0;
+ int lenghtB = 0;
+
+ int pos = descrLineA->relativeName.Find(GlobalResources::fileNameSeparator, true); //start search beginning from end
+ if (pos == wxNOT_FOUND)
+ {
+ stringA = descrLineA->relativeName.c_str();
+ lenghtA = descrLineA->relativeName.Len();
+ }
+ else
+ {
+ stringA = descrLineA->relativeName.c_str() + pos + 1;
+ lenghtA = descrLineA->relativeName.Len() - (pos + 1);
+ }
+
+ pos = descrLineB->relativeName.Find(GlobalResources::fileNameSeparator, true); //start search beginning from end
+ if (pos == wxNOT_FOUND)
+ {
+ stringB = descrLineB->relativeName.c_str();
+ lenghtB = descrLineB->relativeName.Len();
+ }
+ else
+ {
+ stringB = descrLineB->relativeName.c_str() + pos + 1;
+ lenghtB = descrLineB->relativeName.Len() - (pos + 1);
+ }
+
+ int rv = compareString(stringA, stringB, lenghtA, lenghtB);
+ return sortAscending ? (rv == -1) : (rv != -1);
+ }
+}
+
+
+template <bool sortAscending, SideToSort side>
+inline
+bool sortByRelativeName(const FileCompareLine& a, const FileCompareLine& b)
+{
+ const FileDescrLine* descrLineA;
+ const FileDescrLine* descrLineB;
+ getDescrLine<side>(a, b, descrLineA, descrLineB);
+
+ //extract relative name and filename
+ const wxChar* relStringA = NULL;
+ const wxChar* fileStringA = NULL;
+ int relLenghtA = 0;
+ int fileLengthA = 0;
+ if (descrLineA->objType == FileDescrLine::TYPE_DIRECTORY)
+ {
+ relStringA = descrLineA->relativeName.c_str();
+ relLenghtA = descrLineA->relativeName.Len();
+ }
+ else if (descrLineA->objType == FileDescrLine::TYPE_FILE)
+ {
+ relLenghtA = descrLineA->relativeName.Find(GlobalResources::fileNameSeparator, true); //start search beginning from end
+ if (relLenghtA == wxNOT_FOUND)
+ {
+ relLenghtA = 0;
+ fileStringA = descrLineA->relativeName.c_str();
+ fileLengthA = descrLineA->relativeName.Len();
+ }
+ else
+ {
+ relStringA = descrLineA->relativeName.c_str();
+ fileStringA = descrLineA->relativeName.c_str() + relLenghtA + 1;
+ fileLengthA = descrLineA->relativeName.Len() - (relLenghtA + 1);
+ }
+ }
+ else
+ return false; //empty rows should be on end of list
+
+
+ const wxChar* relStringB = NULL;
+ const wxChar* fileStringB = NULL;
+ int relLenghtB = 0;
+ int fileLengthB = 0;
+ if (descrLineB->objType == FileDescrLine::TYPE_DIRECTORY)
+ {
+ relStringB = descrLineB->relativeName.c_str();
+ relLenghtB = descrLineB->relativeName.Len();
+ }
+ else if (descrLineB->objType == FileDescrLine::TYPE_FILE)
+ {
+ relLenghtB = descrLineB->relativeName.Find(GlobalResources::fileNameSeparator, true); //start search beginning from end
+ if (relLenghtB == wxNOT_FOUND)
+ {
+ relLenghtB = 0;
+ fileStringB = descrLineB->relativeName.c_str();
+ fileLengthB = descrLineB->relativeName.Len();
+ }
+ else
+ {
+ relStringB = descrLineB->relativeName.c_str();
+ fileStringB = descrLineB->relativeName.c_str() + relLenghtB + 1;
+ fileLengthB = descrLineB->relativeName.Len() - (relLenghtB + 1);
+ }
+ }
+ else
+ return true; //empty rows should be on end of list
+
+ //compare relative names without filenames first
+ int rv = compareString(relStringA, relStringB, relLenghtA, relLenghtB);
+ if (rv != 0)
+ return sortAscending ? (rv == -1) : (rv != -1);
+ else //compare the filenames
+ {
+ if (descrLineB->objType == FileDescrLine::TYPE_DIRECTORY) //directories shall appear before files
+ return false;
+ else if (descrLineA->objType == FileDescrLine::TYPE_DIRECTORY)
+ return true;
+
+ rv = compareString(fileStringA, fileStringB, fileLengthA, fileLengthB);
+ return sortAscending ? (rv == -1) : (rv != -1);
+ }
+}
+
+
+template <bool sortAscending, SideToSort side>
+inline
+bool sortByFileSize(const FileCompareLine& a, const FileCompareLine& b)
+{
+ const FileDescrLine* descrLineA;
+ const FileDescrLine* descrLineB;
+ getDescrLine<side>(a, b, descrLineA, descrLineB);
+
+ //presort types: first files, then directories then empty rows
+ if (descrLineA->objType == FileDescrLine::TYPE_NOTHING)
+ return false; //empty rows always last
+ else if (descrLineB->objType == FileDescrLine::TYPE_NOTHING)
+ return true; //empty rows always last
+ else if (descrLineA->objType == FileDescrLine::TYPE_DIRECTORY)
+ return false;
+ else if (descrLineB->objType == FileDescrLine::TYPE_DIRECTORY)
+ return true;
+ else //use unformatted filesizes and sort by size
+ return cmpLargeInt<sortAscending>(descrLineA->fileSize, descrLineB->fileSize);
+}
+
+
+template <bool sortAscending, SideToSort side>
+inline
+bool sortByDate(const FileCompareLine& a, const FileCompareLine& b)
+{
+ const FileDescrLine* descrLineA;
+ const FileDescrLine* descrLineB;
+ getDescrLine<side>(a, b, descrLineA, descrLineB);
+
+ return cmpString<sortAscending>(descrLineA->lastWriteTime, descrLineB->lastWriteTime);
+}
+
+
+#endif // SORTING_H_INCLUDED
bgstack15