Extract sorting-algorithm from KFileItemModel into custom class

This commit is contained in:
Peter Penz 2012-04-04 13:35:34 +02:00
parent 4657459937
commit 1e6031c04d
5 changed files with 225 additions and 150 deletions

View file

@ -23,6 +23,7 @@ set(dolphinprivate_LIB_SRCS
kitemviews/kfileitemlistview.cpp
kitemviews/kfileitemlistwidget.cpp
kitemviews/kfileitemmodel.cpp
kitemviews/kfileitemmodelsortalgorithm.cpp
kitemviews/kfileitemmodelfilter.cpp
kitemviews/kfileitemmodelrolesupdater.cpp
kitemviews/kitemlistcontainer.cpp

View file

@ -21,6 +21,7 @@
#include <KDirLister>
#include <KDirModel>
#include "kfileitemmodelsortalgorithm_p.h"
#include <KGlobalSettings>
#include <KLocale>
#include <KStringHandler>
@ -613,7 +614,7 @@ void KFileItemModel::resortAllItems()
m_items.clear();
// Resort the items
sort(m_itemData.begin(), m_itemData.end());
KFileItemModelSortAlgorithm::sort(this, m_itemData.begin(), m_itemData.end());
for (int i = 0; i < itemCount; ++i) {
m_items.insert(m_itemData.at(i)->item.url(), i);
}
@ -887,7 +888,7 @@ void KFileItemModel::insertItems(const KFileItemList& items)
m_groups.clear();
QList<ItemData*> sortedItems = createItemDataList(items);
sort(sortedItems.begin(), sortedItems.end());
KFileItemModelSortAlgorithm::sort(this, sortedItems.begin(), sortedItems.end());
#ifdef KFILEITEMMODEL_DEBUG
kDebug() << "[TIME] Sorting:" << timer.elapsed();
@ -966,7 +967,7 @@ void KFileItemModel::removeItems(const KFileItemList& items)
sortedItems.append(m_itemData.at(index));
}
}
sort(sortedItems.begin(), sortedItems.end());
KFileItemModelSortAlgorithm::sort(this, sortedItems.begin(), sortedItems.end());
QList<int> indexesToRemove;
indexesToRemove.reserve(items.count());
@ -1386,128 +1387,6 @@ int KFileItemModel::sortRoleCompare(const ItemData* a, const ItemData* b) const
return QString::compare(itemA.url().url(), itemB.url().url(), Qt::CaseSensitive);
}
void KFileItemModel::sort(QList<ItemData*>::iterator begin,
QList<ItemData*>::iterator end)
{
// The implementation is based on qStableSortHelper() from qalgorithms.h
// Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
// In opposite to qStableSort() it allows to use a member-function for the comparison of elements.
const int span = end - begin;
if (span < 2) {
return;
}
const QList<ItemData*>::iterator middle = begin + span / 2;
sort(begin, middle);
sort(middle, end);
merge(begin, middle, end);
}
void KFileItemModel::merge(QList<ItemData*>::iterator begin,
QList<ItemData*>::iterator pivot,
QList<ItemData*>::iterator end)
{
// The implementation is based on qMerge() from qalgorithms.h
// Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
const int len1 = pivot - begin;
const int len2 = end - pivot;
if (len1 == 0 || len2 == 0) {
return;
}
if (len1 + len2 == 2) {
if (lessThan(*(begin + 1), *(begin))) {
qSwap(*begin, *(begin + 1));
}
return;
}
QList<ItemData*>::iterator firstCut;
QList<ItemData*>::iterator secondCut;
int len2Half;
if (len1 > len2) {
const int len1Half = len1 / 2;
firstCut = begin + len1Half;
secondCut = lowerBound(pivot, end, *firstCut);
len2Half = secondCut - pivot;
} else {
len2Half = len2 / 2;
secondCut = pivot + len2Half;
firstCut = upperBound(begin, pivot, *secondCut);
}
reverse(firstCut, pivot);
reverse(pivot, secondCut);
reverse(firstCut, secondCut);
const QList<ItemData*>::iterator newPivot = firstCut + len2Half;
merge(begin, firstCut, newPivot);
merge(newPivot, secondCut, end);
}
QList<KFileItemModel::ItemData*>::iterator KFileItemModel::lowerBound(QList<ItemData*>::iterator begin,
QList<ItemData*>::iterator end,
const ItemData* value)
{
// The implementation is based on qLowerBound() from qalgorithms.h
// Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
QList<ItemData*>::iterator middle;
int n = int(end - begin);
int half;
while (n > 0) {
half = n >> 1;
middle = begin + half;
if (lessThan(*middle, value)) {
begin = middle + 1;
n -= half + 1;
} else {
n = half;
}
}
return begin;
}
QList<KFileItemModel::ItemData*>::iterator KFileItemModel::upperBound(QList<ItemData*>::iterator begin,
QList<ItemData*>::iterator end,
const ItemData* value)
{
// The implementation is based on qUpperBound() from qalgorithms.h
// Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
QList<ItemData*>::iterator middle;
int n = end - begin;
int half;
while (n > 0) {
half = n >> 1;
middle = begin + half;
if (lessThan(value, *middle)) {
n = half;
} else {
begin = middle + 1;
n -= half + 1;
}
}
return begin;
}
void KFileItemModel::reverse(QList<ItemData*>::iterator begin,
QList<ItemData*>::iterator end)
{
// The implementation is based on qReverse() from qalgorithms.h
// Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
--end;
while (begin < end) {
qSwap(*begin++, *end--);
}
}
int KFileItemModel::stringCompare(const QString& a, const QString& b) const
{
// Taken from KDirSortFilterProxyModel (kdelibs/kfile/kdirsortfilterproxymodel.*)

View file

@ -274,30 +274,6 @@ private:
*/
int sortRoleCompare(const ItemData* a, const ItemData* b) const;
/**
* Sorts the items by using lessThan() as comparison criteria.
* The merge sort algorithm is used to assure a worst-case
* of O(n * log(n)) and to keep the number of comparisons low.
*/
void sort(QList<ItemData*>::iterator begin, QList<ItemData*>::iterator end);
/** Helper method for sort(). */
void merge(QList<ItemData*>::iterator begin,
QList<ItemData*>::iterator pivot,
QList<ItemData*>::iterator end);
/** Helper method for sort(). */
QList<ItemData*>::iterator lowerBound(QList<ItemData*>::iterator begin,
QList<ItemData*>::iterator end,
const ItemData* value);
/** Helper method for sort(). */
QList<ItemData*>::iterator upperBound(QList<ItemData*>::iterator begin,
QList<ItemData*>::iterator end,
const ItemData* value);
/** Helper method for sort(). */
void reverse(QList<ItemData*>::iterator begin, QList<ItemData*>::iterator end);
int stringCompare(const QString& a, const QString& b) const;
/**
@ -408,6 +384,7 @@ private:
// and done step after step in slotCompleted().
QSet<KUrl> m_urlsToExpand;
friend class KFileItemModelSortAlgorithm; // Accesses lessThan() method
friend class KFileItemModelTest; // For unit testing
};

View file

@ -0,0 +1,148 @@
/***************************************************************************
* Copyright (C) 2012 by Peter Penz <peter.penz19@gmail.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
#include "kfileitemmodelsortalgorithm_p.h"
void KFileItemModelSortAlgorithm::sort(KFileItemModel* model,
QList<KFileItemModel::ItemData*>::iterator begin,
QList<KFileItemModel::ItemData*>::iterator end)
{
// The implementation is based on qStableSortHelper() from qalgorithms.h
// Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
const int span = end - begin;
if (span < 2) {
return;
}
const QList<KFileItemModel::ItemData*>::iterator middle = begin + span / 2;
sort(model, begin, middle);
sort(model, middle, end);
merge(model, begin, middle, end);
}
void KFileItemModelSortAlgorithm::merge(KFileItemModel* model,
QList<KFileItemModel::ItemData*>::iterator begin,
QList<KFileItemModel::ItemData*>::iterator pivot,
QList<KFileItemModel::ItemData*>::iterator end)
{
// The implementation is based on qMerge() from qalgorithms.h
// Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
const int len1 = pivot - begin;
const int len2 = end - pivot;
if (len1 == 0 || len2 == 0) {
return;
}
if (len1 + len2 == 2) {
if (model->lessThan(*(begin + 1), *(begin))) {
qSwap(*begin, *(begin + 1));
}
return;
}
QList<KFileItemModel::ItemData*>::iterator firstCut;
QList<KFileItemModel::ItemData*>::iterator secondCut;
int len2Half;
if (len1 > len2) {
const int len1Half = len1 / 2;
firstCut = begin + len1Half;
secondCut = lowerBound(model, pivot, end, *firstCut);
len2Half = secondCut - pivot;
} else {
len2Half = len2 / 2;
secondCut = pivot + len2Half;
firstCut = upperBound(model, begin, pivot, *secondCut);
}
reverse(firstCut, pivot);
reverse(pivot, secondCut);
reverse(firstCut, secondCut);
const QList<KFileItemModel::ItemData*>::iterator newPivot = firstCut + len2Half;
merge(model, begin, firstCut, newPivot);
merge(model, newPivot, secondCut, end);
}
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;
}
void KFileItemModelSortAlgorithm::reverse(QList<KFileItemModel::ItemData*>::iterator begin,
QList<KFileItemModel::ItemData*>::iterator end)
{
// The implementation is based on qReverse() from qalgorithms.h
// Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
--end;
while (begin < end) {
qSwap(*begin++, *end--);
}
}

View file

@ -0,0 +1,70 @@
/***************************************************************************
* Copyright (C) 2012 by Peter Penz <peter.penz19@gmail.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
#ifndef KFILEITEMMODELSORTALGORITHM_H
#define KFILEITEMMODELSORTALGORITHM_H
#include <libdolphin_export.h>
#include <kitemviews/kfileitemmodel.h>
/**
* @brief Sort algorithm for sorting items of KFileItemModel.
*
* Sorts the items by using KFileItemModel::lessThan() as comparison criteria.
* The merge sort algorithm is used to assure a worst-case
* of O(n * log(n)) and to keep the number of comparisons low.
*
* The implementation is based on qStableSortHelper() from qalgorithms.h
* Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
* The sorting implementations of qAlgorithms could not be used as they
* don't support having a member-function as comparison criteria.
*/
class LIBDOLPHINPRIVATE_EXPORT KFileItemModelSortAlgorithm
{
public:
static void sort(KFileItemModel* model,
QList<KFileItemModel::ItemData*>::iterator begin,
QList<KFileItemModel::ItemData*>::iterator end);
private:
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);
static void reverse(QList<KFileItemModel::ItemData*>::iterator begin,
QList<KFileItemModel::ItemData*>::iterator end);
};
#endif