From 4e67a7c03ce49bddacecd7338915071f3796f8bb Mon Sep 17 00:00:00 2001 From: Pierre Lamot Date: Fri, 25 Mar 2022 11:43:49 +0100 Subject: [PATCH] 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". --- modules/gui/qt/medialibrary/mlbasemodel.cpp | 2 +- modules/gui/qt/medialibrary/mllistcache.cpp | 65 +++++++++++++++++++-- modules/gui/qt/medialibrary/mllistcache.hpp | 45 +++++++++++++- 3 files changed, 105 insertions(+), 7 deletions(-) diff --git a/modules/gui/qt/medialibrary/mlbasemodel.cpp b/modules/gui/qt/medialibrary/mlbasemodel.cpp index 3380071121..0fbe5a9500 100644 --- a/modules/gui/qt/medialibrary/mlbasemodel.cpp +++ b/modules/gui/qt/medialibrary/mlbasemodel.cpp @@ -437,7 +437,7 @@ void MLBaseModel::validateCache() const return; auto loader = createLoader(); - m_cache = std::make_unique(m_mediaLib, std::move(loader)); + m_cache = std::make_unique(m_mediaLib, std::move(loader), false); connect(m_cache.get(), &MLListCache::localSizeChanged, this, &MLBaseModel::onLocalSizeChanged); diff --git a/modules/gui/qt/medialibrary/mllistcache.cpp b/modules/gui/qt/medialibrary/mllistcache.cpp index 4fd48cad79..b9f01bfb2c 100644 --- a/modules/gui/qt/medialibrary/mllistcache.cpp +++ b/modules/gui/qt/medialibrary/mllistcache.cpp @@ -43,14 +43,43 @@ bool cacheDataCompare(const void* dataOld, uint32_t oldIndex, const void* dataNe } -MLListCache::MLListCache(MediaLib* medialib, std::unique_ptr>&& loader, size_t chunkSize) +MLListCache::MLListCache(MediaLib* medialib, std::unique_ptr>&& 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 diff --git a/modules/gui/qt/medialibrary/mllistcache.hpp b/modules/gui/qt/medialibrary/mllistcache.hpp index 56b1e61635..7011e2fbc1 100644 --- a/modules/gui/qt/medialibrary/mllistcache.hpp +++ b/modules/gui/qt/medialibrary/mllistcache.hpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include "util/listcacheloader.hpp" @@ -123,7 +124,7 @@ public: static constexpr ssize_t COUNT_UNINITIALIZED = -1; MLListCache(MediaLib* medialib, std::unique_ptr>&& 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> 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 m_partialIndexRedirect; }; #endif