song/Filter: move each class into a separate source

This commit is contained in:
Max Kellermann 2018-08-02 13:54:36 +02:00
parent 90201e9970
commit d929d0c26f
18 changed files with 691 additions and 345 deletions

View File

@ -1029,6 +1029,14 @@ libconf_a_SOURCES = \
libsong_a_SOURCES = \
src/song/DetachedSong.cxx src/song/DetachedSong.hxx \
src/song/ISongFilter.hxx \
src/song/UriSongFilter.hxx \
src/song/StringFilter.cxx src/song/StringFilter.hxx \
src/song/UriSongFilter.cxx src/song/UriSongFilter.hxx \
src/song/BaseSongFilter.cxx src/song/BaseSongFilter.hxx \
src/song/TagSongFilter.cxx src/song/TagSongFilter.hxx \
src/song/ModifiedSinceSongFilter.cxx src/song/ModifiedSinceSongFilter.hxx \
src/song/AndSongFilter.cxx src/song/AndSongFilter.hxx \
src/song/Filter.cxx src/song/Filter.hxx \
src/song/LightSong.cxx src/song/LightSong.hxx

View File

@ -29,6 +29,9 @@
#include "song/LightSong.hxx"
#include "db/Stats.hxx"
#include "song/Filter.hxx"
#include "song/UriSongFilter.hxx"
#include "song/BaseSongFilter.hxx"
#include "song/TagSongFilter.hxx"
#include "Compiler.h"
#include "config/Block.hxx"
#include "tag/Builder.hxx"

View File

@ -30,6 +30,8 @@
#include "db/DatabaseError.hxx"
#include "db/LightDirectory.hxx"
#include "song/LightSong.hxx"
#include "song/Filter.hxx"
#include "song/TagSongFilter.hxx"
#include "db/Stats.hxx"
#include "config/Block.hxx"
#include "tag/Builder.hxx"
@ -37,7 +39,6 @@
#include "tag/Mask.hxx"
#include "fs/Traits.hxx"
#include "Log.hxx"
#include "song/Filter.hxx"
#include "util/SplitString.hxx"
#include <string>

View File

@ -0,0 +1,63 @@
/*
* Copyright 2003-2018 The Music Player Daemon Project
* http://www.musicpd.org
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include "AndSongFilter.hxx"
ISongFilterPtr
AndSongFilter::Clone() const noexcept
{
auto result = std::make_unique<AndSongFilter>();
for (const auto &i : items)
result->items.emplace_back(i->Clone());
return result;
}
std::string
AndSongFilter::ToExpression() const noexcept
{
auto i = items.begin();
const auto end = items.end();
if (std::next(i) == end)
return (*i)->ToExpression();
std::string e("(");
e += (*i)->ToExpression();
for (++i; i != end; ++i) {
e += " AND ";
e += (*i)->ToExpression();
}
e.push_back(')');
return e;
}
bool
AndSongFilter::Match(const LightSong &song) const noexcept
{
for (const auto &i : items)
if (!i->Match(song))
return false;
return true;
}

View File

@ -0,0 +1,55 @@
/*
* Copyright 2003-2018 The Music Player Daemon Project
* http://www.musicpd.org
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_AND_SONG_FILTER_HXX
#define MPD_AND_SONG_FILTER_HXX
#include "ISongFilter.hxx"
#include "Compiler.h"
#include <list>
/**
* 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;
};
#endif

View File

@ -0,0 +1,35 @@
/*
* Copyright 2003-2018 The Music Player Daemon Project
* http://www.musicpd.org
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include "BaseSongFilter.hxx"
#include "LightSong.hxx"
#include "util/UriUtil.hxx"
std::string
BaseSongFilter::ToExpression() const noexcept
{
return "(base \"" + value + "\")";
}
bool
BaseSongFilter::Match(const LightSong &song) const noexcept
{
return uri_is_child_or_same(value.c_str(), song.GetURI().c_str());
}

View File

@ -0,0 +1,48 @@
/*
* Copyright 2003-2018 The Music Player Daemon Project
* http://www.musicpd.org
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_BASE_SONG_FILTER_HXX
#define MPD_BASE_SONG_FILTER_HXX
#include "ISongFilter.hxx"
#include "Compiler.h"
class BaseSongFilter final : public ISongFilter {
std::string value;
public:
BaseSongFilter(const BaseSongFilter &) = default;
template<typename V>
explicit BaseSongFilter(V &&_value)
:value(std::forward<V>(_value)) {}
const char *GetValue() const noexcept {
return value.c_str();
}
ISongFilterPtr Clone() const noexcept override {
return std::make_unique<BaseSongFilter>(*this);
}
std::string ToExpression() const noexcept override;
bool Match(const LightSong &song) const noexcept override;
};
#endif

View File

@ -19,6 +19,10 @@
#include "config.h"
#include "Filter.hxx"
#include "UriSongFilter.hxx"
#include "BaseSongFilter.hxx"
#include "TagSongFilter.hxx"
#include "ModifiedSinceSongFilter.hxx"
#include "LightSong.hxx"
#include "tag/ParseName.hxx"
#include "tag/Tag.hxx"
@ -75,158 +79,6 @@ locate_parse_type(const char *str) noexcept
return tag_name_parse_i(str);
}
bool
StringFilter::Match(const char *s) const noexcept
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(s != nullptr);
#endif
if (fold_case) {
return fold_case.IsIn(s);
} else {
return StringIsEqual(s, value.c_str());
}
}
std::string
UriSongFilter::ToExpression() const noexcept
{
return std::string("(" LOCATE_TAG_FILE_KEY " ") + (negated ? "!=" : "==") + " \"" + filter.GetValue() + "\")";
}
bool
UriSongFilter::Match(const LightSong &song) const noexcept
{
return filter.Match(song.GetURI().c_str()) != negated;
}
std::string
BaseSongFilter::ToExpression() const noexcept
{
return "(base \"" + value + "\")";
}
bool
BaseSongFilter::Match(const LightSong &song) const noexcept
{
return uri_is_child_or_same(value.c_str(), song.GetURI().c_str());
}
std::string
TagSongFilter::ToExpression() const noexcept
{
const char *name = type == TAG_NUM_OF_ITEM_TYPES
? LOCATE_TAG_ANY_KEY
: tag_item_names[type];
return std::string("(") + name + " " + (negated ? "!=" : "==") + " \"" + filter.GetValue() + "\")";
}
bool
TagSongFilter::MatchNN(const TagItem &item) const noexcept
{
return (type == TAG_NUM_OF_ITEM_TYPES || item.type == type) &&
filter.Match(item.value);
}
bool
TagSongFilter::MatchNN(const Tag &tag) const noexcept
{
bool visited_types[TAG_NUM_OF_ITEM_TYPES];
std::fill_n(visited_types, size_t(TAG_NUM_OF_ITEM_TYPES), false);
for (const auto &i : tag) {
visited_types[i.type] = true;
if (MatchNN(i))
return true;
}
if (type < TAG_NUM_OF_ITEM_TYPES && !visited_types[type]) {
/* If the search critieron was not visited during the
sweep through the song's tag, it means this field
is absent from the tag or empty. Thus, if the
searched string is also empty
then it's a match as well and we should return
true. */
if (filter.empty())
return true;
if (type == TAG_ALBUM_ARTIST && visited_types[TAG_ARTIST]) {
/* if we're looking for "album artist", but
only "artist" exists, use that */
for (const auto &item : tag)
if (item.type == TAG_ARTIST &&
filter.Match(item.value))
return true;
}
}
return false;
}
bool
TagSongFilter::Match(const LightSong &song) const noexcept
{
return MatchNN(song.tag) != negated;
}
std::string
ModifiedSinceSongFilter::ToExpression() const noexcept
{
return std::string("(modified-since \"") + FormatISO8601(value).c_str() + "\")";
}
bool
ModifiedSinceSongFilter::Match(const LightSong &song) const noexcept
{
return song.mtime >= value;
}
ISongFilterPtr
AndSongFilter::Clone() const noexcept
{
auto result = std::make_unique<AndSongFilter>();
for (const auto &i : items)
result->items.emplace_back(i->Clone());
return result;
}
std::string
AndSongFilter::ToExpression() const noexcept
{
auto i = items.begin();
const auto end = items.end();
if (std::next(i) == end)
return (*i)->ToExpression();
std::string e("(");
e += (*i)->ToExpression();
for (++i; i != end; ++i) {
e += " AND ";
e += (*i)->ToExpression();
}
e.push_back(')');
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,

View File

@ -20,13 +20,10 @@
#ifndef MPD_SONG_FILTER_HXX
#define MPD_SONG_FILTER_HXX
#include "lib/icu/Compare.hxx"
#include "AndSongFilter.hxx"
#include "Compiler.h"
#include <memory>
#include <string>
#include <list>
#include <chrono>
#include <stdint.h>
@ -37,195 +34,7 @@
template<typename T> struct ConstBuffer;
enum TagType : uint8_t;
struct Tag;
struct TagItem;
struct LightSong;
class ISongFilter;
using ISongFilterPtr = std::unique_ptr<ISongFilter>;
class ISongFilter {
public:
virtual ~ISongFilter() noexcept {}
virtual ISongFilterPtr Clone() const noexcept = 0;
/**
* Convert this object into an "expression". This is
* only useful for debugging.
*/
virtual std::string ToExpression() const noexcept = 0;
gcc_pure
virtual bool Match(const LightSong &song) const noexcept = 0;
};
class StringFilter {
std::string value;
/**
* This value is only set if case folding is enabled.
*/
IcuCompare fold_case;
public:
template<typename V>
StringFilter(V &&_value, bool _fold_case)
:value(std::forward<V>(_value)),
fold_case(_fold_case
? IcuCompare(value.c_str())
: IcuCompare()) {}
bool empty() const noexcept {
return value.empty();
}
const auto &GetValue() const noexcept {
return value;
}
bool GetFoldCase() const noexcept {
return fold_case;
}
gcc_pure
bool Match(const char *s) const noexcept;
};
class UriSongFilter final : public ISongFilter {
StringFilter filter;
bool negated;
public:
template<typename V>
UriSongFilter(V &&_value, bool fold_case, bool _negated)
:filter(std::forward<V>(_value), fold_case),
negated(_negated) {}
const auto &GetValue() const noexcept {
return filter.GetValue();
}
bool GetFoldCase() const {
return filter.GetFoldCase();
}
bool IsNegated() const noexcept {
return negated;
}
ISongFilterPtr Clone() const noexcept override {
return std::make_unique<UriSongFilter>(*this);
}
std::string ToExpression() const noexcept override;
bool Match(const LightSong &song) const noexcept override;
};
class BaseSongFilter final : public ISongFilter {
std::string value;
public:
BaseSongFilter(const BaseSongFilter &) = default;
template<typename V>
explicit BaseSongFilter(V &&_value)
:value(std::forward<V>(_value)) {}
const char *GetValue() const noexcept {
return value.c_str();
}
ISongFilterPtr Clone() const noexcept override {
return std::make_unique<BaseSongFilter>(*this);
}
std::string ToExpression() const noexcept override;
bool Match(const LightSong &song) const noexcept override;
};
class TagSongFilter final : public ISongFilter {
TagType type;
bool negated;
StringFilter filter;
public:
template<typename V>
TagSongFilter(TagType _type, V &&_value, bool fold_case, bool _negated)
:type(_type), negated(_negated),
filter(std::forward<V>(_value), fold_case) {}
TagType GetTagType() const {
return type;
}
const auto &GetValue() const noexcept {
return filter.GetValue();
}
bool GetFoldCase() const {
return filter.GetFoldCase();
}
bool IsNegated() const noexcept {
return negated;
}
ISongFilterPtr Clone() const noexcept override {
return std::make_unique<TagSongFilter>(*this);
}
std::string ToExpression() const noexcept override;
bool Match(const LightSong &song) const noexcept override;
private:
bool MatchNN(const Tag &tag) const noexcept;
bool MatchNN(const TagItem &tag) const noexcept;
};
class ModifiedSinceSongFilter final : public ISongFilter {
std::chrono::system_clock::time_point value;
public:
explicit ModifiedSinceSongFilter(std::chrono::system_clock::time_point _value) noexcept
:value(_value) {}
ISongFilterPtr Clone() const noexcept override {
return std::make_unique<ModifiedSinceSongFilter>(*this);
}
std::string ToExpression() const noexcept override;
bool Match(const LightSong &song) const noexcept override;
};
/**
* 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;

48
src/song/ISongFilter.hxx Normal file
View File

@ -0,0 +1,48 @@
/*
* Copyright 2003-2018 The Music Player Daemon Project
* http://www.musicpd.org
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_I_SONG_FILTER_HXX
#define MPD_I_SONG_FILTER_HXX
#include "Compiler.h"
#include <memory>
#include <string>
struct LightSong;
class ISongFilter;
using ISongFilterPtr = std::unique_ptr<ISongFilter>;
class ISongFilter {
public:
virtual ~ISongFilter() noexcept {}
virtual ISongFilterPtr Clone() const noexcept = 0;
/**
* Convert this object into an "expression". This is
* only useful for debugging.
*/
virtual std::string ToExpression() const noexcept = 0;
gcc_pure
virtual bool Match(const LightSong &song) const noexcept = 0;
};
#endif

View File

@ -0,0 +1,35 @@
/*
* Copyright 2003-2018 The Music Player Daemon Project
* http://www.musicpd.org
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include "ModifiedSinceSongFilter.hxx"
#include "LightSong.hxx"
#include "util/TimeISO8601.hxx"
std::string
ModifiedSinceSongFilter::ToExpression() const noexcept
{
return std::string("(modified-since \"") + FormatISO8601(value).c_str() + "\")";
}
bool
ModifiedSinceSongFilter::Match(const LightSong &song) const noexcept
{
return song.mtime >= value;
}

View File

@ -0,0 +1,42 @@
/*
* Copyright 2003-2018 The Music Player Daemon Project
* http://www.musicpd.org
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_MODIFIED_SINCE_SONG_FILTER_HXX
#define MPD_MODIFIED_SINCE_SONG_FILTER_HXX
#include "ISongFilter.hxx"
#include <chrono>
class ModifiedSinceSongFilter final : public ISongFilter {
std::chrono::system_clock::time_point value;
public:
explicit ModifiedSinceSongFilter(std::chrono::system_clock::time_point _value) noexcept
:value(_value) {}
ISongFilterPtr Clone() const noexcept override {
return std::make_unique<ModifiedSinceSongFilter>(*this);
}
std::string ToExpression() const noexcept override;
bool Match(const LightSong &song) const noexcept override;
};
#endif

39
src/song/StringFilter.cxx Normal file
View File

@ -0,0 +1,39 @@
/*
* Copyright 2003-2018 The Music Player Daemon Project
* http://www.musicpd.org
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include "StringFilter.hxx"
#include "util/StringCompare.hxx"
#include <assert.h>
bool
StringFilter::Match(const char *s) const noexcept
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(s != nullptr);
#endif
if (fold_case) {
return fold_case.IsIn(s);
} else {
return StringIsEqual(s, value.c_str());
}
}

60
src/song/StringFilter.hxx Normal file
View File

@ -0,0 +1,60 @@
/*
* Copyright 2003-2018 The Music Player Daemon Project
* http://www.musicpd.org
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_STRING_FILTER_HXX
#define MPD_STRING_FILTER_HXX
#include "lib/icu/Compare.hxx"
#include "Compiler.h"
#include <string>
class StringFilter {
std::string value;
/**
* This value is only set if case folding is enabled.
*/
IcuCompare fold_case;
public:
template<typename V>
StringFilter(V &&_value, bool _fold_case)
:value(std::forward<V>(_value)),
fold_case(_fold_case
? IcuCompare(value.c_str())
: IcuCompare()) {}
bool empty() const noexcept {
return value.empty();
}
const auto &GetValue() const noexcept {
return value;
}
bool GetFoldCase() const noexcept {
return fold_case;
}
gcc_pure
bool Match(const char *s) const noexcept;
};
#endif

View File

@ -0,0 +1,82 @@
/*
* Copyright 2003-2018 The Music Player Daemon Project
* http://www.musicpd.org
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include "TagSongFilter.hxx"
#include "LightSong.hxx"
#include "tag/Tag.hxx"
std::string
TagSongFilter::ToExpression() const noexcept
{
const char *name = type == TAG_NUM_OF_ITEM_TYPES
? "any"
: tag_item_names[type];
return std::string("(") + name + " " + (negated ? "!=" : "==") + " \"" + filter.GetValue() + "\")";
}
bool
TagSongFilter::MatchNN(const TagItem &item) const noexcept
{
return (type == TAG_NUM_OF_ITEM_TYPES || item.type == type) &&
filter.Match(item.value);
}
bool
TagSongFilter::MatchNN(const Tag &tag) const noexcept
{
bool visited_types[TAG_NUM_OF_ITEM_TYPES];
std::fill_n(visited_types, size_t(TAG_NUM_OF_ITEM_TYPES), false);
for (const auto &i : tag) {
visited_types[i.type] = true;
if (MatchNN(i))
return true;
}
if (type < TAG_NUM_OF_ITEM_TYPES && !visited_types[type]) {
/* If the search critieron was not visited during the
sweep through the song's tag, it means this field
is absent from the tag or empty. Thus, if the
searched string is also empty
then it's a match as well and we should return
true. */
if (filter.empty())
return true;
if (type == TAG_ALBUM_ARTIST && visited_types[TAG_ARTIST]) {
/* if we're looking for "album artist", but
only "artist" exists, use that */
for (const auto &item : tag)
if (item.type == TAG_ARTIST &&
filter.Match(item.value))
return true;
}
}
return false;
}
bool
TagSongFilter::Match(const LightSong &song) const noexcept
{
return MatchNN(song.tag) != negated;
}

View File

@ -0,0 +1,75 @@
/*
* Copyright 2003-2018 The Music Player Daemon Project
* http://www.musicpd.org
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_TAG_SONG_FILTER_HXX
#define MPD_TAG_SONG_FILTER_HXX
#include "ISongFilter.hxx"
#include "StringFilter.hxx"
#include <stdint.h>
template<typename T> struct ConstBuffer;
enum TagType : uint8_t;
struct Tag;
struct TagItem;
struct LightSong;
class TagSongFilter final : public ISongFilter {
TagType type;
bool negated;
StringFilter filter;
public:
template<typename V>
TagSongFilter(TagType _type, V &&_value, bool fold_case, bool _negated)
:type(_type), negated(_negated),
filter(std::forward<V>(_value), fold_case) {}
TagType GetTagType() const {
return type;
}
const auto &GetValue() const noexcept {
return filter.GetValue();
}
bool GetFoldCase() const {
return filter.GetFoldCase();
}
bool IsNegated() const noexcept {
return negated;
}
ISongFilterPtr Clone() const noexcept override {
return std::make_unique<TagSongFilter>(*this);
}
std::string ToExpression() const noexcept override;
bool Match(const LightSong &song) const noexcept override;
private:
bool MatchNN(const Tag &tag) const noexcept;
bool MatchNN(const TagItem &tag) const noexcept;
};
#endif

View File

@ -0,0 +1,34 @@
/*
* Copyright 2003-2018 The Music Player Daemon Project
* http://www.musicpd.org
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include "UriSongFilter.hxx"
#include "LightSong.hxx"
std::string
UriSongFilter::ToExpression() const noexcept
{
return std::string("(file ") + (negated ? "!=" : "==") + " \"" + filter.GetValue() + "\")";
}
bool
UriSongFilter::Match(const LightSong &song) const noexcept
{
return filter.Match(song.GetURI().c_str()) != negated;
}

View File

@ -0,0 +1,57 @@
/*
* Copyright 2003-2018 The Music Player Daemon Project
* http://www.musicpd.org
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_URI_SONG_FILTER_HXX
#define MPD_URI_SONG_FILTER_HXX
#include "ISongFilter.hxx"
#include "StringFilter.hxx"
class UriSongFilter final : public ISongFilter {
StringFilter filter;
bool negated;
public:
template<typename V>
UriSongFilter(V &&_value, bool fold_case, bool _negated)
:filter(std::forward<V>(_value), fold_case),
negated(_negated) {}
const auto &GetValue() const noexcept {
return filter.GetValue();
}
bool GetFoldCase() const {
return filter.GetFoldCase();
}
bool IsNegated() const noexcept {
return negated;
}
ISongFilterPtr Clone() const noexcept override {
return std::make_unique<UriSongFilter>(*this);
}
std::string ToExpression() const noexcept override;
bool Match(const LightSong &song) const noexcept override;
};
#endif