From ef36ce6ffb7c583f5dba472bafa95f1ec8fc09b4 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