You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
174 lines
5.4 KiB
174 lines
5.4 KiB
/*****************************************************************************
|
|
* Copyright (C) 2023 VLC authors and VideoLAN
|
|
*
|
|
* 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 LOCAL_CACHE_LOADER_HPP
|
|
#define LOCAL_CACHE_LOADER_HPP
|
|
|
|
#include <vector>
|
|
#include <unordered_set>
|
|
#include <algorithm>
|
|
|
|
#include <QObject>
|
|
#include "listcache.hpp"
|
|
|
|
class LocalListCacheLoaderObj: public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
protected:
|
|
inline size_t runTaskAsync(std::function<void(size_t taskId)> task)
|
|
{
|
|
size_t taskId = ++m_taskCounter;
|
|
m_validTasks.insert(taskId);
|
|
|
|
QMetaObject::invokeMethod(
|
|
this, [this, taskId, task]() {
|
|
auto taskIter = m_validTasks.find(taskId);
|
|
if (taskIter == m_validTasks.cend())
|
|
return;
|
|
m_validTasks.erase(taskIter);
|
|
|
|
task(taskId);
|
|
}, Qt::QueuedConnection);
|
|
|
|
return taskId;
|
|
}
|
|
|
|
size_t m_taskCounter = 0;
|
|
std::unordered_set<size_t> m_validTasks = {};
|
|
};
|
|
|
|
/**
|
|
* @brief The LocalListCacheLoader class is designed to act like a ListCache loader for data that
|
|
* are stored in memory. it provide, sorting, filtering and update events through the diffutil mechanism
|
|
*
|
|
* ItemType will be copied locally so it must be easilly copyable (sharedptr or primitive types)
|
|
*
|
|
* model must implement ModelSource interface to retreive data, and data revision
|
|
*
|
|
* data is sorted and filtered on the UI thread
|
|
*/
|
|
template<typename T>
|
|
class LocalListCacheLoader: public LocalListCacheLoaderObj, public ListCacheLoader<T>
|
|
{
|
|
public:
|
|
using ItemType = T;
|
|
using ItemList = std::vector<ItemType>;
|
|
using ItemCompare = std::function<bool(const ItemType&, const ItemType&)>;
|
|
|
|
class ModelSource
|
|
{
|
|
public:
|
|
virtual ~ModelSource() = default;
|
|
//the revision must be incremented each time the model changes
|
|
virtual size_t getModelRevision() const = 0;
|
|
|
|
//return the data matching the pattern
|
|
virtual std::vector<ItemType> getModelData(const QString& pattern) const = 0;
|
|
};
|
|
|
|
public:
|
|
LocalListCacheLoader(
|
|
const ModelSource* source,
|
|
const QString& pattern,
|
|
ItemCompare compare)
|
|
: LocalListCacheLoaderObj()
|
|
, m_source(source)
|
|
, m_compare(compare)
|
|
, m_pattern(pattern)
|
|
{
|
|
}
|
|
|
|
void cancelTask(size_t taskId) override
|
|
{
|
|
m_validTasks.erase(taskId);
|
|
}
|
|
|
|
size_t countTask(std::function<void(size_t taskId, size_t count)> cb) override
|
|
{
|
|
return runTaskAsync([this, cb](size_t taskId) {
|
|
updateData();
|
|
cb(taskId, m_items.size());
|
|
});
|
|
}
|
|
|
|
size_t loadTask(
|
|
size_t offset, size_t limit,
|
|
std::function<void(size_t taskId, std::vector<ItemType>& data)> cb) override
|
|
{
|
|
return runTaskAsync([this, offset, limit, cb](size_t taskId) {
|
|
updateData();
|
|
std::vector<ItemType> data;
|
|
if (offset < m_items.size())
|
|
{
|
|
if (limit == 0 || offset + limit > m_items.size())
|
|
{
|
|
std::copy(m_items.cbegin() + offset, m_items.cend(), std::back_inserter(data));
|
|
}
|
|
else
|
|
{
|
|
data.reserve(limit);
|
|
std::copy_n(m_items.cbegin() + offset, limit, std::back_inserter(data));
|
|
}
|
|
}
|
|
cb(taskId, data);
|
|
});
|
|
}
|
|
|
|
size_t countAndLoadTask(
|
|
size_t offset, size_t limit,
|
|
std::function<void(size_t taskId, size_t count, std::vector<ItemType>& data)> cb) override
|
|
{
|
|
return runTaskAsync([this, offset, limit, cb](size_t taskId) {
|
|
updateData();
|
|
std::vector<ItemType> data;
|
|
if (offset < m_items.size())
|
|
{
|
|
if (limit == 0 || offset + limit > m_items.size())
|
|
{
|
|
std::copy(m_items.cbegin() + offset, m_items.cend(), std::back_inserter(data));
|
|
}
|
|
else
|
|
{
|
|
data.reserve(limit);
|
|
std::copy_n(m_items.cbegin() + offset, limit, std::back_inserter(data));
|
|
}
|
|
}
|
|
cb(taskId, m_items.size(), data);
|
|
});
|
|
}
|
|
|
|
void updateData()
|
|
{
|
|
if (m_revision == m_source->getModelRevision())
|
|
return;
|
|
|
|
m_items = m_source->getModelData(m_pattern);
|
|
std::sort(m_items.begin(), m_items.end(), m_compare);
|
|
|
|
m_revision = m_source->getModelRevision();
|
|
}
|
|
|
|
const ModelSource* m_source;
|
|
ItemCompare m_compare;
|
|
QString m_pattern;
|
|
ItemList m_items;
|
|
size_t m_revision = 0;
|
|
};
|
|
|
|
#endif
|
|
|