From 1154f9b0043c5ce2e0ac20070d107aa610c83b0e Mon Sep 17 00:00:00 2001
From: Digital Artifex <7929434+DigitalArtifex@users.noreply.github.com>
Date: Sun, 7 Jun 2026 02:03:26 -0400
Subject: [PATCH] Changed cache to use objects instead of pointers
---
KomplexHubPlugin/common/paginator.h | 151 ++++++++++++++++--
.../common/slidingcachecontroller.h | 131 ++++++++++-----
2 files changed, 232 insertions(+), 50 deletions(-)
diff --git a/KomplexHubPlugin/common/paginator.h b/KomplexHubPlugin/common/paginator.h
index 0a54b3a..d946cfb 100644
--- a/KomplexHubPlugin/common/paginator.h
+++ b/KomplexHubPlugin/common/paginator.h
@@ -1,3 +1,21 @@
+/*
+ * Komplex Wallpaper Engine
+ * Copyright (C) 2026 @DigitalArtifex
+ * https://digitalartifex.dev - https://github.com/DigitalArtifex
+ *
+ * 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 3 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, see
+ */
#ifndef PAGINATOR_H
#define PAGINATOR_H
@@ -6,80 +24,185 @@
#include "komplex_global.h"
#include "slidingcachecontroller.h"
+/**
+ * @brief The PaginatorNotifier class
+ *
+ * Qt does not support templated QObjects. Pushing it to a notifier class
+ * that the template can inherit fixes this
+ */
+class KOMPLEX_EXPORT PaginatorNotifier : public QObject
+{
+ Q_OBJECT
+signals:
+ auto dataChanged() -> void;
+ auto resultsPerPageChanged() -> void;
+ auto totalResultsChanged() -> void;
+ auto totalPagesChanged() -> void;
+ auto pageChanged() -> void;
+ auto countChanged() -> void;
+};
+
+/**
+ * @brief The Paginator class is a type agnostic pagination controller that uses
+ * the SlidingCacheController as it's backend
+ */
template
-class KOMPLEX_EXPORT Paginator
+class KOMPLEX_EXPORT Paginator : public PaginatorNotifier
{
public:
- Paginator() = default;
- ~Paginator() = default;
-
+ /**
+ * @brief next
+ *
+ * Attempts to get the next page and notifies pageChanged
+ */
auto next() const -> void
{
setOffset(m_offset + m_resultsPerPage);
+ Q_EMIT static_cast(this)->pageChanged();
}
+ /**
+ * @brief previous
+ *
+ * Attempts to get the previous page and notifies pageChanged
+ */
auto previous() const -> void
{
setOffset(m_offset - m_resultsPerPage);
+ Q_EMIT static_cast(this)->pageChanged();
}
+ /**
+ * @brief resultsPerPage
+ * @return
+ */
auto resultsPerPage() const -> qsizetype
{
return m_resultsPerPage;
}
+ /**
+ * @brief setResultsPerPage
+ * @param resultsPerPage
+ */
auto setResultsPerPage(qsizetype resultsPerPage) -> void
{
m_resultsPerPage = resultsPerPage;
+ Q_EMIT static_cast(this)->resultsPerPageChanged();
+
m_data = m_cacheController.chunk(m_offset, m_resultsPerPage);
+ Q_EMIT static_cast(this)->dataChanged();
}
- auto data() const -> QList
+ /**
+ * @brief data
+ * @return a copy of the list of pointers
+ */
+ auto data() const -> QList
{
return m_data;
}
+ /**
+ * @brief count
+ * @return
+ */
auto count() const -> qsizetype
{
return m_data.count();
}
- auto at(qsizetype index) const -> T*
+ /**
+ * @brief at
+ * @param index
+ * @return
+ */
+ auto at(qsizetype index) const -> T
{
if(index < 0 || index >= m_data.count())
{
- return nullptr;
+ return {};
}
return m_data.at(index);
}
+ /**
+ * @brief totalResults
+ *
+ * The total number of results as reported by the controller
+ * @return
+ */
+ auto totalResults() -> qsizetype
+ {
+ return m_cacheController.count();
+ }
+
+ /**
+ * @brief page
+ * @return
+ */
+ auto page() const -> qsizetype
+ {
+ return std::floor(
+ static_cast(m_offset) / m_resultsPerPage
+ );
+ }
+
+ /**
+ * @brief totalPages
+ * @return
+ */
+ auto totalPages() const -> qsizetype
+ {
+ return std::ceil(
+ static_cast(totalResults()) / m_resultsPerPage
+ );
+ }
+
+protected:
+
auto controller() -> SlidingCacheController*
{
return &m_cacheController;
}
- auto offset() const -> qsizetype
- {
- return m_offset;
- }
-
auto setOffset(qsizetype offset) -> void
{
m_offset = offset;
- if(m_offset < 0 || m_offset == std::numeric_limits::max())
+ if(m_offset >= m_totalResults)
+ {
+ m_offset = m_totalResults - m_resultsPerPage;
+ }
+
+ if(m_offset < 0)
+ {
m_offset = 0;
+ }
m_data = m_cacheController.chunk(m_offset, m_resultsPerPage);
+ Q_EMIT this->countChanged();
+ Q_EMIT this->dataChanged();
+ Q_EMIT this->pageChanged();
+ Q_EMIT this->totalPagesChanged();
+ }
+
+ auto onControllerTotalResultsChanged() -> void
+ {
+ Q_EMIT this->totalResultsChanged();
}
private:
+ qsizetype m_page = 0;
+ qsizetype m_totalPages = 0;
+
qsizetype m_offset = 0;
qsizetype m_resultsPerPage = 0;
+ qsizetype m_totalResults = 0;
SlidingCacheController m_cacheController;
- QList m_data;
+ QList m_data;
};
#endif // PAGINATOR_H
diff --git a/KomplexHubPlugin/common/slidingcachecontroller.h b/KomplexHubPlugin/common/slidingcachecontroller.h
index b1bfc77..958e1f5 100644
--- a/KomplexHubPlugin/common/slidingcachecontroller.h
+++ b/KomplexHubPlugin/common/slidingcachecontroller.h
@@ -1,3 +1,21 @@
+/*
+ * Komplex Wallpaper Engine
+ * Copyright (C) 2026 @DigitalArtifex
+ * https://digitalartifex.dev - https://github.com/DigitalArtifex
+ *
+ * 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 3 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, see
+ */
#ifndef SLIDINGCACHECONTROLLER_H
#define SLIDINGCACHECONTROLLER_H
@@ -7,8 +25,26 @@
#include "fetchresult.h"
#include "komplex_global.h"
+/**
+ * @brief The SlidingCacheControllerNotifier class
+ *
+ * Qt does not support templated QObjects. Pushing it to a notifier class
+ * that the template can inherit fixes this
+ */
+class KOMPLEX_EXPORT SlidingCacheControllerNotifier : public QObject
+{
+ Q_OBJECT
+signals:
+ auto countChanged() -> void;
+};
+
+/**
+ * @brief The SlidingCacheController class is a type and endpoint agnostic sliding window
+ * cache controller. It pre-fetches a larger data set that a paginator works on top of.
+ * This minimizes the number of API calls required to serve paged data
+ */
template
-class KOMPLEX_EXPORT SlidingCacheController
+class KOMPLEX_EXPORT SlidingCacheController : public SlidingCacheControllerNotifier
{
public:
@@ -127,14 +163,23 @@ public:
*/
auto clear() -> void
{
- while(!m_cache.isEmpty())
- {
- T *object = m_cache.takeFirst();
- delete object;
- }
+ m_cache.clear();
}
-signals:
+protected:
+ /**
+ * @brief setCount
+ * Sets the total count and notifies countChanged
+ * @param count
+ */
+ auto setCount(qsizetype count) -> void
+ {
+ if(count == m_totalCount)
+ return;
+
+ m_totalCount = count;
+ Q_EMIT static_cast(this)->countChanged();
+ }
private:
/**
@@ -144,6 +189,12 @@ private:
*/
auto slideForward() -> bool
{
+ LOG_ERROR_X(!m_fetch,
+ "SlidingCacheController::slideBackward",
+ "Fetch function not set",
+ false
+ );
+
qsizetype movementSize = SLIDING_CACHE_WINDOW_SIZE;
//after initial inflation we should only arrive here when the prefetch threshold is reached
@@ -154,35 +205,42 @@ private:
m_windowOffset += movementSize;
- QList newCache = m_fetch(
+ FetchResult result = m_fetch(
m_windowOffset,
movementSize
- );
+ );
- if(newCache.isEmpty())
+ if(result.count == 0)
+ {
+ m_windowOffset += movementSize;
+ return false;
+ }
+
+ setCount(result.total);
+
+ if(result.data.isEmpty())
{
m_windowOffset -= movementSize;
return false;
}
- while(!newCache.isEmpty() && !m_cache.isEmpty())
+ while(!result.data.isEmpty() && !m_cache.isEmpty())
{
- T *object = newCache.takeFirst();
- T *oldObject = m_cache.takeFirst();
+ T object = result.data.takeFirst();
+ m_cache.removeFirst();
- delete oldObject;
- m_cache.append(object);
+ m_cache.append(std::move(object));
}
- if(!newCache.isEmpty())
+ if(!result.data.isEmpty())
{
- LOG_ERROR_X((newCache.count() + m_cache.count()) > SLIDING_CACHE_WINDOW_SIZE,
- "SlidingCacheController::slideForward",
- "Cache size imbalance",
- false
- );
+ LOG_ERROR_X((result.data.count() + m_cache.count()) > SLIDING_CACHE_WINDOW_SIZE,
+ "SlidingCacheController::slideForward",
+ "Cache size imbalance",
+ false
+ );
- m_cache.append(newCache);
+ m_cache.append(std::move(result.data));
}
return true;
@@ -196,10 +254,10 @@ private:
auto slideBackward() -> bool
{
LOG_ERROR_X(!m_fetch,
- "SlidingCacheController::slideBackward",
- "Fetch function not set",
- false
- );
+ "SlidingCacheController::slideBackward",
+ "Fetch function not set",
+ false
+ );
qsizetype movementSize = SLIDING_CACHE_WINDOW_SIZE - SLIDING_CACHE_PREFETCH_THRESHOLD;
m_windowOffset -= movementSize;
@@ -212,7 +270,7 @@ private:
FetchResult result = m_fetch(
m_windowOffset,
movementSize
- );
+ );
if(result.count == 0)
{
@@ -220,22 +278,23 @@ private:
return false;
}
+ setCount(result.total);
+
while(!result.data.isEmpty() && !m_cache.isEmpty())
{
- T *object = result.data.takeLast();
- T *oldObject = m_cache.takeLast();
+ T object = result.data.takeLast();
+ m_cache.removeLast();
- delete oldObject;
- m_cache.push_front(object);
+ m_cache.push_front(std::move(object));
}
if(!result.results.isEmpty())
{
LOG_ERROR_X((result.count + m_cache.count()) > SLIDING_CACHE_WINDOW_SIZE,
- "SlidingCacheController::slideBackward",
- "Cache size imbalance",
- false
- );
+ "SlidingCacheController::slideBackward",
+ "Cache size imbalance",
+ false
+ );
m_cache.push_front(std::move(result.data));
}
@@ -278,7 +337,7 @@ private:
* @brief m_cache
* The working cache
*/
- QVector m_cache;
+ QVector m_cache;
};
#endif // SLIDINGCACHECONTROLLER_H