qt: allow to detect moves in MLList cache

This remains is disabled by default, The extra cost isn't really worth it as
move operations originated from the database are very rare, move operations from
the user are usually handled "a priori".
This commit is contained in:
Pierre Lamot 2022-03-25 11:43:49 +01:00 committed by Jean-Baptiste Kempf
parent 35de0a01f5
commit 4e67a7c03c
3 changed files with 105 additions and 7 deletions

View File

@ -437,7 +437,7 @@ void MLBaseModel::validateCache() const
return;
auto loader = createLoader();
m_cache = std::make_unique<MLListCache>(m_mediaLib, std::move(loader));
m_cache = std::make_unique<MLListCache>(m_mediaLib, std::move(loader), false);
connect(m_cache.get(), &MLListCache::localSizeChanged,
this, &MLBaseModel::onLocalSizeChanged);

View File

@ -43,14 +43,43 @@ bool cacheDataCompare(const void* dataOld, uint32_t oldIndex, const void* dataNe
}
MLListCache::MLListCache(MediaLib* medialib, std::unique_ptr<ListCacheLoader<MLListCache::ItemType>>&& loader, size_t chunkSize)
MLListCache::MLListCache(MediaLib* medialib, std::unique_ptr<ListCacheLoader<MLListCache::ItemType>>&& loader, bool useMove, size_t chunkSize)
: m_medialib(medialib)
, m_useMove(useMove)
, m_loader(loader.release())
, m_chunkSize(chunkSize)
{
assert(medialib);
}
size_t MLListCache::fixupIndexForMove(size_t index) const
{
//theses elements have already been moved
for (const PartialIndexRedirect& hole : m_partialIndexRedirect)
{
if (hole.op == PartialIndexRedirect::Operation::DEL)
{
if (hole.index <= index)
index += hole.count;
else
break;
}
else
{
if (hole.index <= index)
{
if (index <= hole.index + hole.count - 1)
return hole.val.add.x + (index - hole.index);
else
index -= hole.count;
}
else
break;
}
}
return index;
}
const MLListCache::ItemType* MLListCache::get(size_t index) const
{
//the view may access the model while we're updating it
@ -63,7 +92,13 @@ const MLListCache::ItemType* MLListCache::get(size_t index) const
if (index >= m_partialLoadedCount)
return nullptr;
else if (index >= m_partialIndex)
return &m_oldData->list.at(index - m_partialIndex + m_partialX);
{
if (m_useMove)
{
index = fixupIndexForMove(index);
}
return &m_oldData->list.at(index + (m_partialX - m_partialIndex));
}
else
return &m_cachedData->list.at(index);
}
@ -275,9 +310,13 @@ void MLListCache::partialUpdate()
};
diffutil_snake_t* snake = vlc_diffutil_build_snake(&diffOp, &m_oldData->list, &m_cachedData->list);
int diffutilFlags = VLC_DIFFUTIL_RESULT_AGGREGATE;
if (m_useMove)
diffutilFlags |= VLC_DIFFUTIL_RESULT_MOVE;
vlc_diffutil_changelist_t* changes = vlc_diffutil_build_change_list(
snake, &diffOp, &m_oldData->list, &m_cachedData->list,
VLC_DIFFUTIL_RESULT_AGGREGATE);
diffutilFlags);
m_partialIndex = 0;
m_partialLoadedCount = m_oldData->loadedCount;
@ -311,8 +350,22 @@ void MLListCache::partialUpdate()
emit localSizeChanged(partialTotalCount);
break;
case VLC_DIFFUTIL_OP_MOVE:
emit beginMoveRows(op.op.move.from, op.op.move.from + op.count - 1, op.op.move.to);
//TODO
m_partialX = op.op.move.x;
if (op.op.move.from > op.op.move.to)
{
m_partialIndex = op.op.move.to;
emit beginMoveRows(op.op.move.from, op.op.move.from + op.count - 1, op.op.move.to);
m_partialIndexRedirect.insert(PartialIndexRedirect(PartialIndexRedirect::Operation::DEL, op.op.move.from, op.count));
m_partialIndex += op.count;
}
else
{
m_partialIndex = op.op.move.from + op.count - 1;
emit beginMoveRows(op.op.move.from, op.op.move.from + op.count - 1, op.op.move.to);
m_partialIndexRedirect.insert(PartialIndexRedirect(PartialIndexRedirect::Operation::ADD, op.op.move.to, op.count, op.op.move.x));
m_partialIndex = op.op.move.from + 1;
m_partialX += op.count;
}
emit endMoveRows();
break;
}
@ -321,6 +374,8 @@ void MLListCache::partialUpdate()
vlc_diffutil_free_snake(snake);
//ditch old model
if (m_useMove)
m_partialIndexRedirect.clear();
m_oldData.reset();
//if we have change outside our cache

View File

@ -27,6 +27,7 @@
#include <cassert>
#include <memory>
#include <vector>
#include <set>
#include <QObject>
#include <QSharedPointer>
#include "util/listcacheloader.hpp"
@ -123,7 +124,7 @@ public:
static constexpr ssize_t COUNT_UNINITIALIZED = -1;
MLListCache(MediaLib* medialib, std::unique_ptr<ListCacheLoader<ItemType>>&& loader,
size_t chunkSize = 100);
bool useMove, size_t chunkSize = 100);
/**
* Return the item at specified index
@ -212,9 +213,12 @@ private:
void asyncFetchMore();
void asyncCountAndLoad();
void partialUpdate();
size_t fixupIndexForMove(size_t index) const;
MediaLib* m_medialib = nullptr;
bool m_useMove = false;
/* Ownershipshared between this cache and the runnable spawned to execute
* loader callbacks */
QSharedPointer<ListCacheLoader<ItemType>> m_loader;
@ -251,6 +255,45 @@ private:
size_t m_partialIndex = 0;
size_t m_partialX = 0;
size_t m_partialLoadedCount = 0;
//represent a redirection of items that are after m_partialIndex
struct PartialIndexRedirect {
enum class Operation
{
ADD,
DEL
};
explicit PartialIndexRedirect(Operation op_, size_t index_, size_t count_, size_t x_ = 0)
: op(op_)
, index(index_)
, count(count_)
{
if (op == Operation::ADD)
{
val.add.x = x_;
}
}
Operation op;
union {
struct {
size_t x;
} add;
struct {
} del;
} val;
size_t index;
size_t count;
//for set ordering
friend bool operator<(const PartialIndexRedirect& l, const PartialIndexRedirect& r)
{
return l.index < r.index;
}
};
//store index redirection keeping index order
std::set<PartialIndexRedirect> m_partialIndexRedirect;
};
#endif