mirror of https://code.videolan.org/videolan/vlc
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:
parent
35de0a01f5
commit
4e67a7c03c
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue