Use std::optional to represent "any value" filters

PR #16460.
This commit is contained in:
Vladimir Golovnev 2022-02-20 13:17:34 +03:00 committed by GitHub
parent c627ed4b6f
commit 2d3ff6a97c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 59 additions and 42 deletions

View file

@ -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<QString> TorrentFilter::AnyCategory;
const std::optional<TorrentIDSet> TorrentFilter::AnyID;
const std::optional<QString> 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<TorrentIDSet> &idSet
, const std::optional<QString> &category, const std::optional<QString> &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<TorrentIDSet> &idSet
, const std::optional<QString> &category, const std::optional<QString> &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<TorrentIDSet> &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<QString> &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<QString> &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);
}

View file

@ -28,6 +28,8 @@
#pragma once
#include <optional>
#include <QSet>
#include <QString>
@ -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<QString> AnyCategory;
static const std::optional<TorrentIDSet> AnyID;
static const std::optional<QString> 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<TorrentIDSet> &idSet = AnyID
, const std::optional<QString> &category = AnyCategory, const std::optional<QString> &tag = AnyTag);
TorrentFilter(const QString &filter, const std::optional<TorrentIDSet> &idSet = AnyID
, const std::optional<QString> &category = AnyCategory, const std::optional<QString> &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<TorrentIDSet> &idSet);
bool setCategory(const std::optional<QString> &category);
bool setTag(const std::optional<QString> &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<QString> m_category;
std::optional<QString> m_tag;
std::optional<TorrentIDSet> m_idSet;
};

View file

@ -140,6 +140,15 @@ namespace
}
}
std::optional<QString> getOptionalString(const StringMap &params, 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<QString> category = getOptionalString(params(), QLatin1String("category"));
const std::optional<QString> 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<TorrentIDSet> 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()))
{