// ************************************************************************** // * 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) Zenju (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef SORTING_H_INCLUDED #define SORTING_H_INCLUDED #include #include #include "../file_hierarchy.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 manually check dynamic casts in this file when needed } inline bool isDirectoryMapping(const FileSystemObject& fsObj) { return dynamic_cast(&fsObj) != nullptr; } 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 makeSortDirection(LessFilename(), Int2Type())(a.getShortName(), b.getShortName()); } } template //side currently unused! bool lessRelativeName(const FileSystemObject& a, const FileSystemObject& b) { const bool isDirectoryA = isDirectoryMapping(a); const Zstring& relDirNameA = isDirectoryA ? a.getObjRelativeName() : //directory beforeLast(a.getObjRelativeName(), FILE_NAME_SEPARATOR); //returns empty string if ch not found const bool isDirectoryB = isDirectoryMapping(b); const Zstring& relDirNameB = isDirectoryB ? b.getObjRelativeName() : //directory beforeLast(b.getObjRelativeName(), FILE_NAME_SEPARATOR); //returns empty string if ch not found //compare relative names without filenames first const int rv = cmpFileName(relDirNameA, relDirNameB); if (rv != 0) return makeSortDirection(std::less(), Int2Type())(rv, 0); else //compare the filenames { if (isDirectoryB) //directories shall appear before files return false; else if (isDirectoryA) return true; return LessFilename()(a.getObjShortName(), b.getObjShortName()); } } 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) != nullptr; const bool isDirB = dynamic_cast(&b) != nullptr; //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) return false; else if (!fileObjB) return true; //return list beginning with largest files first return makeSortDirection(std::less(), Int2Type())(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 makeSortDirection(std::less(), Int2Type())(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 if (dynamic_cast(&a)) return false; //directories last else if (dynamic_cast(&b)) return true; //directories last auto getExtension = [&](const FileSystemObject& fsObj) -> Zstring { const Zstring& shortName = fsObj.getShortName(); const size_t pos = shortName.rfind(Zchar('.')); return pos == Zstring::npos ? Zstring() : Zstring(shortName.c_str() + pos + 1); }; return makeSortDirection(LessFilename(), Int2Type())(getExtension(a), getExtension(b)); } 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 makeSortDirection(std::less(), Int2Type())(a.getCategory(), b.getCategory()); } template inline bool lessSyncDirection(const FileSystemObject& a, const FileSystemObject& b) { return makeSortDirection(std::less(), Int2Type())(a.getSyncOperation(), b.getSyncOperation()); } } #endif // SORTING_H_INCLUDED