From 2d3ff6a97cb52dc825b6d79bf2e68fdd99bc8ba9 Mon Sep 17 00:00:00 2001 From: Vladimir Golovnev Date: Sun, 20 Feb 2022 13:17:34 +0300 Subject: [PATCH] Use std::optional to represent "any value" filters PR #16460. --- src/base/torrentfilter.cpp | 49 ++++++++++++++-------------- src/base/torrentfilter.h | 27 ++++++++------- src/webui/api/torrentscontroller.cpp | 25 ++++++++++---- 3 files changed, 59 insertions(+), 42 deletions(-) diff --git a/src/base/torrentfilter.cpp b/src/base/torrentfilter.cpp index c7de80825..0738455ec 100644 --- a/src/base/torrentfilter.cpp +++ b/src/base/torrentfilter.cpp @@ -31,9 +31,9 @@ #include "bittorrent/infohash.h" #include "bittorrent/torrent.h" -const QString TorrentFilter::AnyCategory; -const TorrentIDSet TorrentFilter::AnyID {{}}; -const QString TorrentFilter::AnyTag; +const std::optional TorrentFilter::AnyCategory; +const std::optional TorrentFilter::AnyID; +const std::optional TorrentFilter::AnyTag; const TorrentFilter TorrentFilter::DownloadingTorrent(TorrentFilter::Downloading); const TorrentFilter TorrentFilter::SeedingTorrent(TorrentFilter::Seeding); @@ -50,7 +50,8 @@ const TorrentFilter TorrentFilter::ErroredTorrent(TorrentFilter::Errored); using BitTorrent::Torrent; -TorrentFilter::TorrentFilter(const Type type, const TorrentIDSet &idSet, const QString &category, const QString &tag) +TorrentFilter::TorrentFilter(const Type type, const std::optional &idSet + , const std::optional &category, const std::optional &tag) : m_type(type) , m_category(category) , m_tag(tag) @@ -58,7 +59,8 @@ TorrentFilter::TorrentFilter(const Type type, const TorrentIDSet &idSet, const Q { } -TorrentFilter::TorrentFilter(const QString &filter, const TorrentIDSet &idSet, const QString &category, const QString &tag) +TorrentFilter::TorrentFilter(const QString &filter, const std::optional &idSet + , const std::optional &category, const std::optional &tag) : m_type(All) , m_category(category) , m_tag(tag) @@ -110,7 +112,7 @@ bool TorrentFilter::setTypeByName(const QString &filter) return setType(type); } -bool TorrentFilter::setTorrentIDSet(const TorrentIDSet &idSet) +bool TorrentFilter::setTorrentIDSet(const std::optional &idSet) { if (m_idSet != idSet) { @@ -121,12 +123,9 @@ bool TorrentFilter::setTorrentIDSet(const TorrentIDSet &idSet) return false; } -bool TorrentFilter::setCategory(const QString &category) +bool TorrentFilter::setCategory(const std::optional &category) { - // QString::operator==() doesn't distinguish between empty and null strings. - if ((m_category != category) - || (m_category.isNull() && !category.isNull()) - || (!m_category.isNull() && category.isNull())) + if (m_category != category) { m_category = category; return true; @@ -135,12 +134,9 @@ bool TorrentFilter::setCategory(const QString &category) return false; } -bool TorrentFilter::setTag(const QString &tag) +bool TorrentFilter::setTag(const std::optional &tag) { - // QString::operator==() doesn't distinguish between empty and null strings. - if ((m_tag != tag) - || (m_tag.isNull() && !tag.isNull()) - || (!m_tag.isNull() && tag.isNull())) + if (m_tag != tag) { m_tag = tag; return true; @@ -196,23 +192,28 @@ bool TorrentFilter::matchState(const BitTorrent::Torrent *const torrent) const bool TorrentFilter::matchHash(const BitTorrent::Torrent *const torrent) const { - if (m_idSet == AnyID) return true; + if (!m_idSet) + return true; - return m_idSet.contains(torrent->id()); + return m_idSet->contains(torrent->id()); } bool TorrentFilter::matchCategory(const BitTorrent::Torrent *const torrent) const { - if (m_category.isNull()) return true; + if (!m_category) + return true; - return (torrent->belongsToCategory(m_category)); + return (torrent->belongsToCategory(*m_category)); } bool TorrentFilter::matchTag(const BitTorrent::Torrent *const torrent) const { - // Empty tag is a special value to indicate we're filtering for untagged torrents. - if (m_tag.isNull()) return true; - if (m_tag.isEmpty()) return torrent->tags().isEmpty(); + if (!m_tag) + return true; - return (torrent->hasTag(m_tag)); + // Empty tag is a special value to indicate we're filtering for untagged torrents. + if (m_tag->isEmpty()) + return torrent->tags().isEmpty(); + + return torrent->hasTag(*m_tag); } diff --git a/src/base/torrentfilter.h b/src/base/torrentfilter.h index f1a01e3fe..a8267593b 100644 --- a/src/base/torrentfilter.h +++ b/src/base/torrentfilter.h @@ -28,6 +28,8 @@ #pragma once +#include + #include #include @@ -61,9 +63,9 @@ public: }; // These mean any permutation, including no category / tag. - static const QString AnyCategory; - static const TorrentIDSet AnyID; - static const QString AnyTag; + static const std::optional AnyCategory; + static const std::optional AnyID; + static const std::optional AnyTag; static const TorrentFilter DownloadingTorrent; static const TorrentFilter SeedingTorrent; @@ -80,15 +82,16 @@ public: TorrentFilter() = default; // category & tags: pass empty string for uncategorized / untagged torrents. - // Pass null string (QString()) to disable filtering (i.e. all torrents). - TorrentFilter(Type type, const TorrentIDSet &idSet = AnyID, const QString &category = AnyCategory, const QString &tag = AnyTag); - TorrentFilter(const QString &filter, const TorrentIDSet &idSet = AnyID, const QString &category = AnyCategory, const QString &tags = AnyTag); + TorrentFilter(Type type, const std::optional &idSet = AnyID + , const std::optional &category = AnyCategory, const std::optional &tag = AnyTag); + TorrentFilter(const QString &filter, const std::optional &idSet = AnyID + , const std::optional &category = AnyCategory, const std::optional &tags = AnyTag); bool setType(Type type); bool setTypeByName(const QString &filter); - bool setTorrentIDSet(const TorrentIDSet &idSet); - bool setCategory(const QString &category); - bool setTag(const QString &tag); + bool setTorrentIDSet(const std::optional &idSet); + bool setCategory(const std::optional &category); + bool setTag(const std::optional &tag); bool match(const BitTorrent::Torrent *torrent) const; @@ -99,7 +102,7 @@ private: bool matchTag(const BitTorrent::Torrent *torrent) const; Type m_type {All}; - QString m_category; - QString m_tag; - TorrentIDSet m_idSet; + std::optional m_category; + std::optional m_tag; + std::optional m_idSet; }; diff --git a/src/webui/api/torrentscontroller.cpp b/src/webui/api/torrentscontroller.cpp index bc3df88ab..267623b03 100644 --- a/src/webui/api/torrentscontroller.cpp +++ b/src/webui/api/torrentscontroller.cpp @@ -140,6 +140,15 @@ namespace } } + std::optional getOptionalString(const StringMap ¶ms, const QString &name) + { + const auto it = params.constFind(name); + if (it == params.cend()) + return std::nullopt; + + return it.value(); + } + QJsonArray getStickyTrackers(const BitTorrent::Torrent *const torrent) { int seedsDHT = 0, seedsPeX = 0, seedsLSD = 0, leechesDHT = 0, leechesPeX = 0, leechesLSD = 0; @@ -255,19 +264,23 @@ namespace void TorrentsController::infoAction() { const QString filter {params()["filter"]}; - const QString category {params()["category"]}; - const QString tag {params()["tag"]}; + const std::optional category = getOptionalString(params(), QLatin1String("category")); + const std::optional tag = getOptionalString(params(), QLatin1String("tag")); const QString sortedColumn {params()["sort"]}; const bool reverse {parseBool(params()["reverse"]).value_or(false)}; int limit {params()["limit"].toInt()}; int offset {params()["offset"].toInt()}; const QStringList hashes {params()["hashes"].split('|', Qt::SkipEmptyParts)}; - TorrentIDSet idSet; - for (const QString &hash : hashes) - idSet.insert(BitTorrent::TorrentID::fromString(hash)); + std::optional idSet; + if (!hashes.isEmpty()) + { + idSet = TorrentIDSet(); + for (const QString &hash : hashes) + idSet->insert(BitTorrent::TorrentID::fromString(hash)); + } - const TorrentFilter torrentFilter(filter, (hashes.isEmpty() ? TorrentFilter::AnyID : idSet), category, tag); + const TorrentFilter torrentFilter {filter, idSet, category, tag}; QVariantList torrentList; for (const BitTorrent::Torrent *torrent : asConst(BitTorrent::Session::instance()->torrents())) {