File indexing completed on 2024-05-12 05:47:29
0001 /* 0002 * SPDX-FileCopyrightText: 2012 Peter Penz <peter.penz19@gmail.com> 0003 * SPDX-FileCopyrightText: 2012 Emmanuel Pescosta <emmanuelpescosta099@gmail.com> 0004 * SPDX-FileCopyrightText: 2013 Frank Reininghaus <frank78ac@googlemail.com> 0005 * 0006 * SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #ifndef KFILEITEMMODELSORTALGORITHM_H 0010 #define KFILEITEMMODELSORTALGORITHM_H 0011 0012 #include <QtConcurrentRun> 0013 0014 #include <algorithm> 0015 0016 /** 0017 * Sorts the items using the merge sort algorithm is used to assure a 0018 * worst-case of O(n * log(n)) and to keep the number of comparisons low. 0019 * 0020 * The implementation is based on qStableSortHelper() from qalgorithms.h 0021 * SPDX-FileCopyrightText: 2011 Nokia Corporation and/or its subsidiary(-ies). 0022 */ 0023 0024 template<typename RandomAccessIterator, typename LessThan> 0025 static void mergeSort(RandomAccessIterator begin, RandomAccessIterator end, const LessThan &lessThan) 0026 { 0027 // The implementation is based on qStableSortHelper() from qalgorithms.h 0028 // SPDX-FileCopyrightText: 2011 Nokia Corporation and/or its subsidiary(-ies). 0029 0030 const int span = end - begin; 0031 if (span < 2) { 0032 return; 0033 } 0034 0035 const RandomAccessIterator middle = begin + span / 2; 0036 mergeSort(begin, middle, lessThan); 0037 mergeSort(middle, end, lessThan); 0038 merge(begin, middle, end, lessThan); 0039 } 0040 0041 /** 0042 * Uses up to \a numberOfThreads threads to sort the items between 0043 * \a begin and \a end. Only item ranges longer than 0044 * \a parallelMergeSortingThreshold are split to be sorted by two different 0045 * threads. 0046 * 0047 * The comparison function \a lessThan must be reentrant. 0048 */ 0049 0050 template<typename RandomAccessIterator, typename LessThan> 0051 static void 0052 parallelMergeSort(RandomAccessIterator begin, RandomAccessIterator end, LessThan lessThan, int numberOfThreads, int parallelMergeSortingThreshold = 100) 0053 { 0054 const int span = end - begin; 0055 0056 if (numberOfThreads > 1 && span > parallelMergeSortingThreshold) { 0057 const int newNumberOfThreads = numberOfThreads / 2; 0058 const RandomAccessIterator middle = begin + span / 2; 0059 0060 QFuture<void> future = 0061 QtConcurrent::run(parallelMergeSort<RandomAccessIterator, LessThan>, begin, middle, lessThan, newNumberOfThreads, parallelMergeSortingThreshold); 0062 parallelMergeSort(middle, end, lessThan, newNumberOfThreads, parallelMergeSortingThreshold); 0063 0064 future.waitForFinished(); 0065 0066 merge(begin, middle, end, lessThan); 0067 } else { 0068 mergeSort(begin, end, lessThan); 0069 } 0070 } 0071 0072 /** 0073 * Merges the sorted item ranges between \a begin and \a pivot and 0074 * between \a pivot and \a end into a single sorted range between 0075 * \a begin and \a end. 0076 * 0077 * The implementation is based on qMerge() from qalgorithms.h 0078 * SPDX-FileCopyrightText: 2011 Nokia Corporation and/or its subsidiary(-ies). 0079 */ 0080 0081 template<typename RandomAccessIterator, typename LessThan> 0082 static void merge(RandomAccessIterator begin, RandomAccessIterator pivot, RandomAccessIterator end, const LessThan &lessThan) 0083 { 0084 // The implementation is based on qMerge() from qalgorithms.h 0085 // SPDX-FileCopyrightText: 2011 Nokia Corporation and/or its subsidiary(-ies). 0086 0087 const int len1 = pivot - begin; 0088 const int len2 = end - pivot; 0089 0090 if (len1 == 0 || len2 == 0) { 0091 return; 0092 } 0093 0094 if (len1 + len2 == 2) { 0095 if (lessThan(*(begin + 1), *(begin))) { 0096 std::swap(*begin, *(begin + 1)); 0097 } 0098 return; 0099 } 0100 0101 RandomAccessIterator firstCut; 0102 RandomAccessIterator secondCut; 0103 int len2Half; 0104 if (len1 > len2) { 0105 const int len1Half = len1 / 2; 0106 firstCut = begin + len1Half; 0107 secondCut = std::lower_bound<RandomAccessIterator, decltype(*firstCut), const LessThan &>(pivot, end, *firstCut, lessThan); 0108 len2Half = secondCut - pivot; 0109 } else { 0110 len2Half = len2 / 2; 0111 secondCut = pivot + len2Half; 0112 firstCut = std::upper_bound<RandomAccessIterator, decltype(*secondCut), const LessThan &>(begin, pivot, *secondCut, lessThan); 0113 } 0114 0115 std::rotate(firstCut, pivot, secondCut); 0116 0117 RandomAccessIterator newPivot = firstCut + len2Half; 0118 merge(begin, firstCut, newPivot, lessThan); 0119 merge(newPivot, secondCut, end, lessThan); 0120 } 0121 0122 #endif