[vlc-devel] [PATCH 05/13] qt: medialib: introduce list cache
Romain Vimont
rom1v at videolabs.io
Mon Nov 23 17:30:19 CET 2020
Add a separate class to provide local data caching, independant of the
MLBaseModel implementation.
It will be used in further commits.
---
modules/gui/qt/Makefile.am | 2 +
modules/gui/qt/util/listcache.hpp | 171 ++++++++++++++++++++++++++++++
2 files changed, 173 insertions(+)
create mode 100644 modules/gui/qt/util/listcache.hpp
diff --git a/modules/gui/qt/Makefile.am b/modules/gui/qt/Makefile.am
index c158dae6eb..9d36265842 100644
--- a/modules/gui/qt/Makefile.am
+++ b/modules/gui/qt/Makefile.am
@@ -202,6 +202,7 @@ libqt_plugin_la_SOURCES = \
gui/qt/util/color_scheme_model.cpp gui/qt/util/color_scheme_model.hpp \
gui/qt/util/imagehelper.cpp gui/qt/util/imagehelper.hpp \
gui/qt/util/i18n.cpp gui/qt/util/i18n.hpp \
+ gui/qt/util/listcache.hpp \
gui/qt/util/navigation_history.cpp gui/qt/util/navigation_history.hpp \
gui/qt/util/qml_main_context.cpp \
gui/qt/util/qml_main_context.hpp \
@@ -342,6 +343,7 @@ nodist_libqt_plugin_la_SOURCES = \
gui/qt/util/audio_device_model.moc.cpp \
gui/qt/util/color_scheme_model.moc.cpp \
gui/qt/util/i18n.moc.cpp \
+ gui/qt/util/listcache.moc.cpp \
gui/qt/util/navigation_history.moc.cpp \
gui/qt/util/qml_main_context.moc.cpp \
gui/qt/util/qmleventfilter.moc.cpp \
diff --git a/modules/gui/qt/util/listcache.hpp b/modules/gui/qt/util/listcache.hpp
new file mode 100644
index 0000000000..d18abe8eb7
--- /dev/null
+++ b/modules/gui/qt/util/listcache.hpp
@@ -0,0 +1,171 @@
+/*****************************************************************************
+ * Copyright (C) 2020 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 LISTCACHE_HPP
+#define LISTCACHE_HPP
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "vlc_common.h"
+#include <memory>
+#include <vector>
+#include <QtGlobal>
+#include <QObject>
+
+/**
+ * `ListCache<T>` represents a cache for a (constant) list of items.
+ *
+ * The caller must provide a `ListCacheLoader<T>`, defining the following
+ * methods:
+ * - `count()` returns the number of items in the list;
+ * - `load(index, count)` returning the items for the requested interval.
+ *
+ * The precise cache strategy is unspecified (it may change in the future), but
+ * the general principle is to keep locally only a part of the whole data.
+ *
+ * The list of items it represents is assumed constant:
+ * 1. the list size will never change once initialized,
+ * 2. the items retrieved by several calls at a specific location should be
+ * "the same".
+ *
+ * Note that (2.) might not always be respected in practice, for example if the
+ * data is retrieved from a database where content changes between calls. The
+ * cache does not really care, the data will just be inconcistent for the user.
+ *
+ * All its public methods must be called from the UI thread.
+ */
+
+template <typename T>
+struct ListCacheLoader
+{
+ virtual ~ListCacheLoader() = default;
+ virtual size_t count() const = 0;
+ virtual std::vector<T> load(size_t index, size_t count) const = 0;
+};
+
+/* Non-template class for signals */
+class ListCacheBase : public QObject
+{
+ Q_OBJECT
+
+signals:
+ void localDataChanged(size_t index, size_t count);
+};
+
+template <typename T>
+class ListCache : public ListCacheBase
+{
+public:
+ static constexpr ssize_t COUNT_UNINITIALIZED = -1;
+
+ ListCache(std::unique_ptr<ListCacheLoader<T>> loader, size_t chunkSize = 100)
+ : m_loader(std::move(loader))
+ , m_chunkSize(chunkSize) {}
+
+ /**
+ * Return the item at specified index
+ *
+ * This returns the local item (`nullptr` if not present), and does not
+ * retrieve anything from the loader.
+ */
+ const T *get(size_t index) const;
+
+
+ /**
+ * Return the number of items or `COUNT_UNINITIALIZED`
+ *
+ * This returns the local count, and does not retrieve anything from the
+ * loader.
+ */
+ ssize_t count() const;
+
+ /**
+ * Init the list size
+ *
+ * This method must be called at most once (the list size is not expected
+ * to change).
+ */
+ void initCount();
+
+ /**
+ * Request to load data so that the item as index will become available
+ */
+ void refer(size_t index);
+
+private:
+ std::unique_ptr<ListCacheLoader<T>> m_loader;
+ size_t m_chunkSize;
+
+ std::vector<T> m_list;
+ ssize_t m_total_count = COUNT_UNINITIALIZED;
+ size_t m_offset = 0;
+};
+
+template <typename T>
+const T *ListCache<T>::get(size_t index) const
+{
+ assert(m_total_count >= 0 && index < static_cast<size_t>(m_total_count));
+ if (index < m_offset || index >= m_offset + m_list.size())
+ return nullptr;
+
+ return &m_list[index - m_offset];
+}
+
+template <typename T>
+ssize_t ListCache<T>::count() const
+{
+ return m_total_count;
+}
+
+template <typename T>
+void ListCache<T>::initCount()
+{
+ assert(m_total_count == COUNT_UNINITIALIZED);
+ m_total_count = static_cast<ssize_t>(m_loader->count());
+}
+
+template <typename T>
+void ListCache<T>::refer(size_t index)
+{
+ if (m_total_count == -1 || index >= static_cast<size_t>(m_total_count))
+ {
+ /*
+ * The request is incompatible with the total count of the list.
+ *
+ * Either the count is not retrieved yet, or the content has changed in
+ * the loader source.
+ */
+ return;
+ }
+
+ /* index outside the known portion of the list */
+ if (index < m_offset || index >= m_offset + m_list.size())
+ {
+ /* FIXME bad heuristic if the interval of visible items crosses a cache
+ * page boundary */
+ m_offset = index - index % m_chunkSize;
+ size_t count = qMin(m_total_count - m_offset, m_chunkSize);
+ m_list = m_loader->load(m_offset, count);
+ if (m_list.size())
+ emit localDataChanged(m_offset, m_list.size());
+ }
+}
+
+#endif
--
2.29.2
More information about the vlc-devel
mailing list