SongFilter: move code from SongFilter to AndSongFilter

This commit is contained in:
Max Kellermann 2018-07-29 18:39:47 +02:00
parent 2da5b7cb65
commit 1b5faf5cbf
2 changed files with 77 additions and 27 deletions

View File

@ -185,19 +185,19 @@ ModifiedSinceSongFilter::Match(const LightSong &song) const noexcept
return song.mtime >= value;
}
SongFilter::SongFilter(TagType tag, const char *value, bool fold_case)
ISongFilterPtr
AndSongFilter::Clone() const noexcept
{
items.emplace_back(std::make_unique<TagSongFilter>(tag, value,
fold_case, false));
}
auto result = std::make_unique<AndSongFilter>();
SongFilter::~SongFilter()
{
/* this destructor exists here just so it won't get inlined */
for (const auto &i : items)
result->items.emplace_back(i->Clone());
return result;
}
std::string
SongFilter::ToExpression() const noexcept
AndSongFilter::ToExpression() const noexcept
{
auto i = items.begin();
const auto end = items.end();
@ -217,6 +217,33 @@ SongFilter::ToExpression() const noexcept
return e;
}
bool
AndSongFilter::Match(const LightSong &song) const noexcept
{
for (const auto &i : items)
if (!i->Match(song))
return false;
return true;
}
SongFilter::SongFilter(TagType tag, const char *value, bool fold_case)
{
and_filter.AddItem(std::make_unique<TagSongFilter>(tag, value,
fold_case, false));
}
SongFilter::~SongFilter()
{
/* this destructor exists here just so it won't get inlined */
}
std::string
SongFilter::ToExpression() const noexcept
{
return and_filter.ToExpression();
}
static std::chrono::system_clock::time_point
ParseTimeStamp(const char *s)
{
@ -352,15 +379,15 @@ SongFilter::Parse(const char *tag_string, const char *value, bool fold_case)
if (!uri_safe_local(value))
throw std::runtime_error("Bad URI");
items.emplace_back(std::make_unique<BaseSongFilter>(value));
and_filter.AddItem(std::make_unique<BaseSongFilter>(value));
break;
case LOCATE_TAG_MODIFIED_SINCE:
items.emplace_back(std::make_unique<ModifiedSinceSongFilter>(ParseTimeStamp(value)));
and_filter.AddItem(std::make_unique<ModifiedSinceSongFilter>(ParseTimeStamp(value)));
break;
case LOCATE_TAG_FILE_TYPE:
items.emplace_back(std::make_unique<UriSongFilter>(value,
and_filter.AddItem(std::make_unique<UriSongFilter>(value,
fold_case,
false));
break;
@ -369,7 +396,7 @@ SongFilter::Parse(const char *tag_string, const char *value, bool fold_case)
if (tag == LOCATE_TAG_ANY_TYPE)
tag = TAG_NUM_OF_ITEM_TYPES;
items.emplace_back(std::make_unique<TagSongFilter>(TagType(tag),
and_filter.AddItem(std::make_unique<TagSongFilter>(TagType(tag),
value,
fold_case,
false));
@ -391,7 +418,7 @@ SongFilter::Parse(ConstBuffer<const char *> args, bool fold_case)
if (*end != 0)
throw std::runtime_error("Unparsed garbage after expression");
items.emplace_back(std::move(f));
and_filter.AddItem(std::move(f));
continue;
}
@ -407,17 +434,13 @@ SongFilter::Parse(ConstBuffer<const char *> args, bool fold_case)
bool
SongFilter::Match(const LightSong &song) const noexcept
{
for (const auto &i : items)
if (!i->Match(song))
return false;
return true;
return and_filter.Match(song);
}
bool
SongFilter::HasFoldCase() const noexcept
{
for (const auto &i : items) {
for (const auto &i : and_filter.GetItems()) {
if (auto t = dynamic_cast<const TagSongFilter *>(i.get())) {
if (t->GetFoldCase())
return true;
@ -433,7 +456,7 @@ SongFilter::HasFoldCase() const noexcept
bool
SongFilter::HasOtherThanBase() const noexcept
{
for (const auto &i : items) {
for (const auto &i : and_filter.GetItems()) {
const auto *f = dynamic_cast<const BaseSongFilter *>(i.get());
if (f == nullptr)
return true;
@ -445,7 +468,7 @@ SongFilter::HasOtherThanBase() const noexcept
const char *
SongFilter::GetBase() const noexcept
{
for (const auto &i : items) {
for (const auto &i : and_filter.GetItems()) {
const auto *f = dynamic_cast<const BaseSongFilter *>(i.get());
if (f != nullptr)
return f->GetValue();
@ -460,7 +483,7 @@ SongFilter::WithoutBasePrefix(const char *_prefix) const noexcept
const StringView prefix(_prefix);
SongFilter result;
for (const auto &i : items) {
for (const auto &i : and_filter.GetItems()) {
const auto *f = dynamic_cast<const BaseSongFilter *>(i.get());
if (f != nullptr) {
const char *s = StringAfterPrefix(f->GetValue(), prefix);
@ -472,14 +495,14 @@ SongFilter::WithoutBasePrefix(const char *_prefix) const noexcept
++s;
if (*s != 0)
result.items.emplace_back(std::make_unique<BaseSongFilter>(s));
result.and_filter.AddItem(std::make_unique<BaseSongFilter>(s));
continue;
}
}
}
result.items.emplace_back(i->Clone());
result.and_filter.AddItem(i->Clone());
}
return result;

View File

@ -200,9 +200,36 @@ public:
bool Match(const LightSong &song) const noexcept override;
};
class SongFilter {
/**
* Combine multiple #ISongFilter instances with logical "and".
*/
class AndSongFilter final : public ISongFilter {
std::list<ISongFilterPtr> items;
public:
const auto &GetItems() const noexcept {
return items;
}
template<typename I>
void AddItem(I &&_item) {
items.emplace_back(std::forward<I>(_item));
}
gcc_pure
bool IsEmpty() const noexcept {
return items.empty();
}
/* virtual methods from ISongFilter */
ISongFilterPtr Clone() const noexcept override;
std::string ToExpression() const noexcept override;
bool Match(const LightSong &song) const noexcept override;
};
class SongFilter {
AndSongFilter and_filter;
public:
SongFilter() = default;
@ -236,12 +263,12 @@ public:
bool Match(const LightSong &song) const noexcept;
const auto &GetItems() const noexcept {
return items;
return and_filter.GetItems();
}
gcc_pure
bool IsEmpty() const noexcept {
return items.empty();
return and_filter.IsEmpty();
}
/**