// ************************************************************************** // * This file is part of the FreeFileSync project. It is distributed under * // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * // ************************************************************************** // #ifndef SORTING_H_INCLUDED #define SORTING_H_INCLUDED #include "../file_hierarchy.h" #include "../shared/system_constants.h" #include "../synchronization.h" #include "../shared/assert_static.h" namespace zen { namespace { struct CompileTimeReminder : public FSObjectVisitor { virtual void visit(const FileMapping& fileObj) {} virtual void visit(const SymLinkMapping& linkObj) {} virtual void visit(const DirMapping& dirObj) {} } checkDymanicCasts; //just a compile-time reminder to check dynamic casts in this file } inline bool isDirectoryMapping(const FileSystemObject& fsObj) { return dynamic_cast(&fsObj) != NULL; } template struct Compare { template bool isSmallerThan(T a, T b) { assert_static(sizeof(T) <= 2 * sizeof(int)); //use for comparing (small) INTEGRAL types only! return a < b; } }; template <> struct Compare { template bool isSmallerThan(T a, T b) { assert_static(sizeof(T) <= 2 * sizeof(int)); //use for comparing (small) INTEGRAL types only! return a > b; } }; template inline bool lessShortFileName(const FileSystemObject& a, const FileSystemObject& b) { //presort types: first files, then directories then empty rows if (a.isEmpty()) return false; //empty rows always last else if (b.isEmpty()) return true; //empty rows always last if (isDirectoryMapping(a)) //sort directories by relative name { if (isDirectoryMapping(b)) return LessFilename()(a.getRelativeName(), b.getRelativeName()); else return false; } else { if (isDirectoryMapping(b)) return true; else return Compare().isSmallerThan( cmpFileName(a.getShortName(), b.getShortName()), 0); } } template bool lessRelativeName(const FileSystemObject& a, const FileSystemObject& b) { if (a.isEmpty()) return false; //empty rows always last else if (b.isEmpty()) return true; //empty rows always last const bool isDirectoryA = isDirectoryMapping(a); const Zstring& relDirNameA = isDirectoryA ? a.getRelativeName() : //directory a.getParentRelativeName(); //file or symlink const bool isDirectoryB = isDirectoryMapping(b); const Zstring& relDirNameB = isDirectoryB ? b.getRelativeName() : //directory b.getParentRelativeName(); //file or symlink //compare relative names without filenames first const int rv = cmpFileName(relDirNameA, relDirNameB); if (rv != 0) return Compare().isSmallerThan(rv, 0); else //compare the filenames { if (isDirectoryB) //directories shall appear before files return false; else if (isDirectoryA) return true; return LessFilename()(a.getShortName(), b.getShortName()); } } template inline bool lessFilesize(const FileSystemObject& a, const FileSystemObject& b) { //empty rows always last if (a.isEmpty()) return false; else if (b.isEmpty()) return true; const bool isDirA = dynamic_cast(&a) != NULL; const bool isDirB = dynamic_cast(&b) != NULL; //directories second last if (isDirA) return false; else if (isDirB) return true; const FileMapping* fileObjA = dynamic_cast(&a); const FileMapping* fileObjB = dynamic_cast(&b); //then symlinks if (fileObjA == NULL) return false; else if (fileObjB == NULL) return true; //return list beginning with largest files first return Compare().isSmallerThan(fileObjA->getFileSize(), fileObjB->getFileSize()); } template inline bool lessFiletime(const FileSystemObject& a, const FileSystemObject& b) { if (a.isEmpty()) return false; //empty rows always last else if (b.isEmpty()) return true; //empty rows always last const FileMapping* fileObjA = dynamic_cast(&a); const FileMapping* fileObjB = dynamic_cast(&b); const SymLinkMapping* linkObjA = dynamic_cast(&a); const SymLinkMapping* linkObjB = dynamic_cast(&b); if (!fileObjA && !linkObjA) return false; //directories last else if (!fileObjB && !linkObjB) return true; //directories last zen::Int64 dateA = fileObjA ? fileObjA->getLastWriteTime() : linkObjA->getLastWriteTime(); zen::Int64 dateB = fileObjB ? fileObjB->getLastWriteTime() : linkObjB->getLastWriteTime(); //return list beginning with newest files first return Compare().isSmallerThan(dateA, dateB); } template inline bool lessExtension(const FileSystemObject& a, const FileSystemObject& b) { if (a.isEmpty()) return false; //empty rows always last else if (b.isEmpty()) return true; //empty rows always last const FileMapping* fileObjA = dynamic_cast(&a); const FileMapping* fileObjB = dynamic_cast(&b); if (fileObjA == NULL) return false; //directories last else if (fileObjB == NULL) return true; //directories last return Compare().isSmallerThan(cmpFileName(fileObjA->getExtension(), fileObjB->getExtension()), 0); } template inline bool lessCmpResult(const FileSystemObject& a, const FileSystemObject& b) { //presort result: equal shall appear at end of list if (a.getCategory() == FILE_EQUAL) return false; if (b.getCategory() == FILE_EQUAL) return true; return Compare().isSmallerThan(a.getCategory(), b.getCategory()); } template inline bool lessSyncDirection(const FileSystemObject& a, const FileSystemObject& b) { return Compare().isSmallerThan(a.getSyncOperation(), b.getSyncOperation()); } } #endif // SORTING_H_INCLUDED