mirror of
https://invent.kde.org/system/dolphin
synced 2024-09-19 00:11:21 +00:00
Change the sort and merge functions to a more generic form.
This might make it easier to reuse the parallel sorting code. Moreover, some the upperBound/lowerBound functions have been removed because equivalents are provided by the STL.
This commit is contained in:
parent
c652807a19
commit
87ac18f031
|
@ -476,7 +476,8 @@ private:
|
||||||
// and done step after step in slotCompleted().
|
// and done step after step in slotCompleted().
|
||||||
QSet<KUrl> m_urlsToExpand;
|
QSet<KUrl> m_urlsToExpand;
|
||||||
|
|
||||||
friend class KFileItemModelSortAlgorithm; // Accesses lessThan() method
|
friend class KFileItemModelLessThan; // Accesses lessThan() method
|
||||||
|
friend class KFileItemModelSortAlgorithm; // Accesses NameRole
|
||||||
friend class KFileItemModelRolesUpdater; // Accesses emitSortProgress() method
|
friend class KFileItemModelRolesUpdater; // Accesses emitSortProgress() method
|
||||||
friend class KFileItemModelTest; // For unit testing
|
friend class KFileItemModelTest; // For unit testing
|
||||||
friend class KFileItemListViewTest; // For unit testing
|
friend class KFileItemListViewTest; // For unit testing
|
||||||
|
|
|
@ -24,26 +24,46 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
class KFileItemModelLessThan
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KFileItemModelLessThan(KFileItemModel* model) :
|
||||||
|
m_model(model)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator()(const KFileItemModel::ItemData* a, const KFileItemModel::ItemData* b)
|
||||||
|
{
|
||||||
|
return m_model->lessThan(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
KFileItemModel* m_model;
|
||||||
|
};
|
||||||
|
|
||||||
void KFileItemModelSortAlgorithm::sort(KFileItemModel* model,
|
void KFileItemModelSortAlgorithm::sort(KFileItemModel* model,
|
||||||
QList<KFileItemModel::ItemData*>::iterator begin,
|
QList<KFileItemModel::ItemData*>::iterator begin,
|
||||||
QList<KFileItemModel::ItemData*>::iterator end)
|
QList<KFileItemModel::ItemData*>::iterator end)
|
||||||
{
|
{
|
||||||
|
KFileItemModelLessThan lessThan(model);
|
||||||
|
|
||||||
if (model->sortRole() == model->roleForType(KFileItemModel::NameRole)) {
|
if (model->sortRole() == model->roleForType(KFileItemModel::NameRole)) {
|
||||||
// Sorting by name can be expensive, in particular if natural sorting is
|
// Sorting by name can be expensive, in particular if natural sorting is
|
||||||
// enabled. Use all CPU cores to speed up the sorting process.
|
// enabled. Use all CPU cores to speed up the sorting process.
|
||||||
static const int numberOfThreads = QThread::idealThreadCount();
|
static const int numberOfThreads = QThread::idealThreadCount();
|
||||||
parallelSort(model, begin, end, numberOfThreads);
|
parallelSort(begin, end, lessThan, numberOfThreads);
|
||||||
} else {
|
} else {
|
||||||
// Sorting by other roles is quite fast. Use only one thread to prevent
|
// Sorting by other roles is quite fast. Use only one thread to prevent
|
||||||
// problems caused by non-reentrant comparison functions, see
|
// problems caused by non-reentrant comparison functions, see
|
||||||
// https://bugs.kde.org/show_bug.cgi?id=312679
|
// https://bugs.kde.org/show_bug.cgi?id=312679
|
||||||
sequentialSort(model, begin, end);
|
sequentialSort(begin, end, lessThan);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KFileItemModelSortAlgorithm::sequentialSort(KFileItemModel* model,
|
template <typename RandomAccessIterator, typename LessThan>
|
||||||
QList< KFileItemModel::ItemData* >::iterator begin,
|
static void sequentialSort(RandomAccessIterator begin,
|
||||||
QList< KFileItemModel::ItemData* >::iterator end)
|
RandomAccessIterator end,
|
||||||
|
LessThan lessThan)
|
||||||
{
|
{
|
||||||
// The implementation is based on qStableSortHelper() from qalgorithms.h
|
// The implementation is based on qStableSortHelper() from qalgorithms.h
|
||||||
// Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
// Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||||
|
@ -53,38 +73,41 @@ void KFileItemModelSortAlgorithm::sequentialSort(KFileItemModel* model,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QList<KFileItemModel::ItemData*>::iterator middle = begin + span / 2;
|
const RandomAccessIterator middle = begin + span / 2;
|
||||||
sequentialSort(model, begin, middle);
|
sequentialSort(begin, middle, lessThan);
|
||||||
sequentialSort(model, middle, end);
|
sequentialSort(middle, end, lessThan);
|
||||||
merge(model, begin, middle, end);
|
merge(begin, middle, end, lessThan);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KFileItemModelSortAlgorithm::parallelSort(KFileItemModel* model,
|
template <typename RandomAccessIterator, typename LessThan>
|
||||||
QList< KFileItemModel::ItemData* >::iterator begin,
|
static void parallelSort(RandomAccessIterator begin,
|
||||||
QList< KFileItemModel::ItemData* >::iterator end,
|
RandomAccessIterator end,
|
||||||
const int numberOfThreads)
|
LessThan lessThan,
|
||||||
|
int numberOfThreads,
|
||||||
|
int parallelSortingThreshold)
|
||||||
{
|
{
|
||||||
const int span = end - begin;
|
const int span = end - begin;
|
||||||
|
|
||||||
if (numberOfThreads > 1 && span > 100) {
|
if (numberOfThreads > 1 && span > parallelSortingThreshold) {
|
||||||
const int newNumberOfThreads = numberOfThreads / 2;
|
const int newNumberOfThreads = numberOfThreads / 2;
|
||||||
const QList<KFileItemModel::ItemData*>::iterator middle = begin + span / 2;
|
const RandomAccessIterator middle = begin + span / 2;
|
||||||
|
|
||||||
QFuture<void> future = QtConcurrent::run(parallelSort, model, begin, middle, newNumberOfThreads);
|
QFuture<void> future = QtConcurrent::run(parallelSort<RandomAccessIterator, LessThan>, begin, middle, lessThan, newNumberOfThreads, parallelSortingThreshold);
|
||||||
parallelSort(model, middle, end, newNumberOfThreads);
|
parallelSort(middle, end, lessThan, newNumberOfThreads, parallelSortingThreshold);
|
||||||
|
|
||||||
future.waitForFinished();
|
future.waitForFinished();
|
||||||
|
|
||||||
merge(model, begin, middle, end);
|
merge(begin, middle, end, lessThan);
|
||||||
} else {
|
} else {
|
||||||
sequentialSort(model, begin, end);
|
sequentialSort(begin, end, lessThan);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KFileItemModelSortAlgorithm::merge(KFileItemModel* model,
|
template <typename RandomAccessIterator, typename LessThan>
|
||||||
QList<KFileItemModel::ItemData*>::iterator begin,
|
static void merge(RandomAccessIterator begin,
|
||||||
QList<KFileItemModel::ItemData*>::iterator pivot,
|
RandomAccessIterator pivot,
|
||||||
QList<KFileItemModel::ItemData*>::iterator end)
|
RandomAccessIterator end,
|
||||||
|
LessThan lessThan)
|
||||||
{
|
{
|
||||||
// The implementation is based on qMerge() from qalgorithms.h
|
// The implementation is based on qMerge() from qalgorithms.h
|
||||||
// Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
// Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||||
|
@ -97,82 +120,29 @@ void KFileItemModelSortAlgorithm::merge(KFileItemModel* model,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len1 + len2 == 2) {
|
if (len1 + len2 == 2) {
|
||||||
if (model->lessThan(*(begin + 1), *(begin))) {
|
if (lessThan(*(begin + 1), *(begin))) {
|
||||||
qSwap(*begin, *(begin + 1));
|
qSwap(*begin, *(begin + 1));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<KFileItemModel::ItemData*>::iterator firstCut;
|
RandomAccessIterator firstCut;
|
||||||
QList<KFileItemModel::ItemData*>::iterator secondCut;
|
RandomAccessIterator secondCut;
|
||||||
int len2Half;
|
int len2Half;
|
||||||
if (len1 > len2) {
|
if (len1 > len2) {
|
||||||
const int len1Half = len1 / 2;
|
const int len1Half = len1 / 2;
|
||||||
firstCut = begin + len1Half;
|
firstCut = begin + len1Half;
|
||||||
secondCut = lowerBound(model, pivot, end, *firstCut);
|
secondCut = std::lower_bound(pivot, end, *firstCut, lessThan);
|
||||||
len2Half = secondCut - pivot;
|
len2Half = secondCut - pivot;
|
||||||
} else {
|
} else {
|
||||||
len2Half = len2 / 2;
|
len2Half = len2 / 2;
|
||||||
secondCut = pivot + len2Half;
|
secondCut = pivot + len2Half;
|
||||||
firstCut = upperBound(model, begin, pivot, *secondCut);
|
firstCut = std::upper_bound(begin, pivot, *secondCut, lessThan);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::rotate(firstCut, pivot, secondCut);
|
std::rotate(firstCut, pivot, secondCut);
|
||||||
|
|
||||||
const QList<KFileItemModel::ItemData*>::iterator newPivot = firstCut + len2Half;
|
RandomAccessIterator newPivot = firstCut + len2Half;
|
||||||
merge(model, begin, firstCut, newPivot);
|
merge(begin, firstCut, newPivot, lessThan);
|
||||||
merge(model, newPivot, secondCut, end);
|
merge(newPivot, secondCut, end, lessThan);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
QList<KFileItemModel::ItemData*>::iterator
|
|
||||||
KFileItemModelSortAlgorithm::lowerBound(KFileItemModel* model,
|
|
||||||
QList<KFileItemModel::ItemData*>::iterator begin,
|
|
||||||
QList<KFileItemModel::ItemData*>::iterator end,
|
|
||||||
const KFileItemModel::ItemData* value)
|
|
||||||
{
|
|
||||||
// The implementation is based on qLowerBound() from qalgorithms.h
|
|
||||||
// Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
|
||||||
|
|
||||||
QList<KFileItemModel::ItemData*>::iterator middle;
|
|
||||||
int n = int(end - begin);
|
|
||||||
int half;
|
|
||||||
|
|
||||||
while (n > 0) {
|
|
||||||
half = n >> 1;
|
|
||||||
middle = begin + half;
|
|
||||||
if (model->lessThan(*middle, value)) {
|
|
||||||
begin = middle + 1;
|
|
||||||
n -= half + 1;
|
|
||||||
} else {
|
|
||||||
n = half;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return begin;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<KFileItemModel::ItemData*>::iterator
|
|
||||||
KFileItemModelSortAlgorithm::upperBound(KFileItemModel* model,
|
|
||||||
QList<KFileItemModel::ItemData*>::iterator begin,
|
|
||||||
QList<KFileItemModel::ItemData*>::iterator end,
|
|
||||||
const KFileItemModel::ItemData* value)
|
|
||||||
{
|
|
||||||
// The implementation is based on qUpperBound() from qalgorithms.h
|
|
||||||
// Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
|
||||||
|
|
||||||
QList<KFileItemModel::ItemData*>::iterator middle;
|
|
||||||
int n = end - begin;
|
|
||||||
int half;
|
|
||||||
|
|
||||||
while (n > 0) {
|
|
||||||
half = n >> 1;
|
|
||||||
middle = begin + half;
|
|
||||||
if (model->lessThan(value, *middle)) {
|
|
||||||
n = half;
|
|
||||||
} else {
|
|
||||||
begin = middle + 1;
|
|
||||||
n -= half + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return begin;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,35 +42,26 @@ public:
|
||||||
static void sort(KFileItemModel* model,
|
static void sort(KFileItemModel* model,
|
||||||
QList<KFileItemModel::ItemData*>::iterator begin,
|
QList<KFileItemModel::ItemData*>::iterator begin,
|
||||||
QList<KFileItemModel::ItemData*>::iterator end);
|
QList<KFileItemModel::ItemData*>::iterator end);
|
||||||
|
|
||||||
private:
|
|
||||||
static void sequentialSort(KFileItemModel* model,
|
|
||||||
QList<KFileItemModel::ItemData*>::iterator begin,
|
|
||||||
QList<KFileItemModel::ItemData*>::iterator end);
|
|
||||||
|
|
||||||
static void parallelSort(KFileItemModel* model,
|
|
||||||
QList<KFileItemModel::ItemData*>::iterator begin,
|
|
||||||
QList<KFileItemModel::ItemData*>::iterator end,
|
|
||||||
const int numberOfThreads);
|
|
||||||
|
|
||||||
static void merge(KFileItemModel* model,
|
|
||||||
QList<KFileItemModel::ItemData*>::iterator begin,
|
|
||||||
QList<KFileItemModel::ItemData*>::iterator pivot,
|
|
||||||
QList<KFileItemModel::ItemData*>::iterator end);
|
|
||||||
|
|
||||||
static QList<KFileItemModel::ItemData*>::iterator
|
|
||||||
lowerBound(KFileItemModel* model,
|
|
||||||
QList<KFileItemModel::ItemData*>::iterator begin,
|
|
||||||
QList<KFileItemModel::ItemData*>::iterator end,
|
|
||||||
const KFileItemModel::ItemData* value);
|
|
||||||
|
|
||||||
static QList<KFileItemModel::ItemData*>::iterator
|
|
||||||
upperBound(KFileItemModel* model,
|
|
||||||
QList<KFileItemModel::ItemData*>::iterator begin,
|
|
||||||
QList<KFileItemModel::ItemData*>::iterator end,
|
|
||||||
const KFileItemModel::ItemData* value);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename RandomAccessIterator, typename LessThan>
|
||||||
|
static void sequentialSort(RandomAccessIterator begin,
|
||||||
|
RandomAccessIterator end,
|
||||||
|
LessThan lessThan);
|
||||||
|
|
||||||
|
template <typename RandomAccessIterator, typename LessThan>
|
||||||
|
static void parallelSort(RandomAccessIterator begin,
|
||||||
|
RandomAccessIterator end,
|
||||||
|
LessThan lessThan,
|
||||||
|
int numberOfThreads,
|
||||||
|
int parallelSortingThreshold = 100);
|
||||||
|
|
||||||
|
template <typename RandomAccessIterator, typename LessThan>
|
||||||
|
static void merge(RandomAccessIterator begin,
|
||||||
|
RandomAccessIterator pivot,
|
||||||
|
RandomAccessIterator end,
|
||||||
|
LessThan lessThan);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue